diff --git a/homeassistant/components/demo/__init__.py b/homeassistant/components/demo/__init__.py index 7384a79adcc..8572ddfbbe2 100644 --- a/homeassistant/components/demo/__init__.py +++ b/homeassistant/components/demo/__init__.py @@ -244,10 +244,17 @@ def _generate_mean_statistics(start, end, init_value, max_diff): return statistics -def _generate_sum_statistics(start, end, init_value, max_diff): +async def _insert_sum_statistics(hass, metadata, start, end, max_diff): statistics = [] now = start - sum_ = init_value + sum_ = 0 + statistic_id = metadata["statistic_id"] + + last_stats = await get_instance(hass).async_add_executor_job( + get_last_statistics, hass, 1, statistic_id, True + ) + if statistic_id in last_stats: + sum_ = last_stats[statistic_id][0]["sum"] or 0 while now < end: sum_ = sum_ + random() * max_diff statistics.append( @@ -258,7 +265,7 @@ def _generate_sum_statistics(start, end, init_value, max_diff): ) now = now + datetime.timedelta(hours=1) - return statistics + async_add_external_statistics(hass, metadata, statistics) async def _insert_statistics(hass: HomeAssistant) -> None: @@ -266,6 +273,7 @@ async def _insert_statistics(hass: HomeAssistant) -> None: now = dt_util.now() yesterday = now - datetime.timedelta(days=1) yesterday_midnight = yesterday.replace(hour=0, minute=0, second=0, microsecond=0) + today_midnight = yesterday_midnight + datetime.timedelta(days=1) # Fake yesterday's temperatures metadata: StatisticMetaData = { @@ -276,98 +284,58 @@ async def _insert_statistics(hass: HomeAssistant) -> None: "has_mean": True, "has_sum": False, } - statistics = _generate_mean_statistics( - yesterday_midnight, yesterday_midnight + datetime.timedelta(days=1), 15, 1 - ) + statistics = _generate_mean_statistics(yesterday_midnight, today_midnight, 15, 1) async_add_external_statistics(hass, metadata, statistics) # Add external energy consumption in kWh, ~ 12 kWh / day # This should be possible to pick for the energy dashboard - statistic_id = f"{DOMAIN}:energy_consumption_kwh" metadata = { "source": DOMAIN, "name": "Energy consumption 1", - "statistic_id": statistic_id, + "statistic_id": f"{DOMAIN}:energy_consumption_kwh", "unit_of_measurement": "kWh", "has_mean": False, "has_sum": True, } - sum_ = 0 - last_stats = await get_instance(hass).async_add_executor_job( - get_last_statistics, hass, 1, statistic_id, True - ) - if statistic_id in last_stats: - sum_ = last_stats[statistic_id][0]["sum"] or 0 - statistics = _generate_sum_statistics( - yesterday_midnight, yesterday_midnight + datetime.timedelta(days=1), sum_, 2 - ) - async_add_external_statistics(hass, metadata, statistics) + await _insert_sum_statistics(hass, metadata, yesterday_midnight, today_midnight, 2) # Add external energy consumption in MWh, ~ 12 kWh / day # This should not be possible to pick for the energy dashboard - statistic_id = f"{DOMAIN}:energy_consumption_mwh" metadata = { "source": DOMAIN, "name": "Energy consumption 2", - "statistic_id": statistic_id, + "statistic_id": f"{DOMAIN}:energy_consumption_mwh", "unit_of_measurement": "MWh", "has_mean": False, "has_sum": True, } - sum_ = 0 - last_stats = await get_instance(hass).async_add_executor_job( - get_last_statistics, hass, 1, statistic_id, True + await _insert_sum_statistics( + hass, metadata, yesterday_midnight, today_midnight, 0.002 ) - if statistic_id in last_stats: - sum_ = last_stats[statistic_id][0]["sum"] or 0 - statistics = _generate_sum_statistics( - yesterday_midnight, yesterday_midnight + datetime.timedelta(days=1), sum_, 0.002 - ) - async_add_external_statistics(hass, metadata, statistics) # Add external gas consumption in m³, ~6 m3/day # This should be possible to pick for the energy dashboard - statistic_id = f"{DOMAIN}:gas_consumption_m3" metadata = { "source": DOMAIN, "name": "Gas consumption 1", - "statistic_id": statistic_id, + "statistic_id": f"{DOMAIN}:gas_consumption_m3", "unit_of_measurement": "m³", "has_mean": False, "has_sum": True, } - sum_ = 0 - last_stats = await get_instance(hass).async_add_executor_job( - get_last_statistics, hass, 1, statistic_id, True - ) - if statistic_id in last_stats: - sum_ = last_stats[statistic_id][0]["sum"] or 0 - statistics = _generate_sum_statistics( - yesterday_midnight, yesterday_midnight + datetime.timedelta(days=1), sum_, 1 - ) - async_add_external_statistics(hass, metadata, statistics) + await _insert_sum_statistics(hass, metadata, yesterday_midnight, today_midnight, 1) # Add external gas consumption in ft³, ~180 ft3/day # This should not be possible to pick for the energy dashboard - statistic_id = f"{DOMAIN}:gas_consumption_ft3" metadata = { "source": DOMAIN, "name": "Gas consumption 2", - "statistic_id": statistic_id, + "statistic_id": f"{DOMAIN}:gas_consumption_ft3", "unit_of_measurement": "ft³", "has_mean": False, "has_sum": True, } - sum_ = 0 - last_stats = await get_instance(hass).async_add_executor_job( - get_last_statistics, hass, 1, statistic_id, True - ) - if statistic_id in last_stats: - sum_ = last_stats[statistic_id][0]["sum"] or 0 - statistics = _generate_sum_statistics( - yesterday_midnight, yesterday_midnight + datetime.timedelta(days=1), sum_, 30 - ) - async_add_external_statistics(hass, metadata, statistics) + await _insert_sum_statistics(hass, metadata, yesterday_midnight, today_midnight, 30) async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: diff --git a/tests/components/demo/test_init.py b/tests/components/demo/test_init.py index 1adfe0a5834..5a407ba25fc 100644 --- a/tests/components/demo/test_init.py +++ b/tests/components/demo/test_init.py @@ -1,4 +1,5 @@ """The tests for the Demo component.""" +import datetime from http import HTTPStatus import json from unittest.mock import ANY, patch @@ -7,10 +8,15 @@ import pytest from homeassistant.components.demo import DOMAIN from homeassistant.components.recorder import get_instance -from homeassistant.components.recorder.statistics import list_statistic_ids +from homeassistant.components.recorder.statistics import ( + async_add_external_statistics, + get_last_statistics, + list_statistic_ids, +) from homeassistant.components.repairs import DOMAIN as REPAIRS_DOMAIN from homeassistant.helpers.json import JSONEncoder from homeassistant.setup import async_setup_component +import homeassistant.util.dt as dt_util from tests.components.recorder.common import async_wait_recording_done @@ -73,6 +79,41 @@ async def test_demo_statistics(hass, recorder_mock): } in statistic_ids +async def test_demo_statistics_growth(hass, recorder_mock): + """Test that the demo sum statistics adds to the previous state.""" + now = dt_util.now() + last_week = now - datetime.timedelta(days=7) + last_week_midnight = last_week.replace(hour=0, minute=0, second=0, microsecond=0) + + statistic_id = f"{DOMAIN}:energy_consumption_kwh" + metadata = { + "source": DOMAIN, + "name": "Energy consumption 1", + "statistic_id": statistic_id, + "unit_of_measurement": "kWh", + "has_mean": False, + "has_sum": True, + } + statistics = [ + { + "start": last_week_midnight, + "sum": 2**20, + } + ] + async_add_external_statistics(hass, metadata, statistics) + await async_wait_recording_done(hass) + + assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}}) + await hass.async_block_till_done() + await hass.async_start() + await async_wait_recording_done(hass) + + statistics = await get_instance(hass).async_add_executor_job( + get_last_statistics, hass, 1, statistic_id, False + ) + assert statistics[statistic_id][0]["sum"] > 2**20 + + async def test_issues_created(hass, hass_client, hass_ws_client): """Test issues are created and can be fixed.""" assert await async_setup_component(hass, REPAIRS_DOMAIN, {REPAIRS_DOMAIN: {}}) diff --git a/tests/components/demo/test_sensor.py b/tests/components/demo/test_sensor.py new file mode 100644 index 00000000000..0adf94d7867 --- /dev/null +++ b/tests/components/demo/test_sensor.py @@ -0,0 +1,59 @@ +"""The tests for the demo sensor component.""" +from datetime import timedelta + +import pytest + +from homeassistant import core as ha +from homeassistant.components.demo import DOMAIN +from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN +from homeassistant.setup import async_setup_component + +from tests.common import mock_restore_cache_with_extra_data + + +@pytest.mark.parametrize("entity_id, delta", (("sensor.total_energy_kwh", 0.5),)) +async def test_energy_sensor(hass: ha.HomeAssistant, entity_id, delta, freezer): + """Test energy sensors increase periodically.""" + assert await async_setup_component( + hass, SENSOR_DOMAIN, {SENSOR_DOMAIN: {"platform": DOMAIN}} + ) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state.state == "0" + + freezer.tick(timedelta(minutes=5, seconds=1)) + await hass.async_block_till_done() + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state.state == str(delta) + + +@pytest.mark.parametrize("entity_id, delta", (("sensor.total_energy_kwh", 0.5),)) +async def test_restore_state(hass: ha.HomeAssistant, entity_id, delta, freezer): + """Test energy sensors restore state.""" + fake_state = ha.State( + entity_id, + "", + ) + fake_extra_data = { + "native_value": 2**20, + "native_unit_of_measurement": None, + } + mock_restore_cache_with_extra_data(hass, ((fake_state, fake_extra_data),)) + + assert await async_setup_component( + hass, SENSOR_DOMAIN, {SENSOR_DOMAIN: {"platform": DOMAIN}} + ) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state.state == str(2**20) + + freezer.tick(timedelta(minutes=5, seconds=1)) + await hass.async_block_till_done() + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state.state == str(2**20 + delta)