# MQTT
# Pricipe MQTT
Het MQTT-protocol (Message Queuing Telemetry Transport) wordt zeer veel gebruikt in IoT toepassingen om sensordata te versturen en deze terug op te halen. MQTT maakt gebruik van een Broker. De clients zijn in staat om zowel data te publiceren als te abonneren (subscribe) bij een broker op data.
In bovenstaande voorbeeld publiceert client B de dak temperatuur in het topic temperature/roof en client A de vloer temperatuur in het topic temperature/floor. Client A is geabonneerd (subscribe) bij de broker op het topic temperature/roof afkomstig van client B.
# Waarom MQTT
De MQTT-broker is een zeer eenvoudig lichtgewicht server die perfect op een raspberry pi kan draaien. Er zijn eveneens gratis publieke MQTT-brokers beschikbaar zoals https://www.hivemq.com/public-mqtt-broker/ (opens new window)
# Client
De Clients kunnen zowel een esp8266, esp32, Raspberry Pi of een ander toestel dat verbonden is met het internet.
# Broker
Er zijn verschillende mogelijkheden om een MQTT-broker op te zetten:
Op een Raspberry pi. Een nadeel hieraan is dat de Raspberry pi niet publiek beschikbaar is.
Een gratis publieke MQTT-broker zoals https://www.hivemq.com/public-mqtt-broker/ (opens new window)
Een betalende dienst eventueel op een virtuele machine.
…
# Gratis publieke MQTT-broker hivemq
# Berichten publiceren en abonneren op een topic
Installeer de PubSubClient bibliotheek in arduino IDE.
# ESP8266
Maak gebruik van het LOLIN (WEMOS) D1 R2 bord. Vertrek van het voorbeeld.
Stel de SSID en het Wifi-paswoord in.
const char* ssid = "........";
const char* password = "........";
2
Stel de broker in:
const char* mqtt_server = "broker.hivemq.com";
Deze code is gebaseerd op https://github.com/knolleary/pubsubclient (opens new window)
Voorbeeldcode waarbij iedere 2 seconden “Hello world” + de waarde van een teller gepubliceerd wordt in het topic “outTopic”.
Eveneens is er geabonneerd (subscribe) op het topic “inTopic”. Wanneer het eerste karakter van de data op het topic inTopic een 1 is, licht de ingebouwde led op, bij een andere karakter licht de ingebouwde led niet op.
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "........";
const char* password = "........";
const char* mqtt_server = "broker.mqtt-dashboard.com";
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
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 = "ESP8266Client-";
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();
unsigned long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
Een verzonden topic kan bekeken worden op http://www.hivemq.com/demos/websocket-client/ (opens new window)
Schrijf vervolgens in op het topic. Voorbeeld:
# Vragen
- Om de hoeveel tijd wordt een bericht gepubliceerd in de voorbeeldcode?
- In welk topic wordt data gepubliceerd?
- Welke data wordt er gepubliceerd?
- Op welk topic is er geabonneerd?
- Met welk teken moet een bericht beginnen zodat de ingebouwde led zou oplichten?
# Opdrachten
- Pas de code aan zodat iedere 30 seconden een teller met 1 verhoogt en deze waarde gepubliceerd wordt in het topic esp/je eigen naam. Bewaar als mqttESP8266Oef1.
- Pas de code aan zodat iedere 30 seconden de lichtsterkte doorgezonden wordt (analoge waarde). De lichtsterkte wordt gepubliceerd in het topic esp/je eigen naamLichtstrekte. Bewaar als mqttESP8266Oef2.
- Wanneer een schakelaar ingedrukt is, stuur je de waarde 1 door naar het topic esp/je eigen naamLicht. Wanneer deze niet ingedrukt is, stuur je 0 door. Laat vervolgens een 2de arduino hierop abonneren. Wanneer 1 doorgezonden is, licht de ingebouwde led op.
# ESP32
Deze code is gebaseerd op https://github.com/knolleary/pubsubclient (opens new window)
# Publiceren van data
In onderstaande voorbeeldcode wordt iedere 2 seconden "Hello world" + de waarde van een teller gepubliceerd in het topic "VTI-Torhout".
#include <WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "........";
const char* password = "........";
const char* mqtt_server = "broker.mqtt-dashboard.com";
const char* publishTopic="VTI-Torhout";
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
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 reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish(publishTopic, "hello world");
}
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() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
value++;
snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
Serial.print("Topic: ");
Serial.println(publishTopic);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish(publishTopic, msg);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
Een verzonden topic kan bekeken worden op http://www.hivemq.com/demos/websocket-client/ (opens new window)
Schrijf vervolgens in op het topic. Voorbeeld:
# Abonneren (subscribe)
In onderstaande voorbeeldcode is er geabonneerd (subscribe) op het topic "VTI-Torhout". Wanneer het eerste karakter van de data in het topic een 1 is, licht de led op, bij een andere karakter licht de led niet op.
#include <WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "........";
const char* password = "........";
const char* mqtt_server = "broker.mqtt-dashboard.com";
const char* subscribeTopic="VTI-Torhout";
#define ledPin 2
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
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(ledPin, HIGH); // Turn the LED on
} else {
digitalWrite(ledPin, 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 = "ESP32Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
client.subscribe(subscribeTopic);
}
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(ledPin, OUTPUT); // Instellen ledPin als uitgang
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# Publiceren en abonneren
In onderstaande voorbeeldcode wordt iedere 2 seconden de waarde "Hello world" + de waarde van een teller gepubliceerd in het topic "VTI-TorhoutPub".
Eveneens is er geabonneerd (subscribe) op het topic "VTI-TorhoutSub". Wanneer het eerste karakter van de data op het topic "VTI-TorhoutSub" een 1 is, licht een led op, bij een andere karakter licht de led niet op.
#include <WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "........";
const char* password = "........";
const char* mqtt_server = "broker.mqtt-dashboard.com";
const char* subscribeTopic = "VTI-TorhoutSub";
const char* publishTopic = "VTI-TorhoutPub";
#define ledPin 2
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
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(ledPin, HIGH); // Turn the LED on
} else {
digitalWrite(ledPin, 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 = "ESP32Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish(publishTopic, "hello world");
// ... and resubscribe
client.subscribe(subscribeTopic);
}
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(ledPin, OUTPUT); // instellen ledPin als uitgang
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
Serial.print("Publish topic: ");
Serial.println(publishTopic);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish(publishTopic, msg);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# Vragen
- Om de hoeveel tijd wordt een bericht gepubliceerd in de voorbeeldcode?
- In welk topic wordt data gepubliceerd?
- Welke data wordt er gepubliceerd?
- Op welk topic is er geabonneerd?
- Met welk teken moet een bericht beginnen zodat de ingebouwde led zou oplichten?
# Opdrachten
- Pas de code aan zodat iedere 30 seconden een teller met 1 verhoogt en deze waarde gepubliceerd wordt in het topic esp/je eigen naam. Bewaar als mqttESP32Oef1.
- Pas de code aan zodat iedere 30 seconden de lichtsterkte doorgezonden wordt (analoge waarde). De lichtsterkte wordt gepubliceerd in het topic esp/je eigen naamLichtstrekte. Bewaar als mqttESP32Oef2.
- Wanneer een schakelaar ingedrukt is, stuur je de waarde 1 door naar het topic esp/je eigen naamLicht. Wanneer deze niet ingedrukt is, stuur je 0 door. Laat vervolgens een 2de arduino hierop abonneren. Wanneer 1 doorgezonden is, licht de ingebouwde led op.
# Python
# Publiceren
Voeg de paho-mqtt bibliotheek toe indien nodig via:
pip install paho-mqtt
Bron: https://www.hivemq.com/blog/mqtt-client-library-paho-python/ (opens new window)
In onderstaande voorbeeldcode wordt iedere 30 seconden de temperatuur van kamer 1 en 2 gepubliceerd in de topics “VTI-Torhout/temp/room1” en "VTI-Torhout/temp/room2".
import paho.mqtt.client as paho
import time
import random
def on_publish(client, userdata, mid):
print("mid: " + str(mid))
client = paho.Client()
client.on_publish = on_publish
client.connect("broker.mqttdashboard.com", 1883)
client.loop_start()
while True:
temperature_room1 = random.randint(5, 20)
temperature_room2 = random.randint(5, 20)
(rc, mid) = client.publish("VTI-Torhout/temp/room1", str(temperature_room1), qos=1)
(rc, mid) = client.publish("VTI-Torhout/temp/room2", str(temperature_room2), qos=1)
time.sleep(30)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Abonneren (Subscribe)
In onderstaande voorbeeldcode is geabonneerd (subscribe) op alles van het topic "VTI-Torhout/temperature/#".
import paho.mqtt.client as paho
def on_subscribe(client, userdata, mid, granted_qos):
print("Subscribed: " + str(mid) + " " + str(granted_qos))
def on_message(client, userdata, msg):
print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
client = paho.Client()
client.on_subscribe = on_subscribe
client.on_message = on_message
client.connect("broker.mqttdashboard.com", 1883)
client.subscribe("VTI-Torhout/temperature/#", qos=1)
client.loop_forever()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Vragen
- Om de hoeveel tijd wordt een bericht gepubliceerd in de voorbeeldcode?
- In welk topic's wordt data gepubliceerd?
- Welke data wordt er gepubliceerd?
- Op welk topic's wordt er geabonneerd?
# Opdrachten
- Pas de code aan zodat iedere 30 seconden een teller met 1 verhoogt en deze waarde gepubliceerd wordt in het topic je eigen naam/teller. Bewaar als mqttRaspberryPiOef1.
- Pas de code aan zodat iedere 30 seconden de temperatuur doorgezonden wordt via een DHT11. De temperatuur wordt gepubliceerd in het topic je eigen naam/Temperatuur. Bewaar als mqttRaspberryPiOef2.
- Wanneer een schakelaar ingedrukt is, stuur je de waarde 1 door naar het topic je eigen naam/Licht. Wanneer deze niet ingedrukt is, stuur je 0 door. Abonneer vervolgens een 2de raspberry pi hierop. Wanneer 1 doorgezonden is, licht een led op.