Always show the start and stop event in logbook (#71600)

This commit is contained in:
J. Nick Koston 2022-05-09 15:21:21 -05:00 committed by GitHub
parent 5430b51358
commit 2560d35f1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 124 deletions

View File

@ -5,7 +5,6 @@ from collections.abc import Callable, Generator, Iterable
from contextlib import suppress from contextlib import suppress
from datetime import datetime as dt, timedelta from datetime import datetime as dt, timedelta
from http import HTTPStatus from http import HTTPStatus
from itertools import groupby
import json import json
import re import re
from typing import Any, cast from typing import Any, cast
@ -338,51 +337,21 @@ def _humanify(
""" """
external_events = hass.data.get(DOMAIN, {}) external_events = hass.data.get(DOMAIN, {})
# Continuous sensors, will be excluded from the logbook # Continuous sensors, will be excluded from the logbook
continuous_sensors = {} continuous_sensors: dict[str, bool] = {}
# Group events in batches of GROUP_BY_MINUTES
for _, g_rows in groupby(
rows, lambda row: row.time_fired.minute // GROUP_BY_MINUTES # type: ignore[no-any-return]
):
rows_batch = list(g_rows)
# Group HA start/stop events
# Maps minute of event to 1: stop, 2: stop + start
start_stop_events = {}
# Process events # Process events
for row in rows_batch: for row in rows:
if row.event_type == EVENT_STATE_CHANGED: event_type = row.event_type
entity_id = row.entity_id if event_type == EVENT_STATE_CHANGED:
if (
entity_id in continuous_sensors
or split_entity_id(entity_id)[0] != SENSOR_DOMAIN
):
continue
assert entity_id is not None
continuous_sensors[entity_id] = _is_sensor_continuous(hass, entity_id)
elif row.event_type == EVENT_HOMEASSISTANT_STOP:
if row.time_fired.minute in start_stop_events:
continue
start_stop_events[row.time_fired.minute] = 1
elif row.event_type == EVENT_HOMEASSISTANT_START:
if row.time_fired.minute not in start_stop_events:
continue
start_stop_events[row.time_fired.minute] = 2
# Yield entries
for row in rows_batch:
if row.event_type == EVENT_STATE_CHANGED:
entity_id = row.entity_id entity_id = row.entity_id
assert entity_id is not None assert entity_id is not None
if continuous_sensors.get(entity_id):
# Skip continuous sensors # Skip continuous sensors
if (
is_continuous := continuous_sensors.get(entity_id)
) is None and split_entity_id(entity_id)[0] == SENSOR_DOMAIN:
is_continuous = _is_sensor_continuous(hass, entity_id)
continuous_sensors[entity_id] = is_continuous
if is_continuous:
continue continue
data = { data = {
@ -391,53 +360,36 @@ def _humanify(
"state": row.state, "state": row.state,
"entity_id": entity_id, "entity_id": entity_id,
} }
if icon := _row_attributes_extract(row, ICON_JSON_EXTRACT): if icon := _row_attributes_extract(row, ICON_JSON_EXTRACT):
data["icon"] = icon data["icon"] = icon
if row.context_user_id:
data["context_user_id"] = row.context_user_id
context_augmenter.augment(data, entity_id, row) context_augmenter.augment(data, entity_id, row)
yield data yield data
elif row.event_type in external_events: elif event_type in external_events:
domain, describe_event = external_events[row.event_type] domain, describe_event = external_events[event_type]
data = describe_event(event_cache.get(row)) data = describe_event(event_cache.get(row))
data["when"] = _row_time_fired_isoformat(row) data["when"] = _row_time_fired_isoformat(row)
data["domain"] = domain data["domain"] = domain
if row.context_user_id: context_augmenter.augment(data, data.get(ATTR_ENTITY_ID), row)
data["context_user_id"] = row.context_user_id
entity_id = data.get(ATTR_ENTITY_ID)
context_augmenter.augment(data, entity_id, row)
yield data yield data
elif row.event_type == EVENT_HOMEASSISTANT_START: elif event_type == EVENT_HOMEASSISTANT_START:
if start_stop_events.get(row.time_fired.minute) == 2:
continue
yield { yield {
"when": _row_time_fired_isoformat(row), "when": _row_time_fired_isoformat(row),
"name": "Home Assistant", "name": "Home Assistant",
"message": "started", "message": "started",
"domain": HA_DOMAIN, "domain": HA_DOMAIN,
} }
elif event_type == EVENT_HOMEASSISTANT_STOP:
elif row.event_type == EVENT_HOMEASSISTANT_STOP:
if start_stop_events.get(row.time_fired.minute) == 2:
action = "restarted"
else:
action = "stopped"
yield { yield {
"when": _row_time_fired_isoformat(row), "when": _row_time_fired_isoformat(row),
"name": "Home Assistant", "name": "Home Assistant",
"message": action, "message": "stopped",
"domain": HA_DOMAIN, "domain": HA_DOMAIN,
} }
elif row.event_type == EVENT_LOGBOOK_ENTRY: elif event_type == EVENT_LOGBOOK_ENTRY:
event = event_cache.get(row) event = event_cache.get(row)
event_data = event.data event_data = event.data
domain = event_data.get(ATTR_DOMAIN) domain = event_data.get(ATTR_DOMAIN)
@ -453,10 +405,6 @@ def _humanify(
"domain": domain, "domain": domain,
"entity_id": entity_id, "entity_id": entity_id,
} }
if row.context_user_id:
data["context_user_id"] = row.context_user_id
context_augmenter.augment(data, entity_id, row) context_augmenter.augment(data, entity_id, row)
yield data yield data
@ -746,6 +694,9 @@ class ContextAugmenter:
def augment(self, data: dict[str, Any], entity_id: str | None, row: Row) -> None: def augment(self, data: dict[str, Any], entity_id: str | None, row: Row) -> None:
"""Augment data from the row and cache.""" """Augment data from the row and cache."""
if context_user_id := row.context_user_id:
data["context_user_id"] = context_user_id
if not (context_row := self.context_lookup.get(row.context_id)): if not (context_row := self.context_lookup.get(row.context_id)):
return return

View File

@ -210,11 +210,8 @@ async def test_filter_sensor(hass_: ha.HomeAssistant, hass_client):
_assert_entry(entries[2], name="ble", entity_id=entity_id4, state="10") _assert_entry(entries[2], name="ble", entity_id=entity_id4, state="10")
def test_home_assistant_start_stop_grouped(hass_): def test_home_assistant_start_stop_not_grouped(hass_):
"""Test if HA start and stop events are grouped. """Test if HA start and stop events are no longer grouped."""
Events that are occurring in the same minute.
"""
entries = mock_humanify( entries = mock_humanify(
hass_, hass_,
( (
@ -223,10 +220,9 @@ def test_home_assistant_start_stop_grouped(hass_):
), ),
) )
assert len(entries) == 1 assert len(entries) == 2
assert_entry( assert_entry(entries[0], name="Home Assistant", message="stopped", domain=ha.DOMAIN)
entries[0], name="Home Assistant", message="restarted", domain=ha.DOMAIN assert_entry(entries[1], name="Home Assistant", message="started", domain=ha.DOMAIN)
)
def test_home_assistant_start(hass_): def test_home_assistant_start(hass_):