Using MQTT for the Internet of Things
Last updated on 2022-08-30 | Edit this page
Overview
Questions
- What is MQTT?
- How does MQTT work?
- What is an MQTT publisher?
- What is an MQTT broker?
- What is an MQTT subscriber?
- What is a client?
- What is a server?
Objectives
- Explain how MQTT works
Adding MQTT to our sketch
What is MQTT?
Message Queuing Telemetry Transport
MQTT (originally an initialism of MQ Telemetry Transport[a]) is a lightweight, publish-subscribe, machine to machine network protocol. It is designed for connections with remote locations that have devices with resource constraints or limited network bandwidth.
There are three components to the MQTT architecture, publishers, subscribers and a broker. Publishers are devices on the Internet of Things that publish messages with a specific topic to a broker. Subscribers subscribe to specific topics on the broker. When a new value for a specific topic is published by a publisher, then all the subscribers to that topic will receive it.
Challenge
Discuss, with the person next to you the following:
- What kind of devices we are likely to find on the Internet of things?
- Who would typically publish information from such devices?
- Who would typically subscribe to the data?
Importing the MQTT library into the Arduino IDE
To be able to enable MQTT functionality we need to add yet another
library to our Arduino IDE. As before select Tools
on the
menu and then Manage Libraries
. Enter
PubSubClient
into the text box for searching. Scroll down
until you find PubSubClient by Nick O'Leary
and click the
Install button:
There are three pieces of information that we will need before we enter the code for sending and messages via MQTT:
- The
ssid
of your Internet access point - The password for the access point
- The IP address or hostname of your MQTT broker
There are several free MQTT servers available on the Internet. Alternatively one can set up one’s own server running an MQTT broker. In the diagrams below two alternative setups are shown. In the first case there is an MQTT server on the Internet that devices can publish or subscribe to. In the second case a local MQTT broker is used which has the advantages that all network traffic can be private, it doesn’t have to be shared to the Internet. For the purposes of this workshop for instance we might want to set up our own server so that we are not dependent on the Internet.
In the sketch below you will have to replace the values assigned to
the variables ssid
, password
and
mqtt_server
. Your instructor should provide you with the
appropriate values which will depend on the MQTT broker you are going to
use.
For now we will continue as if your instructor has set up a local network that includes an access point to which your computer has to connect and an MQTT broker. You might, or might not, be connected to the Internet once you connect to the access point, but that won’t matter.
C
#include <DHT.h>
#include <WiFi.h>
#include <PubSubClient.h>
#define DHT_SENSOR_TYPE DHT22
#define DHT_SENSOR_PIN 32 // ESP32 pin connected to DHT sensor
#define LIGHT_SENSOR_PIN 36 // ESP32 pin GIOP36 (ADC0)
const int readingdelay = 3000;
const char* ssid = "raspi-webgui";
const char* password = "ChangeMe";
const char* mqtt_server = "192.168.0.1";
const String your_name = "/JohnSmith";
DHT dht_sensor(DHT_SENSOR_PIN, DHT_SENSOR_TYPE);
WiFiClient espClient;
PubSubClient client(espClient);
String topic_temperature = your_name + "/dht22/temperature";
String topic_light = your_name + "/ldr/light/";
void setup() {
Serial.begin(9600); // initialize serial
Serial.println(F("Starting ..."));
dht_sensor.begin(); // initialize the DHT sensor
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
float temperature = dht_sensor.readTemperature(); // read temperature in Celsius
int lightlevel = analogRead(LIGHT_SENSOR_PIN); // read light level
if (isnan(temperature)) {
Serial.println("Failed to read from DHT sensor!");
} else {
/* When reading the temperature and light levels, we get the values
as numbers, but when we send it to the MQTT broker the values
have to be converted to strings. We therefore have to declare
variables of type char into which the number values can be transferred
*/
char tempString[8];
char lightString[8];
/**
* Transfer the number values into strings
*/
dtostrf(temperature, 1, 2, tempString);
dtostrf(lightlevel, 1, 2, lightString);
// Print the temperature to the monitor
Serial.print("Temperature: ");
Serial.println(temperature);
// Publish the temperature to the MQTT broker
publishMQTT(topic_temperature, tempString);
// Print the light level to the monitor
Serial.print("Light: ");
Serial.println(lightlevel);
// Publish the light level to the MQTT broker
publishMQTT(topic_light, lightString);
// wait a 3 seconds between readings
delay(readingdelay);
}
}
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(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte * message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
// Create a random client ID
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
Serial.print(clientId + " attempting MQTT connection...");
// Attempt to connect
if (client.connect(clientId.c_str(), "jannetta", "f0r3v3rl1n8x")) {
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(500);
}
}
}
void publishMQTT(String topicString, char payload[8]) {
unsigned int length = topicString.length() + 1;
char topic[length];
topicString.toCharArray(topic, length);
Serial.print(topic);
Serial.print(": ");
Serial.println(payload);
client.publish(topic, payload, true);
}
String byteArrayToString(byte * byteArray, unsigned int length) {
String messageTemp;
for (int i = 0; i < length; i++) {
messageTemp += (char)byteArray[i];
}
return messageTemp;
}
Discussion
Explanation of the code
Key Points
- Keypoint