Jython
Deutsch   English 

13. MQTT-Kommunikation


MQTT (Message Queuing Telemetry Transport) ist ein weit verbreitetes Kommunikationsprotokoll, das die Datenübertragung in Form von Nachrichten über das Internet ermöglicht. MQTT ist eine sinnvolle Alternative zur HTTP-Kommunikation, insbesondere für die Kommunikation mit Microcontroller und mobilen Geräten, bei denen die Ressourcen knapp sind. MQTT kommuniziert auch über TCP, aber sehr sparsam. Im Unterschied zu HTTP-Requests, die viele Daten für den Protokoll-Header brauchen, beträgt der MQTT Overhead nur einige wenige Bytes. Zudem benötigen Clients keine feste IP-Adresse und können sowohl Sender wie Empfänger sein. Ein MQTT-Clients kann zu einem frei gewählten Thema (Topic) Informationen publizieren (publish). Andere Clients können diese Topics abonnieren (subscribe). Die zentrale Komponente von MQTT ist ein sogenannter MQTT-Broker, der die  Kommunkation verwaltet. Der Publisher sendet seine Informationen an den Broker, der sie an alle abonnierten Subscriber weiter leitet. Es gibt keine automatische Rückmeldung an den Publisher, ob und wer die Information tatsächlich gelesen hat. Die Daten werden in Echtzeit zum Broker gesendet und dieser leitet sie an die Subscriber weiter. Die Daten bleiben also nicht beim Broker gespeichert, wie dies bei den meisten Cloundanwendungen der Fall ist.

In der Regel ist der Publisher ein Microcontroller, der Messdaten sammelt, beispielsweise die Lufttemperatur oder andere Zustandsparameter eines Systems. Er publiziert die Informationen periodisch oder bei einem bestimmten Ereignis und diese können von beliebig vielen Subscribern abholt werden.

Im Internet findet man MQTT-Broker, die ihre Dienste gratis zur Verfügung stellen. Man kann z. B. folgende Hosts verwenden:

test.mosquitto.orgm2m.eclipse.org, broker.hivemq.com

Man erstellt die Verbindung zu einem dieser Server über einen WLAN-Accesspoint (SSID/Passwort erforderlich).

 


Beispiel 1
: Der mbRobot als Publisher

Der mbRobot mit eingebauten LinkUp publiziert die Distanz zu einem Objekt, die er mit seinem Ultraschallsensor misst. Die Daten können beim MQTT-Broker mit einem Smartphone oder einem PC abgeholt werden.

Mqtt1.py erstellt über einen Accesspoint die Verbindung zum Brocker "broker.hivemq.com" und publiziert unter dem Topic "/ch/mbrobot" alle 5 Sekunden, die gemessene Distanz.

# Mqtt1.py
import mqtt
from microbit import *
from mbrobot import *

host = "broker.hivemq.com" 
topic = "/ch/mbrobot"

mqtt.connectAP("mySSID", "myPassword")
mqtt.broker(host)
mqtt.connect()
while True:
    dist = getDistance() 
    print(dist)
    mqtt.publish(topic, "Distance: " + str(dist))
    delay(5000)
► In Zwischenablage kopieren
 

 

Erklärungen zum Programmcode:
mqtt.broker(host): Legt die Eigenschaften des Brokers fest (hier nur die IP Adresse
mqtt.connect(): Loggt sich beim Broker ein
topic = "/ch/mbrobot": Die Topic-Bezeichnung kann beliebig gewählt werden. Der Vorspann "/ch/" vermindert die Wahrscheinlichkeit, dass dieser Topicname beim Broker bereits existiert.
mqtt.publish(topic, "Distance: " + str(dist)) Die Message wird unter dem gewählten Topic publiziert.


Als Subscriber kann man eine MQTT-Client-Applikation verwenden, die auf einem PC oder Smartphone installiert wird, z.B.

 

Um die Daten mit einem Smartphone oder PC abzuholen, wählt man den gleichen Broker und abonniert mit Add Subscriber das Topic /ch/mbrobot.

 

MQTTBox

 

Beispiel 2: Der mbRobot als Subscriber

Der mbRobot kann sich mit der Funktion subscribe() ein Topic abonnieren. Damit kann beispielsweise eine Fernsteuerung eingerichtet werden, sodass man von irgendwo auf dem Internet dem Roboter Befehle senden kann. Als Demonstration werden im folgenden Programm die beiden LEDs über das Internet ein- und ausgeschaltet.. Dabei wird das Topic /ch/lamp verwendet. Wenn die Payload "on" ist, werden die beiden roten LEDs eingeschaltet, wenn sie "off" ist, ausgeschaltet.  

Der micro:bit ruft in einer Schleife periodisch die Funktion mqtt.receive() auf, welche die MQTT-Message als Tupel (topic, payload) zuück gibt. Beide sind None, falls keine Message angekommen ist. (Sind seit dem letzten Aufruf mehrere Messages angekommen, so werden diese in einem Empfangsbuffer gespeichert und bei jedem Aufruf die "älteste" zurückgegeben).

# Mqtt2.py
import mqtt
from mbrobot import *
from microbit import *
host = "broker.hivemq.com"
topic = "/ch/lamp"

mqtt.connectAP("mySSID", "myPassword")
mqtt.broker(host)
mqtt.connect()
mqtt.subscribe(topic)
while True:
    topic, payload = mqtt.receive()
    if topic != None:
        if payload == "on":
            ledLeft.write_digital(1)
            ledRight.write_digital(1)
            display.show(Image.YES)
        elif payload == "off":
            ledLeft.write_digital(0)
            ledRight.write_digital(0)
            display.show(Image.NO)
    delay(1000) 
► In Zwischenablage kopieren
 

Erklärungen zum Programmcode:
topic, payload = mqtt.receive(): Es wird periodisch geprüft, ob eine Message empfangen wurde
if topic != None: Nur falls eine Message empfangen wurde, wird etwas gemacht
delay(1000): Prüft nur jede Sekunde (Vermeiden  hoher Systembelastung, analog wie beim Sensor-Polling)


   


Als Fernsteuerung wird MQTT Dash auf einem Smartphone verwendet. Man erstellt eine Verbindung zum gleichen Brocker und publiziert unter dem Topic "/ch/lamp" die Payload "on" bzw. "off".

 

 

Beispiel 3: PIR-Bewegungsdetektor und MQTT zur Überwachung einsetzen

Der mbRobot publiziert unter dem Topic /"ch/pir" ALARM wenn er mit seinem PIR-Bewegungsdetektor eine Bewegung detektiert. Der Smartphone-Client abonniert beim Broker das gleiche Topic und kann die Alarmmeldung abholen. Bei bestimmten Apps kann ein Tonsignal oder die Vibration aktiviert werden,.wenn eine Alamrmeldung empfangen wird.

Der PIR-Bewegungsdetector ist am micro:bit mit drei F-F-Jumperkabeln am P2 angeschlossen so wie im Beispiel 4 im Kapitel Push Nachrichten (unbedingt die richtige Verkabelung achten).

Die Benachrichtigung "ALARM" wird nur dann publiziert, wenn der PIR-Sensor eine Bewegung detektiert hat (Spannungsmessung liefert mehr als 500) , d.h. wenn der state von IDLE auf ALARM gewechselt hat.  Falls keine Bewegung mehr stattfindet, fällt die Spannung nach ca. 10 Sekunden wieder auf einen Wert unter 200 und der state wird wieder auf IDLE gesetzt.

 

# MQTT3.py
import mqtt
from microbit import *
from music import *

host = "broker.hivemq.com" 
topic = "/ch/pir"
mqtt.connectAP("mySSID", "myPassword")
mqtt.broker(host)
mqtt.connect()
pitch(1000, 100)
state = "IDLE"
while True:
    v = pin2.read_analog()    
    if v > 500 and state =="IDLE":
        state = "ALARM"
        mqtt.publish(topic, state)
        play(JUMP_UP)       
    if v < 200 and state == "ALARM":    
        state = "IDLE" 
        mqtt.publish(topic, state)
        play(JUMP_DOWN)              
    delay(500)
► In Zwischenablage kopieren
 

Erklärungen zum Programmcode:

pitch(1000, 100): Nachdem die Verbindung aufgebaut wurde, wird ein kurzer Ton abgespielt, um anzuzeigen, dass die Alarmeinrichtung aktiv ist
state = "IDLE": Es wird eine Zustandsvariable verwendet, die beschreibt, ob der Alarm eben ausgelöst wurde (ALARM) oder der Sensor sich im Detektionsmodus (IDLE) befindet
v = pin2.read_analog(): Gibt den Sensorwert zurück (zwei Spannungspegel)
mqtt.publish(topic, state): Publiziert den aktuellen state
play(JUMP_UP): Zur Demonstration wird bei einem Alarm eine kurze Melodie abgespielt (bei einer "echten" Überwachung müsste man wohl diese Zeile weglassen)

Beispiel 4: Temperatur und Luftfeuchtigkeit publizieren (Wetterstation)
Die einfache Anlage besteht aus einem micro:bit, einem LinkUp (ESP32 Microcontroller) und einem Sensirion Temperatur- und Feuchtigkeitssensor. Der micro:bit startet auf dem LinkUp einen MQTT-Client, der die Sensordaten temp und humi periodisch publiziert. Um diese Daten zu lesen, subscribiert ein MQTT-Client auf einem PC, Tablet oder Smartphone diese beiden Topics.

Das Program ist "robust" aufgebaut, d.h. bei Verlust der Verbindung versucht das System, die Verbindung erneut aufzubauen. Dabei wird der Verbindungsstatus auf dem micro:bit-Display angezeigt.

# Mqtt4.py

from microbit import *
import mqtt, rtc, gc
import sht

host = "broker.hivemq.com"

while True:
    try:
        gc.collect()
        display.show('L')     
        if mqtt.connectAP("raspilink", "aabbaabbaabb"):
            display.show('B')      
            mqtt.broker(host)
            if mqtt.connect():
                while True:
                    display.show(Image.ARROW_E)
                    temp, humi = sht.getValues() 
                    tme = rtc.get()
                    payload_date = "%d.%d\n%02d:%02d" %(tme[2], tme[1], tme[3], tme[4])
                    if not (mqtt.publish("/ch/home/date", payload_date) and 
                            mqtt.publish("/ch/home/temp", "%.1f" % temp) and 
                            mqtt.publish("/ch/home/humi", "%.1f%%" % humi)):
                        display.show('e')
                        sleep(3000)
                        break
                    sleep(2000)
                    s = " : : %.1f - %.1f" % (temp, humi)
                    for _ in range(3):
                        display.scroll(s)
            else:
                display.show('b')
                sleep(3000)
        else:
            display.show('l')
            sleep(3000)
    except:
        display.show('z')
        sleep(3000)
► In Zwischenablage kopieren

Erklärungen zum Programmcode:

gc.collect(): Der Garbage Collector gibt nicht gebrauchte Ressourcen frei (Vermeidung von Memory-Overflow)
sht.getValues() : Gibt ein Tupel mit Temperatur (in Grad Celsius) und Luftfeuchtigkeit (in Prozent) zurück
mqtt.publish("/ch/temp", "%.1f" % temp): Formatierte Ausgabe auf eine Kommastelle gerundet
try-except: Jeder mögliche Fehler wird abgefangen und das Programm baut die Verbindung neu auf