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.
| Punkt | Wert |
|---|---|
opc_type | WEBSOCKET |
| Implementierungsklasse | plantpulse.driver.protocol.websocket.WebSocketDriver |
| Basisbibliothek | java.net.http.HttpClient.WebSocket (Standard-API der Java-21-Runtime) |
| read | ✅ (Nachrichten-Cache) |
| write | ✅ (sendText) |
| Sicherheit | TLS (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
| Feld | Bedeutung | Standardwert | Beispiel |
|---|---|---|---|
host / port | Adresse des WebSocket-Servers | — | 192.168.10.99 / 8765, stream.example.com / 443 |
options.path | Endpoint-Pfad | / | /stream/v1, /realtime/tag |
options.tls | wss verwenden | false | true (wss) / false (ws) |
options.subscribe-message | Nachricht, die direkt nach dem Verbindungsaufbau gesendet wird (optional) | — | {"op":"subscribe","topic":"line1.tempC"} |
timecycle | read-Zyklus (ms) | — | 1000 |
Tatsächliche Endpoint-URL: <scheme>://<host>:<port><path> (scheme ist ws / wss)
Format von Tag plc_address
| Notation | Bedeutung |
|---|---|
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_address | Ergebnis |
|---|---|
_raw_ | {"tempC":25.7,"humid":40.2} |
tempC | 25.7 |
humid | 40.2 |
Ablauf
- Bei
connect()Verbindung zum Endpoint überHttpClient.newWebSocketBuilder().buildAsync(...). - (Optional) Falls
subscribe-messagegesetzt ist, einmaligsendTextsenden. - Alle vom Server gesendeten Textnachrichten werden in
onTextakkumuliert → am Fragmentende wirdhandleMessage()aufgerufen. 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.- In jedem Erfassungszyklus ruft der PLC-Collector
read(plc_address)auf → Cache-Lookup → Rückgabe des Werts. - Beim Aufruf von
write(value)wird der Wert unverändert persendTextan 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 / Symptom | Ursache | Lösung |
|---|---|---|
[WS] connect 실패: ...handshake... | Fehler in URL / Pfad, Server läuft nicht | Direkt mit wscat -c ws://<host>:<port><path> verifizieren |
[WS] connect 실패: ...timeout... | Handshake nicht innerhalb von 5 Sekunden abgeschlossen | Firewall / Port / TLS-Konfiguration prüfen |
read() ist stets ein leerer String | Server sendet keine Nachrichten / subscribe-message nicht gesetzt | Broadcast-Fluss in der Serverkonsole prüfen. Erforderliches Subscribe-Payload eintragen |
| read pro JSON-Key liefert nichts | Nachricht ist kein JSON / verschachtelt (nested) | Über _raw_ empfangen und nachverarbeiten oder separaten Parser einsetzen. (Der aktuelle Treiber extrahiert nur die Top-Level-Ebene) |
| TLS-Zertifikatsfehler | Selbstsigniert (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.cist 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.WebSocketgenutzt. 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
websockets—python -m websockets.server.run :8765