Skip to content

Adaptive Cover Pro ⛅ v2.28.0-beta.8

Pre-release
Pre-release

Choose a tag to compare

@jrhubott jrhubott released this 12 Jun 16:32
· 152 commits to main since this release

ℹ Using release notes from: release_notes/v2.28.0-beta.8.md
Beta.8 adds two refinements to the v2.28.0 line. Measurements-mode FOV sliders are now visible in the Cover Geometry step — pre-populated with the derived angle as an editable suggested_value — so users can accept the calculated angle or override either side independently. The Configuration Summary no longer leaks raw Jinja2 source: any threshold field that holds a template now renders as [template] rather than exposing the expression. Both changes build directly on work already in this beta series (#565 FOV corrections, #577 template threshold fields).

🎯 Highlights

Beta — please test and report back.

  • If you have a cover configured with Measurements mode (reveal width and depth), re-open the Cover Geometry step. Confirm the CONF_FOV_LEFT and CONF_FOV_RIGHT sliders are now visible, pre-populated with the derived angle. Type a different value into one slider and save — confirm the override is stored; leave the other slider untouched and confirm the derived value is used.
  • With a 2 m wide window and 0.5 m reveal depth the suggested angle should be approximately 76°. Verify that value appears.
  • If you use Jinja2 templates in any threshold field (CONF_LUX_THRESHOLD, CONF_IRRADIANCE_THRESHOLD, CONF_CLOUD_COVERAGE_THRESHOLD, CONF_WEATHER_WIND_SPEED_THRESHOLD, CONF_WEATHER_RAIN_THRESHOLD, CONF_TEMP_LOW, CONF_TEMP_HIGH, CONF_OUTSIDE_THRESHOLD), open the Configuration Summary and confirm the entry reads [template] rather than the raw template source.
  • If you had Force Override configured, open the Custom Positions step and confirm slot 5 is populated at priority 100 with your previous trigger sensor and target position. Activate the trigger sensor and confirm the cover moves to the configured position; deactivate it and confirm the cover returns to its calculated position.
  • Confirm that a priority-100 custom position slot commands the cover even when the current time is outside the configured start/end window — this is the safety-bypass behaviour carried over from Force Override.
  • Configure two sensors on a single custom position slot and confirm that either sensor alone is sufficient to trigger the slot (OR logic).
  • Configure a Jinja2 condition template on a custom position slot and confirm the slot activates when the template renders truthy.
  • Call the set_force_override service from an existing automation and confirm the cover still moves to the configured position; check the log for the deprecation warning.

✨ Features

Measurements-mode FOV sliders now visible with editable suggested value (#565, #588)

Previously, when CONF_FOV_MODE was set to FovMode.MEASUREMENTS, the CONF_FOV_LEFT and CONF_FOV_RIGHT sliders were dropped entirely from the Cover Geometry step. Users had no way to inspect the derived angle or override it without switching back to FovMode.ANGLES.

_get_sun_tracking_schema now accepts a source_config parameter, which it forwards to CoverTypePolicy.fov_mode_schema. BlindPolicy.fov_mode_schema uses that config to call fov_from_reveal(width, depth), rounds the result, and emits both FOV keys as vol.Optional(key, description={"suggested_value": derived}) when FovMode.MEASUREMENTS is active and depth > 0. The sliders appear pre-populated with the derived angle. When the user leaves a slider unchanged the frontend submits the suggested_value; _resolve_fov_mode_submit detects that the user did not supply an explicit override and writes the derived value rather than the typed one, so the stored angle always reflects a real number rather than a blank.

Typed overrides win: if the user changes either slider, that value is stored and used instead of the derived angle. The two sides can be overridden independently.

This change builds on the beta.7 fix to fov_from_reveal (#565, #583) that corrected the half-angle formula. Users who re-opened the step after that fix but before this one saw the correct angle in a read-only display; they can now also adjust it without leaving Measurements mode.

Force Override merged into Custom Positions (#563, #584)

The standalone Force Override config step is removed. Its functionality — a sensor-triggered override that bypasses normal automation logic unconditionally — is now expressed as Custom Positions slot 5 at priority 100 (CUSTOM_POSITION_SAFETY_PRIORITY). Any custom position slot whose priority is set to 100 inherits the full safety semantics: it commands the cover outside the configured start/end time window and bypasses both the delta-position and delta-time send gates. The PipelineResult.is_safety flag signals this condition to the command service, which treats it identically to how the old ForceOverrideHandler was treated.

Migration is automatic. The v3.2 minor-version migration (_merge_force_override_into_slot_5) runs on first load after upgrading and copies the legacy force_override_sensors and force_override_position values into slot 5 with priority=100. The legacy keys are left intact for rollback — downgrading to the previous release will restore the old Force Override UI and behaviour without any manual intervention.

Each custom position slot now has a richer trigger model. Beyond the existing single-sensor key, each slot supports a multi-sensor list (custom_position_sensors_N) with OR logic, an optional Jinja2 condition template (custom_position_template_N), and a combine mode (custom_position_template_mode_N, OR or AND) governing how the template result is combined with the sensor states. The legacy single-sensor key (custom_position_sensor_N) is preserved as a rollback mirror — custom_position_slot_sensors reads the list and falls back to the legacy key when the list is absent. mirror_legacy_slot_sensor_keys writes the first sensor from the list back into the legacy key on every save, keeping the rollback path intact.

The set_force_override service is retained for one release as a deprecation shim. It now writes slot 5 at safety priority and logs a deprecation warning; existing automations will continue to function without changes. ControlMethod.FORCE and ControlStatus.FORCE_OVERRIDE_ACTIVE are kept as deprecated enum members so that the companion Lovelace card and any external diagnostics consumers that reference those values do not break immediately.

CUSTOM_POSITION_SLOT_NUMBERS is now (1, 2, 3, 4, 5) and the priority slider ceiling is 100. The "Force Override Triggers" diagnostic sensor entity is retired; async_prune_legacy_sensor_entities_v2 handles orphan cleanup on upgrade.

Cover Geometry step description simplified (#564, #581)

The Cover Geometry config step description is now concise. The previous text enumerated the individual fields inline, duplicating the UI labels already visible on the same screen. That redundant field list is removed in English, German, and French.

🐛 Fixes

Config summary shows [template] for Jinja2 threshold values (#577, #587)

_build_config_summary previously emitted raw threshold values directly into the rendered summary. When a threshold field contained a Jinja2 expression, the full template source appeared verbatim in the UI — a confusing leak of internal syntax that offered no useful information to the user.

A _thresh_display(value, *, placeholder) helper now wraps every threshold lookup. If is_template_string(str(value)) returns true, the helper returns the placeholder string from the new fragments.template_value label ([template] in all three shipped languages) rather than the raw expression. Applied to CONF_WEATHER_WIND_SPEED_THRESHOLD, CONF_WEATHER_RAIN_THRESHOLD, CONF_CLOUD_COVERAGE_THRESHOLD, CONF_LUX_THRESHOLD, CONF_IRRADIANCE_THRESHOLD, CONF_TEMP_LOW, CONF_TEMP_HIGH, and CONF_OUTSIDE_THRESHOLD. The fragments.template_value key was added to _SUMMARY_LABELS_EN and to all three summary_i18n language files (en/de/fr).

Measurements-mode FOV was half the intended value (#565, #583)

fov_from_reveal in engine/sun_geometry.py computed the field-of-view angle as atan(half_width / depth) instead of atan(width / depth). With a 2 m wide window and 0.5 m reveal depth, the old formula returned ≈ 63° where ≈ 76° is geometrically correct. In practice, users who configured FOV via Measurements mode were tracking a window roughly half as wide as their actual opening, causing the integration to start shading too early and stop too late. After upgrading, re-open the Cover Geometry step for any cover that uses Measurements mode and verify the displayed FOV angle reflects your actual window dimensions.

🔧 Internal

  • _get_sun_tracking_schema gained a source_config parameter forwarded to CoverTypePolicy.fov_mode_schema; BlindPolicy.fov_mode_schema uses it to derive and expose the suggested_value for both FOV sliders in FovMode.MEASUREMENTS.
  • _thresh_display helper in _build_config_summary centralises the template-detection guard; fragments.template_value added to _SUMMARY_LABELS_EN and all three summary_i18n files.
  • CUSTOM_POSITION_SLOT_NUMBERS expanded from (1, 2, 3, 4) to (1, 2, 3, 4, 5); priority slider ceiling raised from 99 to 100.
  • mirror_legacy_slot_sensor_keys mirrors the first sensor from the multi-sensor list back into the legacy single-sensor key on every save for rollback fidelity.
  • DEFAULT_TEMPLATE_COMBINE_MODE replaces the motion-specific constant as the shared default for all combine-mode config fields.
  • async_prune_legacy_sensor_entities_v2 prunes the orphaned "Force Override Triggers" diagnostic sensor entity on upgrade.

🧪 Testing

4,454 tests passing. New coverage in tests/test_config_flow_fov_mode.py — FOV slider visibility in Measurements mode, suggested_value pre-population, typed override precedence, and zero-depth guard. New coverage in tests/test_config_flow_summary.py[template] placeholder for all eight threshold fields.

Previously in this beta line

Force Override merged into Custom Positions, FOV formula corrected (beta.7, #563, #565, #584, #583): Force Override no longer exists as a standalone config step; its safety semantics are expressed through Custom Positions slot 5 at priority 100. fov_from_reveal corrected from atan(half_width / depth) to atan(width / depth).

Jinja2 templates in threshold fields and optional occupancy template (beta.6, #577, #578): Nine numeric threshold config fields accept Jinja2 templates; TemplateResolver renders them per coordinator cycle with once-per-transition failure logging. A new optional CONF_MOTION_TEMPLATE field on Motion Override counts as occupancy when it renders truthy.

Configuration Summary translated to user's language (beta.4/beta.5, #258, #575, #576): The narrative Configuration Summary in the config/options flow renders in the user's HA language with English, German, and French shipped. The config_summary bundle (now under summary_i18n/) carries translated leaves for every summary fragment.

Set-position covers can reach true 0% in solar tracking (beta.3/beta.4, #569, #572): A geometry oversight prevented some set-position covers from closing fully during solar tracking. Covers that support arbitrary position commands now close to true 0%.

Same-position gate reverted to exact equality, restoring 1–3% tracking moves (beta.3, #567, #574): A tolerance band silently dropped small solar tracking adjustments. The gate reverts to exact equality; movement hysteresis is preserved in the reconcile path.

String entity_id in service targets now normalizes correctly (beta.3, #570, #571): Services that accept a string entity_id target normalize the value before resolution, fixing silent failures from case or spacing variations.

FOV mode persisted on re-render, fixing save loop (beta.2/beta.3, #565): The selected CONF_FOV_MODE was not written back into the stored options dict before re-render, causing an infinite re-render cycle.

Measurements-mode config-flow save and imperial shaded-area compounding fixes (beta.2, #565): FOV sliders were emitted as vol.Required, blocking the frontend from switching to Measurements mode. Imperial shaded-area values also compounded on each re-render.

Low-sun edge case returns closed position (beta.1, #559, #562): At very low sun elevations, a geometry edge case returned the fully-open position. The cover now closes when the sun is near the horizon.

Write-gating, geometry caching, and sun availability guard (beta.1, #543): _acp_render_signature() skips HA state writes when the calculated position matches the last written value. Pure geometry helpers use @lru_cache to eliminate repeated identical calculations. A guard on sun.sun suppresses solar tracking when the sun entity is unavailable.

Compatibility

Requires Home Assistant 2026.3.0+. No new coupled-component requirements.

References