# Z21 Items and Actions (WebSocket/TCP) Date: 23 février 2026 This document lists practical Z21 control items and their expected actions when exposed through a WebSocket/TCP API. ## Command Table | Item | WebSocket Action | Typical Parameters | Expected Effect | Notes | |---|---|---|---|---| | Connection / Handshake | `z21.connect` | `clientName`, `protocolVersion` | Opens session, validates client, initializes subscriptions | Required before control commands | | Track Power ON | `z21.track.power_on` | none | Energizes track output | Keep idempotent: calling twice stays ON | | Track Power OFF | `z21.track.power_off` | none | Cuts track output immediately | Keep idempotent: calling twice stays OFF | | Emergency Stop | `z21.track.emergency_stop` | optional `scope` (`all`/`loco`) | Immediate stop for all locomotives or selected scope | Higher priority than normal speed commands | | Read Power State | `z21.track.power_state` | none | Returns current state (`on`/`off`/`estop`) | Useful on reconnect | | Loco Acquire | `z21.loco.acquire` | `address` | Reserves/selects locomotive for control | Enforce ownership rules if multi-client | | Loco Speed/Direction | `z21.loco.drive` | `address`, `speedStep`, `direction` | Updates speed and direction | Validate speed-step mode compatibility | | Loco Function Set | `z21.loco.function` | `address`, `fn`, `value` | Sets F0..Fn on/off (or tri-state if supported) | Coalesce bursts for UI sliders/buttons | | Accessory Switch | `z21.accessory.set` | `address`, `state` (`thrown`/`closed`) | Toggles turnout/accessory output | Add optional pulse duration if needed | | Read Loco State | `z21.loco.state` | `address` | Returns cached/current speed, direction, functions | Source can be polled or event-fed | | Subscribe Events | `z21.subscribe` | list of topics | Enables push updates (power, loco, accessory, feedback) | Recommended for reactive UI | | Unsubscribe Events | `z21.unsubscribe` | list of topics | Stops selected event streams | Keep lightweight for mobile clients | ## Special Actions | Special Item | WebSocket Action | Values | Expected Action | Compatibility Note | |---|---|---|---|---| | Switching Mode | `z21.track.switch_mode` | `analog`, `marklin`, `dcc` | Requests output/protocol mode switch | Not always a native Z21 LAN command; may require backend-specific mapping or be unsupported on some hardware/firmware | | Ensure Track Power ON/OFF Exists | `z21.track.power_on` / `z21.track.power_off` | none | Guarantees explicit power control in API | Keep these actions present even if other protocols already define similar commands | ## Suggested Request/Response Shapes ### Request ```json { "type": "z21.track.power_on", "seq": 102, "payload": {} } ``` ### Success Response ```json { "type": "ack", "seq": 102, "ok": true, "result": { "trackPower": "on" } } ``` ### Event Push Example ```json { "type": "event.track.power", "timestamp": "2026-02-23T12:00:00Z", "payload": { "state": "off" } } ``` ## Implementation Notes - Treat `power_on`, `power_off`, and `emergency_stop` as safety-critical and process first. - Make power and mode commands idempotent and return current state after execution. - For `switch_mode`, return explicit capability errors when unsupported, for example: `ERR_UNSUPPORTED_MODE_SWITCH`. - Keep internal model protocol-neutral (`ThrottleCommand`, `FunctionCommand`, `PowerStateEvent`) to simplify interoperability with XpressNet/LocoNet backends. ## Sequence Diagram (Kroki / seqdiag) Example: drive locomotive `id=10` to speed `100` in `forward` direction. ```seqdiag seqdiag { browser [label = "Web Client"]; wsapi [label = "WS API"]; z21gw [label = "Z21 Gateway"]; station [label = "Z21 Command Station"]; browser -> wsapi [label = "WS send\n{type:z21.loco.drive, seq:301,\npayload:{address:10, speedStep:100, direction:forward}}"]; wsapi -> z21gw [label = "validate + map command"]; z21gw -> station [label = "Z21 LAN: set loco 10 speed=100 dir=FWD"]; station -> z21gw [label = "status/ack"]; z21gw -> wsapi [label = "mapped result"]; wsapi -> browser [label = "ACK\n{type:ack, seq:301, ok:true,\nresult:{address:10, speedStep:100, direction:forward}}"]; station -> z21gw [label = "async state broadcast (optional)"]; z21gw -> wsapi [label = "event.track/loco update"]; wsapi -> browser [label = "event.loco.state\n{address:10, speedStep:100, direction:forward}"]; } ```