feat(espnow): Pi bridge client, binary wire, and espnow-sender firmware

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>
This commit is contained in:
2026-05-23 22:44:44 +12:00
parent f4ef85c182
commit 4fc3f46866
42 changed files with 4167 additions and 848 deletions

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 820 420" font-family="system-ui, Segoe UI, sans-serif">
<defs>
<marker id="arrow" markerWidth="8" markerHeight="8" refX="6" refY="3" orient="auto">
<path d="M0,0 L6,3 L0,6 Z" fill="#333"/>
</marker>
<style>
.box { fill: #f4f6f8; stroke: #2c3e50; stroke-width: 2; rx: 8; }
.title { font-size: 16px; font-weight: 700; fill: #1a1a1a; }
.label { font-size: 13px; fill: #333; }
.small { font-size: 11px; fill: #555; }
.line { stroke: #333; stroke-width: 1.5; fill: none; marker-end: url(#arrow); }
.dashed { stroke-dasharray: 6 4; }
</style>
</defs>
<text x="410" y="28" text-anchor="middle" class="title" font-size="18">ESP-NOW LED system  three nodes</text>
<!-- Pi -->
<rect class="box" x="40" y="60" width="220" height="300"/>
<text x="150" y="88" text-anchor="middle" class="title">led-controller</text>
<text x="150" y="108" text-anchor="middle" class="small">Raspberry Pi</text>
<rect x="60" y="125" width="180" height="36" fill="#fff" stroke="#888" rx="4"/>
<text x="150" y="148" text-anchor="middle" class="label">Web UI / REST (JSON)</text>
<rect x="60" y="170" width="180" height="36" fill="#fff" stroke="#888" rx="4"/>
<text x="150" y="193" text-anchor="middle" class="label">db/device.json, groups</text>
<rect x="60" y="215" width="180" height="36" fill="#e8f4fc" stroke="#2980b9" rx="4"/>
<text x="150" y="238" text-anchor="middle" class="label">espnow_wire + binary</text>
<rect x="60" y="260" width="180" height="36" fill="#e8f4fc" stroke="#2980b9" rx="4"/>
<text x="150" y="283" text-anchor="middle" class="label">bridge_ws_client</text>
<text x="150" y="330" text-anchor="middle" class="small">WS client bridge</text>
<!-- Bridge -->
<rect class="box" x="300" y="100" width="220" height="220"/>
<text x="410" y="128" text-anchor="middle" class="title">Bridge ESP32</text>
<text x="410" y="148" text-anchor="middle" class="small">espnow-sender</text>
<rect x="320" y="165" width="180" height="36" fill="#fff" stroke="#888" rx="4"/>
<text x="410" y="188" text-anchor="middle" class="label">WebSocket server /ws</text>
<rect x="320" y="210" width="180" height="36" fill="#fef9e7" stroke="#d4ac0d" rx="4"/>
<text x="410" y="233" text-anchor="middle" class="label">ESP-NOW relay</text>
<text x="410" y="275" text-anchor="middle" class="small">max 20 peers (LRU)</text>
<!-- Drivers -->
<rect class="box" x="560" y="60" width="220" height="300"/>
<text x="670" y="88" text-anchor="middle" class="title">led-driver × N</text>
<text x="670" y="108" text-anchor="middle" class="small">ESP32 LED strips</text>
<rect x="580" y="140" width="180" height="32" fill="#eafaf1" stroke="#27ae60" rx="4"/>
<text x="670" y="161" text-anchor="middle" class="label">boot ANNOUNCE</text>
<rect x="580" y="182" width="180" height="32" fill="#fff" stroke="#888" rx="4"/>
<text x="670" y="203" text-anchor="middle" class="label">store GROUPS</text>
<rect x="580" y="224" width="180" height="32" fill="#fff" stroke="#888" rx="4"/>
<text x="670" y="245" text-anchor="middle" class="label">apply CMD / GROUP_CMD</text>
<text x="670" y="320" text-anchor="middle" class="small">binary only on air</text>
<!-- Arrows -->
<path class="line" d="M 260 278 L 298 200"/>
<text x="268" y="235" class="small">binary WS</text>
<path class="line" d="M 520 230 L 558 200"/>
<text x="528" y="218" class="small">ESP-NOW</text>
<path class="line dashed" d="M 520 260 L 558 280"/>
<text x="528" y="278" class="small">broadcast</text>
<path class="line dashed" d="M 558 160 L 520 175"/>
<text x="530" y="158" class="small">ANNOUNCE</text>
<text x="410" y="400" text-anchor="middle" class="small">d250 bytes per ESP-NOW frame · no JSON on wire</text>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB