Files
portal/examples/led_demo.py
Jimmy d5cab2efdf 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>
2026-06-28 22:46:08 +12:00

100 lines
2.9 KiB
Python
Executable File

#!/usr/bin/env python3
"""Two strips showing different patterns at the same time."""
import argparse
import sys
import time
from leds import LedStrips, board_family, board_model, default_dual_strip_configs, pi5_setup_hint
def _describe(cfg) -> str:
if cfg.backend == "pio":
return f"GPIO {cfg.pin}{cfg.device}"
if cfg.backend == "ws281x":
return f"GPIO {cfg.pin} (channel {cfg.channel})"
return f"/dev/spidev{cfg.spi_bus}.{cfg.spi_device}"
def _wheel(pos: int) -> tuple[int, int, int]:
pos = pos % 256
if pos < 85:
return (255 - pos * 3, pos * 3, 0)
if pos < 170:
pos -= 85
return (0, 255 - pos * 3, pos * 3)
pos -= 170
return (pos * 3, 0, 255 - pos * 3)
def chase(strip, color: tuple[int, int, int], step: int) -> None:
count = len(strip)
strip.fill((0, 0, 0))
strip[step % count] = color
def rainbow(strip, offset: int) -> None:
for i in range(len(strip)):
strip[i] = _wheel(offset + i * 256 // max(len(strip), 1))
def main() -> int:
parser = argparse.ArgumentParser(description="WS2812 dual-strip demo")
parser.add_argument(
"-n",
"--count",
type=int,
nargs=2,
default=[200, 200],
metavar=("STRIP0", "STRIP1"),
help="LED count per strip (default: 10 10)",
)
parser.add_argument(
"--brightness",
type=float,
default=0.25,
help="brightness 0.0-1.0 (default: 0.25)",
)
args = parser.parse_args()
print(f"Board: {board_model()}")
cfg0, cfg1 = default_dual_strip_configs(
args.count[0], args.count[1], brightness=args.brightness
)
print(f"Strip 0: {cfg0.backend}{_describe(cfg0)} (red chase)")
print(f"Strip 1: {cfg1.backend}{_describe(cfg1)} (rainbow)")
step = 0
try:
with LedStrips(args.count[0], args.count[1], brightness=args.brightness) as strips:
while True:
# strip 0: red dot chasing along the strip
chase(strips[0], (255, 0, 0), step)
# strip 1: rainbow scroll — completely independent
rainbow(strips[1], step * 4)
strips.show()
step += 1
time.sleep(0.05)
except KeyboardInterrupt:
print("\nStopped.")
return 0
except FileNotFoundError as exc:
print(f"Error: {exc}", file=sys.stderr)
if board_family() == "pi5":
print("\n" + pi5_setup_hint(args.count[0], args.count[1]), file=sys.stderr)
return 1
except OSError as exc:
print(f"Error: {exc}", file=sys.stderr)
if board_family() == "pi5" and "No such file" in str(exc):
print("\n" + pi5_setup_hint(args.count[0], args.count[1]), file=sys.stderr)
return 1
except Exception as exc:
print(f"Error: {exc}", file=sys.stderr)
return 1
if __name__ == "__main__":
raise SystemExit(main())