Skip to main content

WebSocket Client Driver

Overview

The WebSocket driver is a push model: it connects as a client to an external streaming server (ws / wss) endpoint, caches incoming messages, and returns the most recent value whenever read() is called on each collection cycle.

ItemValue
opc_typeWEBSOCKET
Implementation classplantpulse.driver.protocol.websocket.WebSocketDriver
Underlying libraryjava.net.http.HttpClient.WebSocket (Java 21 runtime standard API)
read✅ (message cache)
write✅ (sendText)
SecurityTLS (wss) — options.tls=true

Where the HTTP driver receives a push (REST POST) from an external system, the WebSocket driver has the edge make an outbound connection as a client to receive streaming messages.


OPC Registration Form / Options

FieldMeaningDefaultExample
host / portWebSocket server address192.168.10.99 / 8765, stream.example.com / 443
options.pathendpoint path//stream/v1, /realtime/tag
options.tlsWhether to use wssfalsetrue (wss) / false (ws)
options.subscribe-messageMessage to send immediately after connection (optional){"op":"subscribe","topic":"line1.tempC"}
timecycleread interval (ms)1000

Actual endpoint URL: <scheme>://<host>:<port><path> (scheme is ws / wss)


Tag plc_address Format

NotationMeaning
Empty value or _raw_The entire last received message (String)
JSON top-level key (e.g. tempC)The value of that key when the message is JSON (converted to String)

Example) If the server pushes {"tempC":25.7,"humid":40.2}:

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

Operation Flow

  1. On connect(), connect to the endpoint with HttpClient.newWebSocketBuilder().buildAsync(...).
  2. (Optional) If subscribe-message is present, send sendText once.
  3. Accumulate every text message sent by the server in onText → call handleMessage() when the fragment ends.
  4. handleMessage() stores the whole message under the _raw_ key. If the message starts with {, it is parsed as JSON and also cached per top-level key.
  5. On each collection cycle the PLC collector calls read(plc_address) → cache lookup → returns that value.
  6. When write(value) is called, the value is sent to the server as-is via sendText.

On onError, connected=false is performed. Automatic reconnection is delegated to the reconnect policy of the upper layer.


curl Registration Example

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"}
]
}'

Common Errors + Resolutions

Message / SymptomCauseResolution
[WS] connect 실패: ...handshake...URL / path error, server not runningVerify directly with wscat -c ws://<host>:<port><path>
[WS] connect 실패: ...timeout...Handshake not completed within 5 secondsCheck firewall / port / TLS settings
read() is always an empty stringServer sends no messages / subscribe-message not configuredCheck the broadcast flow in the server console. Register the required subscribe payload
Per-JSON-key read is emptyMessage is not JSON / is nestedReceive with _raw_ and post-process, or use a separate parser. (The current driver extracts top-level only)
TLS certificate errorSelf-signed certificateUsing a valid cert is recommended in production. As a temporary measure, add cacerts

Limitations / Future Extensions

  • No JSON path support: Extraction at a.b.c depth is not implemented. Top-level keys only. If needed, post-process with ${VALUE} or wait for a future option.
  • No built-in automatic reconnection: Depends on the PLC collector's reconnect interval / policy. A dedicated backoff is planned.
  • Binary frames not handled: Only text frames (onText) are processed. Intended mainly for text streaming such as JSON.
  • per-message-deflate / header authentication: Only the basics of the standard HttpClient.WebSocket are used. Custom headers will be made configurable later.

References

  • 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>
  • Quick dummy server: Python websockets library — python -m websockets.server.run :8765