Powershell und MQTT
MQTT ist das dominante Protokoll in der IoT-Welt um Meldungen zwischen Komponenten zu übertragen und dabei möglichst wenig Bandbreite zu nutzen und dennoch eine halbwegs sichere Übertragung zu gewährleisten. Die Zusammenhänger dazu finden Sie auf MQTT - Telemetriedaten mit IoT. Diese Seite beschäftigt sich damit, wie Sie mit der M2MQTT-Library per PowerShell als Publisher entsprechende Meldungen an einen MQTT-Broker senden und als Subscriber entsprechende Daten abholen können.
Aus Vereinfachungsgründen gehe ich hier auf Authentifizierung, Verschlüsselung etc. nicht weiter ein. In einem internen abgeschotteten IoT-LAN ist das für Test- und Analysezwecke tolerierbar.
MQTT Libraries
Generell ist MQTT nicht auf TCP beschränkt. Auch andere Übertragungswege sind natürlich ebenso erlaubt. Ich beschränke mich hier aber auf TCP. Zuerst habe ich auf dem Kabel mit Wireshark angeschaut, was passiert aber schon schnell wurde klar, dass es viel Bit und Byte-Operationen benötigt hätte, um das alles mit einem TCP-Listener und PowerShell aufzubauen. Also habe ich mich auf die Suche nach vorhandenen Modulen gemacht, die ich in PowerShell nutzen kann. Passend dazu habe ich schon zwei Webseiten gefunden, die eine ganze Menge Module für die unterschiedlichsten Programmiersprachen und Plattformen auflisten:
- Libraries
https://GitHub.com/mqtt/mqtt.GitHub.io/wiki/libraries - MQTT Client Library Encyclopedia
https://www.hivemq.com/mqtt-client-library-encyclopedia
Es gibt zwar keine fertiges Modul für PowerShell aber doch gleich mehrere Module für .NET auf Windows. Ich habe erst einmal die Projektseiten besucht und geprüft, wann sich da zuletzt etwas getan hat und ob es vielleicht schon fertige DLLs gibt. Auch wenn es viele Libraries gibt, so haben wohl zwei die Nase vorne. (Stand Feb 2018)
Library | URL | Letztes Update | Bemerkung |
---|---|---|---|
Paho.MqttDotnet |
Sep 2017 |
Keine eigenständige Library sondern ein Wrapper für eclipse/paho.mqtt.c |
|
MqttDotNet |
2009 |
Schon länger nicht mehr passiert ? |
|
nMQTT |
2013 |
Auch schon über 4 Jahre her |
|
M2MQTT |
https://GitHub.com/eclipse/paho.mqtt.m2mqtt |
2015 |
Auch wenn die Versoin 4.3.0 schon einige Jahr alt istHier passiert noch was und auch die Beschreibung ist aktuell und installiert wird mit "Install-Package". Kann sowohl MQTT Client als auch Server sein. |
KittyHawkMQ |
2016 |
Auch nur als Source Code |
|
StriderMqtt |
2018 |
Kleiner leichtgewichtiger Client aber zum selbst kompilieren |
Das ich niemandem zumuten will, erst mit MonoDevelop oder Visual Studio den Code zu erstellen, habe ich mir M2MQTT genauer angeschaut.
M2MQTT installieren
Durch die Installation in das PowerShell Package Center ist die Einrichtung auf einem Client sehr einfach. Sie starten in einer Admin-PowerShell einfach nur
# Installation per PowerShell Install-Package M2Mqtt
Ggfls. gibt es noch eine Rückfrage zur Installation aber dann landen die Binaries auf ihrem PC.
- Install-Package
https://docs.microsoft.com/en-us/powershell/module/packagemanagement/install-package?view=powershell-5.1
Irgendwie werden sich Windows bzw. die PowerShell und Linux immer ähnlicher.
Bei mir war die NET.4.5-Version auf "C:\Program Files\PackageManagement\NuGet\Packages\M2Mqtt.4.3.0.0\lib\net45\M2Mqtt.Net.dll". Die DLL muss im PowerShell-Script dann noch eingebunden werden, damit Sie die darin enthaltenen Klassen nutzen können.
Add-Type -Path "C:\Program Files\PackageManagement\NuGet\Packages\M2Mqtt.4.3.0.0\lib\net45\M2Mqtt.Net.dll"
- Add-Type
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/add-type?view=powershell-5.1 - Add-Type vs. [reflection.assembly] in
PowerShell
http://www.madwithpowershell.com/2013/10/add-type-vs-reflectionassembly-in.html
Meldung senden (PUBLISH)
Aber mit wenige Zeilen können Sie z.B. einen Wert an einen Broker senden. "broker.hivemq.com" ist ein Test-Broker, den Sie laut Hersteller einfach nutzen können. Einen Status sehen Sie dann auf http://www.mqtt-dashboard.com/index.html. Bei der Menge an Veröffentlichungen (100-200(Sek) werden Sie ihre Meldung aber eher selten dort sehen.
# MQTTClient instanzieren $MqttClient = [uPLibrary.Networking.M2Mqtt.MqttClient]("broker.hivemq.com") # # Verbinden $mqttclient.Connect([guid]::NewGuid()) # Wert schreiben $MqttClient.Publish("sensor/temp", [System.Text.Encoding]::UTF8.GetBytes("20"))
Im Wireshark sind der 3-Wege-TCP-Handshake und der MQTT-"Connect Command" samt der "Connect Ack" zu sehen. Mit einigen Sekunden Abstand sehen Sie dann auch den "Publish Message", die ich unten im Detail aufgezeichnet habe.
Damit ist es schon einmal möglich einen Wert an einen Broker zu senden. Sie brauchen sicher nur wenige Sekunden u das Potential zu erkennen, wenn Sie z.B. Performance Counter an einen MQTT-Broker senden. Hinsichtlich der "Message" gibt es keine Vorgaben. Es muss einfach nur ein String sein aber ob sie hier nur einfach eine Zahl als String, eine JSON/XML-Struktur oder andere Daten senden.
Insofern ist natürlich MQTT auch aus Sicherheitsaspekten kritisch zu betrachten, denn über einen in Internet erreichbaren Broker könnte ich auch Daten aus dem Firmennetzwerk nach extern ausleiten. Durch die "Subscribe"-Logik wird es sicher nicht lange dauern, bis auch Command&Control-Server diesen Kanal verwenden.
Der Client muss aber auch die Verbindung halten, damit der Broker ja erkennt, dass der Client noch da ist. Der Client kann dem Broker nämlich mitteilen, wie er sich bei einem ungeplanten Disconnect verhalten soll. Dazu gibt es einen "Last Will"
- MQTT Essentials Part 9: Last Will and
Testament
https://www.hivemq.com/blog/mqtt-essentials-part-9-last-will-and-testament
Damit ist dann auch verständlich, dass der Client einen Art "Heartbeat" senden muss. Das übernimmt die Library durch entsprechende PING-Requests.
So kann der Broker überwachen, welche Clients online sind. Diese Funktion ist auch für die nächste Funktion wichtig
Meldungen empfangen (SUBSCRIBE)
Ein Client kann auch ein System sein, welches Meldungen vom Broker empfangen will. Dazu muss es einen "SUBSCRIBE" machen und den Pfad übergeben, der für diesen Client interessant ist. Auch hier ist der Heartbeat erforderlich, da der Broker so einen vom Client aufgebauten Kanal zur Rücksendung der Antworten hat. Eine neue Meldung wird aktiv vom Broker an den Client gesendet. Es gibt so gesehen kein "Polling".
Die Nutzung von Subscriptions ist klassisch ein asynchroner Vorgang. Eine Meldung kann jederzeit kommen und ich möcht mein Skript ja nicht mit einem "Warten auf Message" anhalten. Daher muss ich über die "Subscribe"-Methode der Klasse ein oder mehrere MQTT-Pfade mitgeben, die mich interessieren.
# Subscribe $MqttClient.Subscribe("msxfaq/temp",0)
Auch diese Aktion ist im Wireshark zu sehen. Der "Subscribe Request" wird durch einen "Subscribe Ack" bestätigt.
Wenn sich nun auf dem Broker dieser Wert ändert, sollte dieser Client auch die Information dazu bekommen.
Auf Meldungen warten
Die Frage ist nun , wie ich in PowerShell auf diese Events warte. Es gibt hier kein "$mqttclient.getMessage()" o.ä., bei der das Skript dann auf eine Meldung wartet. Die Klasse M2MQTT implementiert aber einen Eventhandler als Callback-Funktion. Ich muss quasi ein Stück Code hinterlegen, welcher von der MQTT.Client-Instanz dann aufgerufen wird. Das geht in PowerShell über "Register-ObjectEvent"
- Powershell und Callback-Funktionen
- Register-ObjectEvent
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/register-objectevent?view=powershell-5.1 - Use Asynchronous Event Handling in
PowerShell
https://blogs.technet.microsoft.com/heyscriptingguy/2011/06/16/use-asynchronous-event-handling-in-powershell/ - Manage Event Subscriptions with
PowerShell
https://blogs.technet.microsoft.com/heyscriptingguy/2011/06/17/manage-event-subscriptions-with-powershell/ - MQTT Essentials Part 5: MQTT Topics &
Best Practices
https://www.hivemq.com/blog/mqtt-essentials-part-5-mqtt-topics-best-practices
Gute Beschreibung wie die Filter-Syntax beim Subscribe funktioniert.
Da ich aber erst mal nicht wusste, was da zurück kommt, habe ich einen einfachen Handler an das Objekt gehängt.
Register-ObjectEvent ` -inputObject $MqttClient ` -EventName MqttMsgPublishReceived ` -Action { $args | Export-Clixml .\mqtt.xml}
Nachdem ich dann in einem anderen Fenster eine neue Meldung per "Publish" gesendet habe, finde ich im Wireshark dann folgende Pakete:
Das erste Paket ist der Versand der Meldung aus einer PowerShell-Umgebung mit der TCP-Quittung in Paket 2. Erst das Paket 3 zeigt, dass auch der Broker die MQTT-Meldung ebenfalls über einen "Publish" an den Subscriber sendet. Die MQTT-Klasse starte dann den hinterlegten Event, der die übergebenen Daten erst einmal in eine XML-Datei ablegen.
Diese kann ich dann losgelöst wieder einfach einlesen und analysieren. Sie enthält zwei Elemente.
PS C:\> (Import-Clixml .\mqtt.xml)[0] IsConnected : True ClientId : broker.hivemq.com CleanSession : True WillFlag : False WillQosLevel : 0 WillTopic : WillMessage : ProtocolVersion : Version_3_1_1 Settings : uPLibrary.Networking.M2Mqtt.MqttSettings PS C:\> (Import-Clixml .\mqtt.xml)[1] Topic : msxfaq/temp2 Message : {49, 48} DupFlag : False QosLevel : 0 Retain : False
Damit habe ich mich dann auf den Weg gemacht, die Daten einzusammeln. Natürlich könnte die Action direkt und sofort mit den Daten die Weiterverarbeitung anzugehen. Zuerst habe ich aber eine Hashtabelle definiert, in der der Event die Ergebnisse ablegt. Durch die Nutzung des "topic" als Key landet in der Hashtabelle immer nur der letzte Wert.
# Variable zum Sammeln der Daten vorbereiten [hashtable]$mqttresults=@{} #Eventhandler registrieren Register-ObjectEvent ` -inputObject $MqttClient ` -EventName MqttMsgPublishReceived ` -Action {Write-host "Event Found Topic: $($args[1].topic) Message $([System.Text.Encoding]::ASCII.GetString($args[1].Message))" -nonewline; $mqttresults[$args[1].topic] = $args[1].Message; write-host " done"} # Entsprechenden Kanal per SUBSCRIBE abonieren. $MqttClient.Subscribe("msxfaq/#",0) #Weitere Verarbeitungen und manchmal auslesen der Events aus $mqttresults
Mein Programm kann nun also diverse andere Dinge tun und letztlich drauf warten, bis es Werte zur Verarbeitung übernehmen soll.
Bei den Eventhandlern sollten Sie wissen, das diese nicht "parallel" ablaufen sondern solange der Event aktiv ist, das Hauptprogramm angehalten wird. Damit ist das Risiko auch überschaubar, wenn der Eventhandler die gleich Variable verarbeitet, wie das eigentliche Programm. Wenn mehrere Events hintereinander anstehen, dann werden diese auch sequentiell abgearbeitet. Es geht also auch kein Event verloren, wenn die Verarbeitung länger dauert. Wenn das Hauptprogramm mit einem "Start-Sleep" gerade wartet, dann wird aber auch kein Event abgearbeitet. Der Event kommt nur zum Tragen, wenn das eigentliche Skript den nächten Befehl abarbeitet.
Verbindung abbauen
Jeder verbundene Client belegt natürlich Ressourcen beim Broker. Natürlich räumt die Garbage Collection eines Betriebssystems den Speicher nach dem Ende wieder auf und gibt auch die TCP-Sockets frei. Aber für den Broker ist damit ja nicht erkennbar, ob er den "Last Will" ausführen soll. Daher ist der Aufruf der "Disconnect"-Methode wünschenswert.
$MqttClient.Disconnect()
In Wireshark ist zu sehen, dass der Client ein "Disconect Req" sendet und darauf hin der Broker die TCP-Connection direkt beendet.
Das ist dann ein schnelles aber doch geordnetes Ende einer Verbindung.
MQTT und Retained Messages
Über die Subscribe-Funktion bekommt der Client natürlich sofort mit, wenn eine neue Meldung anliegt. Wenn er aber erst einmal startet, dann bekommt er per Default nicht die früher eingegangenen Meldungen. Es ist ja kein Postfach sondern ein Abonnement. Wenn Sie heute ein Abonnement für eine Zeitschrift kaufen, dann bekommen Sie ja auch erst die nächste Ausgabe und keine vorherigen Aufgaben. Bei MQTT ist es aber möglich, dass der Broker die letzte vorherige Meldung auch puffert und dem Client beim ersten SUBSCRIBE gleich mit liefert. MQTT bezeichnet dies als "Retained Messages"
Voraussetzung hierfür ist aber, dass der Client schon beim PUBLISH das entsprechende Flag setzt um die Meldung als "Retained" zu setzen.
- Retained Messages
https://www.hivemq.com/blog/mqtt-essentials-part-8-retained-messages
In der Regel ist es also erforderlich, dass Sie etwas "warten". Als Subscriber kann ich weder den Publisher noch den Broker zwingen, die Meldungen als "Retained" zu senden.
Was kommt noch?
Wie Sie sich sicher denken können, ist diese Seite erst der Anfang. Ich musst hier erst mal die Grundlagen zur Nutzung von MQTT in PowerShell legen, um basierend darauf nun weitere Dinge anzugehen.
Ich habe einige Seiten schon angefangen und hier verlinkt, damit ich das später nicht vergesse. Wenn Sie aktuell noch auf einen 404 laufen, dann dauert es einfach noch etwas, bis die Seiten "fertig" sind.
Es gibt noch ganz viele Dinge, die nun möglich sind.
- eigener lokaler Broker
Vielleicht lasse ich auf meinem PRTG-Server einen kleinen Broker mitlaufen, der die MQTT-Publish-Meldungen im LAN erfasst -
PRTG und MQTT
PRTG hat selbst noch keinen MQTT Support aber mit dem Wissen hier sollte es ja kein Problem sein, die Daten von einem Broker per SUBSCRIBE einzusammeln und an PRTG zu melden. -
SONOFF mit ESP8266 Energiemessung mit MQTT
Von der Firma SONOFF gibt es Energiemesser mit ESP8266 und andere Personen haben eine Firmware veröffentlicht, die diese Daten per MQTT versendet. - IoT/MQTT und Azure
Auch Microsoft ist auf dem IoT-Zug und wie wäre mein eigener Broker in Azure ?
https://azure.microsoft.com/de-de/resources/samples/iot-gateway-mqtt-http/
https://www.linkedin.com/pulse/how-mqtt-microsoft-azure-iot-hub-satish-pagare/ - Perfmon-Counter per MQTT senden
Sobald ich auch ein MQTT-Anzeigeclient für meinen Broker habe, möchte ich natürlich auch IT-Daten (Server-last etc) an den Broker senden und nicht immer nur schnöde IoT-Werte eines Temperatursensor.
Sie sehen also, dass diese Seite erst der Anfang einer längeren Reise sein kann.
Weitere Links
- Powershell und Callback-Funktionen
- MQTT - Telemetriedaten mit IoT
- PRTG und MQTT
- SONOFF mit ESP8266
- MQTT
https://de.wikipedia.org/wiki/MQTT - MQTT: Protokoll für das Internet der Dinge
https://www.heise.de/developer/artikel/MQTT-Protokoll-fuer-das-Internet-der-Dinge-2168152.html - Installing and using MQTT Lens with Mosquitto
https://sivatechworld.wordpress.com/2015/08/01/installing-and-using-mqtt-lens-with-mosquitto/ - Mosquitto mqtt Message Broker auf der Synology
http://www.pflipsen.net/2016/01/13/mosquitto-mqtt-message-broker-auf-der-synology/ -
https://www.cloudmqtt.com/docs-php.html
Experimenting with MQTT and PHP
https://www.youtube.com/watch?v=jI-0b6XMM5E - MQTT + Node MCU ( Controlling appliances over Internet using
your SMART Phone)
https://www.youtube.com/watch?v=ekav8Le5a7U - Home Automation with Node.js and MQTT
https://www.youtube.com/watch?v=80DxfDmoZUI - MQTT-Based Sensor Network
https://www.hackster.io/stefaanv/mqtt-based-sensor-network-48ca17 - RabbitMQ-PowerShell-Client
https://GitHub.com/mariuszwojcik/RabbitMQ-PowerShell-Client - Trådfri: ESP8266-Lampen-Gateway
https://www.heise.de/make/artikel/Ikea-Tradfri-Anleitung-fuer-ein-ESP8266-Lampen-Gateway-3598411.html
IKEA Lampen mit ESP8266 über MQTT-Broker ansteuern - PRTG Manual: MQTT Subscribe Custom Sensor (Seit Aug 2020)
https://www.paessler.com/manuals/prtg/mqtt_subscribe_custom_sensor