From 98466056c6658dabd1af24f5e83828541e395c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Stormwall?= Date: Sat, 6 Jun 2026 19:19:22 +0200 Subject: [PATCH] fix: re-align dead-band on sync --- .../easee_solar_charging/coordinator.py | 13 +++++++------ tests/test_coordinator.py | 13 ++++++++++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/custom_components/easee_solar_charging/coordinator.py b/custom_components/easee_solar_charging/coordinator.py index 2249743..63908db 100644 --- a/custom_components/easee_solar_charging/coordinator.py +++ b/custom_components/easee_solar_charging/coordinator.py @@ -127,19 +127,20 @@ class EaseeSolarCoordinator(DataUpdateCoordinator): """Return True only when the target warrants a new service call. - First run: always send. - - Transitions to/from 0: always send (start/stop events). + - Transitions to/from 0: always send immediately (start/stop events). - Outside dead-band: send immediately. - - Inside dead-band: send once per minute so gradual solar drift is applied. + - Inside dead-band (including same value): re-align once per minute so + the charger is periodically re-confirmed even if the target hasn't changed. + - 0 → 0: never resend (charger is already off). """ if self._last_sent_current is None: return True - if target == self._last_sent_current: - return False + # Start / stop transitions fire immediately; 0→0 is a no-op. if target == 0 or self._last_sent_current == 0: - return True + return target != self._last_sent_current if abs(target - self._last_sent_current) >= HYSTERESIS_A: return True - # Within dead-band: resync once per minute + # Within dead-band or same value: re-align once per minute. return ( self._last_sent_at is None or datetime.now(timezone.utc) - self._last_sent_at >= _DEAD_BAND_RESYNC diff --git a/tests/test_coordinator.py b/tests/test_coordinator.py index ae0f920..acdfda5 100644 --- a/tests/test_coordinator.py +++ b/tests/test_coordinator.py @@ -27,10 +27,21 @@ class TestShouldSend: def test_first_run_always_sends(self, coord): assert coord._should_send(8) is True - def test_same_value_no_send(self, coord): + def test_same_value_no_send_when_recent(self, coord): coord._last_sent_current = 8 + coord._last_sent_at = datetime.now(timezone.utc) assert coord._should_send(8) is False + def test_same_value_sends_after_one_minute(self, coord): + coord._last_sent_current = 8 + coord._last_sent_at = datetime.now(timezone.utc) - timedelta(minutes=1, seconds=1) + assert coord._should_send(8) is True + + def test_zero_to_zero_never_resends(self, coord): + coord._last_sent_current = 0 + coord._last_sent_at = datetime.now(timezone.utc) - timedelta(minutes=10) + assert coord._should_send(0) is False + def test_zero_to_nonzero_sends(self, coord): coord._last_sent_current = 0 assert coord._should_send(8) is True