Skip to content

feat: add addressable RGB LED status display system#4

Merged
daharoni merged 5 commits intomainfrom
feat/led-status-display
Mar 13, 2026
Merged

feat: add addressable RGB LED status display system#4
daharoni merged 5 commits intomainfrom
feat/led-status-display

Conversation

@daharoni
Copy link
Member

Summary

  • Add WS2812B (NeoPixel) LED strip support as a background daemon with 10 animated scenes (idle, flashing, testing, error, success, booting, off, solid, rainbow, progress) that reflect bench state at a glance
  • Daemon runs a 30 FPS animation loop, listens on a Unix domain socket for scene change commands from CLI or publisher hooks
  • Publisher hooks automatically trigger LED scenes on flash start/end and health check completion (best-effort, never raises)

Architecture

benchctl led set-scene ...  ──┐
Publisher hooks (flash/health)──┼── LedClient ── Unix socket ── LED Daemon ── rpi_ws281x
                              ──┘                /run/hil-bench/led.sock

New files

File Purpose
src/hilbench/led/_models.py Pydantic IPC models (LedColor, SceneRequest/Response, DaemonStatus)
src/hilbench/led/_strip.py LedStrip Protocol + Ws281xStrip (hardware) + StubStrip (testing)
src/hilbench/led/_scenes.py Scene Protocol, registry, 10 built-in animated scenes
src/hilbench/led/_daemon.py Single-threaded animation loop + Unix socket server
src/hilbench/led/_client.py Client library for IPC
src/hilbench/cli/led_cmd.py CLI: set-scene, off, list-scenes, status, daemon
systemd/hil-bench-led.service Systemd unit
bootstrap/install_led_service.sh Bootstrap installer

Modified files

File Change
src/hilbench/config.py Add LedConfig model + led field on BenchConfig
src/hilbench/exceptions.py Add LedError
src/hilbench/cli/main.py Register led command group
src/hilbench/publisher/_hooks.py Add LED scene triggers in flash/health hooks
src/hilbench/health.py Add led_daemon health check
pyproject.toml Add led optional dep group, mypy override
configs/config.template.yaml Add led: section
configs/bench-config.example.yaml Add led: example
bootstrap/bootstrap_pi.sh Call LED installer
bootstrap/update.sh Refresh LED service

Test plan

  • 69 new unit tests across 5 test files (155 total, all passing)
  • Scene tests run against StubStrip — no hardware needed
  • Daemon tests verify socket IPC, scene switching, boot→idle transition, cleanup
  • CLI tests verify dry-run, mocked client, error handling
  • Ruff lint clean
  • On Pi hardware: enable in config, systemctl start hil-bench-led, benchctl led set-scene rainbow

🤖 Generated with Claude Code

daharoni and others added 5 commits March 13, 2026 09:47
Add WS2812B (NeoPixel) LED strip support as a background daemon with
animated scenes that reflect bench state (idle, flashing, testing,
error, etc.). Any process can trigger scene changes via Unix socket IPC.

- LedConfig model with led_count, gpio_pin, brightness, fps, socket_path
- LedStrip Protocol with Ws281xStrip (hardware) and StubStrip (testing)
- 10 built-in scenes: idle, flashing, testing, error, success, booting,
  off, solid, rainbow, progress — all time-based animations
- Single-threaded daemon with selectors-based event loop at 30 FPS
- LedClient for short-lived Unix socket IPC
- CLI commands: set-scene, off, list-scenes, status, daemon
- Publisher hooks trigger LED scenes on flash/health events
- Health check for LED daemon (only when enabled)
- Systemd unit and bootstrap/update scripts for deployment
- 69 new tests (155 total), all passing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The pyproject.toml mypy override already handles missing imports for
rpi_ws281x, so inline ignore comments are redundant and cause CI
errors with --ignore-missing-imports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers quick start, built-in scenes, Python/CLI/workflow usage, socket
protocol, how to add custom scenes, hardware wiring, and troubleshooting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cache rpi_ws281x.Color in Ws281xStrip.__init__ to avoid per-pixel
import overhead in the 30 FPS render loop. Deduplicate scene-switching
by having _cmd_set_scene delegate to _set_scene. Hoist contextlib
import to module level.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@daharoni daharoni merged commit afe2ace into main Mar 13, 2026
2 checks passed
@daharoni daharoni deleted the feat/led-status-display branch March 13, 2026 17:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant