Bring the five-panel hex portal online with a browser 3D/schematic preview, Pi SPI backends, and renamed multi-panel Pico UDP firmware. Co-authored-by: Cursor <cursoragent@cursor.com>
5.0 KiB
portal
Hexagonal LED portal: five WS2812 matrix panels on Pico UDP adapters, plus a bare floor.
Reference: photo of the physical portal — upright flat-top hex arch, dark frame, red LED grids on each face.
___[2]___
/ \
[1] [3]
| |
[0] [4]
\___________/
floor
WS2812 control for Raspberry Pi 5 (orchestrator) and Pico panel adapters.
Panel IPs
Five Pico panels on 10.1.1.10–10.1.1.14. Examples drive all 5 by default.
Panel sizes
Panels are 9 rows tall; width varies by panel. Edit PANEL_WIDTH_BY_INDEX in leds/array_config.py:
| Panel | Face | IP | Size | LEDs | Firmware |
|---|---|---|---|---|---|
| 0 | bottom-left | 10.1.1.10 | 9×39 | 351 | make deploy PANEL_ID=0 |
| 1 | top-left | 10.1.1.11 | 9×45 | 405 | make deploy PANEL_ID=1 |
| 2 | top | 10.1.1.12 | 9×45 | 405 | make deploy PANEL_ID=2 |
| 3 | top-right | 10.1.1.13 | 9×45 | 405 | make deploy PANEL_ID=3 |
| 4 | bottom-right | 10.1.1.14 | 9×39? | 351 | make deploy PANEL_ID=4 |
Panels 0→1→2→3→4 run clockwise from bottom-left (PORTAL_PANEL_ORDER_CLOCKWISE in leds/array_config.py).
Panel 4 may be 38 or 39 wide — find the exact width:
make deploy PANEL_ID=4
pipenv run python examples/panel_sync_test.py --test width --panel-index 4
Last column that lights → set PANEL_WIDTH_BY_INDEX[4] in leds/array_config.py to column + 1 (342 LEDs for 38, 351 for 39). Firmware takes pixel count from each UDP frame — no re-flash for width changes.
Animations render at each panel's own width automatically.
Examples
Portal web simulator
Preview all five panels in the browser (3D interior view + flat layout map). Uses the same Python animations as the hardware.
pipenv install fastapi "uvicorn[standard]"
pipenv run python examples/portal_simulator.py
# open http://localhost:8765/
Dev mode (default): uvicorn reload for Python changes, browser auto-reload when web/ files change. Disable with --no-reload or --no-browser-reload.
Options: --host 0.0.0.0 --port 8765 to view from another device on the network.
Open via the simulator URL (http://…:8765/) — do not open index.html directly from the filesystem (file://), or module imports will fail.
Frontend uses Web Components and ES modules under web/js/:
| Module | Role |
|---|---|
<portal-app> |
Root layout, frame streaming |
<portal-controls> |
Sidebar settings |
<portal-viewport> |
Three.js 3D scene |
<portal-schematic> |
Flat layout map |
<portal-panel> |
Single LED matrix canvas |
Pico panel (UDP)
WS2812 defaults: GP28 (strip 0) and GP27 (strip 1). Override over UDP:
pipenv run python examples/panel_color_test.py --panel-index 0 --pins 28:405,27:351
| Command | What it does |
|---|---|
pipenv run python examples/panel_rgb_cycle.py |
Red / green / blue on all 5 panels |
pipenv run python examples/panel_color_test.py |
One-shot RGB + white test |
pipenv run python examples/panel_test.py |
Layout tests (corners, rows, chase) |
pipenv run python examples/panel_sync_test.py |
Positioning + sync across all panels |
pipenv run python examples/panel_animations.py |
All animations on all panels |
pipenv run python examples/panel_animations.py rolling |
One animation |
pipenv run python examples/panel_text.py |
Show your name |
pipenv run python examples/animations.py --panel |
Same as panel_animations |
Single panel only:
pipenv run python examples/panel_animations.py --panel-index 1 # 9×45 @ 10.1.1.11
Pi SPI (bench / single matrix)
Optional local SPI tests via rpi5-ws2812 on GPIO 10 — not used for the five portal panels.
405 LEDs need a ~10 KiB SPI frame. Default spidev bufsiz (4096) only updates ~169 LEDs — run once:
pipenv run python examples/setup_spi_bufsiz.py --install # sudo
| Command | What it does |
|---|---|
pipenv run python examples/spi_rgb_test.py |
Red / green / blue over SPI |
pipenv run python examples/spi_panel_test.py |
Corners, rows, chase — verify all LEDs |
pipenv run python examples/animations.py |
All animations on local matrix |
pipenv run python examples/matrix_demo.py |
Rainbow only |
pipenv run python examples/led_demo.py |
Dual-strip chase + rainbow |
Colors use logical RGB everywhere ((255,0,0) = red). Pico firmware remaps to GRB on the wire; Pi SPI uses the same swap when needed. The web simulator stays logical RGB.
# MicroPython on Pico — this is the reference:
np.fill((255, 0, 0)); np.write() # red
pipenv run python examples/panel_rgb_cycle.py # same colors over UDP
Firmware
Pico SDK sources live under firmware/pico/ (see that README for the UDP protocol).
make deploy PANEL_ID=0
make reset && make monitor