diff --git a/homeassistant/components/recorder/statistics.py b/homeassistant/components/recorder/statistics.py index b6af3d60d73..f3b0b27df39 100644 --- a/homeassistant/components/recorder/statistics.py +++ b/homeassistant/components/recorder/statistics.py @@ -12,7 +12,8 @@ from sqlalchemy.ext import baked from sqlalchemy.orm.scoping import scoped_session from homeassistant.const import PRESSURE_PA, TEMP_CELSIUS -from homeassistant.core import HomeAssistant +from homeassistant.core import Event, HomeAssistant, callback +from homeassistant.helpers import entity_registry import homeassistant.util.dt as dt_util import homeassistant.util.pressure as pressure_util import homeassistant.util.temperature as temperature_util @@ -73,6 +74,31 @@ def async_setup(hass: HomeAssistant) -> None: hass.data[STATISTICS_BAKERY] = baked.bakery() hass.data[STATISTICS_META_BAKERY] = baked.bakery() + def entity_id_changed(event: Event) -> None: + """Handle entity_id changed.""" + old_entity_id = event.data["old_entity_id"] + entity_id = event.data["entity_id"] + with session_scope(hass=hass) as session: + session.query(StatisticsMeta).filter( + StatisticsMeta.statistic_id == old_entity_id + and StatisticsMeta.source == DOMAIN + ).update({StatisticsMeta.statistic_id: entity_id}) + + @callback + def entity_registry_changed_filter(event: Event) -> bool: + """Handle entity_id changed filter.""" + if event.data["action"] != "update" or "old_entity_id" not in event.data: + return False + + return True + + if hass.is_running: + hass.bus.async_listen( + entity_registry.EVENT_ENTITY_REGISTRY_UPDATED, + entity_id_changed, + event_filter=entity_registry_changed_filter, + ) + def get_start_time() -> datetime: """Return start time.""" diff --git a/tests/components/recorder/test_statistics.py b/tests/components/recorder/test_statistics.py index 32eaaaab842..0468cc26a23 100644 --- a/tests/components/recorder/test_statistics.py +++ b/tests/components/recorder/test_statistics.py @@ -16,6 +16,7 @@ from homeassistant.const import TEMP_CELSIUS from homeassistant.setup import setup_component import homeassistant.util.dt as dt_util +from tests.common import mock_registry from tests.components.recorder.common import wait_recording_done @@ -93,6 +94,63 @@ def test_compile_hourly_statistics(hass_recorder): assert stats == {} +def test_rename_entity(hass_recorder): + """Test statistics is migrated when entity_id is changed.""" + hass = hass_recorder() + recorder = hass.data[DATA_INSTANCE] + setup_component(hass, "sensor", {}) + + entity_reg = mock_registry(hass) + reg_entry = entity_reg.async_get_or_create( + "sensor", + "test", + "unique_0000", + suggested_object_id="test1", + ) + assert reg_entry.entity_id == "sensor.test1" + + zero, four, states = record_states(hass) + hist = history.get_significant_states(hass, zero, four) + assert dict(states) == dict(hist) + + for kwargs in ({}, {"statistic_ids": ["sensor.test1"]}): + stats = statistics_during_period(hass, zero, **kwargs) + assert stats == {} + stats = get_last_statistics(hass, 0, "sensor.test1") + assert stats == {} + + recorder.do_adhoc_statistics(period="hourly", start=zero) + wait_recording_done(hass) + expected_1 = { + "statistic_id": "sensor.test1", + "start": process_timestamp_to_utc_isoformat(zero), + "mean": approx(14.915254237288135), + "min": approx(10.0), + "max": approx(20.0), + "last_reset": None, + "state": None, + "sum": None, + } + expected_stats1 = [ + {**expected_1, "statistic_id": "sensor.test1"}, + ] + expected_stats2 = [ + {**expected_1, "statistic_id": "sensor.test2"}, + ] + expected_stats99 = [ + {**expected_1, "statistic_id": "sensor.test99"}, + ] + + stats = statistics_during_period(hass, zero) + assert stats == {"sensor.test1": expected_stats1, "sensor.test2": expected_stats2} + + entity_reg.async_update_entity(reg_entry.entity_id, new_entity_id="sensor.test99") + hass.block_till_done() + + stats = statistics_during_period(hass, zero) + assert stats == {"sensor.test99": expected_stats99, "sensor.test2": expected_stats2} + + def record_states(hass): """Record some test states. diff --git a/tests/conftest.py b/tests/conftest.py index 1f5ffc80d0d..ce8e244f420 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -610,7 +610,7 @@ def enable_statistics(): @pytest.fixture -def hass_recorder(enable_statistics): +def hass_recorder(enable_statistics, hass_storage): """Home Assistant fixture with in-memory recorder.""" hass = get_test_home_assistant() stats = recorder.Recorder.async_hourly_statistics if enable_statistics else None