Auf den Spuren von Ted Faison

Tutorial: MQTT mit JavaScript

Tam Hanna

© Shutterstock / tatianasun

Bei großen oder kostenintensiven Deployments mag ein von Hand entwickeltes Protokoll Kosten sparen. Insbesondere bei kleineren Installationen ist es jedoch im Interesse der Aufwandsvermeidung oftmals vernünftiger, auf eine vorgefertigte Implementierung zu setzen.

Das vor wenigen Wochen in Version 5 erschienene MQTT ist ein Klassiker im Feld der eventorientierten Protokolle. Es implementiert die beispielsweise in Ted Faisons Klassiker „Event-Based Programming“ beschriebene Eventarchitektur und ermöglicht zudem die mit Vorteilen verbundene Benutzung einer reduzierten Koppelung und besticht durch eine einfache Wartbarkeit. MQTT galt als Quasistandard im Embedded-Bereich – es gab kaum einen Prozessrechner, für den es nicht ein mehr oder weniger gut entwickeltes SDK gab. Wer mit JavaScript arbeitet, hatte bisher allerdings das Nachsehen. Das von Adam Rudd, Matteo Collina und Maxime Agor entwickelte MQTT.js möchte diese Lücke schließen. In diesem Artikel werfen wir einen kurzen Blick auf die vielfältigen Möglichkeiten.

Infrastrukturales

Auch wenn der eine oder andere nun einen Leserbrief schreibt: MQTT 5.0 spielt zum Zeitpunkt der Drucklegung dieses Hefts nur eine sehr untergeordnete Rolle. Serveranbieter haben zwar Absichtserklärungen veröffentlicht, die neue Version des Protokolls irgendwann zu unterstützen – im Moment arbeiten allerdings so gut wie alle praktischen Implementierungen mit der Vorgängerversion 3.1.1. Problematisch ist, dass die von den meisten Linux-Distributionen angebotene Version des quelloffenen Servers Mosquitto extrem alt ist und mit aktuellen Clients nicht zusammenarbeiten kann. Wer als Server eine X86-Maschine benutzt, kann das Problem durch Einbinden eines zusätzlichen Repositories umgehen:

sudo add-apt-repository ppa:mosquitto-dev/mosquitto-ppa
sudo apt-get update
sudo apt-get install mosquitto mosquitto-clients

Diese für Linux-Nutzer standardisiert erscheinende Befehlsfolge ist insofern hakelig, als das Repository keine Pakete für alternative Prozessorarchitekturen bereithält. Wer seinen MQTT-Server beispielsweise auf einem ARM-basierten Prozessrechner hosten möchte, muss den Code von Hand kompilieren. Problematisch ist hierbei die Erfordernis, divere Bibliotheken für WebSockets und Co bereitzuhalten.

Da dieser Artikel nicht in eine Erklärung von Unix-Administration ausarten soll, gehen wir in den folgenden Schritten davon aus, dass eine korrekt konfigurierte MQTT-Instanz unter der IP-Adresse 192.168.1.106 zum Einsatz bereitsteht. Beachten Sie zudem die Konfigurationsdatei /etc/mosquitto/mosquitto.conf – in ihr finden sich diverse Parameter zum Aktivieren von Logging-Funktionen, die Zustandsinformationen in das Systemlog ausgeben. Diese lassen sich allerdings nicht mittels dmesg abernten. Zum Einsammeln ist der in Abbildung 1 gezeigte Log-Viewer verantwortlich.

Abb. 1: Bei korrekter Konfiguration finden sich hier diverse Informationen über den Prozess

Abb. 1: Bei korrekter Konfiguration finden sich hier diverse Informationen über den Prozess

Im nächsten Schritt müssen wir, wie gewohnt, einen Versionsabgleich von Node.js und NPM durchführen. Auf dem zur Erzeugung dieses Artikels verwendeten Rechner befanden sich die folgenden Versionen, neuere Varianten funktionieren allerdings im Allgemeinen auch problemlos:

tamhan@TAMHAN14:~$ node -v
v8.11.3
tamhan@TAMHAN14:~$ npm -v
5.6.0

Im nächsten Akt müssen wir ein Demoprojekt erzeugen und es mit dem MQTT-Paket ausstatten. Beides sind Aufgaben, die man ganz im Vertrauen an NPM delegieren kann. Aus Platzgründen drucken wir hier nur die einzugebenden Befehle ab und gehen nicht weiter auf das eigentliche Abarbeiten der Assistenten ein:

tamhan@TAMHAN14:~/demo1$ npm init
tamhan@TAMHAN14:~/demo1$ npm install mqtt --save
. . .
+ mqtt@2.18.2
tamhan@TAMHAN14:~/demo1$ touch index.js

Der im Skript verwendete Touch-Befehl sorgt dafür, dass Unix eine leere Datei namens index.js anlegt. Sie wird den Einsprungpunkt des Programms enthalten. Öffnen Sie das File in einem Texteditor ihrer Wahl, und passen Sie seinen Code an:

var mqtt = require('mqtt')
var client  = mqtt.connect('mqtt://192.168.1.106')

Wie bei fast allen Node-Programmen beginnt auch dieses Beispiel mit dem Laden der externen Bibliothek, die fortan in der Variable MQTT zur Verfügung steht. Als nächstes folgt ein Aufruf der connect-Funktion, um den Client zum Aufbau einer Verbindung zu unserem Server zu animieren.

Neben dem hier verwendeten MQTT-Präfix kennt das Framework auch sechs weitere Strings, die die zur Kommunikation mit dem Server zu verwendenden Protokolle beschreiben. Neben klassischem und gesichertem MQTT gibt es sogar auf WebSockets basierende Versionen, mit denen man Firewalls untertunneln kann:

  • mqtt
  • mqtts
  • tcp
  • tls
  • ws
  • wss
MobileTech Conference & Summit 2019
Lars Röwekamp

Android App Development: Survival Guide

mit Lars Röwekamp (OPEN KNOWLEDGE)

Christian Liebel

Progressive Web-Apps mit Angular: hands-on

mit Christian Liebel (Thinktecture AG)

Freilaufende Ereignisse

MQTT.js ist ein vollständig eventorientiertes System. Die on-Methode erlaubt uns das Anmelden von Funktionen, die bei bestimmten Protokollereignissen zum Einsatz kommen. Zum Zeitpunkt der Drucklegung kennt die Bibliothek insgesamt neun Ereignisse, die wir in der Tabelle 1 kurz vorstellen.

String Beschreibung des Ereignisses
connect Erfolgreicher Verbindungsaufbau zum Server bzw. Broker
reconnect Beginn eines Verbindungsversuchs nach Verbindungsverlust
close Wird nach Verbindungsverlust aufgerufen
offline Wird aufgerufen, wenn MQTT.js der Ansicht ist, dass die Internetverbindung nicht besteht
error Ein Parsing- oder Verbindungsfehler ist aufgetreten
end Die end()-Methode wurde aufgerufen
message Ein PUBLISH-Paket ist eingetroffen
packetsend Versendung eines beliebigen MQTT-Pakets
packetreceive Empfang eines beliebigen MQTT-Pakets

Tabelle 1: Ereignisse, die in der Bibliothek vorhanden sind

Wir melden uns hier bei Connect an und führen im Fall des erfolgreichen Verbindungsaufbaus zwei Befehle aus. Das direkte Übergeben der Funktionen ist ein klassisches Designpattern bei der Arbeit mit MQTT.js:

client.on('connect', function () {
  client.subscribe('tamschannel')
  client.publish('tamschannel', 'Hello mqtt')
})

MQTT arbeitet streng kanalorientiert. Für Sie als Entwickler bedeutet das, dass sich Clients beim Server bei bestimmten Kanälen anmelden, oder aber Nachrichten in Kanäle senden können. Wir nutzen hier sowohl subscribe als auch publish. Mittels ersterer melden wir uns im Kanal an, während wir mittels Publisher eine Nachricht in eben diesen senden. Wer Nachrichten senden möchte, muss sich übrigens nicht vorher anmelden. MQTT-Server sind gemäß Protokollspezifikation in der Lage, beim Senden und beim Anmelden noch nicht vorhandene Kanäle anzulegen. Wer eine Nachricht an einen frisch angelegten Kanal sendet, darf sich nicht wundern, wenn diese naturgemäß nirgendwo ankommt. Bei der Installation von MQTT mit dem weiter oben abgedruckten Befehl wandert neben dem Server auch eine Gruppe von Kommandozeilenwerkzeugen auf die Station, die die lokale Interaktion mit MQTT und MQTT-Ereignissen ermöglichen. Wir wollen im ersten Schritt auf der Workstation ein Testprogramm anwerfen, das auf im Kanal eintreffende Ereignisse lauert. Öffnen Sie hierzu ein neues Terminal und geben Sie folgenden Befehl ein:

tamhan@TAMHAN14:~$ mosquitto_sub -h localhost -t tamschannel

Im nächsten Schritt reicht ein Aufruf von node index, um die Node-Umgebung zur Abarbeitung der JavaScript-Datei zu animieren. Wer alle Parameter richtig angegeben hat, sieht das in Abbildung 2 gezeigte Resultat. Wundern Sie sich übrigens nicht darüber, dass sie das Node-Programm durch Eingabe von STRG + C beenden müssen – da der Client mit dem Server verbunden bleibt, beendet sich das Programm nicht automatisch.

Abb. 2: Der erste Test ist problemlos aufseiten der Workstation angekommen

Abb. 2: Der erste Test ist problemlos aufseiten der Workstation angekommen

Nachrichten entgegennehmen

Nachdem wir nun eine Message vom JavaScript-Teil zum Server geschickt haben, wollen wir den Kreis im nächsten Schritt schließen. MQTT 3.1.1 unterscheidet sich insofern von seinem Nachfolger MQTT 5, als sich das Protokoll selbst als datenagnostisch sieht. Das bedeutet, dass sich MQTT nur darauf beschränkt, die Informationen von A nach B zu bringen – was sich in diesen Blobs befindet, und wie man sie interpretiert, ist die alleinige Aufgabe des Entwicklers. Kehren Sie in die Datei index.js zurück und adaptieren Sie den in ihr enthaltenen Code nach folgendem Schema:

client.on('message', function (topic, message) {
  console.log(message.toString())
  client.end()
})

Das Clientobjekt emittiert die diversen in der Tabelle genannten Ereignisse. Wir sprechen hier den Message-Event-Handler an, der logischerweise immer dann aufgerufen wird, wenn eine eingehende Nachricht zur Abarbeitung bereitsteht. Da es sich dabei um ein Bufferobjekt handelt, müssen wir im ersten Schritt die Methode toString aufrufen, um die Inhalte in ein darstellbares Format zu bringen. Nach dem Ausgeben unter Nutzung von console.log fehlt nur noch ein Aufruf von end(), um den Client sauber zu beenden. Wer das vorliegende Programm wie gewohnt ausführt, sieht die Meldung abermals im mosquitto_sub-Fenster. Zudem wird die Programmverarbeitung automatisiert beendet. Der bisher notwendige „Affengriff“ ist nicht mehr erforderlich, um das für die Ausführung von Node verantwortliche Terminal wieder frei zu bekommen.

Ein weiterer netter Aspekt des API ist, dass der vor dem publisher-Aufruf befindliche Aufruf von subscribe auch wirklich zuerst ausgeführt wird – das bedeutet, dass unser Programm das von ihm selbst gesendete Paket auch gleich wieder entgegennehmen kann.

Von tausend Toden

MQTT kann seine Stärken unter anderem dann ausspielen, wenn die Verbindung zwischen Client und Server unzuverlässig ist. Ein Klassiker ist dabei die Funktion des Last Will – der englische Begriff für Testament beschreibt im Großen und Ganzen, was das Feature treibt. Last Wills erlauben dem Client das Festlegen einer Payload, die vom Server abgesendet wird, wenn ein Verbindungsabbruch auftritt. Die Art der Erkennung des Abbruchs ist dabei übrigens von System zu System unterschiedlich – im Allgemeinen gibt es eine Art Time-out, nach dem der Server einen Client als verendet betrachtet, wenn innerhalb dieser Zeitspanne keine Informationen eingegangen sind.

Zur Demonstration des Programmverhaltens müssen wir unseren kleinen Test ein wenig anpassen. Adaptieren Sie die Datei index.js, und ersetzen Sie den Inhalt durch folgenden Code:

var mqtt = require('mqtt')
var client  = mqtt.connect('mqtt://192.168.1.106', {
  will: {
    topic: "tamschannel",
    payload: "Der Client ist gestorben!"
	}
})

Der Aufruf der connect-Methode kann auf Wunsch mit einem mehr oder weniger komplexen Parameterobjekt ausgestattet werden. Wir schreiben das Feld will ein, indem wir neben dem für die Ablebensmeldung zu verwendenden Channel die eigentlich zu übertragende Nachricht einschreiben. Wichtig ist, dass der vorher hinzugefügte Aufruf von end() entfernt werden muss. Im Rahmen von end() sendet der Client ein Paket an den Server, das das Ableben als gewünscht markiert. Die Konsequenz davon ist, dass die Last-Will-Nachricht über den Jordan geht. Clients haben also die Wahl, entweder geordnet zu verschwinden oder aber die Last-Will-Nachricht zu senden. Es spricht allerdings nichts dagegen, bei Bedarf von Hand ein Publish-Paket mit dem Inhalt des Last Will zu senden, bevor man sich mittels end() verabschiedet.

Kehren Sie sodann in eines der Terminalfenster zurück und starten Sie das Programm durch Eingabe von node index. Killen Sie es dann durch Drücken von STRG + C. Nach getaner Arbeit sehen Sie im Monitor das in Abbildung 3 gezeigte Ergebnis.

Abb.3: Die Last-Will-Nachricht wurde nach der Erkennung der Trennung automatisch abgeschickt

Abb.3: Die Last-Will-Nachricht wurde nach der Erkennung der Trennung automatisch abgeschickt

Angemerkt sei, dass der MQTT-Server hier in einer „einfachen“ Situation ist. Da sowohl Client als auch Server auf derselben Maschine liegen, ist ein Verbindungsabbruch durch den geteilten TCP-IP-Stack schnell erkennbar. In der Praxis können bis zu sechzig, oder sogar noch mehr Sekunden vergehen, bevor der Server mitbekommt, dass sein Client in die ewigen Jagdgründe eingefahren ist.

Intim mit dem Paket

Hier stellt sich die Frage, wie der weiter oben angepriesene Keep-alive-Prozess funktioniert, wenn ein Client für längere Zeit keinerlei Informationen sendet. Das MQTT.js-Team hat mit MQTTPacket eine eigene Gruppe von Abstraktionsklassen geschaffen, die Interaktion mit den hier bereitstehenden Standard deklarierten Klassen ermöglichen. Wer den Code direkt in sein Projekt einbinden oder ansehen möchte, findet ihn im Repository auf Github.

Zum Testen ergänzen wir unser Programm, das nach wie vor ohne Aufruf von end() auskommen muss, um folgende Methoden:

client.on('packetsend', function (packet){
console.log("Packet Send aufgerufen")
console.log(packet)
})
client.on('packetreceive', function (packet){
console.log("Packet Receive aufgerufen")
console.log(packet)
})

Neben den bisher verwendeten Ereignissen bietet das Clientobjekt auch die Events packetsend und packetreceive an, die bei jedem beliebigen Eingehen oder Ausgehen eines Pakets aufgerufen werden. Wir übergeben die Payloads direkt an console.log, wo sie deserialisiert werden – eine Situation, in der JSON-Objekte ihre Stärken ausspielen.

Starten Sie das Programm jedenfalls im nächsten Schritt, und warten Sie eine Minute. Die sofort nach dem erstmaligen Aufruf eingehenden und ausgehenden Pakete wollen wir erst später betrachten. Interessanter ist für uns der folgende Austausch, der nach rund einer Minute absoluter Funkstille auftritt:

Packet Send aufgerufen
{ cmd: 'pingreq' }
Packet Receive aufgerufen
Packet {
  cmd: 'pingresp',
  retain: false,
  . . . }

Im ersten Schritt sendet der Client ein pingreq-Paket in Richtung des Servers, mit dem er diesen zum Durchführen eines Ping-Zyklus auffordert. Der Server beantwortet dieses dann mit einem pingresp-Paket. Hinter der Abkürzung verbirgt sich übrigens der Begriff Ping Response. Requests und Responses spielen in MQTT an vielerlei Stelle eine Rolle.

Als Beispiel dafür folgenden Datenaustausch, der die Anmeldung eines Clients bei einem Kanal illustriert:

Packet Send aufgerufen
{ cmd: 'subscribe',
  subscriptions: [ { topic: 'tamschannel', qos: 0 } ],
  . . . }
. . .
Packet Receive aufgerufen
Packet {
  cmd: 'suback',
  . . .}

Im ersten Schritt sendet der Client hierbei ein subscribe-Paket, das vom Server dann mit einem suback-Paket (Kurzform von Subscription Acknowledge) quittiert wird. Hier findet sich übrigens auch einer der wichtigsten Unterschiede zwischen MQTT 3.1.1 und dem Nachfolger MQTT 5 – die ältere Protokollversion kennt keinen Weg, um eine Subskription abzulehnen. Stattdessen kickt der Server den Probleme verursachenden Client einfach. Informationen über die Ursache finden sich, wenn überhaupt, nur im weiter oben erwähnten Systemlog. In MQTT 5.0 ist es erlaubt, eine Ablehnung mit Informationen über das aufgetretene Problem zu versehen, um das Debugging so zu erleichtern. Wer dieses Verhalten nicht wünscht, darf es aber auch deaktivieren. Insbesondere bei sicherheitskritischen Situationen ist es ratsam, Angreifern keine Informationen über den inneren Aufbau des Systems zu liefern.

Und jetzt im Browser

Die weiter oben genannte Liste von Verbindungsoptionen ist kein Scherz. MQTT.js ist nicht nur für die Arbeit im Backend vorgesehen – es ist auch erlaubt, das Framework in Webseiten und anderen Elementen zu verwenden, die für die Ausführung im Browser vorgesehen sind. An dieser Stelle hat man allerdings ein Problem: Die Kommunikation zwischen MQTT-Server und MQTT-Client erfolgt normalerweise nämlich über gewöhnliche TCP-Sockets – eine Kommunikationsmethode, die in Browsern nicht wirklich implementiert ist. Mozilla unternahm zwar im Rahmen von Firefox OS einige Versuche in diese Richtung – wir wollen im Interesse der Pietät allerdings das Schweigen über die ganze Episode fallen lassen. Als Lösung für dieses Problem ersah das MQTT.js-Entwicklerteam ein als Mosca bezeichnetes Framework, das unter http://www.mosca.io/ gehostet ist. Es handelt sich dabei um eine Kombination aus einem Broker und einem Server, die per WebSocket ansprechbar ist.

Zum Zeitpunkt der Drucklegung dieses Hefts sind in der Implementierung einige Einschränkungen gegenüber einer vollständigen MQTT-Serverinstanz zu beachten. Erstens unterstützt der Broker nur die Protokollversionen 3.1 und 3.1.1. Zudem wird im Bereich QoS-Labels nur null und eins unterstützt. Wer Nachrichten mit Qualitätssicherungslevel zwei übertragen möchte, hat Pech gehabt (siehe Kasten „Von der Sicherheit“).

Von der Sicherheit

MQTT kennt drei verschiedene „Absicherungslevels“, die den Grad des Aufwands bei der Nachrichtenübertragung beschreiben. Eine mit QoS null gesendete Nachricht wird vom Sender in Richtung des Empfängers gesendet – was dann passiert, ist in Gottes Hand.

QoS eins garantiert, dass die Nachricht zumindest einmal ankommt – der Server sendet sie so lange weiter, bis eine PUBACK-Nachricht zurückkommt. Da diese verloren gehen kann, ist es möglich, dass eine Nachricht mehrfach zugestellt wird. Das insbesondere bei Cloud-Servern nicht angebotene QoS 2 sichert dies durch eine Gruppe von Paketen ab – eine derartige Nachricht verursacht Unmengen von Paketaustauschen, kommt aber relativ sicher nur einmal an.

Wer keine Instanz von Mosquitto installiert hat, kann das Produkt einfach global installieren und wie gewohnt ausführen:

tamhan@TAMHAN14:~$ sudo npm install mosca pino -g
[sudo] password for tamhan:

Im Stand-alone-Betrieb dient das hauseigene Ascolatori als Backend, das hier im Detail beschrieben ist. Ascoltatori realisiert im Prinzip ein normales Eventsystem. Der einzige Unterschied zum normalem MQTT ist, dass Ascoltatori neben Mosca keine weiteren Interfaces bereitstellt. Wer Mosca mit einem auch für Nicht-JavaScript-Systeme ansprechbaren Mosquitto-Server verbinden möchte, erzeugt stattdessen ein neues Node-Projekt und erweitert es um die Mosca-Bibliothek:

tamhan@TAMHAN14:~/serveradapter$ npm install mosca --save

Erstellen Sie im nächsten Schritt einen Einsprungpunkt, der mit dem Laden des Mosca-Pakets beginnt:

var mosca = require('mosca');

var feld = {
  type: 'mqtt',
  json: false,
  mqtt: require('mqtt'),
  host: '127.0.0.1',
  port: 1883
};

Zur Initialisierung des Broker-Service ist ein Backend-Objekt erforderlich. Die dort angelieferten Informationen bestimmen das Verhalten als Ganzes. Neben Mosquitto ist es erlaubt, verschiedene Datenbanksysteme zu laden. Im nächsten Schritt muss das eigentliche Steuerungsobjekt erzeugt werden:

var settings = {
  port: 1884,
  backend: feld
};

Nach dem Übergeben des Informationsobjekts ist die Auswahl des Ports wichtig. Achten Sie darauf, einen zu verwenden, der noch frei ist. Ist der Port blockiert, scheitert Moskau beim Start. Nach diesen Vorbereitungshandlungen können wir das Programm loslassen:

var server = new mosca.Server(settings);

server.on('ready', setup);
function setup() {
  console.log('Mosca server is up and running');
}

In der Theorie könnten wir an dieser Stelle einen Verbindungsaufbau wagen. In Tests des Autors erwies sich das Programm allerdings als bockig – auf manchen Stationen ist es den Clients schlichtweg nicht möglich, eine Verbindung zum Server aufzunehmen.

Lieber in bequem

Wer – wie wir – eine aktuelle Version von Mosquitto verwendet, kann die weiter oben durchgeführten Schritte auch an den Server delegieren. Öffnen Sie die oben erwähnte Konfigurationsdatei und ergänzen Sie sie um folgende zwei Statements:

# =================================================================
# General configuration
# =================================================================
listener 1885
protocol websockets

Die Syntax der Konfigurationsdatei ist einfach: Alle nicht mit einem # beginnenden Zeilen sind gewöhnliche Kommandos. Listener initialisiert einen neuen Port, der im nächsten Schritt mit einer Schnittstelle verdrahtet wird. protocol websockets weist Mosquitto dazu an, auf dem jeweiligen Port per WebSockets ansprechbar zu sein. Im nächsten Schritt folgt ein Reboot des Servers – die hier gezeigte Syntax ist für Ubuntu 14.04LTS vorgesehen, andere Distributionen verlangen ein anderes Kommando:

tamhan@TAMHAN14:~$ sudo /etc/init.d/mosquitto restart

Die erfolgreiche Einrichtung des Servers bei aktiviertem WebSocket-Support wirft eine zusätzliche Meldung in das Syslog aus, die auf die Aktivierung des neuartigen Protokolls hinweist:

mosquitto[4664]: Opening websockets listen socket on port 1885.

Ärgerlicherweise deaktiviert das Einschreiben des Listeners den gewöhnlichen Port. Zur Behebung des Problems muss zusätzlich ein normaler Port deklariert werden:

port 1883

Ab dem obligaten Reboot funktionieren die diversen Kommandozeilenprogramme wieder problemlos, die WebService-Meldung bleibt am Bildschirm.

Und jetzt online

Das Entwicklerteam schlägt die Werkzeuge Browserify und WebPack vor, um MQTT.js in ein für Webbrowser verständliches Format zu bringen. In Zusammenarbeit mit dem auf die Browserifizierung von Node-Paketen spezialisierten Anbieter unpkg offeriert man eine fertige Datei, die sich direkt laden lässt. Wir wollen diese in den folgenden Schritten verwenden, weshalb die erste Version unseres Testprogramms folgendermaßen aussieht:

<html>
  <body>
    <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
    <script>
      . . .
    </script>
  </body>
</html>

Neben dem script-Tag, das den eigentlichen Testcode aufnehmen wird, findet sich hier nur die Inklusion des Headers. Im nächsten Schritt können wir damit beginnen, einen ersten Versuch in Richtung eines Verbindungsaufbaus zu unternehmen:

var client = mqtt.connect("http://192.168.1.106:1885")
  client.subscribe("mqtt/demo")

connect() nimmt einen HTTP-URL entgegen, der den anzusprechenden Server beschreibt. MQTT.js und die Browserversion stammen – logischerweise – aus derselben Quelle. Daraus folgt, dass wir auch zur Anmeldung der diversen Events auf die bekannte Syntax zurückgreifen können:

  client.on("message", function (topic, payload) {
    client.end()
  })

Im Browser lebende MQTT-Clients sind insofern kritisch, als ihr Lebenszyklus vom Browsertab abhängig ist. Der Aufruf von end() erlaubt uns das Terminieren der Session, was das Absenden eventueller Last-Will-Meldungen blockiert. Unser Programm sendet als ersten Test eine Nachricht an den weiter oben verwendeten tamschannel:

client.publish("tamschannel", "hello browser!")

Öffnen Sie die Datei in einem Browser mit WebSocket-Unterstützung, um sich an der im Testprogramm mosquitto_sub aufscheinenden Nachricht zu erfreuen. Damit ist bewiesen, dass die Kommunikation zwischen einem im Browser lebenden und einem normal laufenden MQTT-Programm problemlos funktioniert.

Unser Programm verbindet sich im vorliegenden Zustand mit dem Kanal mqtt/demo, der vonseiten unserer Testobjekte nicht weiterverwendet wird. Adaptieren Sie den Code folgendermaßen, um die Überprüfung des Lebenszyklus zu ermöglichen:

client.subscribe("tamschannel")

client.on("message", function (topic, payload) {
  console.log("Verbindung endet");
  client.end()
})

Laden Sie das Programm bei geöffneter Webkonsole, um sich an der Ausgabe der Statusmeldung zu erfreuen: Die Applikation funktioniert plangemäß!

MQTT in fortgeschritten

Wer MQTT erstmals einsetzt, benennt Channels mehr oder weniger zufällig. Solange die Strings eindeutig sind, ist alles in Ordnung. Diese Vorgehensweise nutzt die Vorteile des Protokolls nur leidlich aus, da MQTT ein System zur Errichtung von Ordnerstrukturen anbietet. In spezifischer Weise dient der Slash als Topic Seperator – der String messtechnik/oszilloskope/danaher/tds754d würde aus vier Organisationsebenen bestehen. Das Platzieren eines Slashs am Beginn des Strings ist ein klassisches Antipattern, da es die Belastung des Servers mit einer zusätzlichen Organisationsebene erhöht.

Beim Anmelden von Listeners stehen mit den Zeichen + und # als Wildcard bezeichnete Sonderparameter zur Verfügung. Ein + erlaubt hierbei die Elimination eines einzigen Kanals – der String messtechnik/oszilloskope/+/tds754d würde beispielsweise alle Oszilloskope erbeuten, die vom Typ tds754d sind. Der Herstellerstring ist dem Server dabei egal, solange er nicht mehrere Ebenen umfasst. #, auch als Multi-Level-Wildcard bezeichnet, darf nur am Ende eines Strings stehen. Er matcht alle folgenden Organisationsebenen – messtechnik/# erfasst alle “im Angebot” befindlichen Messgeräte.

Fazit

Das Team um Matteo Collina – der Mann ist unter anderem als Mitveranstalter von jsDay in Verona bekannt – leistete mit MQTT.js Großartiges. Wer das eventorientierte Protokoll schon immer mit JavaScript einsetzen wollte, kann das nun mit minimalem Aufwand bewerkstelligen. Das zahlt sich aus, wenn Sie neben JavaScript noch Systeme einbinden wollen, die in anderen Programmiersprachen entstehen.

JavaScript hat die Eigenschaft, ein in sich geschlossenes Ökosystem zu sein. Bis der Entwickler eines für JavaScript vorgesehenen Protokolls eine C-Bibliothek anbietet, fließt noch viel Donauwasser herunter. Im Fall von MQTT wurde dieser Prozess umgekehrt – die Bibliotheken für C, Java, Android und Co. gibt es schon. In diesem Sinne wünscht Ihnen der Autor viel Spaß beim Channeln Ihres inneren Ted Faison.

Geschrieben von
Tam Hanna
Tam Hanna
Tam Hanna befasst sich seit der Zeit des Palm IIIc mit der Programmierung und Anwendung von Handcomputern. Er entwickelt Programme für diverse Plattformen, betreibt Onlinenewsdienste zum Thema und steht unter tamhan@tamoggemon.com für Fragen, Trainings und Vorträge gern zur Verfügung.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: