WebSocket API
In addition to the REST APIs LedFx has a WebSocket API for streaming realtime data. The primary use for this is for things like effect visualizations in the frontend.
Will document this further once it is more well defined. The general structure will be event registration based.
The documentation on websockets need a LOT of legacy implementation. New sections are added as new events are commited, but all the pre-existing behaviour is currently not documented
Websocket client UIDs
This functionality is intended to support notification between clients of connect / disconnect and sync actions
sequenceDiagram
participant Client
participant ClientEndpoint as ClientEndpoint (/api/clients)
participant WebSocketMgr as WebsocketConnection
participant EventSystem as Event System
Note over Client,EventSystem: WebSocket Connection Flow
Client->>WebSocketMgr: Establish WebSocket connection
WebSocketMgr->>WebSocketMgr: Extract client IP from request.remote
WebSocketMgr->>WebSocketMgr: Generate UUID for client
WebSocketMgr->>WebSocketMgr: Store UUID→IP mapping (thread-safe with map_lock)
WebSocketMgr-->>Client: Send JSON {"event_type": "client_id", "client_id": UUID}
WebSocketMgr->>EventSystem: Fire ClientConnectedEvent(UUID, IP)
Note over Client,EventSystem: Client List Retrieval
Client->>ClientEndpoint: GET /api/clients
ClientEndpoint->>WebSocketMgr: get_all_clients()
WebSocketMgr->>WebSocketMgr: Return copy of ip_uid_map (thread-safe)
WebSocketMgr-->>ClientEndpoint: UUID→IP mapping dictionary
ClientEndpoint-->>Client: HTTP 200 with {"result": client_list}
Note over Client,EventSystem: Client Sync Action
Client->>ClientEndpoint: POST /api/clients {"action": "sync", "client_id": UUID}
ClientEndpoint->>ClientEndpoint: Validate JSON and action field
ClientEndpoint->>EventSystem: Fire ClientSyncEvent(client_id or "unknown")
ClientEndpoint-->>Client: HTTP 200 {"result": "success", "action": "sync"}
Note over Client,EventSystem: WebSocket Disconnection Flow
Client->>WebSocketMgr: Close WebSocket connection
WebSocketMgr->>WebSocketMgr: Remove UUID from ip_uid_map (thread-safe with map_lock)
WebSocketMgr->>EventSystem: Fire ClientDisconnectedEvent(UUID, IP)
On opening a websocket connection the client will be assigned a UID stored along with the client IP address. noting that mulitple client can exist on one IP address. Multiple browser tabs for example.
The assigned UID will be returned to the client via an event on the websocket of the following structure
{
"event_type": "client_id",
"client_id": "e59d112e-3652-41e5-acb1-94538b4cb27c"
}
A client can store its own id to enable filtering out of events generated by itself.
Client Events
The following events are available for a client to subscribe to via its websocket
client_connected
Generated when a new client is connected to the backend by its own websocket
{
"event_type": "client_connected",
"client_id": "e59d112e-3652-41e5-acb1-94538b4cb27c",
"client_ip": "1.2.3.4"
}
client_disconnected
Generated when an existing client disconnects its websocket to the backend.
{
"event_type": "client_disconnected",
"client_id": "e59d112e-3652-41e5-acb1-94538b4cb27c",
"client_ip": "1.2.3.4"
}
client_sync
Generated when a client makes a POST to the rest api endpoint /api/clients with “action”: “sync”
This is intended to allow a client to inform other clients they should sync their configuration due to stimulated changes. The receiving client can filter against its own id to avoid self recursive notifications
{
"event_type": "client_sync",
"client_id": "e59d112e-3652-41e5-acb1-94538b4cb27c"
}
client rest api
The following rest api calls support client tracking
/api/clients
GET
Returns a list of all active websocket clients by UID and IP address
{
"823f78cd-24fa-4cd4-908f-979249350dea": "127.0.0.1",
"34361601-1416-428d-9b89-37c82281222d": "127.0.0.1",
"8743a845-40ba-4427-8ae6-361b2be6fac6": "1.2.3.4"
}
POST
Supports an extensible set of actions
“action”: “sync”
Sync action can be used to inform other clients that they should sync their configurations to pick up changes made by the originating client.
Calling client should provide its own websocket id
{
"action": "sync",
"client_id": "e59d112e-3652-41e5-acb1-94538b4cb27c"
}
Will generate a client_sync event sent to all active websockets that are subscribed to the event type
{
"event_type": "client_sync",
"client_id": "e59d112e-3652-41e5-acb1-94538b4cb27c"
}
Diagnostic Events
Diagnostic events are intended to allow improved visibility of performance and development diagnostic via live front end rather than log analysis.
virtual_diag is generated by any virtual running an effect that support advanced / diag and is set to true. At time of writing that is only and all 2d matrix effects. Once established and tested it will be added to all 1d effects as well.
The example given in the following sequence diagram for general_diag is a trivial use case added to noise2d. It will be removed in due course when a better more relevant example is available.
sequenceDiagram
participant V as Virtual Device
participant E as Effect (with LogSec)
participant E2 as Effect (noise2d)
participant LS as LogSec Monitor
participant ES as Events System
participant WS as WebSocket Connection
participant FE as Frontend Client
Note over V,FE: Virtual Diag Event Flow
V->>+E: Execute effect in thread
E->>+LS: log_sec() - Start frame timing
LS->>LS: Track FPS, render times
loop Every Frame
E->>LS: Render frame
LS->>LS: Measure render time
LS->>LS: Update min/max/total times
end
LS->>LS: Check if second boundary crossed
alt Second boundary crossed & diag enabled
LS->>ES: fire_event(VirtualDiagEvent)
Note right of LS: Contains: virtual_id, fps, r_avg, <br/>r_min, r_max, cycle, sleep, phy
ES->>WS: notify_websocket(event)
WS->>FE: send_event(virtual_diag)
Note right of FE: Real-time performance metrics
end
Note over V,FE: General Diag Event Flow
V->>+E2: Execute noise2d effect
alt Test mode enabled
E2->>E2: draw_test() - Draw diagnostic pattern
E2->>ES: fire_event(GeneralDiagEvent)
Note right of E2: Contains: debug message<br/>"Noise2d: {width}x{height}"
ES->>WS: notify_websocket(event)
WS->>FE: send_event(general_diag)
Note right of FE: Diagnostic message for debugging
end
Note over V,FE: WebSocket Subscription Setup
FE->>WS: subscribe_event("virtual_diag")
WS->>ES: add_listener(notify_websocket, "virtual_diag")
FE->>WS: subscribe_event("general_diag")
WS->>ES: add_listener(notify_websocket, "general_diag")
Note over V,FE: Event Distribution System
rect rgb(240, 248, 255)
Note over ES: Events.fire_event() calls all<br/>registered listeners via<br/>loop.call_soon_threadsafe()
end
virtual_diag
The virtual_diag WebSocket event is emitted when a virtual’s diagnostics are updated. It provides real-time performance and timing metrics in units of seconds for a specific virtual entity on a 1 second period
Payload Example:
{
"event_type": "virtual_diag",
"virtual_id": "my_virtual_id",
"fps": 48,
"r_avg": 0.017432,
"r_min": 0.008123,
"r_max": 0.022345,
"cycle": 16.67,
"sleep": 0.014232,
"phy":
{
"fps": 55,
"ver": "0.14.4",
"n": 1024,
"name": "32x32",
"rssi": -45,
"qual": 100
}
}
Fields:
event_type: Always"virtual_diag".virtual_id: Identifier of the virtual entity.fps: Frames per second being rendered.r_avg: Average render time.r_min: Minimum render time.r_max: Maximum render time.cycle: Cycle time for the virtual’s update loop.sleep: Sleep time between cycles.phy: A dictionary containing physical device information:fps: Frames per second reported by the physical device.ver: Firmware version of the device.n: Number of LEDs or pixels in the device.name: Name or identifier of the device.rssi: Signal strength (RSSI) of the device’s connection.qual: Connection quality percentage.
Usage: Subscribe to this event to monitor the performance and timing of virtual devices for diagnostics and optimization.
If a virtual is mapped directly to a device and that device is WLED, then an attempt to read the WLED info and extra key details will be made once per second asynchronously via the /json/info api call and returned on phy, unavailable values will be None.
general_diag
The general_diag WebSocket event is emitted to provide arbitrary diagnostic messages, typically for debugging or informational purposes.
Payload Example:
{
"event_type": "general_diag",
"debug": "Diagnostic message here",
"scroll": false
}
Fields:
event_type: Always"general_diag".debug: The diagnostic message string.scroll: Boolean indicating if the message should be scrolled in the UI oe replaced in each cycle.
Usage: Listen for this event to receive general diagnostic messages from the system, which may be useful for debugging or displaying system status in the frontend. If a monospaced font is used then back end can attempt table live updates with scroll set to false which is default if not explicitly set.
System Events
The documentation on on Events is very incomplete New sections are added as new events are commited, but all the pre-existing behaviour should be considered undocumented
audio_input_device_changed
The audio_input_device_changed WebSocket event is emitted when the audio input device is changed via the /api/audio/devices endpoint or through other configuration updates.
Payload Example:
{
"event_type": "audio_input_device_changed",
"audio_input_device_name": "Stereo Mix (Realtek High Definition Audio)"
}
Fields:
event_type: Always"audio_input_device_changed".audio_input_device_name: The name of the newly selected audio input device.
Usage: Subscribe to this event to be notified when the audio input device changes, allowing frontends to update their UI to reflect the current audio source. This is particularly useful for keeping multiple clients synchronized when audio device settings are changed.