Pi port: serial transport, addressed ESP-NOW bridge, port 80
- Run app on Raspberry Pi: serial to ESP32 bridge at 912000 baud, /dev/ttyS0 - Remove ESP-NOW/MicroPython-only code from src (espnow, p2p, wifi, machine/Pin) - Transport: always send 6-byte MAC + payload; optional to/destination_mac in API and WebSocket - Settings and model DB use project paths (no root); fix sys.print_exception for CPython - Preset/settings controllers use get_current_sender(); template paths for cwd=src - Pipfile: run from src, PORT from env; scripts for port 80 (setcap) and test - ESP32 bridge: receive 6-byte addr + payload, LRU peer management (20 max), handle ESP_ERR_ESPNOW_EXIST - Add esp32/main.py, esp32/benchmark_peers.py, scripts/setup-port80.sh, scripts/test-port80.sh Made-with: Cursor
This commit is contained in:
58
src/main.py
58
src/main.py
@@ -1,14 +1,11 @@
|
||||
import asyncio
|
||||
import gc
|
||||
import json
|
||||
import machine
|
||||
from machine import Pin
|
||||
import os
|
||||
from microdot import Microdot, send_file
|
||||
from microdot.websocket import with_websocket
|
||||
from microdot.session import Session
|
||||
from settings import Settings
|
||||
|
||||
import aioespnow
|
||||
import controllers.preset as preset
|
||||
import controllers.profile as profile
|
||||
import controllers.group as group
|
||||
@@ -18,7 +15,7 @@ import controllers.palette as palette
|
||||
import controllers.scene as scene
|
||||
import controllers.pattern as pattern
|
||||
import controllers.settings as settings_controller
|
||||
from models.espnow import ESPNow
|
||||
from models.transport import get_sender, set_sender
|
||||
|
||||
|
||||
async def main(port=80):
|
||||
@@ -26,8 +23,9 @@ async def main(port=80):
|
||||
print(settings)
|
||||
print("Starting")
|
||||
|
||||
# Initialize ESPNow singleton (config + peers)
|
||||
esp = ESPNow()
|
||||
# Initialize transport (serial to ESP32 bridge)
|
||||
sender = get_sender(settings)
|
||||
set_sender(sender)
|
||||
|
||||
app = Microdot()
|
||||
|
||||
@@ -58,7 +56,7 @@ async def main(port=80):
|
||||
app.mount(pattern.controller, '/patterns')
|
||||
app.mount(settings_controller.controller, '/settings')
|
||||
|
||||
# Serve index.html at root
|
||||
# Serve index.html at root (cwd is src/ when run via pipenv run run)
|
||||
@app.route('/')
|
||||
def index(request):
|
||||
"""Serve the main web UI."""
|
||||
@@ -91,19 +89,25 @@ async def main(port=80):
|
||||
data = await ws.receive()
|
||||
print(data)
|
||||
if data:
|
||||
# Debug: log incoming WebSocket data
|
||||
try:
|
||||
parsed = json.loads(data)
|
||||
print("WS received JSON:", parsed)
|
||||
except Exception:
|
||||
print("WS received raw:", data)
|
||||
|
||||
# Forward raw JSON payload over ESPNow to configured peers
|
||||
try:
|
||||
await esp.send(data)
|
||||
# Optional "to": 12-char hex MAC; rest is payload (sent with that address).
|
||||
addr = parsed.pop("to", None)
|
||||
payload = json.dumps(parsed) if parsed else data
|
||||
await sender.send(payload, addr=addr)
|
||||
except json.JSONDecodeError:
|
||||
# Not JSON: send raw with default address
|
||||
try:
|
||||
await sender.send(data)
|
||||
except Exception:
|
||||
try:
|
||||
await ws.send(json.dumps({"error": "Send failed"}))
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
try:
|
||||
await ws.send(json.dumps({"error": "ESP-NOW send failed"}))
|
||||
await ws.send(json.dumps({"error": "Send failed"}))
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
@@ -113,25 +117,11 @@ async def main(port=80):
|
||||
|
||||
server = asyncio.create_task(app.start_server(host="0.0.0.0", port=port))
|
||||
|
||||
#wdt = machine.WDT(timeout=10000)
|
||||
#wdt.feed()
|
||||
|
||||
# Initialize heartbeat LED (XIAO ESP32S3 built-in LED on GPIO 21)
|
||||
|
||||
led = Pin(15, Pin.OUT)
|
||||
|
||||
|
||||
led_state = False
|
||||
|
||||
while True:
|
||||
gc.collect()
|
||||
for i in range(60):
|
||||
#wdt.feed()
|
||||
# Heartbeat: toggle LED every 500 ms
|
||||
|
||||
led.value(not led.value())
|
||||
await asyncio.sleep_ms(500)
|
||||
await asyncio.sleep(30)
|
||||
# cleanup before ending the application
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
import os
|
||||
port = int(os.environ.get("PORT", 80))
|
||||
asyncio.run(main(port=port))
|
||||
|
||||
Reference in New Issue
Block a user