# 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.

MQTT

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)

HIVEMQ

# 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:

# Gratis publieke MQTT-broker hivemq

# Berichten publiceren en abonneren op een topic

Installeer de PubSubClient bibliotheek in arduino IDE.

Toevoegen bibliotheek

# ESP8266

Maak gebruik van het LOLIN (WEMOS) D1 R2 bord. Vertrek van het voorbeeld.

Voorbeeld MQTT

Stel de SSID en het Wifi-paswoord in.

const char* ssid = "........";
const char* password = "........";
1
2

Stel de broker in:

const char* mqtt_server = "broker.hivemq.com";
1

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);
    }
}
1
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)

HiveMQ Connection

Schrijf vervolgens in op het topic. Voorbeeld:

HiveMQ Publish

# 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);
  }
}
1
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)

HiveMQ Connection

Schrijf vervolgens in op het topic. Voorbeeld:

HiveMQ Publish

# 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();
}
1
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);
  }
}

1
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
1

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)

1
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()


1
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.

# Extra info

Netlify Status (opens new window)