Adaptive Cover Pro ⛅ v2.28.0-beta.12
Pre-releaseℹ Using release notes from: release_notes/v2.28.0-beta.12.md
Beta.12 brings two targeted improvements: a config-entry migration that preserves position-matching behavior for covers upgraded from earlier in the beta line, and a decision-trace enhancement that surfaces the actual held position during manual overrides.
🎯 Highlights
Beta — please test and report back.
- If you're upgrading from beta.11 or earlier with existing covers, restart Home Assistant and confirm that position matching is still enabled for those covers. Open each cover's config entry and verify
enable_position_matchingistrue— the migration should have set it automatically. - Confirm that covers freshly added after the upgrade still default to position matching OFF (the new-install default is unchanged).
- With a manual override active, open the decision trace in diagnostics and confirm the step shows both the held position and what solar would have computed — e.g.
manual override active — holding 35% (solar would-be 60%). - Verify that a held position of 0% is surfaced correctly (not suppressed or treated as absent).
🐛 Fixes
Position matching silently disabled for upgraded covers (#591, #606)
Earlier in the beta line (#591) introduced enable_position_matching as an opt-in, defaulting OFF for new installs. Covers that predated this change had position matching as their implicit behavior — they chased and reconciled — so silently flipping them to command-once was a regression.
The fix is a v3.3 → v3.4 config-entry migration in async_migrate_entry (__init__.py). The new block calls new_options.setdefault(CONF_ENABLE_POSITION_MATCHING, True) for any entry that doesn't already carry the key, then bumps the config entry to minor version 4. MINOR_VERSION on ConfigFlowHandler (config_flow.py) was raised from 3 to 4 so Home Assistant triggers async_migrate_entry for entries below 3.4. New installs are unaffected: the create flow calls options.setdefault(CONF_ENABLE_POSITION_MATCHING, DEFAULT_ENABLE_POSITION_MATCHING), which defaults to OFF.
The migration is additive and rollback-safe — the key is only written when absent. It mirrors the earlier v2 → v3 enable_my_position_entities migration in structure. Four regression tests in tests/test_config_entry_migration.py cover the primary path, the no-op cases (key already true, key already false), and v1 cascading.
✨ Improvements
Held position now visible in the manual override decision trace (#608)
When a manual override was active, the decision trace showed what solar or the default handler would have computed — but not the position the cover was actually being held at. That made it opaque why the cover wasn't moving.
A new held_position field on the DecisionStep dataclass (pipeline/types.py) carries the physical cover position during a manual override step; it is None for all other steps. PipelineRegistry (pipeline/registry.py) populates held_position on the winning manual-override step. Reason strings from ManualOverrideHandler (pipeline/handlers/manual_override.py) now include the held position alongside the would-be position — for example: manual override active — holding 35% (solar would-be 60%). When held_position is None, the handler falls back to the previous style. Both DiagnosticsBuilder (diagnostics/builder.py) and the sensor attributes via _decision_trace_attrs (sensor.py) expose the key only when held_position is not None, so existing consumers are unaffected. Explicit is-not-None checks are used throughout because 0% is a valid held position.
🧹 Maintenance
Black bumped to ~=26.5 (resolves CVE-2026-32274, Dependabot alert #75) and CI workflow speedups applied (pytest xdist, pip cache, concurrency, path gating). Dev and CI tooling only — no runtime changes.
Previously in this beta line
- Custom-position sensor migration gate fixed (beta.11, #563, #607)
- Solar-tracking position forecast in diagnostics, vertical extreme-gamma/high-elevation edge cases removed, legacy custom-position sensor migration added (beta.10, #563, #597, #598, #599, #600, #601)
- FOV generate-from-measurements button replaces two-mode selector, position matching opt-in with disable-retry option, climate status sensor always exposes threshold setpoints and typed
inactive_reasonslugs, FOV preview shown at depth 0 (beta.9, #565, #589, #590, #591, #592, #595, #596) - Measurements-mode FOV sliders visible with editable suggested value, config summary shows [template] for Jinja2 threshold values (beta.8, #565, #577, #587, #588)
- Force Override merged into Custom Positions, FOV formula corrected (beta.7, #563, #565, #584, #583)
- Jinja2 templates in threshold fields and optional occupancy template (beta.6, #577, #578)
- Configuration Summary translated to user's language (beta.4/beta.5, #258, #575, #576)
- Set-position covers can reach true 0% in solar tracking (beta.3/beta.4, #569, #572)
- Same-position gate reverted to exact equality, restoring 1–3% tracking moves (beta.3, #567, #574)
- String entity_id in service targets now normalizes correctly (beta.3, #570, #571)
- FOV mode persisted on re-render, fixing save loop (beta.2/beta.3, #565)
- Measurements-mode config-flow save and imperial shaded-area compounding fixes (beta.2, #565)
- Low-sun edge case returns closed position (beta.1, #559, #562)
- Write-gating, geometry caching, and sun availability guard (beta.1, #543)
Compatibility
Requires Home Assistant 2026.3.0+. No new coupled-component requirements.