diff --git a/homeassistant/components/history_stats/sensor.py b/homeassistant/components/history_stats/sensor.py index b0ce1a8fca5..a42c516f12b 100644 --- a/homeassistant/components/history_stats/sensor.py +++ b/homeassistant/components/history_stats/sensor.py @@ -21,6 +21,7 @@ from homeassistant.const import ( TIME_HOURS, ) from homeassistant.core import HomeAssistant, callback +from homeassistant.exceptions import PlatformNotReady import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.reload import async_setup_reload_service @@ -101,6 +102,9 @@ async def async_setup_platform( history_stats = HistoryStats(hass, entity_id, entity_states, start, end, duration) coordinator = HistoryStatsUpdateCoordinator(hass, history_stats, name) + await coordinator.async_refresh() + if not coordinator.last_update_success: + raise PlatformNotReady from coordinator.last_exception async_add_entities([HistoryStatsSensor(coordinator, sensor_type, name)]) @@ -152,6 +156,7 @@ class HistoryStatsSensor(HistoryStatsSensorBase): super().__init__(coordinator, name) self._attr_native_unit_of_measurement = UNITS[sensor_type] self._type = sensor_type + self._process_update() @callback def _process_update(self) -> None: diff --git a/tests/components/history_stats/test_sensor.py b/tests/components/history_stats/test_sensor.py index f824ee552ca..8907f381a6c 100644 --- a/tests/components/history_stats/test_sensor.py +++ b/tests/components/history_stats/test_sensor.py @@ -9,7 +9,7 @@ import pytest from homeassistant import config as hass_config from homeassistant.components.history_stats import DOMAIN -from homeassistant.const import SERVICE_RELOAD, STATE_UNAVAILABLE, STATE_UNKNOWN +from homeassistant.const import SERVICE_RELOAD, STATE_UNKNOWN import homeassistant.core as ha from homeassistant.helpers.entity_component import async_update_entity from homeassistant.setup import async_setup_component, setup_component @@ -50,7 +50,7 @@ class TestHistoryStatsSensor(unittest.TestCase): self.hass.block_till_done() state = self.hass.states.get("sensor.test") - assert state.state == STATE_UNKNOWN + assert state.state == "0.0" def test_setup_multiple_states(self): """Test the history statistics sensor setup for multiple states.""" @@ -71,7 +71,7 @@ class TestHistoryStatsSensor(unittest.TestCase): self.hass.block_till_done() state = self.hass.states.get("sensor.test") - assert state.state == STATE_UNKNOWN + assert state.state == "0.0" def test_wrong_duration(self): """Test when duration value is not a timedelta.""" @@ -153,12 +153,12 @@ async def test_invalid_date_for_start(hass, recorder_mock): }, ) await hass.async_block_till_done() - assert hass.states.get("sensor.test").state == STATE_UNKNOWN + assert hass.states.get("sensor.test") is None next_update_time = dt_util.utcnow() + timedelta(minutes=1) with freeze_time(next_update_time): async_fire_time_changed(hass, next_update_time) await hass.async_block_till_done() - assert hass.states.get("sensor.test").state == STATE_UNAVAILABLE + assert hass.states.get("sensor.test") is None async def test_invalid_date_for_end(hass, recorder_mock): @@ -178,12 +178,12 @@ async def test_invalid_date_for_end(hass, recorder_mock): }, ) await hass.async_block_till_done() - assert hass.states.get("sensor.test").state == STATE_UNKNOWN + assert hass.states.get("sensor.test") is None next_update_time = dt_util.utcnow() + timedelta(minutes=1) with freeze_time(next_update_time): async_fire_time_changed(hass, next_update_time) await hass.async_block_till_done() - assert hass.states.get("sensor.test").state == STATE_UNAVAILABLE + assert hass.states.get("sensor.test") is None async def test_invalid_entity_in_template(hass, recorder_mock): @@ -203,12 +203,12 @@ async def test_invalid_entity_in_template(hass, recorder_mock): }, ) await hass.async_block_till_done() - assert hass.states.get("sensor.test").state == STATE_UNKNOWN + assert hass.states.get("sensor.test") is None next_update_time = dt_util.utcnow() + timedelta(minutes=1) with freeze_time(next_update_time): async_fire_time_changed(hass, next_update_time) await hass.async_block_till_done() - assert hass.states.get("sensor.test").state == STATE_UNAVAILABLE + assert hass.states.get("sensor.test") is None async def test_invalid_entity_returning_none_in_template(hass, recorder_mock): @@ -228,12 +228,12 @@ async def test_invalid_entity_returning_none_in_template(hass, recorder_mock): }, ) await hass.async_block_till_done() - assert hass.states.get("sensor.test").state == STATE_UNKNOWN + assert hass.states.get("sensor.test") is None next_update_time = dt_util.utcnow() + timedelta(minutes=1) with freeze_time(next_update_time): async_fire_time_changed(hass, next_update_time) await hass.async_block_till_done() - assert hass.states.get("sensor.test").state == STATE_UNAVAILABLE + assert hass.states.get("sensor.test") is None async def test_reload(hass, recorder_mock): @@ -302,56 +302,55 @@ async def test_measure_multiple(hass, recorder_mock): ] } - await async_setup_component( - hass, - "sensor", - { - "sensor": [ - { - "platform": "history_stats", - "entity_id": "input_select.test_id", - "name": "sensor1", - "state": ["orange", "blue"], - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "time", - }, - { - "platform": "history_stats", - "entity_id": "unknown.test_id", - "name": "sensor2", - "state": ["orange", "blue"], - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "time", - }, - { - "platform": "history_stats", - "entity_id": "input_select.test_id", - "name": "sensor3", - "state": ["orange", "blue"], - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "count", - }, - { - "platform": "history_stats", - "entity_id": "input_select.test_id", - "name": "sensor4", - "state": ["orange", "blue"], - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "ratio", - }, - ] - }, - ) - await hass.async_block_till_done() - with patch( "homeassistant.components.recorder.history.state_changes_during_period", _fake_states, ): + await async_setup_component( + hass, + "sensor", + { + "sensor": [ + { + "platform": "history_stats", + "entity_id": "input_select.test_id", + "name": "sensor1", + "state": ["orange", "blue"], + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "time", + }, + { + "platform": "history_stats", + "entity_id": "unknown.test_id", + "name": "sensor2", + "state": ["orange", "blue"], + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "time", + }, + { + "platform": "history_stats", + "entity_id": "input_select.test_id", + "name": "sensor3", + "state": ["orange", "blue"], + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "count", + }, + { + "platform": "history_stats", + "entity_id": "input_select.test_id", + "name": "sensor4", + "state": ["orange", "blue"], + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "ratio", + }, + ] + }, + ) + await hass.async_block_till_done() for i in range(1, 5): await async_update_entity(hass, f"sensor.sensor{i}") await hass.async_block_till_done() @@ -382,56 +381,55 @@ async def test_measure(hass, recorder_mock): ] } - await async_setup_component( - hass, - "sensor", - { - "sensor": [ - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor1", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "time", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor2", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "time", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor3", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "count", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor4", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "ratio", - }, - ] - }, - ) - await hass.async_block_till_done() - with patch( "homeassistant.components.recorder.history.state_changes_during_period", _fake_states, ): + await async_setup_component( + hass, + "sensor", + { + "sensor": [ + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor1", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "time", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor2", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "time", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor3", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "count", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor4", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "ratio", + }, + ] + }, + ) + await hass.async_block_till_done() for i in range(1, 5): await async_update_entity(hass, f"sensor.sensor{i}") await hass.async_block_till_done() @@ -463,56 +461,55 @@ async def test_async_on_entire_period(hass, recorder_mock): ] } - await async_setup_component( - hass, - "sensor", - { - "sensor": [ - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_on_id", - "name": "on_sensor1", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "time", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_on_id", - "name": "on_sensor2", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "time", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_on_id", - "name": "on_sensor3", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "count", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_on_id", - "name": "on_sensor4", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "ratio", - }, - ] - }, - ) - await hass.async_block_till_done() - with patch( "homeassistant.components.recorder.history.state_changes_during_period", _fake_states, ): + await async_setup_component( + hass, + "sensor", + { + "sensor": [ + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_on_id", + "name": "on_sensor1", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "time", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_on_id", + "name": "on_sensor2", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "time", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_on_id", + "name": "on_sensor3", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "count", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_on_id", + "name": "on_sensor4", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "ratio", + }, + ] + }, + ) + await hass.async_block_till_done() for i in range(1, 5): await async_update_entity(hass, f"sensor.on_sensor{i}") await hass.async_block_till_done() @@ -1235,56 +1232,55 @@ async def test_measure_from_end_going_backwards(hass, recorder_mock): ] } - await async_setup_component( - hass, - "sensor", - { - "sensor": [ - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor1", - "state": "on", - "duration": {"hours": 1}, - "end": "{{ now() }}", - "type": "time", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor2", - "state": "on", - "duration": {"hours": 1}, - "end": "{{ now() }}", - "type": "time", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor3", - "state": "on", - "duration": {"hours": 1}, - "end": "{{ now() }}", - "type": "count", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor4", - "state": "on", - "duration": {"hours": 1}, - "end": "{{ now() }}", - "type": "ratio", - }, - ] - }, - ) - await hass.async_block_till_done() - with patch( "homeassistant.components.recorder.history.state_changes_during_period", _fake_states, ), freeze_time(start_time): + await async_setup_component( + hass, + "sensor", + { + "sensor": [ + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor1", + "state": "on", + "duration": {"hours": 1}, + "end": "{{ now() }}", + "type": "time", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor2", + "state": "on", + "duration": {"hours": 1}, + "end": "{{ now() }}", + "type": "time", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor3", + "state": "on", + "duration": {"hours": 1}, + "end": "{{ now() }}", + "type": "count", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor4", + "state": "on", + "duration": {"hours": 1}, + "end": "{{ now() }}", + "type": "ratio", + }, + ] + }, + ) + await hass.async_block_till_done() for i in range(1, 5): await async_update_entity(hass, f"sensor.sensor{i}") await hass.async_block_till_done() @@ -1329,56 +1325,55 @@ async def test_measure_cet(hass, recorder_mock): ] } - await async_setup_component( - hass, - "sensor", - { - "sensor": [ - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor1", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "time", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor2", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "time", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor3", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "count", - }, - { - "platform": "history_stats", - "entity_id": "binary_sensor.test_id", - "name": "sensor4", - "state": "on", - "start": "{{ as_timestamp(now()) - 3600 }}", - "end": "{{ now() }}", - "type": "ratio", - }, - ] - }, - ) - await hass.async_block_till_done() - with patch( "homeassistant.components.recorder.history.state_changes_during_period", _fake_states, ): + await async_setup_component( + hass, + "sensor", + { + "sensor": [ + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor1", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "time", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor2", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "time", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor3", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "count", + }, + { + "platform": "history_stats", + "entity_id": "binary_sensor.test_id", + "name": "sensor4", + "state": "on", + "start": "{{ as_timestamp(now()) - 3600 }}", + "end": "{{ now() }}", + "type": "ratio", + }, + ] + }, + ) + await hass.async_block_till_done() for i in range(1, 5): await async_update_entity(hass, f"sensor.sensor{i}") await hass.async_block_till_done()