From fe393c84e25847b6a2fde2583f803b986720a5d3 Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Sat, 8 Apr 2023 15:36:34 +0100 Subject: [PATCH] Delay utility_meter until HA has started (#91017) * increase information for end user * only warn after home assistant has started * delay utility_meter until HA has startED --- .../components/utility_meter/sensor.py | 17 ++++++--- tests/components/utility_meter/test_sensor.py | 36 +++++++++++-------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py index dd0fb685bac..b7be0bdcfc0 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -35,7 +35,7 @@ from homeassistant.helpers.event import ( async_track_point_in_time, async_track_state_change_event, ) -from homeassistant.helpers.start import async_at_start +from homeassistant.helpers.start import async_at_started from homeassistant.helpers.template import is_number from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.util import slugify @@ -410,8 +410,11 @@ class UtilityMeterSensor(RestoreSensor): if (old_state_val := self._validate_state(old_state)) is not None: return new_state_val - old_state_val + _LOGGER.warning( - "Invalid state (%s > %s)", + "%s received an invalid state change coming from %s (%s > %s)", + self.name, + self._sensor_source_id, old_state.state if old_state else None, new_state_val, ) @@ -423,8 +426,14 @@ class UtilityMeterSensor(RestoreSensor): old_state: State | None = event.data.get("old_state") new_state: State = event.data.get("new_state") # type: ignore[assignment] # a state change event always has a new state + # First check if the new_state is valid (see discussion in PR #88446) if (new_state_val := self._validate_state(new_state)) is None: - _LOGGER.warning("Invalid state %s", new_state.state) + _LOGGER.warning( + "%s received an invalid new state from %s : %s", + self.name, + self._sensor_source_id, + new_state.state, + ) return if self._state is None: @@ -597,7 +606,7 @@ class UtilityMeterSensor(RestoreSensor): self.hass, [self._sensor_source_id], self.async_reading ) - self.async_on_remove(async_at_start(self.hass, async_source_tracking)) + self.async_on_remove(async_at_started(self.hass, async_source_tracking)) async def async_will_remove_from_hass(self) -> None: """Run when entity will be removed from hass.""" diff --git a/tests/components/utility_meter/test_sensor.py b/tests/components/utility_meter/test_sensor.py index d84099b4d66..8dcff8438ad 100644 --- a/tests/components/utility_meter/test_sensor.py +++ b/tests/components/utility_meter/test_sensor.py @@ -35,7 +35,7 @@ from homeassistant.const import ( ATTR_DEVICE_CLASS, ATTR_ENTITY_ID, ATTR_UNIT_OF_MEASUREMENT, - EVENT_HOMEASSISTANT_START, + EVENT_HOMEASSISTANT_STARTED, STATE_UNAVAILABLE, STATE_UNKNOWN, UnitOfEnergy, @@ -105,7 +105,7 @@ async def test_state(hass: HomeAssistant, yaml_config, config_entry_config) -> N await hass.async_block_till_done() entity_id = config_entry_config["source"] - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() hass.states.async_set( @@ -301,7 +301,7 @@ async def test_init(hass: HomeAssistant, yaml_config, config_entry_config) -> No await hass.async_block_till_done() entity_id = config_entry_config["source"] - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() state = hass.states.get("sensor.energy_bill_onpeak") @@ -346,7 +346,7 @@ async def test_unique_id( assert await async_setup_component(hass, DOMAIN, yaml_config) await hass.async_block_till_done() - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() assert len(entity_registry.entities) == 4 @@ -400,7 +400,7 @@ async def test_entity_name(hass: HomeAssistant, yaml_config, entity_id, name) -> assert await async_setup_component(hass, DOMAIN, yaml_config) await hass.async_block_till_done() - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() state = hass.states.get(entity_id) @@ -475,7 +475,8 @@ async def test_device_class( entity_id_energy = "sensor.energy" entity_id_gas = "sensor.gas" - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + await hass.async_block_till_done() hass.states.async_set( @@ -657,7 +658,9 @@ async def test_restore_state( assert state.state == STATE_UNKNOWN # utility_meter is loaded, now set sensors according to utility_meter: - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + await hass.async_block_till_done() state = hass.states.get("select.energy_bill") @@ -719,7 +722,8 @@ async def test_net_consumption( await hass.async_block_till_done() entity_id = config_entry_config["source"] - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + hass.states.async_set( entity_id, 2, {ATTR_UNIT_OF_MEASUREMENT: UnitOfEnergy.KILO_WATT_HOUR} ) @@ -792,7 +796,8 @@ async def test_non_net_consumption( await hass.async_block_till_done() entity_id = config_entry_config["source"] - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + hass.states.async_set( entity_id, 2, {ATTR_UNIT_OF_MEASUREMENT: UnitOfEnergy.KILO_WATT_HOUR} ) @@ -817,7 +822,7 @@ async def test_non_net_consumption( force_update=True, ) await hass.async_block_till_done() - assert "Invalid state " in caplog.text + assert "invalid new state " in caplog.text state = hass.states.get("sensor.energy_bill") assert state is not None @@ -882,7 +887,7 @@ async def test_delta_values( await hass.async_block_till_done() entity_id = config_entry_config["source"] - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) async_fire_time_changed(hass, now) hass.states.async_set( @@ -903,7 +908,7 @@ async def test_delta_values( force_update=True, ) await hass.async_block_till_done() - assert "Invalid state None" in caplog.text + assert "invalid new state from sensor.energy : None" in caplog.text now += timedelta(seconds=30) with freeze_time(now): @@ -992,7 +997,7 @@ async def test_non_periodically_resetting( await hass.async_block_till_done() entity_id = config_entry_config["source"] - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) async_fire_time_changed(hass, now) hass.states.async_set( @@ -1120,7 +1125,8 @@ async def test_non_periodically_resetting_meter_with_tariffs( await hass.async_block_till_done() entity_id = config_entry_config["source"] - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + await hass.async_block_till_done() hass.states.async_set( @@ -1226,7 +1232,7 @@ async def _test_self_reset( assert await async_setup_component(hass, DOMAIN, config) await hass.async_block_till_done() - hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) entity_id = config[DOMAIN]["energy_bill"]["source"] async_fire_time_changed(hass, now)