Adaptive Cover Pro ⛅ v2.28.0-beta.10
Pre-releaseℹ Using release notes from: release_notes/v2.28.0-beta.10.md
Beta.10 ships three focused changes: diagnostics now include a solar-tracking-only position forecast for validating sun and FOV geometry, a pair of commits removes edge-case branches in the vertical cover geometry that were either redundant or contradicted the normal projection path, and a migration step fills the new multi-sensor list key for custom-position slots that were configured before the multi-select was introduced. Seven dependency and CI housekeeping items round out the build.
🎯 Highlights
Beta — please test and report back.
- Confirm the diagnostics panel includes a
position_forecastsection and that the forecast steps change as the sun moves through the day. - Verify the
position_forecastdescription field explicitly identifies it as a solar-tracking projection (not the live decision). - Check that vertical blinds no longer briefly snap fully closed when the sun enters the FOV edge at high elevation and extreme horizontal angle.
- Confirm covers configured before the multi-sensor custom-position update (pre-#563) still show their legacy sensor in the slot after upgrading.
- Verify
set_position_limitsand custom-position options behave identically to beta.9 for existing configs. - Confirm the diagnostics
decision_tracesection is unaffected by the new forecast field.
✨ Features
Solar-tracking forecast in diagnostics dump (a4d721d)
The diagnostics dump now includes a position_forecast section: a solar-tracking-only projection for the rest of today. It holds window geometry constant and walks the sun forward, deliberately ignoring manual override, motion, weather safety, climate, and custom-position handlers. Its purpose is to validate sun/FOV geometry and timing — not to explain why a cover moved or didn't at a given instant (the existing decision_trace section answers that).
DiagnosticsBuilder._build_forecast reads position_forecast from DiagnosticContext. The forecast serializes via its own to_attrs() method and the shared FORECAST_STEP_MINUTES constant — the same wire format the sensor and Lovelace card already consume. A description field is emitted into the dump so a reader cannot mistake the projection for the live decision. The position_forecast field on DiagnosticContext is None until the background recompute produces it; _build_forecast is a no-op until then.
🐛 Fixes
Vertical extreme-gamma and high-elevation edge cases removed (#598, #599, #600, #601)
A spurious fully-closed position sample appeared right at the FOV-entry edge for a high-elevation sun at an extreme horizontal angle (gamma). The fix shipped in two steps.
First (#598/#599) made the extreme-gamma full-closure rule elevation-aware by adding EDGE_CASE_EXTREME_GAMMA_ELEVATION = 45.0: closure was only forced when the sun was low. Then (#600/#601) removed the extreme-gamma and very-high-elevation branches from _edge_case in geometry.py entirely. AdaptiveVerticalCover.calculate_position already carries its own numerical guards — MIN_COS_GAMMA_CLAMP on the cos(gamma) divisor, MIN_TAN_ELEVATION_CLAMP on the sill division, and a negative-distance clamp — so those branches either duplicated the normal path or contradicted it. The constants EDGE_CASE_EXTREME_GAMMA, EDGE_CASE_HIGH_ELEVATION, and the briefly-added EDGE_CASE_EXTREME_GAMMA_ELEVATION are gone. Only EDGE_CASE_LOW_ELEVATION (sun on the horizon → full coverage) remains.
Migrate legacy single-sensor custom-position key to list on upgrade (#563, #597)
A trailing defect of the #563 custom-position-slot work: config entries saved before multi-sensor support was added stored a single custom_position_sensor_N key and did not prefill the new multi-select list in the options flow.
A new helper copy_legacy_slot_sensors_to_list in helpers.py, called by a new v3.2 → v3.3 minor migration step in async_migrate_entry, covers the gap. For each custom-position slot where the new list key is absent and the legacy single-sensor key holds a non-empty value, the legacy value is wrapped in a one-element list under the list key. The migration is additive and rollback-safe — the legacy key is left intact, following the same invariant as the v3.2 migration. It iterates CUSTOM_POSITION_SLOTS.
🔧 Internal
Dependency bumps: pandas to ~=2.3 (#347), black to ~=26.5 (#480), pip (#479), pre-commit/ruff linting group (#481), pytest/pytest-asyncio/hypothesis testing group (#603), codecov-action (#573). Dependabot retargeted at develop (#481); JUnit test results now uploaded to Codecov Test Analytics; codecov/test-results-action pinned to v1; git tagging removed from the deploy script.
🧪 Testing
4,496 tests passing.
Previously in this beta line
- 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. The pandas dependency bumps to ~=2.3 but introduces no new minimum HA version.