Add config flow to the statistics integration

This commit is contained in:
Erik
2022-11-30 12:29:20 +01:00
parent 98f263c289
commit bb3f2079ce
10 changed files with 768 additions and 15 deletions
+45
View File
@@ -0,0 +1,45 @@
"""Test helpers for the statistics integration."""
from datetime import datetime, timedelta
from homeassistant.components import recorder
from homeassistant.components.recorder.db_schema import Statistics
from homeassistant.core import HomeAssistant
from tests.components.recorder.common import async_wait_recording_done
async def generate_statistics(
hass: HomeAssistant,
entity_id: str,
start: datetime,
count: int,
start_value: float = 0.0,
) -> None:
"""Generate LTS data."""
imported_stats = [
{
"start": (start + timedelta(hours=i)),
"max": start_value + i * 2,
"mean": start_value + i,
"min": -(start_value + count * 2) + i * 2,
"sum": start_value + i,
}
for i in range(0, count)
]
imported_metadata = {
"has_mean": True,
"has_sum": False,
"name": None,
"source": "recorder",
"statistic_id": entity_id,
"unit_of_measurement": "°C",
}
recorder.get_instance(hass).async_import_statistics(
imported_metadata,
imported_stats,
Statistics,
)
await async_wait_recording_done(hass)
@@ -0,0 +1,294 @@
"""Test the Statistics config flow."""
from datetime import datetime, timedelta, timezone
from unittest.mock import patch
from freezegun import freeze_time
import pytest
from homeassistant import config_entries
from homeassistant.components.statistics.const import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
import homeassistant.util.dt as dt_util
from .common import generate_statistics
from tests.common import MockConfigEntry
@pytest.mark.parametrize(
"period_type, period_input, period_data",
(
(
"calendar",
{
"calendar_offset": 2,
"calendar_period": "day",
},
{"offset": 2, "period": "day"},
),
(
"fixed_period",
{
"fixed_period_end_time": "2022-03-24 00:00",
"fixed_period_start_time": "2022-03-24 00:00",
},
{"end_time": "2022-03-24 00:00", "start_time": "2022-03-24 00:00"},
),
(
"rolling_window",
{
"rolling_window_duration": {"days": 365},
"rolling_window_offset": {"days": -365},
},
{"duration": {"days": 365}, "offset": {"days": -365}},
),
),
)
async def test_config_flow(
hass: HomeAssistant, period_type, period_input, period_data
) -> None:
"""Test the config flow."""
input_sensor = "sensor.input_one"
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == FlowResultType.FORM
assert result["errors"] is None
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"name": "My statistics",
"entity_id": input_sensor,
"state_characteristic": "value_max_lts",
},
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.MENU
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{"next_step_id": period_type},
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == period_type
with patch(
"homeassistant.components.statistics.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
period_input,
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "My statistics"
assert result["data"] == {}
assert result["options"] == {
"entity_id": input_sensor,
"name": "My statistics",
"period": {period_type: period_data},
"precision": 2.0,
"state_characteristic": "value_max_lts",
}
assert len(mock_setup_entry.mock_calls) == 1
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
assert config_entry.data == {}
assert config_entry.options == {
"entity_id": input_sensor,
"name": "My statistics",
"period": {period_type: period_data},
"precision": 2.0,
"state_characteristic": "value_max_lts",
}
assert config_entry.title == "My statistics"
@pytest.mark.parametrize(
"period_type, period_definition",
(
(
"calendar",
{
"period": "day",
"offset": 2,
},
),
(
"fixed_period",
{
"start_time": "2022-03-24 00:00",
"end_time": "2022-03-24 00:00",
},
),
(
"rolling_window",
{
"duration": {"days": 365},
"offset": {"days": -365},
},
),
),
)
async def test_config_flow_import(
hass: HomeAssistant, period_type, period_definition
) -> None:
"""Test the config flow."""
input_sensor = "sensor.input_one"
with patch(
"homeassistant.components.statistics.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
data={
"entity_id": input_sensor,
"name": "My statistics",
"period": {period_type: period_definition},
"precision": 2.0,
"state_characteristic": "value_max_lts",
},
)
assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "My statistics"
assert result["data"] == {}
assert result["options"] == {
"entity_id": input_sensor,
"name": "My statistics",
"period": {period_type: period_definition},
"precision": 2.0,
"state_characteristic": "value_max_lts",
}
assert len(mock_setup_entry.mock_calls) == 1
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
assert config_entry.data == {}
assert config_entry.options == {
"entity_id": input_sensor,
"name": "My statistics",
"period": {period_type: period_definition},
"precision": 2.0,
"state_characteristic": "value_max_lts",
}
assert config_entry.title == "My statistics"
def get_suggested(schema, key):
"""Get suggested value for key in voluptuous schema."""
for k in schema.keys():
if k == key:
if k.description is None or "suggested_value" not in k.description:
return None
return k.description["suggested_value"]
# Wanted key absent from schema
raise Exception
@freeze_time(datetime(2022, 10, 21, 7, 25, tzinfo=timezone.utc))
async def test_options(recorder_mock, hass: HomeAssistant) -> None:
"""Test reconfiguring."""
now = dt_util.utcnow()
zero = now
start = zero.replace(minute=0, second=0, microsecond=0) + timedelta(days=-2)
await generate_statistics(hass, "sensor.input_one", start, 6)
await generate_statistics(hass, "sensor.input_two", start, 6)
# Setup the config entry
config_entry = MockConfigEntry(
data={},
domain=DOMAIN,
options={
"entity_id": "sensor.input_one",
"name": "My statistics",
"period": {"calendar": {"offset": -2, "period": "day"}},
"precision": 2.0,
"state_characteristic": "value_max_lts",
},
title="My statistics",
)
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
# Check the state of the entity is reflecting the initial settings
state = hass.states.get("sensor.my_statistics")
assert state.state == "10.0"
result = await hass.config_entries.options.async_init(config_entry.entry_id)
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "init"
schema = result["data_schema"].schema
assert get_suggested(schema, "entity_id") == "sensor.input_one"
assert get_suggested(schema, "precision") == 2.0
assert get_suggested(schema, "state_characteristic") == "value_max_lts"
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={
"entity_id": "sensor.input_two",
"precision": 1,
"state_characteristic": "value_min_lts",
},
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.MENU
result = await hass.config_entries.options.async_configure(
result["flow_id"],
{"next_step_id": "rolling_window"},
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "rolling_window"
result = await hass.config_entries.options.async_configure(
result["flow_id"],
{
"rolling_window_duration": {"days": 2},
"rolling_window_offset": {"hours": -1},
},
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["data"] == {
"entity_id": "sensor.input_two",
"name": "My statistics",
"period": {
"rolling_window": {"duration": {"days": 2}, "offset": {"hours": -1}}
},
"precision": 1.0,
"state_characteristic": "value_min_lts",
}
assert config_entry.data == {}
assert config_entry.options == {
"entity_id": "sensor.input_two",
"name": "My statistics",
"period": {
"rolling_window": {"duration": {"days": 2}, "offset": {"hours": -1}}
},
"precision": 1.0,
"state_characteristic": "value_min_lts",
}
assert config_entry.title == "My statistics"
# Check config entry is reloaded with new options
await hass.async_block_till_done()
# Check the entity was updated, no new entity was created
assert len(hass.states.async_all()) == 1
# Check the state of the entity has changed as expected
state = hass.states.get("sensor.my_statistics")
assert state.state == "-12.0"
+1 -1
View File
@@ -13,7 +13,7 @@ from homeassistant.components.sensor import (
SensorDeviceClass,
SensorStateClass,
)
from homeassistant.components.statistics import DOMAIN as STATISTICS_DOMAIN
from homeassistant.components.statistics.const import DOMAIN as STATISTICS_DOMAIN
from homeassistant.components.statistics.sensor import StatisticsSensor
from homeassistant.const import (
ATTR_DEVICE_CLASS,