fix(espnow): bridge async rx, uplink framing, driver RX handling

Bridge uses async for on AIOESPNow, pack_ws_uplink to Pi, AP channel
from settings. Driver applies binary wire and JSON commands on receive.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-23 22:45:13 +12:00
parent 4fc3f46866
commit 1a69fabd98
2 changed files with 48 additions and 28 deletions

View File

@@ -1,5 +1,4 @@
import asyncio
import time
from microdot import Microdot
from microdot.websocket import WebSocketError, with_websocket
@@ -8,7 +7,7 @@ import aioespnow
import machine
import network
from settings import Settings
from espnow_wire import BROADCAST_MAC, pack_ws_uplink
wdt = machine.WDT(timeout=10000)
wdt.feed()
@@ -17,9 +16,19 @@ print(settings)
app = Microdot()
ch = settings.get("wifi_channel", 6)
try:
ch = max(1, min(11, int(ch)))
except (TypeError, ValueError):
ch = 6
ap_if = network.WLAN(network.AP_IF)
ap_if.active(True)
ap_if.config(ssid=settings.get("name"), password=settings.get("ap_password"))
ap_if.config(
ssid=settings.get("name"),
password=settings.get("ap_password"),
channel=ch,
)
print(ap_if.ifconfig())
sta_if = network.WLAN(network.STA_IF)
@@ -28,37 +37,47 @@ print(sta_if.config("channel"))
esp = aioespnow.AIOESPNow()
esp.active(True)
esp.add_peer(b"\xff\xff\xff\xff\xff\xff")
esp.add_peer(BROADCAST_MAC)
clients = set()
@app.route("/ws")
@with_websocket
async def ws(request, ws):
clients.add(ws)
while True:
try:
raw = await ws.receive()
except WebSocketError as err:
print(err)
break
if not raw:
break
try:
await esp.asend(b"\xff\xff\xff\xff\xff\xff", raw)
print(raw)
except Exception as err:
print(err)
break
ws.close()
clients.discard(ws)
try:
while True:
try:
raw = await ws.receive()
except WebSocketError as err:
print(err)
break
if not raw:
break
try:
await esp.asend(BROADCAST_MAC, raw)
except Exception as err:
print(err)
break
finally:
clients.discard(ws)
async def _espnow_receive_loop():
async for host, msg in esp.airecv():
print(host, msg)
for client in clients:
await client.send(msg)
async for host, msg in esp:
if not host or not msg:
continue
print("espnow rx", len(msg), "B")
frame = pack_ws_uplink(host, msg)
dead = []
for client in list(clients):
try:
await client.send(frame)
except Exception:
dead.append(client)
for client in dead:
clients.discard(client)
async def _wdt_feed_loop():
@@ -66,11 +85,12 @@ async def _wdt_feed_loop():
await asyncio.sleep(1)
wdt.feed()
async def main():
asyncio.create_task(_wdt_feed_loop())
asyncio.create_task(_wdt_feed_loop())
asyncio.create_task(_espnow_receive_loop())
await app.start_server(host="0.0.0.0", port=80)
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main())