MQTT: Protokoll für das Internet der Dinge

Praxis

Von der Theorie zur Praxis

Durch das Einbringen der MQTT-Bibliothek in die Eclipse Foundation entstand das Eclipse-Paho-Projekt. Derzeit sind Implementierungen in C, C++, Java, JavaScript, Lua und Python verfügbar. Im Folgenden werden die Beispiele anhand der Java-Implementierung gezeigt, wobei sie für alle Programmiersprachen ähnlich und generell leicht übertragbar sind. Doch zuerst benötigt man einen MQTT-Broker als zentralen Kommunikationsserver. Die Auswahl hierfür ist groß – von Open Source bis kommerziell, es gibt aber auch Public Broker. Letztere sind offen über das Internet zugänglich und für erste Versuche und Demonstrationszwecke prädestiniert. Falls man einen lokalen Broker bevorzugt, eignet sich HiveMQ mit installiertem MessageLog-Plugin, da alle Verbindungsinformationen auf der Konsole ausgegeben werden.

Bevor sich nun Nachrichten über MQTT verschicken oder empfangen lassen, ist erst eine Verbindung zum Broker herzustellen. In den Beispielen wird der Public Broker www.mqttdashboard.com verwendet, und der folgende Quellcode zeigt wie ein Verbindungsaufbau aussieht.

MqttClient client = new MqttClient(
"tcp://broker.mqttdashboard.com,
"MyfirstMQTTClient",
new MemoryPersistence()
);

client.connect();

Dazu werden die URL des Brokers und ein eindeutiger Name für den Client benötigt. Die MemoryPersistence-Klasse sorgt für das Zwischenspeichern von Nachrichten, die sich aufgrund eines Verbindungsabbruchs derzeit nicht versenden lassen.

Durch den Aufruf der Connect-Methode ist die Verbindung aufgebaut. Interessant ist hierbei der eindeutige Name, auch "Client ID" genannt, sie identifiziert jeden Client und darf auf jedem Broker nur einmal vergeben sein. Falls sich ein Client mit einer gleichen Client ID verbindet, wird die Verbindung zum vorherigen Client getrennt. Dieses Konzept hört sich im ersten Moment unlogisch an, doch im Fall eines erneuten Verbindungsaufbaus eines Clients ist es durchaus sinnig, da oftmals Timeouts vorheriger Verbindungen noch nicht abgelaufen sind. Ein etwas umfangreicherer Verbindungsaufbau mit "Last Will und Testament" ist hier zu sehen:

MqttClient client = new MqttClient(
"tcp://broker.mqttdashboard.com,
"MyfirstMQTTClient",
new MemoryPersistence()
);

MqttConnectOptions mqttConnectOptions;

mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setWill(
"Zuhause/Wohnzimmer/Temperatur/Status", // Topic
"offline".getBytes("UTF-8"), // Nachricht
1, // QoS
true); // Retained Message

client.connect(mqttConnectOptions);

Dabei wird dem Broker mitgeteilt, dass bei Abbruch der Verbindung die Nachricht offline auf den Topic Zuhause/Wohnzimmer/Temperatur/Status mit dem QoS-Level 1 geschickt werden soll. Sobald die Verbindung steht, lässt sich eine Nachricht verschicken oder diverse Topics abonnieren. Das zeigen die beiden folgenden Code-Beispiele. Die Nachricht umfasst die aktuelle Temperatur des Sensors und wird über den passenden Topic verschickt. Dabei benutzt dieser QoS-Level 1 und eine "Retained Message". Ersterer stellt sicher, dass die Nachricht auch mindestens einmal ankommt, und die "Retained Message sorgt dafür, dass die Nachricht automatisch an alle neuen Clients gesendet wird (siehe Erklärung oben).

client.publish(
"Zuhause/Wohnzimmer/Temperatur", //Topic
"23.4".getBytes("UTF-8"), //Nachricht
1, //QoS
true); //Retained Message

Das zweite Beispiel zeigt den Quellcode eines Datennutzers, beispielsweise der erwähnten mobilen Anwendung. Diese verbindet sich ebenfalls zum selben Broker und implementiert einen Callback. Die Methode messageArrived wird immer aufgerufen, sobald eine Nachricht eintrifft. Im Beispiel ist das nur der Fall, wenn
der Topic Zuhause/Wohnzimmer/Temperatur verwendet wird, da dieser abonniert wurde. Die anderen beiden Methoden dienen zum Überprüfen, ob eine Nachricht zugestellt wurde, (delieveryComplete) und der Handhabung eines Verbindungsabbruchs ([i]connectionLost[]/i]).

client.connect();

client.setCallback(new MqttCallback() {
@Override
public void messageArrived
(String arg0, MqttMessage arg1) throws Exception {
// Weiterverarbeiten der Nachricht
}

@Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
}

@Override
public void connectionLost(Throwable arg0) {
}
});

client.subscribe("Zuhause/Wohnzimmer/Temperatur", 2);

Weitere Beispiele befinden sich in einem GitHub-Repository. Dabei wird der beschriebenen Anwendungsfall noch mit einem Web-Dashboard verknüpft, das Live-Updates anzeigen kann. Dafür kommt die Paho-JavaScript-Bibliothek zum Einsatz, die über Websockets MQTT-Nachrichten zwischen Webbrowser und Broker austauscht. Wie das im Detail funktioniert, kann man auf der HiveMQ-Website nachlesen.

Einsatzszenarien

Dadurch dass jeder Sensor, jedes Gerät und sogar jeder Webbrowser ein MQTT-Client sein kann,ergeben sich viele Anwendungsfälle für das Protokoll. Ein oft genanntes Beispiel ist der Facebook Messenger. Als Gründe für den Einsatz nennen die Entwickler die geringe Netzwerklatenz, die minimale Beanspruchung der Bandbreite und eine längere Akkulaufzeit. MQTT benötigt im besten Fall für das Senden nur zwei Byte an Protokollinformationen pro Nachricht, der Rest ist die Nachricht in Binärdarstellung.

Die Skalierung auf viele Tausende gleichzeitiger Verbindungen ist für Facebook wichtig, aber auch auch für die Vernetzung von Automobilen, um mehr Sicherheit und Komfort im Auto zu bieten. Dabei wird MQTT zur Übertragung von GPS-Koordinaten oder Sensordaten über Mobilfunk verwendet. Durch intelligente Auswertungen lässt sich bestimmen, ob einzelne Teile zu tauschen sind oder sich auf der im Navigationssystem hinterlegten Route ein Stau befindet. Hier kommt wieder die effiziente Bandbreitennutzung von MQTT ins Spiel, da man oft mit Datenvolumen von wenigen Megabyte im Monat auskommen muss.