Definitionen für den NodeState.
In der letzten Folge haben wir ein kleines Aktor-Projekt verwirklicht, bei dem wir eine LED über MQTT aus der Ferne schalten konnten. Zur Erinnerung: Unsere Hardware, das Pretzel-Board, ist mit einem WLAN-Chip ESP8266 ausgerüstet, der von einem ATmega328 über AT-Befehle gesteuert wird. Auf letzterem läuft Arduino-Software, die wir in den letzten Folgen Schritt für Schritt entwickelt haben; dazu gehört eine kleine TCP/IP-Bibliothek und eine rudimentäre MQTT-Library für das Zusammenstellen der nötigen Bytes, die zum MQTT-Testbroker geschickt werden müssen (siehe MQTT-Spezifikation). Die Kommunikation beginnt mit einer CONNECT-Anfrage; wir überprüfen danach, ob der Testbroker mit festgelegten CONNACK-Bytes antwortet. Danach senden wir alle 15 s die sogenannten PINGREQ-Bytes. Der Testserver beantwortet diese ebenfalls mit einer festgelegten Bytefolge (PINGRESP) und weiß jetzt, dass der Client noch auf eine offengehaltene Verbindung angewiesen ist. Außerdem haben wir uns mit SUBSCRIBE noch auf das Topic „/ElektorMyJourneyIoT/TestTopic/test“ abonniert, um Nachrichten des steuernden Clients (bei uns als PC-Software realisiert) zu empfangen und die LED zu schalten. Und wir schicken unter dem Topic „…/TestTopicBack/…“ noch PUBLISH-Nachrichten als Rückmeldung heraus, wenn dies erledigt wurde.

So weit, so gut – hin und wieder passiert es allerdings, dass die Verbindung vom Aktor-Board zum MQTT-Testserver draußen im Netz abbricht. Dies kann man detektieren, wenn ein PINGREQ nicht mehr beantwortet wurde. In der letzten Folge haben wir dann einfach nur die rote LED eingeschaltet. Mit einem Druck auf den Taster konnte der User dann erneut veranlassen, dass sich der Aktor-Client beim Testserver anmeldet und auf das erwähnte Topic abonniert.

Das Ganze ist natürlich nicht sehr praxistauglich, wenn der Aktor irgendwo „im Feld“ untergebracht ist. Stellt man nun auf der Seite des steuernden MQTT-Clients fest, dass die Rückmeldungen ausbleiben, dann müsste man rausfahren und das Aktor-Board wieder „scharf schalten“. Und so weiter, und so fort.

Ein erneutes Verbinden lässt sich aber auch prima automatisieren; in der Arduino-Software aus der letzten Folge sind schon alle Funktionen hierzu vorhanden. Was ich für diese Folge verbessert habe, kann man gut erkennen, wenn man den neuen Sketch (Download unten) mit dem Sketch aus der letzten Folge vergleicht.

MQTT State Machine

Ich habe ein paar Definitionen für einen „NodeState“ eingeführt (siehe Screenshot). Positive Zahlenwerte stehen für den normalen Betriebsauflauf, 0 und negative Werte für Fehler. Die Funktionen zum Verbinden und Abonnieren auf das Topic (ConnectAndSubscribeToTopic()) und zum Aussenden des Pings (SendPingRequestToBroker()) schalten im Fehlerfall jetzt nicht nur die LED rot, sondern geben auch einen (dann negativen) Wert zur Hauptschleife zurück. Dort ist eine winzige State Machine verwirklicht. Anhand des zurückgegebenen Wertes wird eine Variable MQTTClient_Connected bedient, die nur zwei Zustände kennt: Nämlich true, wenn der Verbindungsversuch und später das Pingen erfolgreich waren und die Verbindung (noch) steht und false, wenn ein Fehler aufgetreten ist. In ersterem Fall verhält sich das Board wie in der letzten Folge: Es wird regelmäßig ein Ping ausgesandt und auf Schaltnachrichten gelauscht, die über MQTT hereinkommen. Beim Eintreffen wird der Aktor entsprechend geschaltet und über MQTT eine Rückmeldung veröffentlicht.
Ist jedoch MQTTClient_Connected == false, dann wird über die Funktion ConnectAndSubscribeToTopic() ein (erneuter) Verbindungsversuch unternommen. MQTTClient_Connected ist übrigens auch am Anfang des Programms auf false gesetzt, so dass der erste Verbindungsversuch sofort nach dem Einloggen in das WLAN-Netzwerk erfolgt und nicht erst, wenn der Benutzer den Taster betätigt. Mit einem Druck auf den Taster kann dieser aber nach wie vor eine erneute Verbindung erzwingen.

Statusmeldungen über MQTT

Weil nun so vieles automatisch abläuft, gibt das Board Statusmeldungen aus, und zwar lokal über die serielle Schnittstelle (was etwa beim Einrichten im Feld hilft) als auch über MQTT (auf dem gleichen Topic wie die Aktor-Rückmeldungen). Da im Fehlerfall natürlich kein Versenden von Statusmeldungen über MQTT möglich ist, wird der Fehler in der Variable NodeStateLog zwischengespeichert und die entsprechende Meldung ausgesandt, wenn die Verbindung wieder steht. Bei den Statusmeldungen stehen ein „S1“ bis „S3“ für einen normalen Betrieb und „E0“ bis „E4“ für Fehler.

Probieren Sie es aus – das Setup ist das gleiche wie in der letzten Folge. Neben dem Arduino-Code, wo Sie wie immer zuerst die SSID und das Passwort Ihres WLAN-Netzwerks eintragen müssen, ist auch der MQTT-Client für den PC im Download enthalten. Das Aktor-Board arbeitet nun auch über längere Zeit ohne äußeren Eingriff; man kann in der seriellen Ausgabe erkennen, dass die Verbindung von Zeit zu Zeit automatisch neu etabliert wird (beim PC-Client kann von Zeit zu Zeit noch ein Neustart nötig sein). Die insgesamt unzuverlässige Verbindung hängt damit zusammen, dass wir (noch) mit einem ziemlich unsicheren, öffentlich zugänglichen Testbroker arbeiten.

Es gibt noch viel zu tun – weiter geht es in den nächsten Folgen!