Czytaj książkę: «MQTT im IoT»
Einstieg in die M2M-Kommunikation
ISBN: 978-3-86802-519-4
© 2014 entwickler.press
Ein Imprint der Software & Support Media GmbH
1 M2M-Kommunikation mit MQTT
Das Internet der Dinge ist in aller Munde. Dank günstigen Einplatinencomputern wie Raspberry Pi und Arduino ist es möglich, preiswerte Geräte z. B. für die Erhebung und Auswertung von Sensordaten über das Internet zu vernetzen. Grund genug, sich Paho, die Referenzimplementierung des MQTT-Protokolls zur Maschine-zu-Maschine-(M2M-)Kommunikation für Java, genauer anzusehen und in einem konkreten Anwendungsfall einzusetzen.
Der Begriff „Internet of Things“ wurde bereits 2009 von Kevin Ashton geprägt 1 und bezeichnet die Vernetzung von Dingen der realen Welt über das Internet oder geschlossene Netzwerke. Die Grundidee ist simpel: Physische Geräte können miteinander kommunizieren und so Daten untereinander austauschen oder gar gesteuert werden. Populär ist dieser Ansatz heute bereits bei der Erhebung von Sensordaten, die man dann über das Internet an interessierte Clients sendet. Diese Daten werden in der Folge meist aggregiert und für Menschen lesbar in Form von Diagrammen oder Statistiken aufbereitet.
Die Anwendungsszenarien sind praktisch unbegrenzt. Stellen Sie sich vor, Ihr Wecker würde automatisch zehn Minuten später klingeln, da er benachrichtigt wird, dass Ihre Zugverbindung fünfzehn Minuten Verspätung hat. Gleichzeitig würde Ihre Kaffeemaschine sich automatisch auch zehn Minuten später einschalten, damit ihr Frühstückskaffee nicht kalt ist, bis Sie aufstehen. Klingt wie Zukunftsmusik? Das alles ist heute schon möglich. Die Firma Ericsson prognostiziert, dass bis 2020 mindestens 50 Milliarden Geräte über das Internet kommunizieren werden 2. Möglich ist das dank der zunehmenden Verbreitung von IPv6 und offenen Maschine-zu-Maschine-(M2M-)Kommunikationsprotokollen, die leichtgewichtig genug sind, um mit möglichst wenig Protokoll-Overhead sogar über Mobilfunknetze eine günstige Kommunikation zu erlauben.
MQTT
Das Message-Queue-Telemetry-Transport-(MQTT-)Protokoll wurde 1999 von Andy Stanford-Clark (IBM) und Arlen Nipper (Eurotech) als ein M2M-Kommunikationsprotokoll mit minimalen Protokoll-Overhead entwickelt, um vernetzten Geräten eine Möglichkeit zu bieten, möglichst bandbreiten- und batterieschonend zu kommunizieren. Das Protokoll schlägt mit einem ereignisgesteuerten Ansatz einen anderen Weg ein als beispielsweise HTTP, welches auf Request/Response basiert. MQTT benutzt das Publish Subscribe Pattern (Abb. 1.1). Das bedeutet, dass die Clients sich untereinander nicht kennen und einen zentralen Verteiler, einen so genannten Broker, zur Kommunikation nutzen. Der Broker ist dafür zuständig, dass eine gesendete Nachricht alle interessierten Clients erreicht. Wenn ein Client sich mit einem Broker verbindet, teilt dieser dem Broker mit, für welche so genannten Topics er benachrichtigt werden möchte, also welche Topics er abonnieren will. Diesen Vorgang nennt man Subscribe. Wenn ein Client eine Nachricht sendet, muss er darin angeben, an welches Topic diese Nachricht gesendet werden soll. Diesen Vorgang nennt man Publish. Durch diese Architektur ist es möglich, hochskalierbare Lösungen mit Tausenden von Clients zu entwickeln, ohne dass Abhängigkeiten zwischen den teilnehmenden Clients entstehen.

Abbildung 1.1: Publish Subscribe mit MQTT
Der Unterschied zu HTTP ist, dass ein Client nicht erst durch einen Request anfragen muss, ob neue Informationen vorhanden sind, sondern dieser automatisch vom Broker benachrichtigt wird. Sollte ein Client nicht verbunden oder der Broker nicht erreichbar sein, implementiert das Protokoll selbst Mechanismen zum Persistieren der Nachrichten und dem automatischen Senden, sobald Broker oder Client wieder erreichbar sind.
Topics
Jeder Client kann frei wählen, zu welchem Topic er publishen oder subscriben möchte. Topics sind frei wählbare Strings und können mittels einem „/“ hierarchisch aufgebaut werden. Beispiele wären home/temperature und home/brightness. Das Root Topic wäre hier „zuhause“ und die untergeordneten Topics wären temperature und brightness. Ein Client könnte entweder ein konkretes Kind-Topic abonnieren oder mittels einer Wildcard (#) alle Kind-Topics eines Eltern-Topics abonnieren. Beispielsweise könnte er home/# abonnieren, was zur Folge hätte, dass er alle Nachrichten für home/temperature und home/brightness zugestellt bekommt. Bei den Topic-Namen wird zwischen Groß- und Kleinschreibung unterschieden.
Eclipse Paho
Anfang 2012 gründete sich das Paho-Projekt unter der Schirmherrschaft der Eclipse Foundation mit dem Ziel, Open-Source-Implementierungen von M2M-Protokollen bereitzustellen. Zurzeit wird die Referenzimplementierung des MQTT-Protokolls in Form von Clients für Java, C, C++, JavaScript, Lua und Python bereitgestellt. Das Paho-Projekt ist zwar noch recht jung, die Java- und C-Implementierungen werden jedoch seit Jahren bei IBM und Eurotech, welche auch die initiale Implementierung bereitgestellt haben, eingesetzt und sind für den produktiven Einsatz geeignet. Wir sehen uns nun anhand der Implementierung eines konkreten Anwendungsfalls die Paho-Bibliothek für Java genauer an.
Anwendungsfall
Wie bereits angesprochen, ist MQTT ideal für bandbreitenschonende Kommunikation von Sensordaten, weshalb wir in folgendem Beispiel einen solchen Anwendungsfall herausgreifen und implementieren. In diesem Fall realisieren wir eine Überwachung von Temperatur und Helligkeit in einem Raum. Das heißt wir haben ein Gerät, dass Temperatur und Helligkeit misst, beispielsweise einen Raspberry Pi, und diese Daten zu einem öffentlichen Broker schickt. Wie Abbildung 1.2 zeigt, empfängt ein zweites Gerät die Daten, zeigt diese an und gibt eine Warnung aus, sollte der Raspberry Pi ausfallen. Damit kann man, auch wenn man nicht zu Hause ist, die Sensordaten im Blick behalten und benachrichtigt werden, sofern der Sensorclient nicht mehr richtig funktionieren sollte.

Abbildung 1.2: Darstellung des Anwendungsfalls
Eclipse Paho und Maven
Nachdem der Anwendungsfall festgelegt ist, können wir mit der Implementierung der Clients beginnen. Zuvor aber noch kurz einige Worte zum Einrichten eines neuen Projekts unter Verwendung von Eclipse Paho und Maven. Die Paho-Bibliothek befand sich zum Zeitpunkt der Fertigstellung dieses shortcuts noch nicht im Maven Central Repository. Es ist deshalb notwendig, das Eclipse Paho Maven Repository 3 in das Projekt einzubinden, da ansonsten die Bibliothek nicht gefunden wird. Das vollständige Beispiel ist bei GitHub verfügbar und kann unter 4 heruntergeladen werden.
Implementierung Sensorclient
Wir implementieren zunächst den Sensorclient, welcher ein Thermometer und die Helligkeitsmessung simuliert und jede Sekunde einen Datensatz an einen öffentlich zugänglichen Broker sendet. Zunächst müssen wir eine Instanz der Klasse MqttClient erzeugen (Listing 1.1).
public class Publisher {
public static final String BROKER_URL = "tcp://broker.mqttdashboard.com:1883";
private MqttClient client;
public Publisher() {
String clientId = Utils.getMacAddress() + "-pub";
try {
client = new MqttClient(BROKER_URL, clientId);
} catch (MqttException e) {
e.printStackTrace();
System.exit(1);
}
}
}
Listing 1.1
Als Parameter für den Konstruktor wird der URL zum Broker und eine eindeutige Client-ID benötigt. Als Client-ID bietet sich die MAC-Adresse des Rechners an, da diese eindeutig ist. Zusätzlich wird noch -pub an die Client-ID gehängt, da unsere zwei unabhängigen Clients (einer zum Senden, einer zum Empfangen) sonst dieselbe Client-ID besäßen. Es ist wichtig, dass die Client-ID eindeutig ist, da der MQTT-Broker pro ID nur einen Client zulässt. Falls schon ein Client mit derselben ID gerade eine Verbindung zum Broker aufgebaut hat, wird die Verbindung des „älteren“ Clients abgebrochen. Die maximale Länge einer Client-ID beträgt laut der Spezifikation 23 Zeichen, viele Broker erlauben jedoch eine Erweiterung auf mehr Zeichen.
Nachdem wir eine Instanz von MqttClient haben, können wir uns mittels der connect(…)-Methode zum Broker verbinden (Listing 1.2). Die connect(…)-Methode bietet uns an, eine Instanz von MqttConnectOptions zu übergeben. Wir erzeugen uns ein neues Objekt von MqttConnectOptions und setzen cleanSession auf false. Damit signalisieren wir dem Broker, dass wir bei einer Verbindung zum Broker mit einer alten Session weiterarbeiten möchten, falls der Client schon einmal verbunden war. Damit ist es möglich, dass bei einer Quality of Service von 1 oder 2 (Kasten: „Quality of Service“) keine ausstehenden Nachrichten verlorengehen. Zusätzlich geben wir für den Client ein „Last Will and Testament“ (LWT) Topic an. Ein LWT-Topic ist ein Topic, für das der Broker eine Nachricht sendet, falls die Verbindung zu einem Client unvorhergesehen abbricht. Damit ist es möglich, dass man interessierte Clients darüber benachrichtigt, dass ein anderer Client nicht mehr an der Kommunikation teilnimmt.
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(false);
options.setWill(client.getTopic("home/LWT"),
"I'm gone".getBytes(), 0, false);
client.connect(options);
Listing 1.2
Quality of Service
Das MQTT-Protokoll definiert drei Arten von Quality of Services (QoS):
• QoS 0: At most once delivery
• QoS 1: At least once delivery
• QoS 2: Exactly once delivery
Mit einer QoS definiert ein Client, wie wichtig es ist, dass die Nachricht auch wirklich bei den Empfängern ankommt. Eine QoS von 0 bedeutet, dass die Nachricht höchstens einmal beim Empfänger ankommt. Es ist unter gewissen Umständen auch möglich, dass eine Nachricht gar nicht beim Empfänger ankommt. QoS 1 bedeutet, dass garantiert wird, dass die Nachricht mindestens einmal bei den Empfängern ankommt. Es kann aber auch passieren, dass die Nachricht mehrmals ankommt. QoS 2 bedeutet, dass garantiert wird, dass die Nachricht exakt einmal bei den jeweiligen Empfängern ankommt.
Umso höher der QoS-Level ist, desto weniger performant wird die Übertragung, da eine zusätzliche Kommunikation zwischen den Clients und dem Broker nötig ist, um sicherzustellen, dass die Nachricht auch wirklich angekommen ist.
Zuletzt implementieren wir eine einfache Endlosschleife, in der der Publish-Client jede Sekunde einen zufälligen Wert für die Helligkeit an das Topic home/brightness und einen zufälligen Temperaturwert an das Topic home/temperature sendet (Listing 1.3). Dazu holen wir uns ein Topic Object mittels der Methode client.getTopic(…) und führen dort die Methode publish(…) mit unserer gewünschten MqttMessage aus. Um zu überprüfen, dass die Nachricht auch wirklich gesendet wurde, kann man auf der Seite http://www.mqttdashboard.com das gewünschte Topic abonnieren und sehen, was an den Broker bisher gesendet wurde.
public static final String TOPIC_TEMPERATURE = "home/temperature";
//…
while (true) {
publishBrightness();
Thread.sleep(500);
publishTemperature();
Thread.sleep(500);
}
//…
private void publishTemperature() throws MqttException {
Darmowy fragment się skończył.