Adaptive Cover Pro ⛅ v2.22.0-beta.2
Pre-releaseℹ Using release notes from: release_notes/v2.22.0-beta.2.md
v2.22.0-beta.2
🎯 v2.22.0-beta.2 — Refactor + Post-Settle Cap Grace (Developer + Issue-33 Beta)
This beta carries everything from v2.22.0-beta.1 (the nine-phase internal refactor) plus a targeted fix for a venetian false-override bug discovered after beta.1: on KNX, Shelly 2PM, and other real-motor actuators, cover.state can settle to open/closed before the tilt-walk burst finishes publishing, causing DualAxisSequencer.is_in_suppression_with_cap to reject legitimate motor drift as a user move. If you are running real venetian hardware that was tripping false manual-override after a position command, please install this beta and report back on issue #33.
⚠️ Should I install this?
- If you ran v2.22.0-beta.1 and it worked, install this — it adds the post-settle cap grace fix on top.
- If you are on v2.21.5 and seeing false manual-override on venetian blinds after a position command (issue #33), please install this beta and report back.
- If you are on v2.21.5 and not hitting any issue, you may want to stay there.
🔑 Highlights
- NEW in beta.2: A 5-second post-settle cap grace in
DualAxisSequencer.is_in_suppression_with_capeliminates false venetian manual-override on KNX, Shelly 2PM, FGR223, and similar actuators that publish their tilt-walk burst aftercover.statehas already reportedopen/closed(issue #33). - Coordinator shrunk by ~640 lines of code; responsibility distributed into
managers/,state/,pipeline/, andcover_types/where it belongs. - Manual-override detection extracted from
coordinator.process_entity_state_changeintomanagers/cover_command/state_classifier.py; all five prior issue-specific fixes (#147, #172, #186, #271, #285) preserved verbatim. - Cover-type-specific behaviour consolidated onto
CoverTypePolicysubclasses; the coordinator and pipeline handlers no longer branch on cover-type strings or hardcoded capability keys. StubSingleAxisPolicyandStubDualAxisPolicyadded as canary types; ~60 regression tests now run across all real and stub policies to catch future regressions early.- Net diff (beta.1 refactor): 62 files changed, +3,682 / −1,251 lines.
🐛 Bug Fixes (new in beta.2)
- Post-settle cap grace prevents false venetian override (#33, commit 8c911d3):
DualAxisSequencer.is_in_suppression_with_capguards against false manual-override by bypassing the geometry-bounded backrotate cap whilecover.stateis in a moving set. On real KNX, Shelly 2PM, and FGR223 actuators, however, the carriage reportsopenorclosedbefore the full tilt-walk burst has drained from the HA state machine, so the cap would reassert mid-burst and flag the trailing delta as a user grab — latching manual override immediately after a programmatic position command. The fix adds aVENETIAN_POST_SETTLE_CAP_GRACE_SECONDS = 5.0constant and checks the elapsed time sincestamp_position_commandwas called insideis_in_suppression_with_cap: for 5 seconds after the stamp, the cap bypass stays active even whencover.statehas already settled. Once the grace tail expires, the geometry-bounded cap reasserts normally and will still detect a genuine user move. Also tightened the manual-override reason string inmanagers/manual_override.py— the redundant "(no recent position cmd)" suffix was removed.
🧹 Chores
-
Phase A — latent-defect cleanup at the policy boundary: Six surgical fixes around
CoverTypePolicy:GlareZoneHandlerdowncast guarded;VenetianPolicy.is_in_tilt_suppressionsignature harmonised; return-to-default switch gate moved to a policyClassVar; manual-override threshold deduped; custom-position priority default unified;CoverTypePolicysafe-defaults added. -
Phase B —
TimeoutControllerfor the manager timeout pattern: Consolidates the timeout-spawn/await/expiry/nullify pattern shared byMotionManager,WeatherManager, andGracePeriodManagerintomanagers/common/timeout_controller.py. Removes ~80 lines of duplication. -
Phase C —
DualAxisSequencerrelocated tocover_types/venetian/: Movesmanagers/dual_axis_sequencer.pyand the flatcover_types/venetian.pyinto a newcover_types/venetian/package (policy.py+sequencer.py). Zero behavior change; the sequencer now lives alongside the policy that owns it. -
Phase D —
PipelineSnapshotBuilderextracted from coordinator: Five coordinator methods (~213 LOC) move intopipeline/snapshot_builder.py. Climate, force-sensor, and custom-position reads, plus snapshot assembly, are no longer inline in the coordinator. -
Phase E —
WindowTransitionTrackerextracted from coordinator: ~130 lines of transition tracking move intostate/window_transition_tracker.py. Removes_last_sun_validity_stateand_prev_sunset_activeas coordinator instance attributes. -
Phase F —
StateClassifierextracted from coordinator: Moves a 256-line manual-override detection block intomanagers/cover_command/state_classifier.py. Issue-specific logic for #147, #172, #186, #271, and #285 is preserved exactly. -
Phase G — eliminate last cover-type literals, harden guard: Replaces remaining
SensorType.VENETIAN ==checks withClassVarflags (exposes_dual_axis_sensor,custom_position_includes_tilt). Adds a regression guard that scans for banned literal patterns to prevent the pattern from re-entering. -
Phase H — stub policies + parametrised cross-type invariants: Introduces
StubSingleAxisPolicyandStubDualAxisPolicy; production code must tolerate an unknown policy. Parametrises ~60 regression tests across all real and stub policies. -
Phase I — wiki anchor + display label onto the policy: Consolidates per-type label and wiki-URL mappings onto
CoverTypePolicy.wiki_anchor()anddisplay_label()hooks. Removes hardcoded mappings fromconfig_flow.py.
🧪 Testing
- 3380 tests passing (up from 3375 in v2.22.0-beta.1).
- New tests in
tests/test_manual_override_venetian.pycover the inside-grace and post-grace cases for the post-settle cap-grace tail, including astamp_age_secondsbackdating helper that lands stamps outside the 5s window while staying inside the overall suppression window. - New tests in
tests/test_cover_types/test_venetian_sequencer.pycover the cap grace: large delta inside grace returns true with settled state, large delta past grace returns false, small delta past grace still suppresses, and in-motion bypass still passes any delta.
Compatibility
- Home Assistant 2026.3.0+
- Python 3.11+