From dc5888ab4af85bf62d01a8dcd891a400232d6a99 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 10 Dec 2021 19:09:29 +0100 Subject: [PATCH] Correct recorder.statistics.get_last_statistics (#61421) --- .../components/recorder/statistics.py | 43 +++++++++++++++---- homeassistant/components/sensor/recorder.py | 4 +- tests/components/recorder/test_statistics.py | 33 ++++++++++---- 3 files changed, 62 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/recorder/statistics.py b/homeassistant/components/recorder/statistics.py index 2b60e6fbf00..02c00722e72 100644 --- a/homeassistant/components/recorder/statistics.py +++ b/homeassistant/components/recorder/statistics.py @@ -834,8 +834,12 @@ def statistics_during_period( return _reduce_statistics_per_month(result) -def get_last_statistics( - hass: HomeAssistant, number_of_stats: int, statistic_id: str, convert_units: bool +def _get_last_statistics( + hass: HomeAssistant, + number_of_stats: int, + statistic_id: str, + convert_units: bool, + table: type[Statistics | StatisticsShortTerm], ) -> dict[str, list[dict]]: """Return the last number_of_stats statistics for a given statistic_id.""" statistic_ids = [statistic_id] @@ -845,16 +849,19 @@ def get_last_statistics( if not metadata: return {} - baked_query = hass.data[STATISTICS_SHORT_TERM_BAKERY]( - lambda session: session.query(*QUERY_STATISTICS_SHORT_TERM) - ) + if table == StatisticsShortTerm: + bakery = STATISTICS_SHORT_TERM_BAKERY + base_query = QUERY_STATISTICS_SHORT_TERM + else: + bakery = STATISTICS_BAKERY + base_query = QUERY_STATISTICS + + baked_query = hass.data[bakery](lambda session: session.query(*base_query)) baked_query += lambda q: q.filter_by(metadata_id=bindparam("metadata_id")) metadata_id = metadata[statistic_id][0] - baked_query += lambda q: q.order_by( - StatisticsShortTerm.metadata_id, StatisticsShortTerm.start.desc() - ) + baked_query += lambda q: q.order_by(table.metadata_id, table.start.desc()) baked_query += lambda q: q.limit(bindparam("number_of_stats")) @@ -874,11 +881,29 @@ def get_last_statistics( statistic_ids, metadata, convert_units, - StatisticsShortTerm, + table, None, ) +def get_last_statistics( + hass: HomeAssistant, number_of_stats: int, statistic_id: str, convert_units: bool +) -> dict[str, list[dict]]: + """Return the last number_of_stats statistics for a statistic_id.""" + return _get_last_statistics( + hass, number_of_stats, statistic_id, convert_units, Statistics + ) + + +def get_last_short_term_statistics( + hass: HomeAssistant, number_of_stats: int, statistic_id: str, convert_units: bool +) -> dict[str, list[dict]]: + """Return the last number_of_stats short term statistics for a statistic_id.""" + return _get_last_statistics( + hass, number_of_stats, statistic_id, convert_units, StatisticsShortTerm + ) + + def _statistics_at_time( session: scoped_session, metadata_ids: set[int], diff --git a/homeassistant/components/sensor/recorder.py b/homeassistant/components/sensor/recorder.py index 25cb81ded12..3cfe8d45b70 100644 --- a/homeassistant/components/sensor/recorder.py +++ b/homeassistant/components/sensor/recorder.py @@ -517,7 +517,9 @@ def _compile_statistics( # noqa: C901 last_reset = old_last_reset = None new_state = old_state = None _sum = 0.0 - last_stats = statistics.get_last_statistics(hass, 1, entity_id, False) + last_stats = statistics.get_last_short_term_statistics( + hass, 1, entity_id, False + ) if entity_id in last_stats: # We have compiled history for this sensor before, use that as a starting point last_reset = old_last_reset = last_stats[entity_id][0]["last_reset"] diff --git a/tests/components/recorder/test_statistics.py b/tests/components/recorder/test_statistics.py index d510d6ef612..c4dd33ce840 100644 --- a/tests/components/recorder/test_statistics.py +++ b/tests/components/recorder/test_statistics.py @@ -14,6 +14,7 @@ from homeassistant.components.recorder.models import ( ) from homeassistant.components.recorder.statistics import ( async_add_external_statistics, + get_last_short_term_statistics, get_last_statistics, get_metadata, list_statistic_ids, @@ -40,7 +41,7 @@ def test_compile_hourly_statistics(hass_recorder): for kwargs in ({}, {"statistic_ids": ["sensor.test1"]}): stats = statistics_during_period(hass, zero, period="5minute", **kwargs) assert stats == {} - stats = get_last_statistics(hass, 0, "sensor.test1", True) + stats = get_last_short_term_statistics(hass, 0, "sensor.test1", True) assert stats == {} recorder.do_adhoc_statistics(start=zero) @@ -91,20 +92,20 @@ def test_compile_hourly_statistics(hass_recorder): ) assert stats == {} - # Test get_last_statistics - stats = get_last_statistics(hass, 0, "sensor.test1", True) + # Test get_last_short_term_statistics + stats = get_last_short_term_statistics(hass, 0, "sensor.test1", True) assert stats == {} - stats = get_last_statistics(hass, 1, "sensor.test1", True) + stats = get_last_short_term_statistics(hass, 1, "sensor.test1", True) assert stats == {"sensor.test1": [{**expected_2, "statistic_id": "sensor.test1"}]} - stats = get_last_statistics(hass, 2, "sensor.test1", True) + stats = get_last_short_term_statistics(hass, 2, "sensor.test1", True) assert stats == {"sensor.test1": expected_stats1[::-1]} - stats = get_last_statistics(hass, 3, "sensor.test1", True) + stats = get_last_short_term_statistics(hass, 3, "sensor.test1", True) assert stats == {"sensor.test1": expected_stats1[::-1]} - stats = get_last_statistics(hass, 1, "sensor.test3", True) + stats = get_last_short_term_statistics(hass, 1, "sensor.test3", True) assert stats == {} @@ -236,7 +237,7 @@ def test_rename_entity(hass_recorder): for kwargs in ({}, {"statistic_ids": ["sensor.test1"]}): stats = statistics_during_period(hass, zero, period="5minute", **kwargs) assert stats == {} - stats = get_last_statistics(hass, 0, "sensor.test1", True) + stats = get_last_short_term_statistics(hass, 0, "sensor.test1", True) assert stats == {} recorder.do_adhoc_statistics(start=zero) @@ -392,6 +393,22 @@ def test_external_statistics(hass_recorder, caplog): }, ) } + last_stats = get_last_statistics(hass, 1, "test:total_energy_import", True) + assert last_stats == { + "test:total_energy_import": [ + { + "statistic_id": "test:total_energy_import", + "start": period2.isoformat(), + "end": (period2 + timedelta(hours=1)).isoformat(), + "max": None, + "mean": None, + "min": None, + "last_reset": None, + "state": approx(1.0), + "sum": approx(3.0), + }, + ] + } # Update the previously inserted statistics external_statistics = {