In the second post in this series, I will setup two ESP8266 microcontrollers with MQTT publishing through a Raspberry Pi-hosted Mosquitto broker. The idea is that the microcontrollers will send sensor data (like temperatures or other events) that one or several MQTT subscribers can act on.
For an overview of MQTT, Mosquitto and paho-mqtt, see my previous post:
MQTT client libraries for Arduino
I have three different WiFi-based microcontrollers at my disposal that I can use for IP-based communication of sensor data.
They are all based on the ESP8266-chip that has a TCP/IP WiFi-stack, and each development board provides a USB-connection for programming and debugging and GPIO pins for connecting sensors and other electronics.
I will use the Arduino IDE for programming the microcontrollers. Though the brands of the boards are different, the “General ESP8266 board”-settings in the Arduino IDE works well for all of them in my examples.
There are several libraries available for the Arduino IDE that let’s you program an MQTT client. I will use the PubSub client library in this example.
The PubSub client library
To get started we need a WiFiClient object (from the ESP8266WiFi library) that sets up the WiFi communication. Then I create a PubSubClient and pass in the required parameters (the host name/ip-address of the broker + port and a reference to the WiFiClient). Calling connect() with an arbitrary client name on the MQTTClient object connects to the broker, and then we can add subscriptions to any number of topics with multiple subscribe() calls.
In the loop method, a publish() is made from the PubSubClient to the broker. mqttClient.loop() will check for new incoming messages and trigger the calllback if there are any messages to process. This method also maintains the connection to the broker so it should be called regularly. The sketch looks like this:
After this sketch is uploaded to an ESP8266-board, we can run a subscriber on the Raspberry Pi (or any other machine on the local LAN):
mosquitto_sub -h 192.168.1.16 -t 'ESP8266/#'
Every tenth second, there should be a new value coming to the subscriber and it should be echoed in the terminal.
If we make a publish call from the RPi with a topic that the ESP8266 listens to:
mosquitto_pub -h 192.168.1.16 -t 'InterestingTopics/Hellos' -m 'Hello from RPi'
there will be a serial output in the Arduino IDE from the ESP8266 saying “Hello from RPi”.
Setting up a real environment with sensors
In my IoT-environment I have the ESP8266 boards placed in two different places where they measure different things:
- Board 1: Placed in the garage. Measures indoor- and outdoor temperatures and humidity levels.
- Board 2: Placed on the ground floor. Measures indoor temperature and humidity and also the soil moisture level for one houseplant.
These 7 measurements can be structured in a topic hierarchy:
Setting up the garage ESP8266 board
The first board is located in our garage. It has two DHT22 temperature/humidity sensors attached. One DHT22 is placed on the outside wall and its wires goes through a ventilation shaft to the ESP8266 board that is located on the inside.
The sketch for this board looks like this:
Setting up the groundfloor ESP8266 board
The ground floor ESP8266 board has one DHT22 sensor for temperature and humidity and also a soil moisture sensor. The moisture sensor gives an analogue 0-3.3V signal on moisture level but also a digital 0v/3.3V when the moisture level reaches a certain value (that can be adjusted by a rotary resistor). As the ESP8266 boards only can handle max 1V as analogue signal level but max 3.3V as digital input, I have used the digital signal.
The sketch is very similar to the GarageClient. What’s different is the sensor values that are fetched in the Arduino loop:
Setting up the subscriber
For the Python script created in Part 1 to handle these new data, I only need to change what topics to subscribe to. As I want to listen to all “Home” messages, I simply subscribe to “Home/#”:
With the publishers set up to send data every 10 minutes, the output from the subscriber looks like this:
2016-06-24 15:04:15.363821: Home/GroundFloor/Humidity b'50.90' 2016-06-24 15:04:15.407021: Home/GroundFloor/Temperature b'25.10' 2016-06-24 15:04:15.410185: Home/GroundFloor/PlantStatus b'Plant is ok!' 2016-06-24 15:05:45.564683: Home/Outdoor/Humidity b'82.0' 2016-06-24 15:05:45.612739: Home/Outdoor/Temperature b'19.79' 2016-06-24 15:05:45.624698: Home/Garage/Humidity b'61.40' 2016-06-24 15:05:45.631266: Home/Garage/Temperature b'23.39' 2016-06-24 15:14:10.216790: Home/GroundFloor/Humidity b'50.90' 2016-06-24 15:14:10.257263: Home/GroundFloor/Temperature b'25.10' 2016-06-24 15:14:10.261389: Home/GroundFloor/PlantStatus b'Plant is ok!'
The next step will be to extend the Python subscriber so that it persists all incoming data in a database. This will be the topic for the next post in this series:
All code for these examples are available from GitHub: