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

68
leds/colors.py Normal file
View File

@@ -0,0 +1,68 @@
"""Color helpers for LED animations."""
from __future__ import annotations
import math
from typing import Tuple
RGB = Tuple[int, int, int]
def wheel(pos: int) -> RGB:
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 heat_color(temperature: float) -> RGB:
"""Map 0.01.0 heat to black → red → yellow → white."""
t = max(0.0, min(1.0, temperature))
if t < 0.25:
return (int(t * 4 * 255), 0, 0)
if t < 0.5:
return (255, int((t - 0.25) * 4 * 255), 0)
if t < 0.75:
return (255, 255, int((t - 0.5) * 4 * 255))
return (255, 255, 255)
def hsv_to_rgb(h: float, s: float, v: float) -> RGB:
h = h % 1.0
i = int(h * 6)
f = h * 6 - i
p = int(v * (1 - s) * 255)
q = int(v * (1 - f * s) * 255)
t = int(v * (1 - (1 - f) * s) * 255)
v255 = int(v * 255)
match i % 6:
case 0:
return (v255, t, p)
case 1:
return (q, v255, p)
case 2:
return (p, v255, t)
case 3:
return (p, q, v255)
case 4:
return (t, p, v255)
case _:
return (v255, p, q)
def dim(color: RGB, scale: float) -> RGB:
scale = max(0.0, min(1.0, scale))
return (int(color[0] * scale), int(color[1] * scale), int(color[2] * scale))
def blend(a: RGB, b: RGB, t: float) -> RGB:
t = max(0.0, min(1.0, t))
return (
int(a[0] + (b[0] - a[0]) * t),
int(a[1] + (b[1] - a[1]) * t),
int(a[2] + (b[2] - a[2]) * t),
)