Two of the features which most impressed me of the Particle Photon were its built-in WiFi, and the possibility of updating the device over the air (OTA). However, using a Photon as, say, a simple temperature sensor is quite expensive at over EUR 23.00 when purchased here.
Dirt cheap in comparison is one of the ESP family of microcontrollers and development boards, and I ordered a few so-called NodeMCU dev kits (right in photo at EUR 3.89 a piece) and Wemos D1 (center, at EUR 3.63 per unit). I have not made a mistake on the price tags; they even include postage and handling from China. All we need is a fortnight’s patience. (And while waiting you find that the adorable Wemos-D1 has a boat-load of shields which you should also have ordered … :-)
Both of these are based on the ESP8266, and as such they have on-board WiFi. The NodeMCU can be flashed with firmware which supports the Lua programming language (or even BASIC I hear). I’ve settled on using an environment I’m more or less comfortable with, namely the Arduino for ESP8266 firmware which is trivial to install through the Arduino IDE.
These little microcontrollers just work, but what is a bit of a chore is having to invent boilerplate code which enables reconnection, reboot on error, etc.
I stumbled over a project called homie-esp8266 created by Marvin Roger. It’s basically a small framework which couples the ESP8266 to MQTT and provides automatic connection/reconnection handling, JSON configuration, an optional Web UI to configure the microcontroller which starts up in Access Point mode initially, and Over-The-Air support for updating the code I create for the ESP8266. Yes: OTA support, and TLS.
Martin has obviously carefully thought about how a device should interact with its environment, and the code reflects this. So, as an example, when one of my sensors launches, it will publish these retained MQTT messages:
sensors/homie/cf3a07e0/$nodes light:light,temperature:temperature,relay:relay
sensors/homie/cf3a07e0/$online true
sensors/homie/cf3a07e0/$name Livingroom bookshelf
sensors/homie/cf3a07e0/$localip 192.168.1.192
sensors/homie/cf3a07e0/$fwname h-sensor
sensors/homie/cf3a07e0/$fwversion 1.0.1
sensors/homie/cf3a07e0/temperature/unit c
sensors/homie/cf3a07e0/$signal 96
sensors/homie/cf3a07e0/temperature/degrees 23.38
$nodes
inform the consumer about the type of endpoints I’ve made available on the device. $online
indicates whether the device is currently alive, $name
is a description I initially assign to the device, $signal
is an indication of WiFi coverage as seen by the microcontroller, etc. Then the device starts publishing a temperature and whatever other sensor data I wish to make available from the device.
The homie-esp8266 framework also listens for messages: for example, I can switch a relay I have connected to a Wemos-D1 with the following command:
mosquitto_pub -t 'sensors/homie/cf3a07e0/relay/on/set' -m true
The code I create for the device is invoked when Homie receives above publish, and it can then do something, e.g. switch the relay on, and instruct Homie to note that the action occurred, whereupon Homie will publish a retained value indicating the current state to (note the missing /set
at the end of this topic):
sensors/homie/cf3a07e0/relay/on true
Using the homie-esp8266 framework makes this trivial to do:
#include <Homie.h>
#define RELAY_PIN 16
HomieNode relayNode("relay", "relay");
bool relayHandler(String message)
{
if (message == "true") {
digitalWrite(RELAY_PIN, HIGH);
Homie.setNodeProperty(relayNode, "on", "true");
} else if (message == "false") {
digitalWrite(RELAY_PIN, LOW);
Homie.setNodeProperty(relayNode, "on", "false");
} else {
return false;
}
return true;
}
void setup()
{
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
Homie.setFirmware("h-sensor", "1.0.1");
relayNode.subscribe("on", relayHandler);
Homie.registerNode(relayNode);
Homie.setup();
}
void loop()
{
Homie.loop();
}
I mentioned above that Homie, can be configured via a Web-based interface when a device initially starts (to be quite clear: the site in the screenshot justs hosts the HTML to talk to your Homie ESP; the device itself doesn’t talk to the cloud):
Once that is done, the device connects to the WiFi network you specify during configuration, and starts operating on that. Alternatively, we can upload a JSON configuration file to the flash file system on the device or create that programatically (which is what I did, using a small sketch). The great advantage of storing the configuration separately from the actual Homie firmware is I can reflash (for example OTA) a different sketch onto the device and it will use the previous configuration settings (e.g. for MQTT broker, port, etc.).
OTA updates are triggered by publishing a version number to the $ota
endpoint; Homie then verifies the version it’s received is higher than the one it’s running, and instructs the ESP to boot and get the update via HTTP/HTTPS. (How this works is rather well explained here.) I think it’s important to mention that the homie-esp8266 framework is cloudless; it doesn’t require a cloud service, and it talks exactly to the servers you configure it to speak to.
Homie’s documentation is good and plentiful, and there are examples to get us started quickly. Marvin has been tremendously helpful, and he very quickly implemented the possibility to define a base_topic
for MQTT publishes when I asked him to.
A stamp-sized chip with on-board WiFi and 4MB of flash which speaks MQTT over TLS and can be updated OTA for under EUR 4.00. Exciting times.
Further reading:
-
Ben found another firmware for ESPs called ESPEasy. I gave it a glance, and it looks quite capable, but it appears to be geared to people who want a bit more of a toolbox on their ESP.
-
A small PCB for an ESP8266 sensor device with Homie and OpenHAB