MQTT
MQTT, or Message Queuing Telemetry Transport, is a great protocol of when working with microcontrollers and sending relative small data payloads across networks. It was designed for the Internet of Things in mind, allowing for the fact that connections will invariably break and recover as devices move in and out of network range.
The best MQTT library for the mote mini is a fork of Nick O'Leary's PubSubClient by Ian Tester (@imroy) (BTW Nick O'Leary is also the lead developer for the nodeRED project). We are using @imroy's version as it supports the definition of custom port numbers. You need to install this library manually from github:
- Download the ZIP file of the latest release listed here
- In the Arduino IDE, go to
Sketch > Include Library > Add .ZIP Library...
and select the ZIP file - After installation you should be able to see the
PubSubClient
example sketches underFile > Examples > PubSubClient
.
A Brief Introduction
MQTT is a protocol – an agreed-upon set of communication methods that devices can use to send data between each other. Think of this as two devices saying: “OK, let's use English as the language to talk to one another. We'll do whatever we need to do on our ends to communicate with our sensors/peripherals, but when I send the data over to you, it'll be in English.”
The key things to note are that you'll need the following ‘actors’ in a MQTT topology:
(running on IoTa server)") B[mote B] --- Z C[any device supporting MQTT] --- Z Z --- D[mote C] Z --- E[mote D]
You need an MQTT server to handle incoming/outgoing messages. The server is like a post office – it routes and/or broadcasts messages depending on who the incoming message it meant for. One difference, as hinted in the previous sentence, is the ‘broadcast’: you can create a message that is meant for an entire fleet of devices through what is known as wildcarding.
HiveMQ does a great job of describing wildcarding – be sure to read it.
MQTT in the Arduino IDE environment
To use MQTT with your mote / mote mini, you will need to have WiFi properly set up. Once your mote has Internet connectivity (or local network where your server is running on), you can then configure the MQTT events and listeners.
1. Set up WiFi
The following code provides a simplified, annotated version of the WiFiClient example found in the Arduino IDE (File > Examples > ESP8266WiFi > WiFiClient
). It also has additional lines specific to our server configuration that you should take note of:
|
|
Upload and test this code on your mote mini – remember to open the Serial Monitor at 115200 baud to listen in to what your mote mini is doing. If you get the WiFi connected
message along with a local IP address, you are good to proceed to the next step.
2. Create a MQTT connection
Let's build on top of the above example and throw in the MQTT libraries. We will connect to the MQTT server that's running on iota.mdit.space
.
|
|
Unpacking this code…
Seems like quite a lot of new code here! Here are the same details broken down into bite-sized sections. Please note that the following 2x sections are just excerpts of code from the above recipe, so these won't compile if you only paste the below blocks into your Arduino IDE:
2a. Initialisation
|
|
This first part initialises the basic WiFi and MQTT instances that will be used in the rest of the sketch.
chipID
and devID
are just convenient String variables that store a unique code for your mote/mote mini in the device memory. This is crucial because you might have multiple devices talking to the server, and you want unique names for each. An example of devID
(yours will have a different 6-digit code after ‘ESP’):
ESP9a3c23
2b. Callback
|
|
Callbacks form one of the core concepts of Internet-related data services. Typically, a device (any device, from a mote to a laptop) puts out a request to some address, then continues doing its own tasks. When the response comes back, the callback function is triggered and the device process the incoming response. This is important because the Internet will not return information immediately, even if you have a very fast connection. This callback concept allows your device to not ‘hang’ and freeze up waiting for a response, which may also never arrive (for example, when your connection drops).
This block here basically prints the incoming topic and payload from the MQTT server. You can then, in this function, process the data and act on it accordingly.
2c. Custom device ID parser
A parser is just a little script that processes incoming data into something else. This function simply builds the ‘ESPxxxxxx’ device ID name from the system device information:
|
|
2d. void setup()
You should know what void setup()
does by now – it runs code ONCE when the device starts up/resets. In here it just establishes a Serial port connection via the mote programmer board's USB port, initialises the unique device ID, and registers the callback function to trigger when it receives data from the MQTT server:
|
|
2e. void loop()
You should know what void loop()
does, too – it runs code REPEATEDLY after setup concludes. This is where most of the interaction/processing happens. Due to its length let's break it down further into two segments:
|
|
This first section of the loop block above checks that we are still connected via WiFi – remember that devices will invariably drop off a WiFi network quite easily – walking it out of range, router resets, cat knocking the router off, etc… When it goes down, it will attempt to reconnect.
Next:
|
|
This portion above then proceeds with MQTT connection checking. Remember that WiFi and MQTT are two different things. The MQTT service needs WiFi to run; without WiFi there can be no MQTT service.
Next we perform a similar connectivity check in line 7 – if the MQTT connection has gone down, reconnect again, provided our WiFi connection is still up. mqtt_client.loop()
basically ‘pings’ the MQTT server once every so often just to let it know that the device is still connected and ‘alive’ – again, very useful things to have when dealing with wireless connections.
Finally, let's take a closer look at lines 11-23 from the above code block:
- Lines 11-15 connects the device to the MQTT server using
devID
as the unique identifier. It authenticates with a MQTT username and password (line 12) known only to us, sets a ‘keep-alive’ ping of 10 seconds (line 13) to keep reminding the MQTT server that the mote mini is still there, and declares a ‘clean session’ to be false, i.e. ‘dirty’, so that the oldest message will reach the device even after it reconnects (line 14). - Line 21 publishes an event to the MQTT server, using “group0/outTopic” as its topic name, and “hello world” as the payload. MQTT data is sent out as a topic/payload pair, which is akin to you sending an email with a subject title and body text. Notice the topic name and hopefully your familiarity with the MQTT intro flows on wildcarding and multi-level topics? You need to use a unique topic name for your group if you don't want stray messages from other groups!
- Line 22 subscribes to a topic called “group0/inTopic”. This means if the MQTT server sends any data out with a topic “group0/inTopic”, this device will receive it. Please note that there is NO basic wildcard support that you can do from within the Arduino IDE environment for now.
Next: where and how does this data go on the MQTT server?
We now have covered basic MQTT functionality on a mote/mote mini. That's Part 1, getting the electronic device to subscribe to and publish MQTT data. Part 2 deals with processing the data on the server.
Follow through to the IoTa > IoTa + MQTT section to see how we can accept the "hello world"
data on the server, and send a reply back to our device.
Once you get the basics of this relationship between device and server, you can then proceed to replace "hello world"
with sensor readings, instructions to trigger physical actuators, or read data off web services! More specific examples will be shared in class.
Further notes
The use of MQTT implies that you MUST have an MQTT data broker running on a server somewhere. This means your mote will rely on a seperate server to publish and/or receive data. While this is normally not a bad thing (a Raspberry Pi running Mosquitto on a local network can easily be a server), projects that are meant to run independently, i.e. off the Internet and/or electrical grid, will probably have challenges working with any networked data protocol.