Hallo Gemeinde :)
Heute haben wir mal etwas, was sich schon einige gewünscht hatten: die Verbindung mit einem eigenen MQTT Server für die Bedienung und Überwachung aus der Ferne.
Dazu kurz ein Wort, wie unsere iOS/Android-App funktioniert. Die App verbindet sich automatisch über die Internetverbindung des Handys mit einem Server von uns, auf dem ein MQTT Broker läuft. Dafür benötigt man einen QR-Code, also eine ID. Diese ID stellt wiederum das Haupttopic des Users dar, der User hat nur auf dieses Topic Zugriff.
Gleichzeitig verbindet sich die LTE-Bridge, die wir anbieten, mit genau diesem Topic zu dem gleichen Server. Damit haben wir eine bestehende Verbindung zwischen der Bridge und der App auf dem Handy. Die Bridge stellt letztendlich HTTP-Requests an das System auf dem Raspberry Pi, dieser gibt eine Antwort aus, welche wiederum von der Bridge an den Server und damit an die App geschickt wird. Die Bridge und das System auf dem Raspberry Pi müssen dementsprechend im selben Netzwerk sein.
Jetzt haben sich natürlich einige Leute gedacht, warum so eine LTE-Bridge kaufen, wenn ich doch schon einen Router mit SIM-Karte im Wohnmobil habe? Weil die Daten ja irgendwie zwischen der App und dem WoMo hin- und hergesendet werden müssen... es muss also ein Server dazwischen hängen (außer man arbeitet nur lokal, aber das wäre ja witzlos). Vom Router zum Server ist kein Problem, der Server hat eine statische IP, die immer dieselbe bleibt. Andersherum wird es schon schwieriger.
Außerdem müsste man dann jedem User irgendwie Zugriff auf den Server geben, was erstens aufwendig und zweitens auch nicht sehr schlau wäre.
Ich könnte euch jetzt noch viel mehr technisches Blabla um die Ohren hauen, warum und wie was funktioniert, aber zurück zum Thema:
So sieht der Flow aus, eine kleine aber feine Zusammenstellung einiger Nodes, gepaart mit einer dynamischen MQTT Subscription :)
Mal Schritt für Schritt:
Die Inject Node "Connect" am Anfang wird einmalig bei Systemstart ausgeführt, damit die Verbindung zum Server hergestellt wird. Könnte man auch in regelmäßigen Abständen ausführen lassen, z. B. alle paar Stunden, falls die Verbindung mal abbrechen sollte.
In der Function Node "set broker & pass" werden die Domain des Brokers (bzw. die IP-Adresse des Servers) eingetragen, dazu der Port (8883 verschlüsselt, 1883 unverschlüsselt), sowie der Benutzername und das Passwort für den Broker. Mit "node.send(msg)" senden wir die erste Payload an unsere MQTT-Node um die Verbindung herzustellen, danach ändern wir die Aktion, geben unser Topic an und senden auch diese Informationen an die MQTT-Node, damit wir zu unserem Topic subscriben. Die Raute # ist übrigens eine Wildcard, also alles was unter diesem Topic gesendet wird, können wir empfangen bzw. können wir dorthin senden. Wenn ihr unseren Server benutzen wollt, ist das Topic genau wie der Username, dazu aber weiter unten mehr. Mit "force": true sagen wir dem Broker, dass eine eventuell bestehende Verbindung getrennt und neu hergestellt werden soll.
Die darauffolgende MQTT-Node ist wie gesagt so eingestellt, dass wir unsere Daten dynamisch an diese übergeben können.
Sobald wir dann verbunden sind, kommt der spaßige Teil "get topics and respond". Hier mal ein Auszug der Node:
Wir filtern nach den Nachrichten, die von unserer App gesendet werden, setzen die entsprechende URL, um die HTTP-API anzusprechen und bereiten schonmal das Antworttopic vor (einfach ein "ans" hinter das Requesttopic).
In den ersten drei Zeilen splitten wir das Haupttopic, was ja aus der ID und der eigentlichen Anfrage besteht, alles was Antworten sind (also "ans" beinhaltet) filtern wir raus. Diese "ans" Nachrichten bekommen wir logischerweise auch, wir sind ja subscribed. (Ich hoffe, ihr könnt meinem Denglisch noch folgen :D)
Überall dort, wo msg.method auf "PUT" gesetzt wird, wird etwas geschaltet, also die Relays, Wifi-Relays, Dimmer und die Heizung. Alles mit "GET" gibt uns Informationen über die aktuellen Zustände, wir haben Batterie, BMS, Heizung, Temperaturen, Relays, Wifi-Relays, Dimmer und Wasserstände zur Auswahl.
Im Großen und Ganzen war es das schon, jetzt wird die HTTP-API angefragt, die Antwort wird in ein JSON umgewandelt und zurückgeschickt an den MQTT-Broker auf dem Server mit dem zuvor gesetzten Topic.
Smartphone-APP
Jetzt ist es nun aber so, dass in der aktuellen Version der App ein anderer Server benutzt wird. Die App benötigt also erstmal ein Update, damit man eigene MQTT-Broker einstellen kann. Und man benötigt natürlich einen Server, über welchen das Ganze dann läuft.
Sobald die App dann ein Update bekommen hat, wird es die Möglichkeit geben einen eigenen Server zu benutzen, oder aber kostenpflichtig weiter unsere Server zu benutzen. Damit spart man sich die Bridge, wenn man schon einen Internetzugang im WoMo verbaut hat. Oder man benutzt zur Sicherheit beides, falls mal die Bridge oder der Router warum auch immer keinen Empfang haben sollte.
Requests
Die Requests sind immer nach einem ganz bestimmten Schema aufgebaut, nämlich mit einem "get" string im Raw Format. Im MQTT-Explorer sieht das dann folgendermaßen aus:
Wenn wir diesen Befehl absenden bekommen wir unter dem Topic "<ID>/levelans" unsere Antwort geliefert, mit den Werten der Wasserstände vom Raspberry Pi.
Das Ganze funktionert mit den Subtopics /batt, /bms, /conniot, /heat, /temp, /relay, /wrelay, /dimmer und /level. Das /conniot Topic benutzen wir für den Connection Test in der App, also ob die App eine Verbindung bis zum Raspberry aufbauen kann.
Um nun Sachen schalten zu können, müssen wir unseren String ein wenig anpassen. Hier mal am Beispiel eines Relays:
Beachtet hierbei, dass wir immer noch im Raw Format senden und kein JSON. Achtet ebenso auf die Groß- und Kleinschreibung und die einfachen Anführungszeichen. Es funktioniert nur in diesem bestimmten Format, es sei denn, man bearbeitet die entsprechende Function Node, aber das ist das Format, dass wir auch für unsere App bzw. auf der Bridge benutzen. Das Beispiel würde also Relay 1 anschalten, mit "false" können wir es wieder ausschalten.
Wifi-Relays schalten wir genau so, nur dass wir im Raw-String "wrelayId" benutzen, also zum Beispiel {'wrelayId':'one','state':true}. Immer dran denken das Topic entsprechend anzupassen, in diesem Fall auf "<ID>/wrelay"
Die Dimmer können ähnlich gesteuert werden, auch hier schicken wir "{'dimmerId':'four','state':55}" an das Topic <ID>/dimmer und erhalten eine Antwort auf <ID>/dimmerans.
Beachtet, dass die Werte wie true/false Booleans sind, wenn wir sie in Anführungszeichen setzen würden, ergäbe das einen String und das funktioniert nicht. Ebenso bei den Dimmern, die zu setzende Value ist vom Typ Integer, also eine einfache Zahl, ebenso ohne Anführungszeichen.
Zum Schluss noch die Heizung, dafür schicken wir als Payload ganz simpel ein true oder false mit:
Im Anhang findet ihr den Flow aus dem Screenshot oben. Wenn ihr Probleme oder Fragen habt, immer her damit! Ansonsten viel Spaß beim Basteln und Ausprobieren! :)
Link zum Flow: