Schalten mit SignalK – Teil 2

Nachdem wir im ersten Teil herausgefunden haben, wie ein „PUT-Request“ an den SignalK-Server gesendet und dort von Node-RED empfangen wird, erzeugen wir in diesem Teil den PUT-Request von einem Arduino Uno aus. Dazu müssen wir die Kommunikation von UDP auf einen Websocket umstellen. Zusätzlich wollen wir die Antwort des Servers empfangen und verarbeiten, damit wir rückmelden können, ob der PUT-Request erfolgreich durchgeführt wurde.

Verwendete Hardware und Software

  • PC mit Debian GNU Linux 10.0
  • Raspberry PI 3 mit Raspbian Buster Lite (02.12.2020) (Konfiguration ist hier beschrieben)
  • Arduino IDE 1.8.13
  • Arduino UNO oder Arduino MEGA
  • Wiznet W5100 Ethernet-Shield
  • Die Bibliothek ArduinoHttpClient Version 0.4.0
  • Die Bibliothek ArduinoJson Version 6.17.2

Details des Sketches

Den Sketch findet ihr auf unserem github: https://github.com/Vehicle-Hacks/Arduino-SignalK/releases/tag/v0.3.0, oder ihr clont das Repository mit git:

git clone -b v0.3.0 https://github.com/Vehicle-Hacks/Arduino-SignalK.git

Werfen wir einen kurzen Blick auf den Arduino-Sketch – einiges davon dürfte uns von der Seite Arduino Uno als SignalK-Quelle bereits bekannt sein. Der Sketch hat drei Aufgaben: Er liest einen Druckknopf aus und sendet den Ziel-Zustand an den SignalK-Server, er empfängt die Antwort und liest den Status aus und schaltete eine LED, um Rückmeldung zu geben.

Im oberen Teil des Sketches (Configuration and Includes) werden die Ethernet-, ArduinoHttpClient- und ArduinoJson-Bibliotheken inkludiert und benötigte globale Variablen angelegt. Dem WebSocketClient übergeben wir beim Anlegen die Adresse und den Port (3000) des SignalK-Servers. Für den Druckknopf brauchen wir neben dem Pin noch zwei Hilfsvariablen, um uns den gewünschten Ausgangszustand (switchOutput) zu merken und den Druckknoppf zu „entprellen“. Für die LED brauchen wir neben dem Zielzustand noch die Information, ob sie gerade blinkt und in welchem Zustand sie aktuell ist, da wir sie blinken lassen wollen, während der Request vom Server bearbeitet wird.

Im nächsten Abschnitt (SignalK Messages Sent by Arduino) wird das JSON des PUT-Requests definiert. Wichtig ist hier der Pfad des Switches: „electrical.inputs.testinput“, der dem des PUT-Handlers in Node-RED entsprechen muss. Hier ist der gleiche Pfad definiert, den wir im letzten Beitrag zum Testen von Node-RED verwendet haben.

Danach kommt der eigentlich Code. Hier wird als erstes die Funktion switchStateChanged() definiert, die bei einer Zustandsänderung aufgerufen wird und den PUT-Request an den SignalK-Server sendet. Der Aufbau ist im Prinzip genau so wie beim Senden per UDP. Nur müssen wir hier drauf achten, dass das Paket vom verwendeten WebSocketClient komplett im (knappen) RAM des Arduino zusammengebaut wird, wodurch die Größe des JSON beschränkt ist – allerdings ist das für den ersten Versuch noch kein Problem.

Als nächstes folgt die setup()-Funktion, die die Initialisierung der Netzwerk-Hardware und des WebSocketClient vornimmt. Für den WebSocketClient müssen wir die korrekte URL auf dem SignalK-Server angeben. Da wir keine Informationen vom SignalK-Server auswerten wollen außer den Antworten auf unsere Request, übergeben wir zusätzlich den Parameter „subscribe=none“ mit der URL.

Am Anfang der loop()-Funktion überprüfen wir zunächst, ob der WebSocketClient eine Botschaft vom Server erhalten hat – falls ja, überprüfen wir, ob es die Antwort zu einem PUT-Request war. Falls das so ist und der statusCode erfolg meldet, schalten wir die LED gemäß dem angefragten Zustand. Falls die Botschaft ein Feld „name“ enthält, gehen wir davon aus, dass es die Hello-Message ist und geben Server-Namen und -Version aus. Andere Botschaften werden nicht verarbeitet.

Im nächsten Abschnitt überprüfen wir, ob der Druckknopf betätigt wurde. Da der Schalter in der Regel für mehrere Zyklen für jeden Betätigungsvorgang gedrückt ist, reicht es nicht, im Fall von „HIGH“ einfach den Ziel-Zustand zu wechseln sondern wir müssen die Logik „entprellen“. Daher wird der Zustand nur geändert, wenn der Druckknopf von nicht betätigt auf betätigt wechselt (also auf die steigende Flanke). Im Falle einer Betätigung wird der Zustand gewechselt und die Funktion switchStateChanged() aufgerufen, um einen PUT-Request an den SignalK-Server zu senden.

Im letzten Abschnitt wird die LED blinken gelassen, solange wir auf Antwort vom Server arbeiten. Da diese normalerweise sehr schnell kommt, findet das Blinken normalerweise nicht statt. Ich konnte es nur im Fehlerfall testen, wenn der PUT-Request nicht korrekt vom Server verarbeitet wurde.

Hardware-Aufbau zum Testen

Auch wenn es nur ein einfacher Aufbau ist, nachfolgend der Hardware-Aufbau zum Testen. Der Pin 4 für den Schalter wird über einen 10 kOhm-Widerstand aus Masse gehalten und beim Schaltvorgang auf +5V gezogen. Die LED ist über einen 220 Ohm-Wiederstand mit dem Pin 5 verbunden.

Fritzing-Bild vom Testaufbau des Arduino UNO mit Schalter und LED
Testaufbau für den Arduino UNO mit Schalter und LED

Schalten in Node-RED mit dem Arduino

Um den Test durchzuführen, muss auf dem Raspberry PI der SignalK-Server mit dem Node-RED Plugin gestartet sein. In Node-RED muss ein PUT-Handler, wie im letzten Beitrag beschrieben, erstellt sein. Falls ihr den Beitrag bereits nachvollzogen habt, sollte die Node-RED-Konfiguration gespeichert worden sein und der Handler beim neuen Starten des SignalK-Servers bereits vorhanden sein. In der Node-RED Admin-Oberfläche am besten wieder den „Debug“-Tab öffnen, damit ihr die Ausgabe der PUT-Handlers sehen könnt.

Anschließend könnt ihr den Sketch auf den Arduino laden und am besten einen seriellen Monitor öffnen. Wenn alles funktioniert, solltet ihr im seriellen Monitor den Namen des SignalK-Servers und die Version sehen. Wenn ihr jetzt auf den Druckknopf drückt, sollte die LED abwechselnd an- und wieder ausgehen. Im Hintergrund wird ein PUT-Request an den SignalK-Server gesendet und erst beim Erhalten des Status-Code 200 die LED geschaltet. Das lässt sich im Debug-Tab der Node-RED-Oberfläche überprüfen, wo die entgegengenommenen PUT-Requests sichtbar sind.

Serieller Monitor der Arduino-IDE mit der Ausgabe bei erfolgreicher Verbindung zum SignalK-Server
Serieller Monitor der Arduino-IDE mit der Ausgabe vom Arduino bei erfolgreicher Verbindung

Um einen Fehlerfall zu testen, könnt ihr den Pfad des Switches entweder in Node-RED oder im Arduino-Sketch ändern. Ich habe ihn in Node-RED auf „electrical.inputs.testinput2“ geändern. Danach reicht es nicht, nur auf „Deploy“ zu klicken sondern der SignalK-Server auf dem Raspberry PI muss beendet und neu gestartet werden. Da der Arduino dabei die Websocket-Verbindung verliert, muss auch er per Reset neu gestartet werden. Da nun kein PUT-Handler mit passenden Pfad auf dem SignalK-Server gefunden werden kann, liefert er den Status-Code 405 zurück, die LED am Arduino blinkt und es gibt eine Fehlerausgabe im seriellen Monitor. Nach beiden Tests hat er bei mir folgenden Inhalt:

Serieller Monitor der Arduino-IDE mit Fehlercode bei nicht gefundenem PUT-Handler

Ergebnis und nächste Schritte

Mit dem hier vorgestellten Sketch ist es nun möglich, einen Schalter vom Arduino auszulesen, den Ziel-Zustand per PUT-Request an den SignalK-Server zu schicken und dort in Node-RED zu verarbeiten und auf dem Arduino auf die Rückmeldung vom SignalK-Server zu reagieren. Natürlich sind noch viele Punkte offen: Es ist z.B. die UUID nicht Standard-Konform und wird nicht ausgewertet und der Sketch ist noch nicht auf den Einsatz von mehreren Schaltern optimiert. Da die nächste – vielleicht noch spannendere – Aufgabe aber ist, vom SignalK-Server aus eine Last zu schalten, belassen wir es hier dabei. Optimierungen können wir vornehmen, wenn die erste Version vom Gesamt-System steht.