Publish/Subscribe model #
MQTT is a lightweight publish/subscribe messaging protocol designed for machine to machine telemetry in low bandwidth environments. It is useful for use with low power sensors, but is applicable to many scenarios. The MQTT protocol is based on the principle of publishing messages and subscribing to topics. Multiple clients connect to a server often termed as a “broker”. The broker is a central communication point that transmits the messages between senders and the clients who subscribed to receive the messages on a certain topic. Clients include the topic in the message, when publishing to the broker. The topic is the routing information for the broker. The broker delivers all the messages on a specific topic to the client, if the client has subscribed to it. The broker and MQTT act as a simple, common interface for everything to connect to. The data producers and the data consumers are independant of each other.
Subscription to MQTT topics #
Messages in MQTT are published on topics. There is no need to configure a topic, publishing on it is enough. Topics are simple strings treated as a hierarchy, using a slash (/) as a separator.
Clients can receive messages by subscribing to a topic.
In figure above, we see Client 1 (the Publisher, a temperature sensor) sending temperature to the broker. Client 2 and Client 3 subscribed to the topic and will receive all the messages on that topic. In this case, a sample topic for sending temperature of room S25 in Duboue building of UPPA could be UPPA/Duboue/S25/temp.
A subscription can be to an exact topic, in which case the client will receive all the messages on that exact
topic, or it may include wildcards. Two wildcards are available, +
or #
. The +
sign can be used as a wildcard for a
single level of hierarchy. The subscription to UPPA/Duboue/+
/temp would result in all the messages sent to UPPA/Duboue/S25/temp as well as any topic with an arbitrary value in the place of S25, for example, UPPA/Duboue/S24/temp. The #
sign would then replace several level of hierarchy and is very useful when the detailed hierarchy is not known. For instance UPPA/# would get all data, and topics, from UPPA university. A detailed example is shown in figure above.
Multiple applications have been developed on MQTT which include Amazon Web Services, EVERYTHING IoT platform, Facebook Messenger and many others which are available on PlayStore for Android and AppStore for iOS. An example of Google PlayStore is shown in figure 3 below.
Further documentation on MQTT is available on their official website http://mqtt.org/.
Brief description of the code #
We will briefly explain the steps used in the example below to use the MQTT protocol.
Include the publish/subscribe library
#include <PubSubClient.h>
Test parameters for MQTT: topic, temperature and MQTT server address
char *topicin = "UPPA/test";
char *topicout = "UPPA/Duboue/S25/temp";
char *msgTemp = "22.5";
char* mqtt_server = "test.mosquitto.org";
Define the publish/subscribe client
WiFiClient espClient;
PubSubClient client(espClient);
Define a function callback()
to process incoming message from a given subscribed topic. This is not needed if you only publish, which is more typical of an end-device.
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]);
}
Define a function reconnect()
to keep trying to connect to the MQTT broket until it is successful. Here the client id can be random because the MQTT broker we use does not require authentication.
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
In function setup(), setup the MQTT server
client.setServer(mqtt_server, 1883);
In function loop()
, check if client is connected, if not then reconnect
void loop() {
if (!client.connected()) {
reconnect();
}
At the end, publish the message on specified topic
int e=client.publish(topicout, msgTemp);
Complete working example #
// if you have an ESP8266 based board
#define ESP8266
#if defined ESP8266 || defined ARDUINO_ESP8266_ESP01
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
#include <PubSubClient.h>
// Update these with values suitable for your network.
char* ssid = "iPhoneD";
char* password = "345hello";
char *topicin = "UPPA/test";
char *topicout = "UPPA/Duboue/S25/temp";
char *msgTemp = "22.5";
char* mqtt_server = "test.mosquitto.org";
WiFiClient espClient;
PubSubClient client(espClient);
int WiFi_status = WL_IDLE_STATUS;
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();
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
} 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() {
delay(3000);
Serial.begin(38400);
// Print a start message
Serial.println(F("Simple MQTT demo"));
setup_wifi();
client.setServer(mqtt_server, 1883);
//client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
//client.loop();
WiFi_status = WiFi.status();
if ( WiFi_status != WL_CONNECTED) {
while ( WiFi_status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network
WiFi_status = WiFiWiFi.begin(ssid, password);
delay(500);
}
Serial.println("Connected to AP");
}
Serial.print("Publishing: status=");
int e=client.publish(topicout, msgTemp);
Serial.println(e);
delay(7500);
}
The code is ready for an Heltec WiFi LoRa 32 board so OLED is activated.
Testing and receiving the published MQTT message #
To test the MQTT publishing from the IoT device, we will use a computer with an MQTT client to listen for a specific topic.
IMPORTANT. In all the following examples and assignments, if you do not have access to a computer with a terminal window to use mosquitto_sub
and mosquitto_pub
command line, you can use the HiveMQ
MQTT web client to subscribe and publish in place of mosquitto_sub
and mosquitto_pub
. In this case, also replace the MQTT broker test.mosquitto.org
by broker.hivemq.com
in the Arduino example.
char* mqtt_server = "broker.hivemq.com";
mosquitto_sub
takes at least 2 parameters: -h
and -t
to indicate respectively the MQTT broker and the topic to subscribe to. In the Arduino example, the MQTT broker used was test.mosquitto.org
and the published topic was "UPPA/Duboue/S25/temp"
. The -v
option will display information in verbose mode to get the complete topic in presence of a wildcard.
The command would then look like:
mosquitto_sub -v -h test.mosquitto.org -t UPPA/#
which means subscribe to all topics under UPPA/
. Each time that the IoT device is publishing, you should see on your computer terminal an output similar to:
> mosquitto_sub -v -h test.mosquitto.org -t UPPA/#
UPPA/Duboue/S25/temp 22.5
UPPA/Duboue/S25/temp 22.5
UPPA/Duboue/S25/temp 22.5
...
Going a step further: use Node-RED to create complex data workflows #
See Node-RED
Enjoy!
2021 - Congduc Pham