diff --git a/src/controllers/preset.py b/src/controllers/preset.py index 4c2a3dc..059b83e 100644 --- a/src/controllers/preset.py +++ b/src/controllers/preset.py @@ -179,14 +179,20 @@ async def send_presets(request, session): batch = test_batch last_msg = test_msg else: - await send_chunk(batch) + try: + await send_chunk(batch) + except Exception: + return json.dumps({"error": "ESP-NOW send failed"}), 503, {'Content-Type': 'application/json'} await asyncio.sleep_ms(SEND_DELAY_MS) messages_sent += 1 batch = {name: preset_obj} last_msg = build_message(presets=batch, save=save_flag, default=default_id) if batch: - await send_chunk(batch) + try: + await send_chunk(batch) + except Exception: + return json.dumps({"error": "ESP-NOW send failed"}), 503, {'Content-Type': 'application/json'} await asyncio.sleep_ms(SEND_DELAY_MS) messages_sent += 1 diff --git a/src/main.py b/src/main.py index 0eca195..f6d95d6 100644 --- a/src/main.py +++ b/src/main.py @@ -99,7 +99,13 @@ async def main(port=80): print("WS received raw:", data) # Forward raw JSON payload over ESPNow to configured peers - await esp.send(data) + try: + await esp.send(data) + except Exception: + try: + await ws.send(json.dumps({"error": "ESP-NOW send failed"})) + except Exception: + pass else: break diff --git a/src/models/espnow.py b/src/models/espnow.py index 247e10c..357dda0 100644 --- a/src/models/espnow.py +++ b/src/models/espnow.py @@ -1,3 +1,5 @@ +import network + import aioespnow @@ -20,11 +22,17 @@ class ESPNow: if getattr(self, "_initialized", False): return - # Initialize ESPNow once (no disk persistence) + # ESP-NOW requires a WiFi interface to be active (STA or AP). Activate STA + # so ESP-NOW has an interface to use; we don't need to connect to an AP. + try: + sta = network.WLAN(network.STA_IF) + sta.active(True) + except Exception as e: + print("ESPNow: STA active failed:", e) + self._esp = aioespnow.AIOESPNow() self._esp.active(True) - try: self._esp.add_peer(b"\xff\xff\xff\xff\xff\xff") except Exception: @@ -56,6 +64,6 @@ class ESPNow: try: await self._esp.asend(b"\xff\xff\xff\xff\xff\xff", payload) except Exception as e: - # Log send failures but don't crash the app print("ESPNow.send error:", e) + raise diff --git a/src/static/presets.js b/src/static/presets.js index 50af1b2..c2b2af4 100644 --- a/src/static/presets.js +++ b/src/static/presets.js @@ -25,6 +25,18 @@ const getEspnowSocket = () => { espnowPendingMessages = []; }; + espnowSocket.onmessage = (event) => { + try { + const data = JSON.parse(event.data); + if (data && data.error) { + console.error('ESP-NOW:', data.error); + alert('ESP-NOW send failed. ' + (data.error === 'ESP-NOW send failed' ? 'Check device WiFi/interface.' : data.error)); + } + } catch (_) { + // Ignore non-JSON or non-error messages + } + }; + espnowSocket.onclose = () => { espnowSocketReady = false; espnowSocket = null;