# portal Hexagonal LED portal: five WS2812 matrix panels on Pico UDP adapters, plus a bare floor. Reference: [photo of the physical portal](https://technical.kiwi/images/portal/IMG_20241029_220222.jpg) — 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: ```bash 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. ```bash 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 | |--------|------| | `` | Root layout, frame streaming | | `` | Sidebar settings | | `` | Three.js 3D scene | | `` | Flat layout map | | `` | Single LED matrix canvas | ### Pico panel (UDP) WS2812 defaults: **GP28** (strip 0) and **GP27** (strip 1). Override over UDP: ```bash 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: ```bash 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`](https://github.com/niklasr22/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: ```bash 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. ```python # MicroPython on Pico — this is the reference: np.fill((255, 0, 0)); np.write() # red ``` ```bash 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). ```bash make deploy PANEL_ID=0 make reset && make monitor ```