v0.51.3 — Fix conditions silently fail-opening in prod
The big one this patch covers is the user-reported "rotation conditions don't honour the entity state" bug in prod. Full diagnosis below.
Fixed
-
Rotation conditions silently fail-opening in prod. The scheduler tick's HA-state refresh runs in a background thread.
ha_core.serverresolves its base URL + token viacurrent_app.config, which is a request-scoped proxy and raisesRuntimeError: Working outside of application contextoutside a Flask request. The exception was swallowed by the closure inapp_factory._ha_get_states, which returned[].ConditionEvaluator.refresh_ha_statesthen replaced the cache with empty. Every condition's entity then resolved to "not in HA cache", fail-open kicked in, and gated rotation steps fired regardless of the entity state. The manual "Test conditions" button worked because that runs in a request context. Fixed by pushing an app context inside the closure so the background thread can resolvecurrent_appcorrectly. -
Defence in depth on the same bug.
refresh_ha_statesnow refuses to overwrite a populated cache with an empty result. Logs a warning instead. Without this, a future closure-level swallow (or a transient HA blip that returns[]) would silently fail-open every condition again. -
Drawer battery item leaking into the desktop top nav. v0.51.0 switched the mobile-drawer Batteries item from
<div>to<a>so the indicator could navigate to/devices/battery. That made the existing.topnav a { display: inline-flex }rule beat the unscoped.topbar-batteries--drawer { display: none }hide rule on desktop (specificity 0,1,1 vs 0,1,0), so the drawer's icon + label + device list rendered inline in the desktop header alongside the popover trigger. Scoped the drawer rules to.topnavso the specificity matches.
Changed
- Events page condition rows: dropped the heavy green/red left rail on each step row in the conditions display in favour of a small pass/fail dot at the start of the line. Page ids are now resolved to friendly names via the page store at render time, so a later rename updates the display automatically (slug stays in the data layer).
How to verify the prod fix
After updating, watch /events?type=conditions for your rotation's next tick. The observed value should now read the actual HA state (off or on) instead of "not in HA cache (fail-open)", and the gated step should be skipped / walked to rather than fired as scheduled.
Full Changelog: v0.51.1...v0.51.3