MQTT: Protokoll für das Internet der Dinge

Die Eignung für eine zuverlässige und effiziente Kommunikation auch über instabile Mobilfunk-Netze und die Vernetzung vieler Tausender Geräte ist in vielen Situation gefragt. Deshalb zählt MQTT (Message Queue Telemetry Transport) inzwischen zu einem der wichtigsten Protokolle im Internet der Dinge.

In Pocket speichern vorlesen Druckansicht 5 Kommentare lesen
Lesezeit: 14 Min.
Von
  • Christian Götz
Inhaltsverzeichnis

Die Eignung für eine zuverlässige und effiziente Kommunikation auch über instabile Mobilfunk-Netze und die Vernetzung vieler Tausender Geräte ist in vielen Situation gefragt. Deshalb zählt MQTT (Message Queue Telemetry Transport) inzwischen zu einem der wichtigsten Protokolle im Internet der Dinge.

Da MQTT meistens in den Bereichen "Maschine zu Maschine" und "Internet der Dinge" zum Einsatz kommt, ist es etwas überraschend, dass die Geschichte des Protokolls bereits 1999 beginnt. Die Firmen IBM und Arcom Control Systems entwickelten das Protokoll im Zuge eines gemeinsamen Projekts zur Überwachung einer Ölpipeline. Da die mobile Infrastruktur damals noch in keinem Verhältnis zum aktuellen Ausbau stand, gab es
nicht unerhebliche Herausforderungen. Eine davon war die Datenübertragung über Satellit und terrestrische Netze mit möglichst geringen Kosten. Ebenso sollte eine generische Lösung gefunden werden, die über eine direkte Punkt-zu-Punkt-Verbindung hinaus geht und die Sensoren als Datenproduzenten von den Datennutzern entkoppelt.

Um die Herausforderungen zu bewältigen, wurden folgende Eigenschaften für das Protokoll erarbeitet:

  • Die Implementierung muss einfach sein, um auch Geräte mit eingeschränkten Ressourcen damit zu vernetzen.
  • Es muss unterschiedliche Servicequalitäten bei der Datenübertragung geben, damit die Übertragung auch in instabilen Netzen gewährleistet wird.
  • Die Übertragung muss einfach und effizient die zur Verfügung stehende Bandbreite nutzen.
  • Da bei Wiederaufnahme abgebrochener Verbindungen oft Metainformationen erneut gesendet werden, wäre es von Vorteil, diese serverseitig zu speichern (Session-awareness).
  • Das Protokoll sollte unterschiedliche Datentypen übertragen können und nicht auf eine bestimmte Struktur festgelegt sein (datenagnostisch).

Andy Standford-Clark und Arlen Nipper haben zum Erreichen dieser Ziele das Protokoll Message Queuing Telemetry Transport (MQTT) entwickelt, das bei IBM in der Folge in verschiedenen Projekten zum Einsatz kommt. 2010 wurde es dann offiziell unter einer freien Lizenz veröffentlicht, was auch Open-Source-Implementierungen ermöglichte. Im folgenden Jahr brachten IBM und Eurotech (vormals Arcom) ihre MQTT-Bibliothek unter das Dach der Eclipse Foundation und gaben damit der breiten Verwendung des Protokolls einen weiteren Schub. Denn die einst identifizierten Ziele und ihre Umsetzung verlangen auch 2014 eine Technik für skalierbare Echtzeitkommunikation mit minimaler Breitband- und Ressourcennutzung. Unter Echtzeit ist eine Datenübertragung ohne Polling oder ähnliche Mechanismen zu verstehen. Es kann sehr wohl zu Verzögerungen aufgrund unzuverlässiger Netzwerke kommen.

MQTT implementiert das Publish/Subscribe-Pattern. Der Paradigmenwechsel von einer Request/Response- zu einer ereignisgesteuerten Publish/Subscribe-Architektur ist hierbei der zentrale Aspekt. Sie ersetzt die Punkt-zu-Punkt-Verbindungen durch einen zentralen Server (Broker), zu dem sich Datenproduzenten und -nutzer gleichermaßen verbinden können. Das Senden (publish) und Empfangen (subscribe) von Nachrichten funktioniert über sogenannte Topics. Ein Topic ist ein String, der eine Art Betreff der Nachricht darstellt, aber ähnlich einer URL aufgebaut ist. Ein Temperatursensor in einem Wohnzimmer könnte beispielsweise seine aktuelle Temperatur auf folgendem Topic veröffentlichen: Zuhause/Wohnzimmer/Temperatur.

Der Ablauf einer Übertragung von Temperaturwerten zu einem Mobilgerät und einem Laptop im Publish/Subscribe-Verfahren (Abb. 1)

Eine mobile App kann sich nun ebenfalls zum Broker verbinden und den gleichen Topic abonnieren (subscribe), um alle Nachrichten zu erhalten, die der Temperatursensor versendet. Die komplette Kommunikation funktioniert rein über Topics, und der Sensor und das Mobiltelefon wissen nichts über die Existenz des jeweils anderen. Der Ablauf ist in Abbildung 1 dargestellt. Topics haben noch ein weiteres wichtiges Konzept, wodurch sie flexibel sind – nämlich Wildcards.

Zuhause/Wohnzimmer/Temperatur
Zuhause/Wohnzimmer/Luftfeuchtigkeit
Zuhause/Schlafzimmer/Temperatur
Zuhause/Schlafzimmer/Luftfeuchtigkeit

In oben stehenden Codebeispiel sind vier Topics aufgelistet, und je ein Sensor sendet eine neue Nachricht auf den jeweiligen Topic, sobald sich ein Wert geändert hat. Man kann nun je nach Anwendungsfall Wildcards benutzen, um mehrere Topics zu abonnieren.

Zuhause/+/Temperatur
Zuhause/Wohnzimmer/#
#

Hier sind alle möglichen Wildcard-Operatoren aufgelistet. Im ersten Fall bekommt die mobile Anwendung nur alle Nachrichten über neue Temperaturwerte, im zweiten Fall nur alle Werte aus dem Wohnzimmer und im dritten Fall alle Werte. Dabei lässt sich der +-Operator immer nur für eine Hierarchiestufe einsetzen und der
#-Operator für beliebig viele Hierarchiestufen mit der Bedingung, dass dieser am Ende stehen muss. Möchte man also Zuhause und Zimmer nicht genau benennen, sind zwei +-Operatoren zu benutzen: +/+/Temperatur. Falsch wäre #/Temperatur.

Ein weiteres wichtiges Konzept sind die drei Servicequalitäten bei der Datenübertragung 0, 1 und 2. Dazu muss man wissen, dass MQTT auf TCP basiert, weshalb eine große Zuverlässigkeit beider Übertragung gegeben ist. Trotzdem ist das bei Netzen mit vielen Übertragungsfehlern durch Verbindungsprobleme, wie bei mobilen Netzen, keine ausreichende Lösung. Daher hat das Protokoll Mechanismen eingebaut, die das erfolgreiche Übertragen von Nachrichten garantieren.

Die Zusicherung variiert von keiner Garantie (Level 0) über die, dass die Nachricht mindestens einmal ankommt (Level 1), bis hin zur Garantie, dass die Nachricht genau einmal ankommt (Level 2). Der Unterschied zwischen Level 1 und 2 liegt darin, dass es bei Level 1 passieren kann, dass eine Nachricht öfter einen Client erreicht. Je nach Anwendungsfall sollte der passende Level gewählt werden, denn je höher der Level, desto höher ist die benötigte Bandbreite.

Mit den Möglichkeiten, die Publish/Subscribe und die Verwendung von QoS-Level (Quality of Service) kann man viele Probleme lösen. Da verschiedene Clients immer wieder mal die Verbindung verlieren, kann es passieren, dass eine mobile Applikation, die sich neu verbunden hat, nicht weiß, ob überhaupt ein Temperatursensor verbunden ist und was der aktuelle Wert des Sensors ist. Außerdem erfährt man nicht, ob ein Sensor ausgefallen ist. Für diese Probleme gibt es in MQTT die Konzepte "Last Will and Testament" und "Retained Messages". Jeder Client kann beim Verbinden eine Nachricht mit seinem letzten Willen an den Broker schicken, bestehend aus Topic und Nachricht. Sobald der Broker das Unterbrechen der Verbindung merkt, sendet dieser die Nachricht im Auftrag des Clients.

Das Ganze funktioniert nur, wenn die Anwendung zum Zeitpunkt verbunden ist, an dem die Verbindung des Sensors abbricht. Abhilfe schafft hier eine "Retained Message". Sie ist eine Nachricht, die vom Broker gespeichert und jedem Client, der sich neu verbindet und den jeweiligen Topic abonniert, zugestellt wird. Es lässt sich für jeden Topic nur eine Nachricht speichern. Dies kann benutzt werden, um beispielsweise den letzten Wert des Sensors auf dem Topic Zuhause/Wohnzimmer/Temperatur oder den Status des Sensors auf Zuhause/Wohnzimmer/Temperatur/Status zu speichern. Dadurch können auch neu verbundene Geräte den letzten Wert empfangen, auch wenn sie zum Zeitpunkt des Sendens nicht verbunden waren.

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.

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.

2013 hat sich eine Gruppe aus Unterstützern zusammengetan, um unter dem Dach von OASIS die Standardisierung des Protokolls zu erreichen. Ziele waren eine robustere Spezifikation und die Regelung von Grenzfällen, um möglichst zeitnah eine einvernehmlich akzeptierte Version 3.1.1 zu haben. Auch sollte der etwas unpräzise Schreibstil einem RFC-artigen Stil weichen. Alle Anpassungen, die über das Klarstellen der Spezifikation hinausgehen, wurden durch das Komitee für eine erste Minor-Version nicht berücksichtigt. Der ursprüngliche Plan sah vor, dass die Verabschiedung am Ende des ersten Quartals 2014 abgeschlossen ist. Allerdings hat das technische Komitee im Februar diese auf Anfang des dritten Quartals verschoben, da die Fertigstellung des ersten Arbeitsentwurfs der Spezifikation deutlich mehr Zeit in Anspruch genommen hatte als geplant.

Trotz der Verzögerungen im Standard ist MQTT ein offenes und produktiv einsetzbares Protokoll, dessen Hauptanwendungsfälle im Bereich des Internet der Dinge liegen. Die Skalierung auf viele Tausend gleichzeitig verbundene Geräte und die Effizienz bei Übertragung und Ressourcennutzung der Geräte bieten eine Lösung für Probleme, die durch das altehrwürdige HTTP nicht realisierbar sind.

Die Anzeige und Alarmierung durch Live-Daten von Sensoren auf mobilen Geräte und Webbrowsern bieten Entwicklern die Möglichkeit, den Mehrwert ihrer Applikationen zu erhöhen. Der Anwender hat damit aktuellere Daten, und es entstehen weniger Kosten auf beiden Seiten.

Christian Götz
ist Geschäftsführer und Gründer der dc-square GmbH. Das Unternehmen entwickelt skalierbare Kommunikationslösungen und Webdashboards auf Basis von MQTT als Bausteine für Anwendungen im Bereich Internet der Dinge und der Industrie 4.0.
(ane)