Replace serial/Wi-Fi driver transport paths with WebSocket bridge client, binary espnow_wire delivery, device announce registry, and restructured espnow-sender (AP + broadcast passthrough). Includes docs and tests. Co-authored-by: Cursor <cursoragent@cursor.com>
2.5 KiB
ESP-NOW binary protocol
See also: espnow-architecture.md (diagrams, flows, configuration).
All ESP-NOW datagrams and Pi↔bridge WebSocket frames use binary only (no JSON on the wire). Maximum ESP-NOW payload length: 250 bytes.
ESP-NOW packet
| Offset | Field |
|---|---|
| 0 | Magic 0x4C ('L') |
| 1 | Message type |
| 2… | Type-specific body |
Message types
| Value | Name | Direction |
|---|---|---|
0x01 |
ANNOUNCE |
Driver → broadcast |
0x02 |
GROUPS |
Controller → driver |
0x03 |
CMD |
Controller → driver |
0x04 |
GROUP_CMD |
Controller → broadcast |
0x10 |
BRIDGE_CH |
Controller → broadcast |
ANNOUNCE (0x01)
Driver settings at boot. Sender MAC is taken from the ESP-NOW peer address (not repeated in the body).
| Field | Type |
|---|---|
| name_len | u8 |
| name | UTF-8 |
| num_leds | u16 LE |
| color_order | u8 enum: 0=rgb, 1=rbg, 2=grb, 3=gbr, 4=brg, 5=bgr |
| startup_mode | u8: 0=default, 1=last, 2=off |
| brightness | u8 0–255 |
| device_type | u8: 0=led |
GROUPS (0x02)
| Field | Type |
|---|---|
| count | u8 |
| × count | u8 id_len + UTF-8 group id |
CMD (0x03)
Bytes 2… are a v2 binary envelope (see src/util/binary_envelope.py): 5-byte header + presets/select/default blobs. Total packet ≤ 250 bytes.
GROUP_CMD (0x04)
| Field | Type |
|---|---|
| group_id_len | u8 |
| group_id | UTF-8 |
| cmd_envelope | v2 binary envelope |
Drivers apply the nested envelope only if group_id is in their stored group list.
BRIDGE_CH (0x10)
| Field | Type |
|---|---|
| channel | u8 (1–11) |
Sets the bridge ESP32 STA channel (not forwarded to LED drivers as a command).
Pi ↔ bridge WebSocket frame
Binary WebSocket messages only.
| Offset | Field |
|---|---|
| 0 | flags: bit0 = broadcast destination; bit1 reserved |
| 1–6 | peer MAC (6 bytes); ignored if broadcast |
| 7… | ESP-NOW packet (magic + type + body) |
Broadcast destination uses peer ff:ff:ff:ff:ff:ff.
The bridge maintains at most 20 ESP-NOW peers (LRU eviction).
v2 command envelope
Native binary sections (no JSON). Header:
| Byte | Meaning |
|---|---|
| 0 | Version 2 |
| 1 | Brightness wire 0–127 (maps to 0–255); 128–255 = unchanged |
| 2 | Presets section length |
| 3 | Select section length |
| 4 | Default section length |
See binary_envelope.py for blob layouts.