Fix relay not turning off after integration restart

On restart, pv_state resets to IDLE so the computed decision is always
  False on the first recalculate. Comparing against self.decision (also
  False) meant relay_control was never called, leaving the relay physically
  ON past the PV target and cut-off temperature limits.

  - Compare decision against the actual relay_on state instead of the
    coordinator's previous self.decision, so any discrepancy (including
    one left by a restart or an external integration) is corrected
    immediately on every recalculate.
  - Call _recalculate() at the end of async_setup() so the relay is synced
    on startup without waiting for an external state-change event.

  Co-Authored-By: Claude
This commit is contained in:
2026-05-12 10:24:45 +03:00
parent 74f5ca457e
commit 0b284bda4d
@@ -174,6 +174,10 @@ class BoilerAuxHeaterCoordinator:
# B4: Restore persisted boost state
await self._async_restore_boost_state()
# Sync relay to current decision immediately, without waiting for a
# state change event (handles relay left ON before a restart).
self._recalculate()
async def _async_restore_boost_state(self) -> None:
"""Restore bath boost state from storage after HA restart."""
data = await self._store.async_load()
@@ -431,7 +435,6 @@ class BoilerAuxHeaterCoordinator:
allowed = hp_aux_off and allow_usage and boiler_temp_ok
# F1: Compute decision reason
old_decision = self.decision
if manual_override:
self.decision = True
self.decision_reason = "Manual override"
@@ -463,7 +466,7 @@ class BoilerAuxHeaterCoordinator:
self.decision = False
self.decision_reason = "OFF: No heating demand"
if self.decision != old_decision:
if self.decision != relay_on:
self.hass.async_create_task(self._async_control_relay(self.decision))
self._notify_listeners()