Add multi-panel Pico UDP firmware and Python LED control.

Pico panels get static IPs on 10.1.1.10–14 with per-panel LED counts, Makefile deploy targets, and Python examples for animations, sync tests, and direct Pi SPI control.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-28 22:46:08 +12:00
parent d8323bb9a3
commit d5cab2efdf
52 changed files with 4677 additions and 1 deletions

75
leds/strips.py Normal file
View File

@@ -0,0 +1,75 @@
"""Control two WS2812 strips with board-appropriate defaults."""
from __future__ import annotations
from leds.config import StripConfig, default_dual_strip_configs
from leds.strip import LedStrip
class LedStrips:
"""Drive two WS2812 strips. Use default configs or pass StripConfig per strip."""
def __init__(
self,
count0: int,
count1: int,
*,
config0: StripConfig | None = None,
config1: StripConfig | None = None,
brightness: float = 1.0,
) -> None:
if config0 is None or config1 is None:
defaults = default_dual_strip_configs(
count0, count1, brightness=brightness
)
config0 = config0 or defaults[0]
config1 = config1 or defaults[1]
self._strips = (
_strip_from_config(config0),
_strip_from_config(config1),
)
@property
def strip0(self) -> LedStrip:
return self._strips[0]
@property
def strip1(self) -> LedStrip:
return self._strips[1]
def __getitem__(self, index: int) -> LedStrip:
if index not in (0, 1):
raise IndexError("strip index must be 0 or 1")
return self._strips[index]
def show(self) -> None:
for strip in self._strips:
strip.show()
def clear(self) -> None:
for strip in self._strips:
strip.clear()
def close(self) -> None:
for strip in self._strips:
strip.close()
def __enter__(self) -> LedStrips:
return self
def __exit__(self, *_exc) -> None:
self.close()
def _strip_from_config(config: StripConfig) -> LedStrip:
return LedStrip(
config.count,
backend=config.backend,
pin=config.pin,
channel=config.channel,
device=config.device,
brightness=config.brightness,
spi_bus=config.spi_bus,
spi_device=config.spi_device,
)