Building a battery powered WiFi IoT Sensor with ESP8266, MS-5611 (GY-63), nodemcu and MQTT

Introduction

The ESP8266 is a 32 bit micro controller with an integrated WiFi chipset and TCP/IP stack. The flash is connected via SPI. Firmware upgrades can be done via the serial port after booting with GPIO0 pulled to ground (I’m using esptool.py). A GCC based toolchain is available. This led to a few alternative firmwares (the stock one provides AT commands to use the ESP8266 as wifi module). For our IoT sensor (buzzword bingo!) we’re going to use nodemcu. It will allow us to write code for the MCU in lua script. The EPS8266 can be sourced in different variants. I’m using the ESP12 as it has headers for most of the MCUs pins. Mine is soldered onto a PCB (bought as bundle on eBay) to make interfacing easier. The PCB also pulls up CH_PD, which is needed to start up the ESP:
ESP8266 ESP12

Circuit requirements

The two 4,7k pull-ups on GPIO0 and GPIO2 prevent a “zombie” mode when returning from deep sleep (more details here). GPIO16 has to be wired together with RST (orange wire on the right) and also pulled high. Deep sleep is implemented by running an internal timer which will reset (!) the ESP to get out of the sleep mode. Without that wiring, node.dsleep() from nodemcu is not going to work.

As the ESP needs 3,3v, a step-up converter will provide that voltage from two NiMH batteries. Make sure to use an USB/serial-TTL converter with 3,3V levels. There’re reports on the net from people having fried the chip with 5V levels.

MS-5611 sensor communication

A MS-5611 sensor will provide us with pressure and temperature readings. The data sheet can be found here: MS5611 Datasheet. I’m using the GY-63 from a Chinese eBay seller. It provides headers for I2C:
GY-63

The I2C communication is straightforward. Nodemcu provides i2c support. Depending on the solder bridge it talks on 0x76 or 0x77 (default on the gy63). 0x1e will reset the chip, afterwards 6 words of factory calibration eprom data can be gathered starting at 0xa2. 3 bytes of A/D data can be sampled from 0x48 (D1, pressure) and 0x50 (D2, temp) after writing 0x00 and waiting a bit. This screenshot from the scope shows a temperature response:
MS5611 I2C Communication

The formula for calculating the sensor values from A/D data is specified in the data sheet. nodemcu allows us to use it 1:1 in lua:

dT = D2 - caldata[5]*2^8
TEMP = 2000 + dT * caldata[6] / 2 ^ 23
OFF = caldata[2] * 2 ^ 16 + (caldata[4] * dT)/2^7
SENS = caldata[1] * 2 ^ 15 + (caldata[3] * dT)/2^8
P = (D1 * SENS / 2^21 - OFF)/2^15

You can find the complete lua snippet here. “read_pressure(dev_addr) and read_temp(dev_addr) will provide you with the sensor data. Don’t forget to specify the proper pins in the file. Be aware that the pin numbers don’t correspond to the GPIOx. A mapping table can be found in the nodemcu README.

MQTT publish

Nodemcu also provides us with MQTT support. Be aware that you need a broker supporting version 3.1.1 for nodemcu firmware version 20150127 and later. Using it is straight-forward in our example:

m:publish("sensors/".. CLIENTID .. "/temperature",read_temp(i2c_addr),0,0, function(conn)
print ("temp published")
m:publish("sensors/".. CLIENTID .. "/pressure",read_pressure(i2c_addr),0,0, function(conn)
print ("pressure published")
node.dsleep(60*1000000)
end)
end)

Please note the callback functions. nodemcu needs to run background tasks. Hence we can’t use blocking functions but need to rely on callbacks. The callback from the second publish will put the ESP into deep sleep. The whole code can be found here. Also worth mentioning is the “dofile(“baro.lc”) call. I had to compile (with “node.compile(‘baro.lua’)”) the baro.lua code into a .lc file. This will save heap space (and also instructions during each wakeup). When using the non-compiled version, the second MQTT publish did not work due to lack of heap space.

Autostart

As the deep sleep resets the ESP on wakeup, and as we also want our code to start automatically on power up, we need an “init.lua” file to get things going. You can find it here. It is not directly calling the mqtt.lua code, but setting up a timer. This gives us three seconds to interrupt the “autostart”, which is quite helpful during development (or to change SSID settings). A second timer makes sure that we enter deep sleep after 15 seconds. This will kick in if the mqtt publish would not callback for whatever reasons (e.g. connection errors). Clearing timers 0 and 1 right after startup will provide you with a lua shell.

To facilitate development, you can use the Java based ESPlorer tool:
ESPlorer
It allows easy file uploads, and provides buttons for commands like the timer reset. Very recommended.

MQTT broker

The Mosquitto project provides us with a version 3.1.1 message broker. The stock packages on Debian wheezy don’t support 3.1.1 yet. Follow these instructions to configure the mosquitto repository.

Interfacing ago control

A few lines of python together with the agoclient and the paho mqtt client module will bridge the MQTT messages to ago control. You can find the sample code here. Debug output from agoMQTT.py:

2015-03-01 18:52:35,003 AgoMQTT INFO Received MQTT message on topic sensors/ESP8266-10316383/pressure: 970.11159829194
2015-03-01 18:52:35,046 AgoConnection TRACE Sending message [sub=event.environment.pressurechanged]: {'instance': 'mqtt', 'uuid': 'e093a180-b2fb-445a-a0b7-e4a196429c87', 'unit': 'mBar', 'level': 970.11159829194}
2015-03-01 18:52:34,930 AgoMQTT INFO Received MQTT message on topic sensors/ESP8266-10316383/temperature: 25.032241477966
2015-03-01 18:52:34,942 AgoConnection TRACE Sending message [sub=event.environment.temperaturechanged]: {'instance': 'mqtt', 'uuid': 'b4e0a793-164d-49c6-a8f1-e691a5232ec3', 'unit': 'degC', 'level': 25.032241477966}

So finally we have data logging and nice graphs in ago control:
agocontrol graph
Screen Shot 2015-03-02 at 16.13.15
Of course you can do a lot more things in ago control with the sensor data, like triggering action based on sensor values.

Conclusion

While there are a lot of Wifi modules on the market, the ESP8266 has some benefits. It is very cheap, it has a toolchain and powerful firmwares. Together with MQTT and ago control it is very easy to build powerful IoT (buzzword bingo! again) devices. I’ll measure power consumptions over the next days. The code needs to be cleaned up, there’s still some potential for power usage reduction. “mqtt.lua” should be compiled. Removing debug statements will also save some cycles. Comments welcome.