The idea
A small networked device — an ESP32 with an RGB LED strip or a single addressable bulb — sits on a developer's desk or on a shared wall in the team room and shows one thing: the current state of your CI pipeline. Green means the last build passed, yellow means one is running, red means something's broken. It polls (or gets pushed to via webhook) your CI provider's API and updates within a few seconds of a status change.
Why build this
Broken builds sit unnoticed for hours because nobody's watching the CI dashboard tab, and Slack notifications get buried in the noise of every other channel. A physical light is ambient information: you see it without deciding to look, the way you notice a stoplight change color out of the corner of your eye while cooking. Teams used to buy Ambient Orbs and Philips Hue hacks for this a decade ago, but ESP32 boards are now $4, addressable LEDs are cheap and well-documented (FastLED, NeoPixel libraries), and every CI provider (GitHub Actions, CircleCI, GitLab CI, Buildkite) exposes a clean REST API or webhook you can hit without scraping HTML. It's a weekend hardware build with a genuinely daily-use payoff.
Stack sketch
- Microcontroller: ESP32 (Wi-Fi built in, plenty of GPIO, cheap dev boards from Adafruit/Seeed)
- LEDs: WS2812B addressable strip or a single Neopixel, driven with the FastLED Arduino library
- Firmware: Arduino/C++ or MicroPython, polling a status endpoint every 10–15 seconds, or better, subscribing to a lightweight MQTT topic
- Bridge service: a small self-hosted Node.js or Go service that receives CI webhooks (GitHub Actions
workflow_run, CircleCI webhook, GitLab pipeline hooks), normalizes them into a singlepass/fail/runningstate per repo, and republishes to MQTT (Mosquitto) or exposes a/statusJSON endpoint the device polls - Config: a tiny YAML file mapping repo/branch to a "which light" ID, so one bridge service can drive multiple desk lights for multiple teams
- Power/enclosure: USB-powered, 3D-printed or laser-cut diffuser case so the LED reads as a smooth glow rather than a bare chip
Scope for v1
- One repo, one branch (e.g.,
main), one light - Bridge service supports GitHub Actions webhooks only
- Three states: green (passing), red (failing), pulsing yellow (build in progress)
- Device polls the bridge's
/statusendpoint over HTTP every 10 seconds — no MQTT yet, simpler to ship - Manual Wi-Fi credential entry via a captive portal on first boot (WiFiManager library)
- Out of scope: multi-repo support, brightness/color customization UI, mobile app, MQTT, historical uptime stats
Where it could go
The natural next step is fanning out to multiple repos and multiple lights per team, with the bridge service maintaining a small registry so a new light just needs a device ID and a repo mapping to start working — no firmware changes. From there, add other CI providers (CircleCI, GitLab, Jenkins via a generic webhook shim) and let the light encode more than pass/fail: a slow pulse for "deploy in progress," a distinct color for "flaky test retrying." A version with a small e-ink or OLED panel could show which commit and author triggered the current build, turning the ambient light into a glanceable dashboard rather than just a signal.
Watch out for
CI webhook payloads vary enough between providers that your normalization layer needs real test coverage per provider, not just a happy-path parse — a malformed or delayed webhook should fail safe (hold last known state, don't flash red on a network hiccup). Also budget for Wi-Fi reliability: office networks with client isolation or captive portals can silently strand ESP32 devices, so build in a local status LED or serial log for debugging connectivity separately from CI state.