feat(espnow): improve bridge transport and driver sync

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-28 00:38:09 +12:00
parent 088fe161a8
commit 8403df531d
6 changed files with 49 additions and 11 deletions

8
bulk.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
PORT="${1:-/dev/ttyACM0}"
while true; do
ls "$PORT" && led-cli -p "$PORT" --erase --src --patterns && led-cli -p "$PORT" --reset -f
sleep 0.5
done

View File

@@ -68,7 +68,7 @@ def process_data(payload, settings, presets, controller_ip=None, save=False):
set_groups = bool(data.get("set_groups")) set_groups = bool(data.get("set_groups"))
groups = data.get("groups") groups = data.get("groups")
if set_groups and isinstance(groups, list): if set_groups and isinstance(groups, list):
dg.groups_replace(groups) dg.groups_replace(groups, settings)
print("groups set", dg.list_groups()) print("groups set", dg.list_groups())
elif isinstance(groups, list) and groups: elif isinstance(groups, list) and groups:
if not any(dg.in_group(str(g)) for g in groups): if not any(dg.in_group(str(g)) for g in groups):
@@ -96,6 +96,7 @@ def process_data(payload, settings, presets, controller_ip=None, save=False):
settings.save() settings.save()
if "save" in data and "device_config" in data: if "save" in data and "device_config" in data:
settings.save() settings.save()
_flush_pending_select(settings, presets)
_VALID_DEVICE_COLOR_ORDERS = frozenset({"rgb", "rbg", "grb", "gbr", "brg", "bgr"}) _VALID_DEVICE_COLOR_ORDERS = frozenset({"rgb", "rbg", "grb", "gbr", "brg", "bgr"})
@@ -196,6 +197,18 @@ def _run_select(presets, settings, preset_name, step=None):
return False return False
def _flush_pending_select(settings, presets):
global _pending_select
if _pending_select is None:
return
preset_name, step = _pending_select
if preset_name not in presets.presets and preset_name not in ("on", "off"):
return
_pending_select = None
if not _run_select(presets, settings, preset_name, step):
print("select failed (pending):", preset_name)
def apply_presets(data, settings, presets): def apply_presets(data, settings, presets):
global _pending_select global _pending_select
presets_map = data["presets"] presets_map = data["presets"]
@@ -219,13 +232,10 @@ def apply_presets(data, settings, presets):
pass pass
presets.edit(id, preset_data) presets.edit(id, preset_data)
# Same message often carries select; apply now while presets are loaded. # Same message often carries select; apply now while presets are loaded.
if "select" in data: if "select" in data or "s" in data:
apply_select(data, settings, presets) apply_select(data, settings, presets)
elif _pending_select is not None: else:
preset_name, step = _pending_select _flush_pending_select(settings, presets)
_pending_select = None
if preset_name in presets.presets or preset_name in ("on", "off"):
_run_select(presets, settings, preset_name, step)
def _select_list_for_this_device(select_val, settings): def _select_list_for_this_device(select_val, settings):
@@ -276,6 +286,11 @@ def apply_select(data, settings, presets):
if not preset_name: if not preset_name:
return return
step = select_list[1] if len(select_list) > 1 else None step = select_list[1] if len(select_list) > 1 else None
if preset_name not in presets.presets and preset_name not in ("on", "off"):
try:
presets.load(settings)
except Exception:
pass
if preset_name not in presets.presets and preset_name not in ("on", "off"): if preset_name not in presets.presets and preset_name not in ("on", "off"):
_pending_select = (preset_name, step) _pending_select = (preset_name, step)
print("select deferred (preset not loaded yet):", preset_name) print("select deferred (preset not loaded yet):", preset_name)

View File

@@ -1,11 +1,23 @@
"""In-memory group membership for GROUP_CMD filtering.""" """Group membership for GROUP_CMD filtering; persisted in settings.json."""
_groups = [] _groups = []
def groups_replace(group_ids): def load_from_settings(settings):
global _groups
g = settings.get("groups") if settings is not None else None
if isinstance(g, list):
_groups = [str(x) for x in g if str(x).strip()]
else:
_groups = []
def groups_replace(group_ids, settings=None, *, persist=True):
global _groups global _groups
_groups = [str(g) for g in group_ids] _groups = [str(g) for g in group_ids]
if persist and settings is not None:
settings["groups"] = list(_groups)
settings.save()
def in_group(group_id): def in_group(group_id):

View File

@@ -112,7 +112,7 @@ def _handle_packet(host, pkt, settings, presets):
if mt == MSG_GROUPS: if mt == MSG_GROUPS:
ids = parse_groups(pkt) ids = parse_groups(pkt)
if ids is not None: if ids is not None:
dg.groups_replace(ids) dg.groups_replace(ids, settings)
_groups_received = True _groups_received = True
print("groups", ids) print("groups", ids)
return return

View File

@@ -6,6 +6,7 @@ import gc
import json import json
import network import network
import espnow import espnow
import device_groups as dg
from presets import Presets from presets import Presets
from controller_messages import apply_startup_pattern, process_data from controller_messages import apply_startup_pattern, process_data
from espnow_transport import _handle_packet, init_espnow from espnow_transport import _handle_packet, init_espnow
@@ -17,6 +18,7 @@ wdt.feed()
machine.freq(160000000) machine.freq(160000000)
settings = Settings() settings = Settings()
dg.load_from_settings(settings)
print(settings) print(settings)
gc.collect() gc.collect()

View File

@@ -35,6 +35,7 @@ class Settings(dict):
self["brightness"] = 32 self["brightness"] = 32
self["wifi_channel"] = WIFI_CHANNEL_DEFAULT self["wifi_channel"] = WIFI_CHANNEL_DEFAULT
self["groups"] = []
def save(self): def save(self):