Audio-reactive LED control that uses WLED's built-in effects instead of streaming pixels. The board renders the effect itself; this script only pushes small JSON control updates (brightness/speed/intensity) derived from the audio.
Spotify ─▶ BlackHole ─▶ RMS envelope ─▶ JSON /json/state ─▶ WLED renders on-device
The sibling project SpotifyLeds computes every pixel on the Mac and streams the whole frame over UDP (DNRGB). That's "Option B" — great for custom effects, but the per-frame packet grows with the strip: ~3 KB/frame at 1092 LEDs, and it falls apart past a few thousand LEDs (packet count, MTU, Wi-Fi throughput).
This project is "Option A": pick a WLED effect + palette once, then send a handful of bytes per update to nudge brightness/speed/intensity. Bandwidth is constant no matter how many LEDs you drive — the ESP does the per-pixel work.
Trade-off: you get WLED's built-in effects (100+ of them), not the custom Python effects from SpotifyLeds. Audio-reactivity here means "modulate an effect's parameters," not "control each pixel."
- Python 3.9+
- BlackHole 2ch set up as a Multi-Output Device (audio plays and is captured), same as SpotifyLeds
- A WLED device reachable on your LAN (no realtime UDP needed — just the normal HTTP JSON API, which is always on)
pip install -r requirements.txt
- See what your board offers:
python3 discover.py 192.168.0.194 # list all effects + palettes python3 discover.py 192.168.0.194 --grep fire - Edit the config block at the top of spotify_wled.py:
WLED_HOST,EFFECT,PALETTE,SEND_HZ, and theTARGETSmapping. - Run it:
python3 spotify_wled.py # drive the board python3 spotify_wled.py --dry-run # print patches without a device (checks audio/mapping)
| File | Purpose |
|---|---|
| spotify_wled.py | Entry point: config, resolve effect/palette, audio→param send loop. |
| discover.py | CLI to list a device's effects and palettes with their indices. |
| wledapi/client.py | WLED JSON-API client (keep-alive HTTP) + name↔index Catalog. |
| wledapi/audio.py | BlackHole capture → smoothed 0..1 loudness level (own thread). |
| wledapi/mapping.py | Target spec + build_patch: level → WLED fields, with change-throttling. |
Each Target maps the 0..1 level onto one WLED field over [lo, hi] with an
optional gamma curve. bri is global brightness (top-level); sx/ix are
per-segment speed/intensity (segment=True). A target is only sent when it
moves by at least min_delta, so a steady signal produces no traffic.
- Rate: WLED handles ~10–25 HTTP updates/s comfortably; the change-delta
throttle keeps real traffic well below
SEND_HZ. For higher rates or lower latency, MQTT is a lighter transport than HTTP — a possible future backend. - Control UI: SpotifyLeds' web control panel (
web_ui.py+index.html) could be ported to pick effect/palette/mapping live instead of via config. - On-board sound reactive: alternatively WLED's AudioReactive usermod does reactivity entirely on the ESP (needs a mic/line-in on the board), removing the Mac from the loop — different hardware path, not what this project does.