TigerJython4Kids | HomeTurtlegrafikRobotikDatenbanken |
DU LERNST HIER... |
wie du über das Internet mehrere Systeme (Oxocard, Raspberry Pi, Arduino, PC) miteinander verbindest, um Kurzinformationen auszutauschen. Das MQTT-Protokoll (Message Queuing Telemetry Transfer) wurde erfunden, um den Datenaustausch schlank zu halten. Es verwendet TCP/IP als Transport-Protokoll. Im Zentrum, als quasi als Nabe eines Rades, befindet sich ein MQTT-Server, der "Broker" genannt wird. Geräte, die untereinander Informationen austauschen möchten sind sozusagen über Speichen mit dem Broker verbunden. Sie werden MQTT-Clients genannt. |
MUSTERBEISPIELE |
Ein Client (Publisher) kann zu einem bestimmten Thema (Topic) Informationen (Payload) publizierten. Andere Clients (Subscriber) können auf dieses Thema ein Abonnement abschliessen. 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. In einem typischen Musterbeispiel ist der Publisher ein Microcontroller, der Messdaten sammelt, beispielsweise die Lufttemperatur oder andere Zustandsparameter eines Systems, z.B. einen Zählerstand- Er publiziert die Informationen alle Minuten und diese können von beliebig vielen Subscriber abholt werden. (Da ein Publisher auch gleichzeitig Subscriber sein kann, können Informationen auch ausgetauscht werden.) ![]() Zuerst schreibst du einen Publisher, der die Anzahl Tastenbetätigungen als Zählerstand publiziert. Du verwendest dazu einen MQTT-Broker kennen, der seine Dienste gratis zur Verfügung stellt. Du kannst wählen zwischen den folgenden Servern: test.mosquitto.org, m2m.eclipse.org, broker.hivemq.com Du nimmst die Verbindung zu einem dieser Server über das Internet auf, wobei du einen WLAN-Accesspoint mit einer dir bekannten SSID/Passwort verwendet, beispielsweise über einen Tethering-Dienst auf deinem Smartphone. Mit Wlan.connect() loggst du dich dort ein. Nachfolgend erstellst du mit client = MQTTClient(broker) ein Client-Objekt und stellst mit client.connect() die Verbindung zum Broker her. Jedes Mal, wenn du die linke untere Taste drückst, publizierst du mit client.publish() den neuen Wert. Auf dem LED-Display zeigst du einige Informationen als Scrolltext dar. Programm: from mqttclient import MQTTClient from oxobutton import * from oxocard import * broker = "broker.hivemq.com" topic = "/ch/count" btn1 = Button(BUTTON_R2) # button at right bottom btn2 = Button(BUTTON_L2) # button at left bottom bigTextScroll("Connect AP.") Wlan.connect("myssid", "mypassword") bigTextScroll("Connect broker.") client = MQTTClient(broker) client.connect() count = 0 bigTextScroll("Press left button.") while not btn1.wasPressed(): if btn2.wasPressed(): count += 1 if count == 100: count = 0 display(count) client.publish(topic, str(count)) client.disconnect() bigTextScroll("Disconnected.") Um die Informationen abzuholen, schreibst du einen Subscriber, der wiederum über einen Accesspoint auf das Internet kommt (es kann der gleiche sein). Auch hier erzeugst du ein Client-Objekt und registrierst eine Callbackfunktion onMessageReceived(), die vom System automatisch aufgerufen wird, wenn eine Mitteilung zum abonnierten Topic eintrifft. Dazu musst du mit client.subscribe() das Topic abonnieren. Auch hier zeigst du auf dem LED-Display einige Informationen, insbesondere den erhaltenen Zählerwert dar. Programm: from mqttclient import MQTTClient from oxobutton import * from time import sleep from oxocard import * def onMessageReceived(topic, payload): display(payload) broker = "broker.hivemq.com" topic = "/ch/count" button = Button(BUTTON_R2) # button at right bottom bigTextScroll("Connect AP.") Wlan.connect("myssid", "mypassword") bigTextScroll("Connect broker.") client = MQTTClient(broker) client.set_callback(onMessageReceived) client.connect() bigTextScroll("Subscribing.") client.subscribe(topic) while not button.wasPressed(): sleep(0.5) client.disconnect() bigTextScroll("Disconnected.") Weil eingehende Mitteilungen automatisch die Funktion onMessageReceived() aufrufen, kannst du dich im Hauptprogramm darauf beschränken, in einer Schleife zu prüfen, ob du das Programm mit einem Buttonklick abbrechen willst. |
MIT CALLBACK-FUNKTIONEN UMGEHEN |
Das Programmieren mit Callbacks muss gelernt sein, da es etwas ungewöhnlich ist, dass das laufende Programm irgendwann und an irgendeiner Stelle durch das System unterbrochen wird und nachfolgend die Callbackfunktion zur Ausführung gelangt. Als Leitplanke gilt, dass die Callbackfunktion möglichst kurz sein soll, d.h. möglichst rasch zurückkehren muss. Sie darf also in der Regel keine sleep() und keine Wiederholschleifen enthalten. In vielen Fällen genügt es, wenn du in der Callbackfunktion eine globale Variable neu zuweist, deren neuer Wert du im Hauptprogramm verwendest. Nach der Rückkehr aus dem Callback fährt das Programm genau dort weiter, wo es unterbrochen wurde.
Zuerst betrachtest du das Steuerungsprogramm, das auf einem MQTT-Broker das Topic /ch/roll publiziert. In der Endlosschleife wird vom Beschleunigungssensor der Roll-Winkel geholt und je nach Bereich die Zustandsvariable state auf einen der drei Werte gesetzt. Aus Effizienzgründen willst du aber nur im Fall, wo sich der Zustand ändert, den neuen Zustand publizieren und den ersten Buchstaben auf dem LED-Display ausschreiben. Der Trick, um dies zu erreichen, ist die Verwendung einer Variablen oldState, die den vorhergehenden Zustand abspeichert. Nur wenn state und oldState verschieden sind, wird der neue Zustand übertragen und oldState auf state gesetzt. Programm: from mqttclient import MQTTClient from oxocard import * from oxoaccelerometer import * acc = Accelerometer.create() #broker = "m2m.eclipse.org" #broker = "test.mosquitto.org" broker = "broker.hivemq.com" topic = "/ch/roll" insertBigChar("V", RED) Wlan.connect("myssid", "mypassword") client = MQTTClient(broker) client.connect() oldState = "" state = "STOP" while True: roll = acc.getRoll() if roll > -10 and roll < 10: state = "STOP" elif roll > 20: state = "RIGHT" elif roll < -20: state = "LEFT" if state != oldState: client.publish(topic, state) insertBigChar(state[0]) oldState = state sleep(0.01) Du kannst das Programm testen, indem du den MQTT-Subscriber auf dem PC laufen lässt. Nun zur Oxocard mit der laufenden Schlange: Du musst zuerst wieder den MQTT-Client erzeugen und ebenfalls das Topic /ch/roll abonnieren. Am besten ist es, wenn du dir vorstellst, dass das Programm in drei Zuständen sein kann: Im Zustand "RIGHT", wenn sich die Schlange nach rechts, im Zustand "LEFT", wenn sich die Schlage nach links bewegt und im Zustand "STOP", wenn die Schlage still steht. Der Zustandswechsel wird dir als Message vom Broker mitgeteilt. Dabei wird vom System her die Callbackfunktion onMessageReceived() aufgerufen und wir haben es so eingerichtet, dass die payload gerade einer der drei Zustandswerte ist. Darum genügt es, im Callback der Variablen state den Wert von payload zuzuweisen. def onMessageReceived(topic, payload): global state state = payload (Wir haben uns also extrem gut an die Regel gehalten, dass Callbacks möglichst kurz sein sollen!) Programm: from oxosnake import * from mqttclient import MQTTClient from oxobutton import * def onMessageReceived(topic, payload): # State receiver global state state = payload #broker = "m2m.eclipse.org" #broker = "test.mosquitto.org" broker = "broker.hivemq.com" topic = "/ch/roll" state = "RIGHT" makeSnake(pos = (4, 4), heading = 90, speed = 70) Wlan.connect("myssid", "mypassword") client = MQTTClient(broker) client.registerCallback(onMessageReceived) client.connect() client.subscribe(topic) while True: # State dispatcher if state == "LEFT": setHeading(-90) forward() elif state == "RIGHT": setHeading(90) forward() elif state == "STOP": sleep(0.1) # Snake round-robin if getX() == 11: setX(0) if getX() == -4: setX(7) |
MERKE DIR... |
Mit MQTT kannst du sehr einfach kurze Informationen an mehrere Empfänger versenden. Dazu benötigst du einen MQTT-Broker, der für den Datenaustausch zwischen MQTT-Clients zuständig ist. Diese können Informationen zu einem Topic publizieren oder sich auf ein bestimmtes Topics abonnieren. Für den Datenaustausch werden nur wenige Bytes verwendet, er ist daher effizient und kostengünstig. Zu Testzwecken kannst du auch einen Publisher oder Subscriber verwenden, der unter TigerJython auf dem PC läuft. Du kannst die Programme von hier downloaden. Du kannst für deine Tests auch einen Online verfügbaren MQTT-Client verwenden, beispielsweise auf http://www.hivemq.com/demos/websocket-client . |
ZUM SELBST LÖSEN |
|
Falls dir nur eine Oxocard zur Verfügung steht oder zu Testzwecken kannst du als MQTT-Client deinen Computer verwenden.
Publisher:
Auf dem Computer startest du (mit dem grünen Knopf) folgendes Programm:
from time import sleep from gconsole import * from mqttclient import MQTTClient #host = "broker.dynns.com" #host = "test.mosquitto.org" host = "broker.hivemq.com" #host = "m2m.eclipse.org" topic = "/ch/count" makeConsole() m = MQTTClient() if m.connect(host): gprintln("Connection to " + host + " established") n = 0 while not isDisposed(): gprintln("Sending: " + str(n)) m.publish(topic, n) n += 1 sleep(0.01) else: gprintln("Connection to " + host + " failed")
Subsriber:
Auf dem Computer startest du (mit dem grünen Knopf) folgendes Programm:
from paho.mqtt import subscribe #host = "m2m.eclipse.org" host = "broker.hivemq.com" topic = "/ch/count" def messageReceived(client, userdata, message): print "messageReceived - payload:", message.payload print "subscribing to host", host, "for topic", topic subscribe.callback(messageReceived, topic, hostname = host)