Add history/history_during_period websocket endpoint (#71688)

This commit is contained in:
J. Nick Koston 2022-05-11 17:52:22 -05:00 committed by GitHub
parent 81e8d2ab86
commit e2cef55162
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 655 additions and 88 deletions

View file

@ -1070,3 +1070,409 @@ async def test_list_statistic_ids(
response = await client.receive_json()
assert response["success"]
assert response["result"] == []
async def test_history_during_period(hass, hass_ws_client, recorder_mock):
"""Test history_during_period."""
now = dt_util.utcnow()
await async_setup_component(hass, "history", {})
await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", "on", attributes={"any": "attr"})
await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", "off", attributes={"any": "attr"})
await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", "off", attributes={"any": "changed"})
await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", "off", attributes={"any": "again"})
await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", "on", attributes={"any": "attr"})
await async_wait_recording_done(hass)
do_adhoc_statistics(hass, start=now)
await async_wait_recording_done(hass)
client = await hass_ws_client()
await client.send_json(
{
"id": 1,
"type": "history/history_during_period",
"start_time": now.isoformat(),
"end_time": now.isoformat(),
"entity_ids": ["sensor.test"],
"include_start_time_state": True,
"significant_changes_only": False,
"no_attributes": True,
}
)
response = await client.receive_json()
assert response["success"]
assert response["result"] == {}
await client.send_json(
{
"id": 2,
"type": "history/history_during_period",
"start_time": now.isoformat(),
"entity_ids": ["sensor.test"],
"include_start_time_state": True,
"significant_changes_only": False,
"no_attributes": True,
"minimal_response": True,
}
)
response = await client.receive_json()
assert response["success"]
assert response["id"] == 2
sensor_test_history = response["result"]["sensor.test"]
assert len(sensor_test_history) == 3
assert sensor_test_history[0]["s"] == "on"
assert sensor_test_history[0]["a"] == {}
assert isinstance(sensor_test_history[0]["lu"], float)
assert isinstance(sensor_test_history[0]["lc"], float)
assert "a" not in sensor_test_history[1]
assert sensor_test_history[1]["s"] == "off"
assert isinstance(sensor_test_history[1]["lc"], float)
assert sensor_test_history[2]["s"] == "on"
assert sensor_test_history[2]["a"] == {}
await client.send_json(
{
"id": 3,
"type": "history/history_during_period",
"start_time": now.isoformat(),
"entity_ids": ["sensor.test"],
"include_start_time_state": True,
"significant_changes_only": False,
"no_attributes": False,
}
)
response = await client.receive_json()
assert response["success"]
assert response["id"] == 3
sensor_test_history = response["result"]["sensor.test"]
assert len(sensor_test_history) == 5
assert sensor_test_history[0]["s"] == "on"
assert sensor_test_history[0]["a"] == {"any": "attr"}
assert isinstance(sensor_test_history[0]["lu"], float)
assert isinstance(sensor_test_history[0]["lc"], float)
assert sensor_test_history[1]["s"] == "off"
assert isinstance(sensor_test_history[1]["lc"], float)
assert sensor_test_history[1]["a"] == {"any": "attr"}
assert sensor_test_history[4]["s"] == "on"
assert sensor_test_history[4]["a"] == {"any": "attr"}
await client.send_json(
{
"id": 4,
"type": "history/history_during_period",
"start_time": now.isoformat(),
"entity_ids": ["sensor.test"],
"include_start_time_state": True,
"significant_changes_only": True,
"no_attributes": False,
}
)
response = await client.receive_json()
assert response["success"]
assert response["id"] == 4
sensor_test_history = response["result"]["sensor.test"]
assert len(sensor_test_history) == 3
assert sensor_test_history[0]["s"] == "on"
assert sensor_test_history[0]["a"] == {"any": "attr"}
assert isinstance(sensor_test_history[0]["lu"], float)
assert isinstance(sensor_test_history[0]["lc"], float)
assert sensor_test_history[1]["s"] == "off"
assert isinstance(sensor_test_history[1]["lc"], float)
assert sensor_test_history[1]["a"] == {"any": "attr"}
assert sensor_test_history[2]["s"] == "on"
assert sensor_test_history[2]["a"] == {"any": "attr"}
async def test_history_during_period_impossible_conditions(
hass, hass_ws_client, recorder_mock
):
"""Test history_during_period returns when condition cannot be true."""
now = dt_util.utcnow()
await async_setup_component(hass, "history", {})
await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", "on", attributes={"any": "attr"})
await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", "off", attributes={"any": "attr"})
await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", "off", attributes={"any": "changed"})
await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", "off", attributes={"any": "again"})
await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", "on", attributes={"any": "attr"})
await async_wait_recording_done(hass)
do_adhoc_statistics(hass, start=now)
await async_wait_recording_done(hass)
after = dt_util.utcnow()
client = await hass_ws_client()
await client.send_json(
{
"id": 1,
"type": "history/history_during_period",
"start_time": after.isoformat(),
"end_time": after.isoformat(),
"entity_ids": ["sensor.test"],
"include_start_time_state": False,
"significant_changes_only": False,
"no_attributes": True,
}
)
response = await client.receive_json()
assert response["success"]
assert response["id"] == 1
assert response["result"] == {}
future = dt_util.utcnow() + timedelta(hours=10)
await client.send_json(
{
"id": 2,
"type": "history/history_during_period",
"start_time": future.isoformat(),
"entity_ids": ["sensor.test"],
"include_start_time_state": True,
"significant_changes_only": True,
"no_attributes": True,
}
)
response = await client.receive_json()
assert response["success"]
assert response["id"] == 2
assert response["result"] == {}
@pytest.mark.parametrize(
"time_zone", ["UTC", "Europe/Berlin", "America/Chicago", "US/Hawaii"]
)
async def test_history_during_period_significant_domain(
time_zone, hass, hass_ws_client, recorder_mock
):
"""Test history_during_period with climate domain."""
hass.config.set_time_zone(time_zone)
now = dt_util.utcnow()
await async_setup_component(hass, "history", {})
await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass)
hass.states.async_set("climate.test", "on", attributes={"temperature": "1"})
await async_recorder_block_till_done(hass)
hass.states.async_set("climate.test", "off", attributes={"temperature": "2"})
await async_recorder_block_till_done(hass)
hass.states.async_set("climate.test", "off", attributes={"temperature": "3"})
await async_recorder_block_till_done(hass)
hass.states.async_set("climate.test", "off", attributes={"temperature": "4"})
await async_recorder_block_till_done(hass)
hass.states.async_set("climate.test", "on", attributes={"temperature": "5"})
await async_wait_recording_done(hass)
do_adhoc_statistics(hass, start=now)
await async_wait_recording_done(hass)
client = await hass_ws_client()
await client.send_json(
{
"id": 1,
"type": "history/history_during_period",
"start_time": now.isoformat(),
"end_time": now.isoformat(),
"entity_ids": ["climate.test"],
"include_start_time_state": True,
"significant_changes_only": False,
"no_attributes": True,
}
)
response = await client.receive_json()
assert response["success"]
assert response["result"] == {}
await client.send_json(
{
"id": 2,
"type": "history/history_during_period",
"start_time": now.isoformat(),
"entity_ids": ["climate.test"],
"include_start_time_state": True,
"significant_changes_only": False,
"no_attributes": True,
"minimal_response": True,
}
)
response = await client.receive_json()
assert response["success"]
assert response["id"] == 2
sensor_test_history = response["result"]["climate.test"]
assert len(sensor_test_history) == 5
assert sensor_test_history[0]["s"] == "on"
assert sensor_test_history[0]["a"] == {}
assert isinstance(sensor_test_history[0]["lu"], float)
assert isinstance(sensor_test_history[0]["lc"], float)
assert "a" in sensor_test_history[1]
assert sensor_test_history[1]["s"] == "off"
assert isinstance(sensor_test_history[1]["lc"], float)
assert sensor_test_history[4]["s"] == "on"
assert sensor_test_history[4]["a"] == {}
await client.send_json(
{
"id": 3,
"type": "history/history_during_period",
"start_time": now.isoformat(),
"entity_ids": ["climate.test"],
"include_start_time_state": True,
"significant_changes_only": False,
"no_attributes": False,
}
)
response = await client.receive_json()
assert response["success"]
assert response["id"] == 3
sensor_test_history = response["result"]["climate.test"]
assert len(sensor_test_history) == 5
assert sensor_test_history[0]["s"] == "on"
assert sensor_test_history[0]["a"] == {"temperature": "1"}
assert isinstance(sensor_test_history[0]["lu"], float)
assert isinstance(sensor_test_history[0]["lc"], float)
assert sensor_test_history[1]["s"] == "off"
assert isinstance(sensor_test_history[1]["lc"], float)
assert sensor_test_history[1]["a"] == {"temperature": "2"}
assert sensor_test_history[4]["s"] == "on"
assert sensor_test_history[4]["a"] == {"temperature": "5"}
await client.send_json(
{
"id": 4,
"type": "history/history_during_period",
"start_time": now.isoformat(),
"entity_ids": ["climate.test"],
"include_start_time_state": True,
"significant_changes_only": True,
"no_attributes": False,
}
)
response = await client.receive_json()
assert response["success"]
assert response["id"] == 4
sensor_test_history = response["result"]["climate.test"]
assert len(sensor_test_history) == 5
assert sensor_test_history[0]["s"] == "on"
assert sensor_test_history[0]["a"] == {"temperature": "1"}
assert isinstance(sensor_test_history[0]["lu"], float)
assert isinstance(sensor_test_history[0]["lc"], float)
assert sensor_test_history[1]["s"] == "off"
assert isinstance(sensor_test_history[1]["lc"], float)
assert sensor_test_history[1]["a"] == {"temperature": "2"}
assert sensor_test_history[2]["s"] == "off"
assert sensor_test_history[2]["a"] == {"temperature": "3"}
assert sensor_test_history[3]["s"] == "off"
assert sensor_test_history[3]["a"] == {"temperature": "4"}
assert sensor_test_history[4]["s"] == "on"
assert sensor_test_history[4]["a"] == {"temperature": "5"}
# Test we impute the state time state
later = dt_util.utcnow()
await client.send_json(
{
"id": 5,
"type": "history/history_during_period",
"start_time": later.isoformat(),
"entity_ids": ["climate.test"],
"include_start_time_state": True,
"significant_changes_only": True,
"no_attributes": False,
}
)
response = await client.receive_json()
assert response["success"]
assert response["id"] == 5
sensor_test_history = response["result"]["climate.test"]
assert len(sensor_test_history) == 1
assert sensor_test_history[0]["s"] == "on"
assert sensor_test_history[0]["a"] == {"temperature": "5"}
assert sensor_test_history[0]["lu"] == later.timestamp()
assert sensor_test_history[0]["lc"] == later.timestamp()
async def test_history_during_period_bad_start_time(
hass, hass_ws_client, recorder_mock
):
"""Test history_during_period bad state time."""
await async_setup_component(
hass,
"history",
{"history": {}},
)
client = await hass_ws_client()
await client.send_json(
{
"id": 1,
"type": "history/history_during_period",
"start_time": "cats",
}
)
response = await client.receive_json()
assert not response["success"]
assert response["error"]["code"] == "invalid_start_time"
async def test_history_during_period_bad_end_time(hass, hass_ws_client, recorder_mock):
"""Test history_during_period bad end time."""
now = dt_util.utcnow()
await async_setup_component(
hass,
"history",
{"history": {}},
)
client = await hass_ws_client()
await client.send_json(
{
"id": 1,
"type": "history/history_during_period",
"start_time": now.isoformat(),
"end_time": "dogs",
}
)
response = await client.receive_json()
assert not response["success"]
assert response["error"]["code"] == "invalid_end_time"