WebSocket¶
Die REST-API eignet sich gut, um auf ausgelöste Requests Daten gezielt abzufragen und zurückzugeben. Allerdings hat das Konzept einen entscheidenden Nachteil um die Benutzeroberfläche aktuell zu halten. Ein Dashboard müsste dafür ständig Anfragen an den Server senden (Polling), was Last erzeugt und in den meisten Fällen nur die CPU blockiert und keine Änderungen zurückgibt, da es keine gibt.
Deshalb ergänz eine WebSocket-Schnittstelle die REST-API: Über diese kann das Backend Aktualisierungen direkt an die Oberflächen senden, sobald sie auftreten.
Für diese und weitere Funktionalitäten wird Socket.IO als Framework genutzt.
Verbindungsaufbau¶
Die WebSocket-Verbindung wird über die URL api/v1/ws aufgebaut.
Nach dem Verbindungsaufbau empfängt der Client zunächst keine Daten sondern registriert erst, für welche Geräte dieser Aktualisierungen erhält.
Abonnements¶
Damit ein Client nicht die Telemetrie und Aktualisierungen aller Geräte empfängt stellt Socket.IO ein Abonnement-Modell zur Verfügung. Für jedes Gerät existiert intern ein eigener Raum (device:<uuid>).
Somit kann ein Client den jeweiligen Raum der eingebundenen Geräte abonnieren und bekommt auch nur diese Daten.
| Ereignis (Client → Server) | Bedeutung |
|---|---|
subscribe mit uuid |
Gerät abonnieren: Raum beitreten |
unsubscribe mit uuid |
Abonnement beenden: Raum verlassen |
Server-Ereignisse¶
Für jedes abonnierte Gerät sendet der Server drei Arten von Ereignissen:
| Ereignis (Server → Client) | Nutzlast | Bedeutung |
|---|---|---|
telemetry |
{ uuid, data, timestamp } |
Neue Messwerte des Geräts |
status |
{ uuid, status } |
Verbindungsstatus wechselt (online/offline) |
invalidate |
{ uuid } |
Das Thing Model hat sich geändert |
Bei einer Neuanmeldung eines Geräts wird ein invalidate-Event gesendet. Dieses signalisiert den Frontends, die das Gerät eingebunden haben, dass das Thing Model möglicherweise nicht mehr aktuell ist.
Dies kann beispielsweise der Fall sein, wenn das Gerät zwischenzeitlich verändert oder neu geflasht wurde.
Die betroffenen Clients können anschließend über die REST-API das aktualisierte Thing Model abrufen.
Zusammenspiel mit MQTT¶
- Telemetrie wird ausgelöst, wenn ein Gerät Werte per MQTT sendet.
Das Backend sendet daraufhin das
telemetry-Ereignis dabei vor dem Schreiben in die Datenbank, damit die Daten möglichst schnell in der Oberfläche aktualisiert werden. - Status ergibt sich aus dem Verbindungszustand des Geräts. Verliert ein Gerät die Verbindung, meldet der Broker dies über die LWT-Nachricht.
Das Backend gibt den Wechsel als
status-Ereignis an die Oberflächen weiter.
sequenceDiagram
participant Geraet as Gerät
participant MQTT as MQTT-Broker
participant Backend as Backend
participant UI as Oberfläche
UI->>Backend: subscribe(uuid)
Geraet->>MQTT: Telemetrie publizieren
MQTT->>Backend: Telemetrie
Backend-->>UI: telemetry
Backend->>Backend: Queue + DB
Geraet--xMQTT: Verbindung verloren
MQTT->>Backend: Last Will (offline)
Backend-->>UI: status (offline)