WebSocket クライアントドライバ
概要
WebSocket ドライバは、外部 streaming server (ws / wss) の endpoint にクライアントとして接続し、
受信したメッセージをキャッシュして、収集周期ごとに read() すると最新値を返す push モデルである。
| 項目 | 値 |
|---|---|
opc_type | WEBSOCKET |
| 実装クラス | plantpulse.driver.protocol.websocket.WebSocketDriver |
| 基盤ライブラリ | java.net.http.HttpClient.WebSocket (Java 21 runtime 標準 API) |
| read | ✅ (メッセージキャッシュ) |
| write | ✅ (sendText) |
| セキュリティ | TLS (wss) — options.tls=true |
HTTP ドライバが外部システムの push (REST POST) を受け取るモデルであるのに対し、WebSocket ドライバは
edge が クライアントとして outbound 接続 し streaming メッセージを受け取るモデルである。
OPC 登録フォーム / オプション
| フィールド | 意味 | デフォルト値 | 例 |
|---|---|---|---|
host / port | WebSocket サーバーアドレス | — | 192.168.10.99 / 8765, stream.example.com / 443 |
options.path | endpoint path | / | /stream/v1, /realtime/tag |
options.tls | wss を使用するか | false | true (wss) / false (ws) |
options.subscribe-message | 接続直後に送信するメッセージ (オプション) | — | {"op":"subscribe","topic":"line1.tempC"} |
timecycle | read 周期 (ms) | — | 1000 |
実際の endpoint URL: <scheme>://<host>:<port><path> (scheme は ws / wss)
タグ plc_address 形式
| 表記 | 意味 |
|---|---|
空値または _raw_ | 最後に受信したメッセージ 全体 (String) |
JSON top-level キー (例: tempC) | メッセージが JSON の場合、該当キーの値 (String に変換) |
例) サーバーが {"tempC":25.7,"humid":40.2} を push した場合:
plc_address | 結果 |
|---|---|
_raw_ | {"tempC":25.7,"humid":40.2} |
tempC | 25.7 |
humid | 40.2 |
動作フロー
connect()時にHttpClient.newWebSocketBuilder().buildAsync(...)で endpoint に接続。- (オプション)
subscribe-messageがあれば一度sendTextを送信。 - サーバーが送信するすべてのテキストメッセージを
onTextで蓄積 → fragment 終了時にhandleMessage()を呼び出し。 handleMessage()はメッセージ全体を_raw_キーに保存。メッセージが{で始まる場合は JSON parsing 後、 top-level キーごとにもキャッシュ。- 収集周期ごとに PLC collector が
read(plc_address)を呼び出し → キャッシュ lookup → その値を返す。 write(value)呼び出し時はsendTextでそのまま server へ送信。
onError 発生時は connected=false で処理。自動再接続は上位 layer の reconnect ポリシーに委任する。
curl 登録例
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"}
]
}'
よくあるエラーと対処
| メッセージ / 症状 | 原因 | 対処 |
|---|---|---|
[WS] connect 실패: ...handshake... | URL / path の誤り、サーバー未稼働 | wscat -c ws://<host>:<port><path> で直接検証 |
[WS] connect 실패: ...timeout... | 5 秒以内にハンドシェイクが完了しない | ファイアウォール / ポート / TLS 設定を点検 |
read() が常に空文字列 | サーバーがメッセージを送信していない / subscribe-message 未設定 | サーバーコンソールで broadcast の流れを確認。必要な subscribe payload を登録 |
| JSON キーごとの read が空 | メッセージが JSON でない / 入れ子 (nested) | _raw_ で受け取った後に後処理、または別途 parser を用意。(現在の driver は top-level のみ抽出) |
| TLS 証明書エラー | 自己署名 (self-signed) | 運用環境では valid cert の使用を推奨。暫定的には cacerts を追加 |
制限事項 / 今後の拡張
- JSON path 非対応: 現時点で
a.b.cの深い階層の抽出は未実装。top-level key のみ。必要な場合は${VALUE}での後処理、または今後のオプション導入で対応。 - 自動再接続は内蔵していない: PLC collector の reconnect 周期 / ポリシーに依存。独自のバックオフは今後対応。
- binary frame 非対応: text frame (
onText) のみ処理。JSON などのテキスト streaming が主用途。 - per-message-deflate / ヘッダー認証: 標準
HttpClient.WebSocketの基本機能のみ使用。カスタムヘッダーは今後オプション化予定。
参考
- Java 標準
java.net.http.WebSocketAPI:<https://docs.oracle.com/en/java/javase/17/docs/api/java.net.http/java/net/http/WebSocket.html> - 手軽な dummy server: Python
websocketsライブラリ —python -m websockets.server.run :8765