Skip to content

v1.2.0

Choose a tag to compare

@posch-dev posch-dev released this 23 Jun 18:34
· 4 commits to 4dedbfc85d1f74e3fdcb7e9e7f0f9e37c23deb5b since this release

Release Notes v1.2.0

New features

  • Webhooks. Each panel has a webhooks toggle in the web UI now. Turn it on and you can add HTTP requests that fire on on_enter (panel becomes active) and on_exit (panel gets switched away from). Device-level webhooks fire on power on/off and active hours start/end. Now Playing gets an extra trigger, on_song_change, which fires when a new song actually shows up on the display (after the GIF uploads and the slot switches, not when the poller first detects it).
  • Webhook template variables for Now Playing. The on_song_change body and URL support {{accent1_hex}}, {{accent1_rgb}}, {{accent1_r}}, {{accent1_g}}, {{accent1_b}}, {{accent1_hsv}}, {{title}}, {{artist}}, {{album}}, same thing for accent2 and accent3. There's also full-brightness variants ({{accent1_full_hex}}, {{accent1_full_rgb}}, {{accent1_full_r/g/b}}) that keep the same hue and saturation but at 100% value, for stuff like WLED strips that handle brightness on their own.
  • Webhook editor in the web UI. It's a modal with method dropdown (GET/POST/PUT/PATCH/DELETE), URL field, key-value header rows you can add and remove like in iOS Shortcuts, and a body textarea that only shows for methods that actually have a body. Now Playing gets a collapsible "Variables" section with clickable buttons that insert the variable at your cursor position.
  • Active hours grace period. When active hours end, the display spends 2 minutes sending a black screen every 10 seconds to make sure the panel is actually off before going into the sleep loop.
  • Install script. ./install.sh checks for Python 3.11+, python3-venv, and Bluetooth, creates a .venv inside the repo, installs everything there, and sets up the smartpixeldashboard systemd service. No more pip install --break-system-packages.
  • Disabled panels are greyed out in the Trigger tab now with a "disabled" badge, and you can't click their inputs.
  • Event grace period. Dashboard panels triggered by upcoming calendar events now stay visible past the departure time (or event start if there's no travel time) for a configurable grace period.

Accent colors

  • Rewrote the accent color algorithm. Colors are picked by prominence now (how many pixels on the cover share that hue) instead of vibrancy. Most common color becomes accent1 (artist text, visualizer bottom), second most common is accent2 (album text, visualizer middle), third is accent3 (visualizer top).
  • Monochrome covers (like Jesus Is King, which is basically all blue) now get saturation and value variants of the dominant hue instead of random colors at 120 degree offsets that have nothing to do with the cover.
  • accent3 (visualizer top) is now always the color most different from accent1 (visualizer bottom). Before this, accent2 could end up being the most contrasting one, stuck in the middle where nobody notices it.
  • Placeholder cover when there's no album art is just black with a centered white music note now. Was a gradient before.
  • Fallback accent colors (no cover art) changed from pink/blue/yellow to lime green, orange, and turquoise.

BLE stability

  • Fixed a bug where Now Playing would randomly lose BLE connection because it did all its BLE writes (GIF uploads, slot switches, brightness changes, slot deletes) without the ble_lock. Every other panel used the lock. So when Now Playing uploaded a GIF while the clock task sent a frame or the slot clearer deleted a slot at the same time, the concurrent writes corrupted the connection and the whole thing crashed.
  • Fixed a bug where a failed GIF upload just printed "upload failed" and kept looping with a dead BLE client forever. The exception got caught and swallowed inside run_loop, so it never made it up to startup.py where the reconnect logic lives. Upload failures now kill the mode task, startup.py catches that, and it reconnects.
  • Fixed a bug where tick_loop and clear_slots tasks were never cancelled on reconnect. Every time BLE dropped and came back, a new tick_loop got created without cancelling the old one. After a few reconnects you'd have multiple tick loops running in parallel, all calling scheduler.tick() every second, which made modes expire and switch around randomly.
  • Quick reconnect. If BLE disconnects and comes back within 2 minutes, slot clearing gets skipped. The display picks up where it left off instead of wiping all 256 slots. Disconnects longer than 2 minutes still do a full clear like a fresh boot.
  • Fixed a bug where _black_keepalive in Now Playing swallowed all BLE exceptions with except Exception: pass. If the connection dropped while keepalive was running, it just looped endlessly trying to send black frames to a dead client, hogging the ble_lock every time.

Bug fixes

  • Fixed a bug where the accent color algorithm produced pink/magenta instead of red for covers that are mostly red (like My Beautiful Dark Twisted Fantasy). The hue averaging used a linear mean, which breaks for hues near 0/360 degrees. Pixels at 351 degrees (red) and 6 degrees (warm brown) averaged to ~178 degrees (cyan) instead of ~358 degrees (red). Switched to circular mean with atan2(sin, cos).
  • Fixed a bug where playing music while manually holding Clock (or any panel you triggered manually from the web UI) would still auto-switch to Now Playing. has_user_trigger() had a m != "clock" filter that excluded Clock from the check, so manually triggering Clock didn't count as a user trigger and the now playing watcher just ignored it.
  • Fixed a bug where the calendar POST endpoint returned a 400 when the request body was empty or not a dict. The auto-trigger should fire regardless of whether there's event data in there. Now it always triggers the dashboard (if auto-trigger is on) and only appends event data when there's a valid dict.
  • Fixed a bug where changing the Now Playing font in the web UI or config did absolutely nothing. display.set_font() was never called with the config value, so it was hardcoded to the default forever. Now it reads from config on start and checks for changes every poll cycle.

Web UI

  • Weather settings card is inside the Dashboard settings now, so it hides when Dashboard is disabled. "City Name" field only shows when wttr.in is the selected provider.
  • Device tab active hours toggle matches the verse panel layout now (toggle left, label right, sub-row hidden by default).

Docs

  • README setup section rewritten with clone + ./install.sh workflow, venv instructions, and correct systemd service name (smartpixeldashboard).
  • README documents webhooks now, with an asterisk noting on_song_change is Now Playing only.
  • API endpoint list has all endpoints now: /display/power, GET /mode, GET /calendar, POST /dashboard/trigger.
  • Now Playing docs updated with webhooks section, template variables, full-brightness variants, corrected font default (3 instead of 1).
  • Clock, Verse of Day, and Dashboard docs each got a short webhooks section.
  • requirements.txt uses minimum versions (>=) instead of pinned (==) so it actually installs on different architectures.