A Beginner's Guide to MQTT

A Beginner's Guide to MQTT

MQTT (Message Queuing Telemetry Transport) is a lightweight, Machine to Machine (M2M) messaging protocol, primarily used in low power and resource constrained devices, because of which it’s widely employed in embedded computers or microcontrollers within the IoT community. This article will be an introduction to MQTT, followed by a step by step guide of making a simple MQTT client program for XinaBox CW01.

The Architecture:

MQTT is based on the publish/subscribe architecture, where the sender (publisher) sends the messages to a central communication hub known as the broker. The publisher also sends a topic along with the message. The subscribers, interested in a specific topic, subscribe to that topic, and the broker pushes all the messages with the matching topic to the interested subscribers. Notice the example below. A temperature sensor publishes a message “21°C” to the topic “temperature”, and the broker pushes the messages to clients subscribed to the said topic.

Courtesy of HiveMQ

Topics:

As mentioned earlier, messages are published against topics. A topic is a string treated as a hierarchical structure with multiple levels, with slash ‘/’ separating each topic level. Think of how you would use your computer directory structure to manage your documents, pictures, videos and other content, and each directory (such as pictures) can be further broken down to sub directories (such as family, friends, business etc).This allows for a clean classification of messages. For instance, multiple sensor nodes (clients) may all publish their weather information on the following topic pattern, with their name and weather parameter value being replaced as appropriate

[client_name]/weather/[feed]

Some possible topics using such schematic are

jack/weather/temperature
olivia/weather/barometric_pressure

Client can either subscribe to the exact topic, or can use special characters (known as wildcards) to filter out and subscribe to multiple topics following a desired pattern. MQTT provides two such wildcards. One is the multi-level wildcard ‘#’, which filters the topics against all the remaining levels of the hierarchy. This wildcard can only be used at the end of the topic. For example, to get all the weather feeds for the client “jack”, following topic can be used

jack/weather/#

Or to subscribe to every possible feed against the client jack use this

jack/#

Another such wildcard, the single-level wildcard ‘+’, is used for a single level of hierarchy, and can be used at any level. For example, to get the temperature feed for all the clients, topic can be structured like this

+/weather/temperature

Note: You may be wondering why use # when we can use + at any level. Well subscribing to a topic such a jack/# will give output on all the topics such as jack/weather/humidity, jack/weather/temperature or jack/weather/temperature/fahrenheit (multi level), but topic such as jack/+ will only give output on topics of the likes of jack/weather or jack/garage (single level), and not on the topics previously mentioned.

MQTT Client using CW01

Things you will need

 

Steps

  • First you will need to setup Arduino IDE for XinaBox's chips. Visit Getting Started for Arduino IDE to get quickly started with it.
  • Go to Tools > Include Library > Manage Libraries and search for pubsubclient. Install the one by Nick O’Leary as I already have below

  • Create a new sketch file. Start by including the required libraries at the beginning
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

Define the CW01 built-in LED

#define BUILTIN_LED 5 // Blue LED

Set the MQTT broker of your choice. We are using a public broker by Mosquitto

const char* mqtt_server = "test.mosquitto.org";

Create a PubSubClient object wrapping the WiFiClient

WiFiClient espClient;
PubSubClient client(espClient);

Create a setup_wifi function to connect to the specified WiFi

void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

randomSeed(micros());

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}

Create a function named callback that gets called whenever we receive a new message at the subscribed topic. This function simply prints the received message, as well as turns the built-in LED on if the message received is “1”, and off if it is “0”

void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();

// Switch on the LED if an 1 was received as first character
if ((char)payload[0] == '1') {
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED on
} else {
digitalWrite(BUILTIN_LED, LOW); // Turn the LED off
}
}

Create another function reconnect that reconnects to the broker whenever it disconnects (using a random client ID), as well publish message "hello world" to the outTopic and subscribe to the inTopic.

void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "CWO1-Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopic", "hello world");
// ... and resubscribe
client.subscribe("inTopic");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}

In the setup function we need to setup wifi connection, as well as specify our mqtt broker, port and callback function for receiving messages against subscribed topic

void setup() {
pinMode(BUILTIN_LED, OUTPUT);
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}

And in loop we first check if connection to the broker is established (and try to reconnect if not), followed by publishing a message “hello world” prefixed with some number every 4 seconds.

void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();

long now = millis();
if (now - lastMsg > 4000) {
lastMsg = now;
++value;
snprintf (msg, 75, "hello world #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg);
}
}

Complete code will look something like this. Don’t forget to replace the WiFi ssid and password according to your WiFi

#include 
#include

#define BUILTIN_LED 5 // Blue LED

// Update these with values suitable for your network.
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
const char* mqtt_server = "test.mosquitto.org";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

randomSeed(micros());

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();

// Switch on the LED if an 1 was received as first character
if ((char)payload[0] == '1') {
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED on
} else {
digitalWrite(BUILTIN_LED, LOW); // Turn the LED off
}
}

void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "CW01-Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopic", "hello world");
// ... and resubscribe
client.subscribe("inTopic");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}

void setup() {
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}

void loop() {

if (!client.connected()) {
reconnect();
}
client.loop();

long now = millis();
if (now - lastMsg > 4000) {
lastMsg = now;
++value;
snprintf (msg, 75, "hello world #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg);
}
}
  • After uploading the code, open up the serial monitor (baud rate 115200), and you will see the published messages being printed like this

  • Next let’s use some external MQTT client to subscribe to those messages being published at outTopic, as well as publish to topic we have subscribed to in the code (inTopic) to control our built-in LED. We will be using Google Chrome extension called MQTTLens as our client, but there are tons of such desktop and browser client apps that you can choose from

  • Add a new connection, provide the broker and port (keeping everything else as default) as shown below and save changes.

  • Now try to provide outTopic as topic and subscribe, and you will start receiving the messages being published by our xChip.
  • Finally let's test out our subscribed topic. Enter the topic inTopic, the message 1 and hit PUBLISH, and hopefully you will see the built-in LED light up.
Previous article Kuils River high school starts space learning programme
Next article XinaBox's xChips Enable Modular Electronics for Makers & STEM Education

Leave a comment

Comments must be approved before appearing

* Required fields