diff --git a/homeassistant/components/sofar/sensor.py b/homeassistant/components/sofar/sensor.py index f446a9af5e4d..01d78cedfb9a 100644 --- a/homeassistant/components/sofar/sensor.py +++ b/homeassistant/components/sofar/sensor.py @@ -7,6 +7,7 @@ from enum import IntEnum from typing import cast, override from sofar_modbus.modern.device import SofarInverter +from sofar_modbus.modern.enums import SystemState from homeassistant.components.sensor import ( RestoreSensor, @@ -142,6 +143,9 @@ class SofarSensor(SofarEntity, SensorEntity): class SofarCountdownSensor(SofarSensor): """Defines a Sofar countdown, published as the moment it runs out.""" + # A positive register alone doesn't mean the countdown is active. + _ACTIVE_STATES = (SystemState.WAITING, SystemState.CHECKING) + def __init__( self, runtime_data: SofarRuntimeData, @@ -156,7 +160,11 @@ class SofarCountdownSensor(SofarSensor): def native_value(self) -> datetime | None: component = getattr(self.coordinator.device, self.entity_description.component) seconds = getattr(component, self.entity_description.key) - if not isinstance(seconds, int) or seconds <= 0: + if ( + not isinstance(seconds, int) + or seconds <= 0 + or component.system_state not in self._ACTIVE_STATES + ): # A restart must not land inside the finished countdown's slack. self._deadline = _deadline_filter() return None diff --git a/tests/components/sofar/test_sensor.py b/tests/components/sofar/test_sensor.py index 86998a9b50ac..ab325c2584c5 100644 --- a/tests/components/sofar/test_sensor.py +++ b/tests/components/sofar/test_sensor.py @@ -426,6 +426,7 @@ async def test_countdown_holds_its_deadline_until_it_restarts( """Test a countdown ticking with the clock keeps one deadline.""" mock_config_entry.add_to_hass(hass) unit = mock_connection.for_unit(1) + unit.holding[0x0404] = 0 # Waiting unit.holding[0x0417] = 300 with patch( @@ -460,6 +461,34 @@ async def test_countdown_holds_its_deadline_until_it_restarts( assert hass.states.get(entity_id).state != deadline +async def test_countdown_ignores_a_stale_register_while_grid_connected( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + mock_connection: MockModbusConnection, + mock_config_entry: MockConfigEntry, +) -> None: + """Test a positive register is ignored once the inverter is connected.""" + mock_config_entry.add_to_hass(hass) + unit = mock_connection.for_unit(1) + unit.holding[0x0404] = 2 # Grid connected + unit.holding[0x0417] = 60 # Left over from the last startup wait + + with patch( + "homeassistant.components.sofar.async_get_unit", + side_effect=lambda hass, entry, params, unit_id: mock_connection.for_unit( + unit_id + ), + ): + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done(wait_background_tasks=True) + + entity_id = entity_registry.async_get_entity_id( + SENSOR_DOMAIN, DOMAIN, f"{MOCK_SERIAL}_waiting_time" + ) + assert entity_id is not None + assert hass.states.get(entity_id).state == STATE_UNKNOWN + + async def test_countdown_restarting_after_idle_gets_a_new_deadline( hass: HomeAssistant, freezer: FrozenDateTimeFactory, @@ -470,6 +499,7 @@ async def test_countdown_restarting_after_idle_gets_a_new_deadline( """Test a finished countdown's deadline is not reused by the next one.""" mock_config_entry.add_to_hass(hass) unit = mock_connection.for_unit(1) + unit.holding[0x0404] = 0 # Waiting unit.holding[0x0417] = 10 with patch(