TigerJython | xx für Gymnasien |
Deutsch English |
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.org, m2m.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) |
|
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) |
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) |
|
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) |
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) |
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 |