Skip to content

Adaptive Cover Pro ⛅ v2026.8.3

Latest

Choose a tag to compare

@jrhubott jrhubott released this 20 Aug 03:29

Highlights

2026.8.3 is an in-month patch: four bug fixes back-ported from develop, no new features, no configuration changes and nothing to migrate. Two of them fix things the UI told users outright wrongly. The occupancy countdown no longer reads "expired" for its entire life, which is what made the occupancy sensors look inverted (#1266). The Configuration Summary's cloud-suppression line said "weather in {sunny, …}" when suppression actually fires when the weather is not in that set — the exact opposite of what every install was configured to do, in all three shipped languages (#1301). The other two restore a blind spot's sky-compass wedge, which has published nothing at all on current stable (#1291), and let cleared optional config fields actually stay cleared (#1267).

Fixed

  • The occupancy timeout end time is measured from the timer, not the last detection (#1266): _motion_status_attrs derived motion_timeout_end_time from last_motion_time — the occupancy detection stamp — plus the timeout, but the no-motion timer starts on the clear edge. Anyone present for longer than the configured timeout pushed the published end time into the past the instant the timer actually started, so the card rendered "expires in expired" for the whole live countdown. With the default 300 second timeout, five minutes of continuous presence was enough.

    MotionManager now stamps _timeout_started_at when the timer starts and owns the formula behind a timeout_end_time property; the sensor publishes that verbatim and drops its private _timeout_seconds reach. The second half of the defect was the state after the countdown ends: _on_motion_timeout_expired set _motion_timeout_active without clearing the stamp, so the property kept returning a past timestamp for the entire no-occupancy state. All four exits from "timer counting" — record_motion_detected, cancel_motion_timeout, set_no_motion, and the timer firing naturally — now clear it, so the property honors its documented contract: a time while the timer runs, None otherwise. The attribute name and payload shape are unchanged, and the companion card already renders nothing when the attribute is absent, so no card release is needed.

    This is most of why the issue was filed as an inversion. The remaining half is wording: reason_i18n.py prints "occupancy timeout active" beside "No Occupancy" and "occupancy timeout not active" beside "Occupancy Detected". Both statements are true about the internal flag and both read as the inverse of the occupancy state next to them. That is a separate change across all three translation bundles and is not fixed here.

  • Cleared optional config fields round-trip (#1267): Emptying the Motion Template field in the options flow did not stick — the old template stayed in the config entry with no way to delete it from the UI. optional_entities() fills in None for any key voluptuous dropped from user_input, and it has to run before options.update() for a clear to overwrite anything. async_step_motion_override never called it.

    Auditing the rest of the options flow for the same defect class turned up two more paths with no clearing call at all. async_step_interp left CONF_INTERP_START / CONF_INTERP_END set, so a custom interpolation range could not be removed once configured. _render_blind_spot_slot's mapped comprehension skips any key missing from user_input, silently dropping a cleared right_gamma (slots 2 and 3) or elevation (all slots). All three now reuse the existing optional_entities() helper, inserted after each step's validation early-return so a rejected form clears nothing. left_gamma carries a schema default in every slot and is excluded on purpose.

  • Blind spots publish their gamma range again (#1291): The per-slot sub-key tuple in DiagnosticsBuilder._build_configuration copied only left, right, elevation and elevation_mode into the diagnostics configuration dict, so left_gamma / right_gamma never reached it. The sun sensor's gamma-preferred branch in _sun_position_attrs was therefore dead on that path, and because the options flow has written gamma keys only since v3.8, the legacy fallback found nothing either. Every configured blind spot published no blind_spot_range and no blind_spot_ranges at all — while the engine, which reads raw entry options, kept computing the correct position. That is why the card's sky compass showed no wedge while the blind sat exactly where it should.

    This is live on 2026.8.2: it carries both the four-key tuple and the gamma-only form keys, so any blind spot configured on current stable publishes nothing. Widening the tuple activates the already-correct gamma branch; no sensor change and no card change are needed. Entries migrated from before v3.8 hold both key sets, so gamma now wins over legacy in the published attribute, matching what the engine already does. That can shift a drawn wedge by up to the one-degree repair sliver clamp_gamma_pair applies — correct, but visible if you compare a screenshot from before and after.

    The gap that let this survive was the test shape: the new sensor tests drive a gamma-only entry through the real DiagnosticsBuilder instead of hand-feeding the configuration dict. Issue #1292, which layers a blind_spot_slots attribute on top of blind_spot_ranges, depends on this fix but is not shipped here.

  • The cloud-suppression summary states its trigger the right way round (#1301): The Configuration Summary rendered "skips sun tracking when weather in {sunny, partlycloudy, clear}". ClimateProvider sets is_sunny to weather_state in weather_condition and the priority-60 handler suppresses on not r.is_sunny, so suppression fires when the live weather state is not in the configured set. The summary told users the exact opposite of what their configuration does, and matched the option's own help text only by accident.

    cloud.weather_in now reads "weather not in {…}". Fixing the operator rather than restructuring the shared "skips sun tracking when …" stem keeps the terse, copula-free register of the sibling fragments it sits beside in the joined condition list (lux < X lx, cloud > Y%); those three are already correct, and rephrasing only the weather clause positively would either break that sentence or drag them in with it. Since #906 made the DE and FR summary bundles live, German and French users saw the same inverted wording, so all three bundles land together. The existing test pinned the buggy string as correct, which is how this shipped in the first place; its assertion now expresses the real semantics. A related finding from the same audit — the summary presenting the weather-state check as an OR triple — is tracked in #1302 and is not fixed here.

Testing

12,565 tests passing.

Compatibility

Home Assistant 2026.3.0+ and Python 3.11+. No migration runs for this release, and no new or changed configuration options. The companion Lovelace card (jrhubott/adaptive-cover-pro-card) is a separate repo with its own release cycle and needs no update for this patch.