Building a Multisensor for Home Assistant – Part 2

In part 1, I was building a light sensor, but now it’s morphed into a multi-sensor

Running against my recent terrible Aliexpress streak, the remaining bits actually arrived. Here’s the items I’ve used to build a great little multi-sensor that pumps data into Home Assistant:

Total: US$8.38
Item Details Price
Main Board Wemos Mini D1 (probably a clone). ESP8266 chip with integrated Wifi US$3.30
Luminosity Sensor TLS2561 I²C module US$1.11
Temp/Pressure/Humidity Sensor Bosch BME280 I²C module US$3.97

It’s a little surprising that the triple sensor is the most expensive part of the whole thing, but Bosch make nice electronics, and the BME280 is the current pick of the crop for these sorts of sensors. Probably total overkill for my use case. If you don’t care about air pressure and you wanted to save a dollar* you could get away with a DHT22.

*I bet you complain about $1.99 iPhone games too.

Tidying Up

First: procrastinate. I finally managed to find a use for this little multi-storage case I had lying around. Because it was cheaper to buy components in 5s and 10s, I now have a veritable caché of components. I just wish I had a label printer.

It’s ok, I know you want to be me.

Hooking Up

Here’s what the three components look like plugged together:

Components hooked together on breadboard

It’s nice that the pinouts for the TLS2561 and the BME280 line up with each other, so they can share columns on the breadboard and hook up tidily.

On the Wemos board, the pinouts connect like this:

ESP8266 pin Labelled board pin I²C Usage
3.3v 3V3 VCC

If you wire everything up like that, then the libraries I reference will work fine. In fact anything that uses Wire.h to talk I2C will work without having to redefine the pins used.

Reading Data

I’m using Platformio via the Atom editor to build code for this device. Platformio’s library management makes it almost trivially simple to talk to these devices. A quick search turned up several libraries for each of the sensors. This is what I used:

Both libraries have working example code that I used to prove that everything was wired up properly and spitting out debug data via the serial monitor. There’s some optional intricacies regarding configuration of the sensors for optimal accuracy/power balance, but the default settings seemed to work perfectly fine for me.

I would note though that I didn’t have much luck with the Adafruit sensor libraries. They worked fine on Arduino, but failed to work for me on the ESP8266. Probably caused by different pin configurations that a bit of debugging would fix, but the libraries above worked perfectly well for me, so being the lazy person I am, I used them instead.


There’s a few ways to do get data from Internet of Shit devices, but the canonical approach for plumbing IoT things together is MQTT. If you’ve never heard of it, don’t worry: neither had I until I started exploring home automation. MQTT is a nice, compact publish-subscribe protocol (I believe the kids call it pubsub), most commonly implemented using Mosquitto running on Linux.

You can publish data to MQTT by simply spitting messages at “topics”. Topics don’t need to exist, you can just create them on the fly. For example you can send the temperature value 22.4 from the command line into MQTT like this:

mosquitto_pub -h my.mqtt.servername -t 'some/random/topic/temperature' -m '22.4'

If you’re using Home Assistant, it comes with a built-in MQTT server, which is perfectly nice. However, because I’m a masochistic completionist, I’ve got a docker-compose system already running a bunch of important stuff (ahem, home videos) on my own server, so it was straightforward to set up a “proper” Mosquitto server using the official Eclipse container:

image: eclipse-mosquitto:latest
restart: always

view raw
hosted with ❤ by GitHub

Ingesting Data into Home Assistant

This bit is super easy (I keep saying stuff is easy, but this part really is). Home Assistant has a built-in MQTT component that can create sensors and switches from MQTT topics.

Given the above example, where we pushed a value into some/random/topic/temperature, we could turn that into a temperature sensor in Home Assistant with a teeny bit of yaml:

platform: mqtt
state_topic: "some/random/topic/temperature"
name: "Some Random Temperature Sensor"
unit_of_measurement: "°C"

view raw
hosted with ❤ by GitHub

From there, Home Assistant takes care of keeping track of any new values that appear on that topic in MQTT. It’ll create nice graphs, and you can drive automation off the values of this sensor. All pretty neat really. So the trick is to get the ESP8266 to publish data to MQTT.

You could write code in your sketch to make direct HTTP calls to MQTT containing the relevant topics and data, but that would be dumb. Ask yourself the important questions, like: what are you going to do when you have a fleet of 40 multi-sensors reporting humidity at 10 second intervals from every cupboard in your home? You’re not building home automation for ants.

Enter: Homie

Homie is a really great library that you can use with Platformio to quickly create configurable firmware to run on your ESP8266. It has some of the best documentation I’ve seen for an open source IoT project, and a well-documented “convention” that it adheres to.

One gotcha: don’t use the Platformio library manager to install Homie, because (as of writing) you’ll end up with the 1.5.0 branch. Instead download the zip of the develop branch and install that. The 2.0.0 branch is significantly improved from 1.5.0. I’m sure the 2.0.0 branch will be available to install directly sometime, but for now the zip is the only way to get it.

With Homie running on your ESP8266, you can send custom configuration json over the air (yes, you heard me: through the goddamn air). This means you can load the same code on every one of your 40 cupboard humidity sensors, then send custom config to give each one a unique name and the wifi access details. Neat! Now you’re going to have to assign an entire new DHCP subnet for your homies.

If you’ve done any Arduino/ESP “hello world” code, then you can use Homie. It introduces a setupHandler() and a loopHandler() where you write your code, and pretty much all I did was to lift the sample code for the TSL2561 and BME280 libraries, create some HomieNode objects, and set their values in the loopHandler(). The result, when I request the homie topic from my MQTT server looks like this:

homie/multi-sensor-1/$homie 2.0.0
homie/multi-sensor-1/$implementation esp8266
homie/multi-sensor-1/$implementation/version 2.0.0
homie/multi-sensor-1/$implementation/ota/enabled true
homie/multi-sensor-1/lux/$type lux
homie/multi-sensor-1/lux/$properties unit,lux
homie/multi-sensor-1/lux/unit lux
homie/multi-sensor-1/lux/lux 0.88
homie/multi-sensor-1/temperature/$type degrees
homie/multi-sensor-1/temperature/$properties unit,degrees
homie/multi-sensor-1/temperature/unit c
homie/multi-sensor-1/temperature/degrees 20.62
homie/multi-sensor-1/humidity/$type relative
homie/multi-sensor-1/humidity/$properties unit,relative
homie/multi-sensor-1/humidity/unit %
homie/multi-sensor-1/humidity/relative 61.00
homie/multi-sensor-1/pressure/$type hectopascals
homie/multi-sensor-1/pressure/$properties unit,hectopascals
homie/multi-sensor-1/pressure/unit hPa
homie/multi-sensor-1/pressure/hectopascals 1013.56
homie/multi-sensor-1/$name Multi Sensor
homie/multi-sensor-1/$localip 192.168.OP.SEC.LOL.IOT.¯\_(ツ)_/¯
homie/multi-sensor-1/$stats/interval 60
homie/multi-sensor-1/$stats/signal 100
homie/multi-sensor-1/$stats/uptime 84546
homie/multi-sensor-1/$fw/name awesome-multisensor
homie/multi-sensor-1/$fw/version 1.0.0
homie/multi-sensor-1/$fw/checksum 727ba7ce6ae18c465ff767f23543e5b6
homie/multi-sensor-1/$online true

view raw
mqtt data
hosted with ❤ by GitHub

Sweet as! You can see amongst all that ceremony, there are a few  lines that look exactly like what Home Assistant is looking for:

homie/multi-sensor-1/pressure/hectopascals 1013.56

homie/multi-sensor-1/temperature/degrees 20.62

The Upshot

Hooking it all up, I end up with some sweet, sweet sensor data rolling into Home Assistant.

Tune in next time when I annoy the shit out of my family by automating the lights based on luminosity data.

Summary of sensor values
Yes, the units on these graphs are completely screwed. Unsure what’s going on there, but I presume Home Assistant got confused.

My Terrible Code

Don’t copy this.

#include <Homie.h>
#include <SparkFunTSL2561.h>
#include <BME280I2C.h>
#include <Wire.h>
#include <SPI.h>
SFE_TSL2561 light;
BME280I2C bme;
boolean gain; // Gain setting, 0 = X1, 1 = X16;
unsigned int ms; // Integration ("shutter") time in milliseconds
unsigned long lastDataSent = 0;
// data nodes
HomieNode luxNode("lux", "lux");
HomieNode tempNode("temperature", "degrees");
HomieNode humidityNode("humidity", "relative");
HomieNode pressureNode("pressure", "hectopascals");
// custom setting for frequency of update
HomieSetting<long> intervalSetting("interval", "How often should this device send data (in seconds)");
void setupHandler() {
if (!bme.begin()) {
Homie.getLogger() << "Could not find a valid BME280 sensor, check wiring!" << endl;
gain = 0;
unsigned char time = 1;
Homie.getLogger() << "Setting up light sensor" << endl;
void sendLux() {
unsigned int data0, data1;
if (light.getData(data0,data1))
double lux; // Resulting lux value
boolean good; // True if neither sensor is saturated
// Perform lux calculation:
good = light.getLux(gain,ms,data0,data1,lux);
Homie.getLogger() << "Lux: " << lux << " lux" << endl;
// getData() returned false because of an I2C error, inform the user.
byte error = light.getError();
void sendTemp() {
float temp(NAN), hum(NAN), pres(NAN);
uint8_t pressureUnit(1);, temp, hum, true, pressureUnit);
Homie.getLogger() << "Temp: " << temp << "°C" << endl;
Homie.getLogger() << "Humidity: " << hum << "% RH" << endl;
Homie.getLogger() << "Pressure: " << pres << "hPa" << endl;
void loopHandler() {
if (millis() – lastDataSent >= intervalSetting.get() * 1000UL || lastDataSent == 0) {
lastDataSent = millis();
void setup() {
Serial << endl << endl;
intervalSetting.setDefaultValue(10).setValidator([] (long candidate) {
return (candidate >= 1) && (candidate <= 3600);
Homie_setFirmware("awesome-multisensor", "1.0.0");
void loop() {
void printError(byte error)
// If there's an I2C error, this function will
// print out an explanation.
Homie.getLogger() << "I2C error: " << error << ", ";
case 0:
Homie.getLogger() << "success";
case 1:
Homie.getLogger() << "data too long for transmit buffer";
case 2:
Homie.getLogger() << "received NACK on address (disconnected?)";
case 3:
Homie.getLogger() << "received NACK on data";
case 4:
Homie.getLogger() << "other error";
Homie.getLogger() << "unknown error";
Homie.getLogger() << endl;

view raw
hosted with ❤ by GitHub

1 comment

  1. Dear Ben.
    Thank you for your amazing Home Assistant articles using Homie and ESP8266.
    I look forward to part. 3 😀.
    I am most familiar with Arduino IDE, and my question is therefore: Can the same code and libraries be used under Arduino IDE?.
    However, I will consider trying Platformio in the near future.

    Best Regards
    Sune Bielefeldt


Leave a comment

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s