Zum Hauptinhalt springen

WebSocket-Client-Treiber

Überblick

Der WebSocket-Treiber verbindet sich als Client mit dem Endpoint eines externen Streaming-Servers (ws / wss), cacht die eingehenden Nachrichten und liefert bei jedem read() im Erfassungszyklus den zuletzt empfangenen Wert zurück — ein Push-Modell.

PunktWert
opc_typeWEBSOCKET
Implementierungsklasseplantpulse.driver.protocol.websocket.WebSocketDriver
Basisbibliothekjava.net.http.HttpClient.WebSocket (Standard-API der Java-21-Runtime)
read✅ (Nachrichten-Cache)
write✅ (sendText)
SicherheitTLS (wss) — options.tls=true

Während der HTTP-Treiber ein Modell ist, das den Push (REST POST) eines externen Systems entgegennimmt, baut der WebSocket-Treiber eine ausgehende Client-Verbindung vom Edge auf und empfängt darüber Streaming-Nachrichten.


OPC-Registrierungsformular / Optionen

FeldBedeutungStandardwertBeispiel
host / portAdresse des WebSocket-Servers192.168.10.99 / 8765, stream.example.com / 443
options.pathEndpoint-Pfad//stream/v1, /realtime/tag
options.tlswss verwendenfalsetrue (wss) / false (ws)
options.subscribe-messageNachricht, die direkt nach dem Verbindungsaufbau gesendet wird (optional){"op":"subscribe","topic":"line1.tempC"}
timecycleread-Zyklus (ms)1000

Tatsächliche Endpoint-URL: <scheme>://<host>:<port><path> (scheme ist ws / wss)


Format von Tag plc_address

NotationBedeutung
Leerwert oder _raw_Zuletzt empfangene Nachricht vollständig (String)
JSON-Top-Level-Key (z. B. tempC)Wert dieses Keys, wenn die Nachricht JSON ist (in String konvertiert)

Beispiel: Wenn der Server {"tempC":25.7,"humid":40.2} pusht:

plc_addressErgebnis
_raw_{"tempC":25.7,"humid":40.2}
tempC25.7
humid40.2

Ablauf

  1. Bei connect() Verbindung zum Endpoint über HttpClient.newWebSocketBuilder().buildAsync(...).
  2. (Optional) Falls subscribe-message gesetzt ist, einmalig sendText senden.
  3. Alle vom Server gesendeten Textnachrichten werden in onText akkumuliert → am Fragmentende wird handleMessage() aufgerufen.
  4. handleMessage() speichert die vollständige Nachricht unter dem Key _raw_. Beginnt die Nachricht mit {, wird sie als JSON geparst und zusätzlich pro Top-Level-Key gecacht.
  5. In jedem Erfassungszyklus ruft der PLC-Collector read(plc_address) auf → Cache-Lookup → Rückgabe des Werts.
  6. Beim Aufruf von write(value) wird der Wert unverändert per sendText an den Server gesendet.

Bei onError erfolgt die Behandlung über connected=false. Der automatische Wiederverbindungsaufbau ist der Reconnect-Policy der übergeordneten Ebene überlassen.


curl-Registrierungsbeispiel

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_WS_LINE1",
"opc_type": "WEBSOCKET",
"opc_name": "Line1 WebSocket Stream",
"opc_agent_ip": "192.168.10.99",
"opc_agent_port": "8765",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": {
"path": "/stream/v1",
"tls": "false",
"subscribe-message": "{\"op\":\"subscribe\",\"topic\":\"line1\"}"
},
"tag_list": [
{"tag_id":"OPC_WS_LINE1_T01","tag_name":"TempC","plc_address":"tempC","data_type":"Float"},
{"tag_id":"OPC_WS_LINE1_T02","tag_name":"Humid","plc_address":"humid","data_type":"Float"},
{"tag_id":"OPC_WS_LINE1_T03","tag_name":"Raw", "plc_address":"_raw_","data_type":"String"}
]
}'

Häufige Fehler + Lösungen

Meldung / SymptomUrsacheLösung
[WS] connect 실패: ...handshake...Fehler in URL / Pfad, Server läuft nichtDirekt mit wscat -c ws://<host>:<port><path> verifizieren
[WS] connect 실패: ...timeout...Handshake nicht innerhalb von 5 Sekunden abgeschlossenFirewall / Port / TLS-Konfiguration prüfen
read() ist stets ein leerer StringServer sendet keine Nachrichten / subscribe-message nicht gesetztBroadcast-Fluss in der Serverkonsole prüfen. Erforderliches Subscribe-Payload eintragen
read pro JSON-Key liefert nichtsNachricht ist kein JSON / verschachtelt (nested)Über _raw_ empfangen und nachverarbeiten oder separaten Parser einsetzen. (Der aktuelle Treiber extrahiert nur die Top-Level-Ebene)
TLS-ZertifikatsfehlerSelbstsigniert (self-signed)Im Produktivbetrieb ein gültiges Zertifikat verwenden. Übergangsweise cacerts ergänzen

Einschränkungen / geplante Erweiterungen

  • Kein JSON-Path-Support: Extraktion in der Tiefe a.b.c ist derzeit nicht implementiert — nur Top-Level-Keys. Bei Bedarf Nachverarbeitung über ${VALUE} oder spätere Option.
  • Kein integrierter Reconnect: Abhängig von Reconnect-Zyklus / -Policy des PLC-Collectors. Ein eigenes Backoff folgt später.
  • Keine Verarbeitung von Binary-Frames: Nur Text-Frames (onText). Ausgelegt auf textbasiertes Streaming wie JSON.
  • per-message-deflate / Header-Authentifizierung: Es werden nur die Grundfunktionen des Standards HttpClient.WebSocket genutzt. Benutzerdefinierte Header sollen künftig als Option verfügbar werden.

Referenzen

  • Java-Standard-java.net.http.WebSocket-API: <https://docs.oracle.com/en/java/javase/17/docs/api/java.net.http/java/net/http/WebSocket.html>
  • Schneller Dummy-Server: Python-Bibliothek websocketspython -m websockets.server.run :8765