In den bisherigen Folgen habe ich verschiedene Open-Source-Bibliotheken genutzt, um zwei MQTT-Clients für den PC und Android-Smartphones zu programmieren. Vom Handy aus können wir nun irgendwo auf der Welt Steuerbefehle absetzen, die über einen öffentlichen MQTT-Broker an einen MQTT-Client auf dem PC und hierüber per USB an ein Controllerboard weitergeleitet werden. Schon ganz nett, allerdings benötigen wir einen laufenden PC als Relaisstation. Und auch mit der umgekehrten Richtung haben wir uns noch nicht beschäftigt. Eine klassische IoT-Anwendung ist ja zum Beispiel das Versenden von Messwerten, vom Controllerboard aus ins Internet.

Wir sollten also innerhalb der nächsten Folgen einen MQTT-Client auf einem Controllerboard zum Laufen bekommen, der Nachrichten veröffentlichen (Publish) und abonnieren kann (Subscribe). Wir erinnern uns, dass MQTT auf TCP/IP aufsetzt. Neben einem Netzwerkanschluss oder WLAN-Modul auf dem Board sollten wir also auch über eine gut getestete TCP/IP-Library verfügen. Es bieten sich hier zum Beispiel Arduino-Boards mit Ethernet-Shield an; und genau für die Arduino-IDE gibt es eine MQTT-Bibliothek, die schon fast zu einer Art Standard geworden ist. Es handelt sich um den PubSubClient.cpp/.h von Nick O‘Leary (http://pubsubclient.knolleary.net/index.html); den Sourcecode kann man bei GitHub herunterladen.

Wir könnten uns nun einen Uno mit Ethernet-Shield besorgen, alle nötigen Bibliotheken in die Arduino-IDE integrieren und versuchen, eines der mitgelieferten Beispiele zum Laufen zu bekommen. Ich gehe hier jedoch einen anderen Weg, der zu einem besseren Verständnis von MQTT führt. Damit werden wir in die Lage versetzt, eigene MQTT-Bibliotheken zu programmieren, für beliebige Controllerboards. Zur Vereinfachung habe ich mir zuerst einmal nur angeschaut, welche Funktionen für das Veröffentlichen von MQTT-Nachrichten nötig sind. Eine solche Minimal-Bibliothek würde ja bereits genügen, damit ein Sensorknoten Messwerte in die Cloud übermitteln kann.

Nach etwas Studium des PubSubClient-Sourcecodes sieht man, was man benötigt:
  • Ganz zu Beginn muss eine Funktion aus der TCP-Library aufgerufen werden, die unser Programm als TCP-Client mit einem TCP-Server verbinden kann (sie könnte beispielsweise TCPClient_Connect heißen). Wir geben dieser die IP-Adresse unseres öffentlichen MQTT-Servers mit.
  • Danach muss eine MQTT-Connect-Anfrage zum MQTT/TCP-Server gesendet und eine Bestätigung angenommen werden. Das kann in einer Funktion erledigt werden, die zum Beispiel MQTTClient_Connect heißt. Hierzu wird auf eine Funktion TCPClient_Send zurückgegriffen, die einfach Bytes über TCP versenden und im Gegenzug eine Antwort vom Server in Form von Bytes zurückerhalten kann.
  • Die Funktion MQTTClient_Publish sendet Nutzdaten (Payload) zum MQTT-Server, um sie auf einem bestimmten Topic zu veröffentlichen. Die Funktion greift ebenfalls auf TCPClient_Send zurück, um die entsprechenden Bytes zu übermitteln. Im einfachsten Fall (Quality of Service = 0) kommt hier keine Antwort vom Server zurück.
  • Zwei Hilfsfunktionen (in der PubSubClient-Library heißen sie …_Write und …_WriteString) erleichtern das Zusammenstellen der Bytes, die über TCP zum Server gesendet werden müssen; einmal für die Connect-Anfrage und einmal für die Publish-Nachricht.
     
Sowohl in der Connect-Anfrage als auch in der Publish-Nachricht gibt es diverse optionale Bestandteile. Minimal sind in der Connect-Anfrage die Client-ID und in der Publish-Nachricht das Topic und natürlich die Nutzdaten mitzugeben (letztere können aber auch 0 Bytes lang sein). Das Bild zeigt, wie beide Datenfelder codiert werden müssen. Wie man sieht, ist das Zusammenstellen der Bytes wirklich kein Hexenwerk, und man erkennt auch, wie leichtgewichtig das Protokoll ist. Ich habe allerdings noch eine weitere Vereinfachung angenommen: Beide Nachrichten dürfen hier maximal 128 Bytes lang sein. Wenn man beim Topic unter 48 Bytes und bei der Nutzlast unter 64 Bytes bleibt, dann passt’s auf jeden Fall. Und noch eine Vereinfachung: Wir können nach dem Verbinden mit dem MQTT-Server nur ein paar Minuten Nachrichten lang veröffentlichen (mehr über die Keep Alive Time in einer der nächsten Folgen). Die ganzen Specs – zum Beispiel für längere Nachrichten – findet man unter http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html.

Ich habe mir mit diesen Infos eine Minimal-Bibliothek auf Basis der PubSubClient-Library geschrieben; und zwar zuerst einmal für den PC in C#, weil man hier schon über eine gute TCP-Bibliothek verfügt und sich Daten leicht anzeigen lassen. Zum Test habe ich einen weiteren kleinen MQTT-Client für den PC programmiert, der Nachrichten zwar nur veröffentlichen kann, aber dabei nicht mehr auf die umfangreiche .NET-MQTT-Bibliothek M2Mqtt aus Folge 4 angewiesen ist. Den Sourcecode und die funktionierende Anwendung können Sie unten herunterladen. Das erfolgreiche Versenden kann man beispielsweise mit meinem großen MQTT-Test-Client aus Folge 5 testen. In dessen Textfeld „Topic to subscribe“ geben Sie einfach ein kurzes Topic-Keyword ein wie zum Beispiel „min“. Beim Drücken des Buttons „Subscribe“ wird das Keyword wie immer zum Topic „/ElektorIoTJourney/min/test“ ergänzt. Nun können Sie den Minimal-Client testen. Nach dem Start des Programms sehen Sie bereits, welche Bytes innerhalb der Connect-Anfrage zum öffentlichen MQTT-Server geschickt wurden (wie auch bisher benutzen wir test.mosquitto.org). Die Client-ID ist zum Beispiel „elektorIoT“. Der Server sollte mit den Bytes „32 2 0 0“ geantwortet haben. Nun können Sie das Topic-Keyword „min“ sowie Text in die entsprechenden Textboxen eingeben und die Nachricht mit dem Button „Publish“ veröffentlichen.

Es gibt noch viel zu tun – in der nächsten Folge geht es weiter. Bis dahin bekommt der eine oder andere Leser sicher Lust, einen eigenen Minimal-Client für eine Plattform seiner Wahl zu schreiben. Gerne hören wir davon über die Kommentarfunktion unten!