The weather station and home monitor I built using the Particle-Core were working perfectly well, except that the weather station, being far from any power source, need to be run on battery. However, the power consumption of the Particle-Core was not too battery friendly even though it is designed to wake up each 10 minutes to report to Thingspeak the current temperature and humidity, the battery will ran out in a week or so. So I decided to give the new comer – the ESP8266 – a try.
I have a few NodeMCU dev boards on hand, and the NodeMCU is a breadboard friendly ESP8266 running a Lua interpreter and come with USB serial, a LED and buttons for Flashing and Reset. The ESP8266 is fully Wi-Fi capable and has very low power consumption. See my other post here about this board.
I also switched the temperature and relative humidity sensor from the AM2321 (it uses a non-standard I2C protocol and thus will not work with most standard I2C libraries) to a more accurate and modern one, the SI7021 from Silicon Labs which utilises “low-K polymer dielectrics provides excellent accuracy and long term stability, along with low drift and low hysteresis.” according to their documentation. This sensor also “combine fully factory-calibrated humidity and temperature sensor elements with an analog to digital converter, signal processing and an I2C host interface.”, perfect for this renewal.
SI7021 uses I2C, so it should be easy given the I2C support come with the NodeMCU, however, to my surprise, the NodeMCU firmware already comes with the library to support SI7021! Even though it does not come pre-included in the binary download, the module can be found in the firmware source (downloaded separately). Grab the file si7021.lua and download it together with the rests of the Lua files, a simple
si7021 = require("si7021")
will include the module into your Lua script and allow you to read the data from the sensor.
The following code allows you to obtain temperature and relative humidity readings from the sensor into the variables ‘t’ and ‘h’ for temperature and relative humidity:
SDA_PIN = 6 -- sda pin, GPIO12 SCL_PIN = 5 -- scl pin, GPIO14 si7021 = require("si7021") si7021.init(SDA_PIN, SCL_PIN) si7021.read(OSS) h = si7021.getHumidity() t = si7021.getTemperature()
In the previous version of my weather station, the data was uploaded periodically to thingspeak so that I can retrieve (the latest one) for my other applications, as well as to keep a historic record of the weather changes. This is still needed but I have a better idea.
Thingspeak uses a REST API and uploading data to it is not a big issue especially the ESP8266 already has Wi-Fi connectivity and the Lua library supports HTTP communications. However, getting the data uploaded and fetching it back for other devices is not efficient as each of these devices will need to pull from the Thingspeak API to get the latest results and if the Internet connection is out or become slow, the whole chain of information flow will be broken, this is definitely not ideal. Besides, this is a pull model and it works as long as the rate of data update is not high, and it is definitely not real time.
This is when MQTT comes into the picture.
MQTT is a light weight protocol developed by IBM for IoT and SCADA applications. It employs the pub/sub (publish/subscribe) architecture and is suitable for may IoT use case scenarios. The IoT devices could publish their sensor readings and at the same time, subscribe to a certain topics – they could be used to control the action of the IoT device (re-calibrate the sensors, flush buffers, etc..).
The NodeMCU firmware already supports the MQTT protocol, and since Lua on the NodeMCU is fully event driven, this make the choice of using of MQTT even more natural.
To initialise the MQTT client:
mqtt.Client(clientname, timeout, username, password) e.g. m = mqtt.Client("Client_Name", 120, null, null)
To connect the MQTT client to a MQTT broker:
mqtt:connect( host, port, secure, auto_reconnect, function(client)) e.g. m:connect(MQTTBrokerIP, MQTTBrokerPort, 0, 1)
To publish the temperature sensor reading, assuming the value is in ‘t’ with QoS=0 and retain=0:
mqtt:publish(topic,message,qos,retain) e.g. m:publish("home/outdoor/temperature",t,0,0)
See, it is easy! Now the sensor readings will be published to the MQTT broker whenever your logic decided.
Next step, the Broker.
A broker in the MQTT architecture serves as an aggregation point to collect and distribute information received from various publishing systems. Other than publishing information, a system can also subscribe to one or more specific “topic” such as home/livingroom/temperature or bank/bayareabranch/room3/sensors/motion, etc.. Wildcards are available when a system desire to subscribe to a group or hierarchy of topics.
I have chosen to use the Mosquitto as the MQTT broker, it supports the latest MQTT protocol 3.1.1 and is light-weighted, open-sourced, free and runs very well on a Raspberry Pi.
Configuration is dead simple – none required. The default port it listens to is 1883 but you can change it to whatever ports you like and can be done by changing the mosquitto.conf or by using the -p option.
You can even use the pub/sub commands that come with the mosquitto to publish to the subscribers:
mosquitto_pub -h broker_ip -t topic -m message e.g. mosquitto_pub -h 127.0.0.1 -t "home/livingroom/light02/dim" -m "58"
or to listen to the published information:
mosquitto_sub -h broker_ip -t topic e.g. mosquitto_sub -h 127.0.0.1 -t "home/livingroom/temperature" 24.8 24.6 24.7
On the Mac, you can use homebrew to install the mosquitto clients. It has both the mosquitto_pub and mosquitto_sub available.
Next is the control logic, what to do with all these sensors’ output.