feat(streaming): introduce WebSocket Streaming API bridging event bus
ApiServer: add AsyncWebSocket at /ws; accept JSON {event, payload} (string or object) and dispatch via ctx.fire; mirror all local events to clients using NodeContext::onAny.\nNodeContext: add onAny subscriber API.\nNeoPatternService: add api/neopattern/color event to set solid color.\nCluster: centralize cluster/broadcast sending in core; services delegate.\nAPI: add generic /api/node/event and /api/cluster/event endpoints in respective services.\nTests: add ws-color-client, ws-cluster-broadcast-color, http-cluster-broadcast-color.\nDocs: add StreamingAPI.md; update README and test/README.\nFixes: robust WS JSON parsing on ESP8266 and payload handling.
This commit is contained in:
71
docs/StreamingAPI.md
Normal file
71
docs/StreamingAPI.md
Normal file
@@ -0,0 +1,71 @@
|
||||
## Streaming API (WebSocket)
|
||||
|
||||
### Overview
|
||||
|
||||
The streaming API exposes an event-driven WebSocket at `/ws`. It bridges between external clients and the internal event bus:
|
||||
|
||||
- Incoming WebSocket JSON `{ event, payload }` → `ctx.fire(event, payload)`
|
||||
- Local events → broadcasted to all connected WebSocket clients as `{ event, payload }`
|
||||
|
||||
This allows real-time control and observation of the system without polling.
|
||||
|
||||
### URL
|
||||
|
||||
- `ws://<device-ip>/ws`
|
||||
|
||||
### Message Format
|
||||
|
||||
- Client → Device
|
||||
```json
|
||||
{
|
||||
"event": "<event-name>",
|
||||
"payload": "<json-string>" | { /* inline JSON */ }
|
||||
}
|
||||
```
|
||||
|
||||
- Device → Client
|
||||
```json
|
||||
{
|
||||
"event": "<event-name>",
|
||||
"payload": "<json-string>"
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
- The device accepts `payload` as a string or a JSON object/array. Objects are serialized into a string before dispatching to local subscribers to keep a consistent downstream contract.
|
||||
- A minimal ack `{ "ok": true }` is sent after a valid inbound message.
|
||||
|
||||
### Event Bus Integration
|
||||
|
||||
- The WebSocket registers an `onAny` subscriber to `NodeContext` so that all local events are mirrored to clients.
|
||||
- Services should subscribe to specific events via `ctx.on("<name>", ...)`.
|
||||
|
||||
### Examples
|
||||
|
||||
1) Set a solid color on NeoPattern:
|
||||
```json
|
||||
{
|
||||
"event": "api/neopattern/color",
|
||||
"payload": { "color": "#FF0000", "brightness": 128 }
|
||||
}
|
||||
```
|
||||
|
||||
2) Broadcast a cluster event (delegated to core):
|
||||
```json
|
||||
{
|
||||
"event": "cluster/broadcast",
|
||||
"payload": {
|
||||
"event": "api/neopattern/color",
|
||||
"data": { "color": "#00FF00", "brightness": 128 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Reference Implementation
|
||||
|
||||
- WebSocket setup and bridging are implemented in `ApiServer`.
|
||||
- Global event subscription uses `NodeContext::onAny`.
|
||||
|
||||
Related docs:
|
||||
- [`ClusterBroadcast.md`](./ClusterBroadcast.md) — centralized UDP broadcasting and CLUSTER_EVENT format
|
||||
|
||||
Reference in New Issue
Block a user