Refactor logbook data to use a dataclass (#89534)

pull/89544/head
J. Nick Koston 2023-03-11 01:45:27 -10:00 committed by GitHub
parent fccdd7b102
commit 01e1221443
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 39 additions and 27 deletions

View File

@ -19,7 +19,7 @@ from homeassistant.const import (
ATTR_NAME,
EVENT_LOGBOOK_ENTRY,
)
from homeassistant.core import Context, Event, HomeAssistant, ServiceCall, callback
from homeassistant.core import Context, HomeAssistant, ServiceCall, callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entityfilter import (
INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA,
@ -35,7 +35,6 @@ from . import rest_api, websocket_api
from .const import ( # noqa: F401
ATTR_MESSAGE,
DOMAIN,
LOGBOOK_ENTITIES_FILTER,
LOGBOOK_ENTRY_CONTEXT_ID,
LOGBOOK_ENTRY_DOMAIN,
LOGBOOK_ENTRY_ENTITY_ID,
@ -43,9 +42,8 @@ from .const import ( # noqa: F401
LOGBOOK_ENTRY_MESSAGE,
LOGBOOK_ENTRY_NAME,
LOGBOOK_ENTRY_SOURCE,
LOGBOOK_FILTERS,
)
from .models import LazyEventPartialState # noqa: F401
from .models import LazyEventPartialState, LogbookConfig
CONFIG_SCHEMA = vol.Schema(
{DOMAIN: INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA}, extra=vol.ALLOW_EXTRA
@ -97,7 +95,6 @@ def async_log_entry(
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Logbook setup."""
hass.data[DOMAIN] = {}
@callback
def log_message(service: ServiceCall) -> None:
@ -134,8 +131,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
else:
filters = None
entities_filter = None
hass.data[LOGBOOK_FILTERS] = filters
hass.data[LOGBOOK_ENTITIES_FILTER] = entities_filter
external_events: dict[
str, tuple[str, Callable[[LazyEventPartialState], dict[str, Any]]]
] = {}
hass.data[DOMAIN] = LogbookConfig(external_events, filters, entities_filter)
websocket_api.async_setup(hass)
rest_api.async_setup(hass, config, filters, entities_filter)
hass.services.async_register(DOMAIN, "log", log_message, schema=LOG_MESSAGE_SCHEMA)
@ -149,14 +149,16 @@ async def _process_logbook_platform(
hass: HomeAssistant, domain: str, platform: Any
) -> None:
"""Process a logbook platform."""
logbook_config: LogbookConfig = hass.data[DOMAIN]
external_events = logbook_config.external_events
@callback
def _async_describe_event(
domain: str,
event_name: str,
describe_callback: Callable[[Event], dict[str, Any]],
describe_callback: Callable[[LazyEventPartialState], dict[str, Any]],
) -> None:
"""Teach logbook how to describe a new event."""
hass.data[DOMAIN][event_name] = (domain, describe_callback)
external_events[event_name] = (domain, describe_callback)
platform.async_describe_events(hass, _async_describe_event)

View File

@ -44,6 +44,3 @@ AUTOMATION_EVENTS = {EVENT_AUTOMATION_TRIGGERED, EVENT_SCRIPT_STARTED}
# Events that are built-in to the logbook or core
BUILT_IN_EVENTS = {EVENT_LOGBOOK_ENTRY, EVENT_CALL_SERVICE}
LOGBOOK_FILTERS = "logbook_filters"
LOGBOOK_ENTITIES_FILTER = "entities_filter"

View File

@ -27,7 +27,7 @@ from homeassistant.helpers.entityfilter import EntityFilter
from homeassistant.helpers.event import async_track_state_change_event
from .const import ALWAYS_CONTINUOUS_DOMAINS, AUTOMATION_EVENTS, BUILT_IN_EVENTS, DOMAIN
from .models import LazyEventPartialState
from .models import LogbookConfig
def async_filter_entities(hass: HomeAssistant, entity_ids: list[str]) -> list[str]:
@ -63,9 +63,8 @@ def async_determine_event_types(
hass: HomeAssistant, entity_ids: list[str] | None, device_ids: list[str] | None
) -> tuple[str, ...]:
"""Reduce the event types based on the entity ids and device ids."""
external_events: dict[
str, tuple[str, Callable[[LazyEventPartialState], dict[str, Any]]]
] = hass.data.get(DOMAIN, {})
logbook_config: LogbookConfig = hass.data[DOMAIN]
external_events = logbook_config.external_events
if not entity_ids and not device_ids:
return (*BUILT_IN_EVENTS, *external_events)

View File

@ -1,11 +1,13 @@
"""Event parser and human readable log generator."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, cast
from sqlalchemy.engine.row import Row
from homeassistant.components.recorder.filters import Filters
from homeassistant.components.recorder.models import (
bytes_to_ulid_or_none,
bytes_to_uuid_hex_or_none,
@ -14,11 +16,23 @@ from homeassistant.components.recorder.models import (
)
from homeassistant.const import ATTR_ICON, EVENT_STATE_CHANGED
from homeassistant.core import Context, Event, State, callback
from homeassistant.helpers.entityfilter import EntityFilter
import homeassistant.util.dt as dt_util
from homeassistant.util.json import json_loads
from homeassistant.util.ulid import ulid_to_bytes
@dataclass
class LogbookConfig:
"""Configuration for the logbook integration."""
external_events: dict[
str, tuple[str, Callable[[LazyEventPartialState], dict[str, Any]]]
]
sqlalchemy_filter: Filters | None = None
entity_filter: EntityFilter | None = None
class LazyEventPartialState:
"""A lazy version of core Event with limited State joined in."""

View File

@ -52,10 +52,9 @@ from .const import (
LOGBOOK_ENTRY_SOURCE,
LOGBOOK_ENTRY_STATE,
LOGBOOK_ENTRY_WHEN,
LOGBOOK_FILTERS,
)
from .helpers import is_sensor_continuous
from .models import EventAsRow, LazyEventPartialState, async_event_to_row
from .models import EventAsRow, LazyEventPartialState, LogbookConfig, async_event_to_row
from .queries import statement_for_request
from .queries.common import PSEUDO_EVENT_STATE_CHANGED
@ -97,16 +96,14 @@ class EventProcessor:
self.entity_ids = entity_ids
self.device_ids = device_ids
self.context_id = context_id
self.filters: Filters | None = hass.data[LOGBOOK_FILTERS]
logbook_config: LogbookConfig = hass.data[DOMAIN]
self.filters: Filters | None = logbook_config.sqlalchemy_filter
format_time = (
_row_time_fired_timestamp if timestamp else _row_time_fired_isoformat
)
external_events: dict[
str, tuple[str, Callable[[LazyEventPartialState], dict[str, Any]]]
] = hass.data.get(DOMAIN, {})
self.logbook_run = LogbookRun(
context_lookup=ContextLookup(hass),
external_events=external_events,
external_events=logbook_config.external_events,
event_cache=EventCache({}),
entity_name_cache=EntityNameCache(self.hass),
include_entity_name=include_entity_name,

View File

@ -20,13 +20,13 @@ from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.json import JSON_DUMP
import homeassistant.util.dt as dt_util
from .const import LOGBOOK_ENTITIES_FILTER
from .const import DOMAIN
from .helpers import (
async_determine_event_types,
async_filter_entities,
async_subscribe_events,
)
from .models import async_event_to_row
from .models import LogbookConfig, async_event_to_row
from .processor import EventProcessor
MAX_PENDING_LOGBOOK_EVENTS = 2048
@ -361,7 +361,8 @@ async def ws_event_stream(
entities_filter: EntityFilter | None = None
if not event_processor.limited_select:
entities_filter = hass.data[LOGBOOK_ENTITIES_FILTER]
logbook_config: LogbookConfig = hass.data[DOMAIN]
entities_filter = logbook_config.entity_filter
async_subscribe_events(
hass,

View File

@ -6,6 +6,7 @@ from typing import Any
from homeassistant.components import logbook
from homeassistant.components.logbook import processor
from homeassistant.components.logbook.models import LogbookConfig
from homeassistant.components.recorder.models import (
process_timestamp_to_utc_isoformat,
ulid_to_bytes_or_none,
@ -64,7 +65,8 @@ def mock_humanify(hass_, rows):
ent_reg = er.async_get(hass_)
event_cache = processor.EventCache({})
context_lookup = processor.ContextLookup(hass_)
external_events = hass_.data.get(logbook.DOMAIN, {})
logbook_config = hass_.data.get(logbook.DOMAIN, LogbookConfig({}, None, None))
external_events = logbook_config.external_events
logbook_run = processor.LogbookRun(
context_lookup,
external_events,