Refactor logbook data to use a dataclass (#89534)
This commit is contained in:
parent
fccdd7b102
commit
01e1221443
7 changed files with 39 additions and 27 deletions
|
@ -19,7 +19,7 @@ from homeassistant.const import (
|
||||||
ATTR_NAME,
|
ATTR_NAME,
|
||||||
EVENT_LOGBOOK_ENTRY,
|
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 import config_validation as cv
|
||||||
from homeassistant.helpers.entityfilter import (
|
from homeassistant.helpers.entityfilter import (
|
||||||
INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA,
|
INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA,
|
||||||
|
@ -35,7 +35,6 @@ from . import rest_api, websocket_api
|
||||||
from .const import ( # noqa: F401
|
from .const import ( # noqa: F401
|
||||||
ATTR_MESSAGE,
|
ATTR_MESSAGE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
LOGBOOK_ENTITIES_FILTER,
|
|
||||||
LOGBOOK_ENTRY_CONTEXT_ID,
|
LOGBOOK_ENTRY_CONTEXT_ID,
|
||||||
LOGBOOK_ENTRY_DOMAIN,
|
LOGBOOK_ENTRY_DOMAIN,
|
||||||
LOGBOOK_ENTRY_ENTITY_ID,
|
LOGBOOK_ENTRY_ENTITY_ID,
|
||||||
|
@ -43,9 +42,8 @@ from .const import ( # noqa: F401
|
||||||
LOGBOOK_ENTRY_MESSAGE,
|
LOGBOOK_ENTRY_MESSAGE,
|
||||||
LOGBOOK_ENTRY_NAME,
|
LOGBOOK_ENTRY_NAME,
|
||||||
LOGBOOK_ENTRY_SOURCE,
|
LOGBOOK_ENTRY_SOURCE,
|
||||||
LOGBOOK_FILTERS,
|
|
||||||
)
|
)
|
||||||
from .models import LazyEventPartialState # noqa: F401
|
from .models import LazyEventPartialState, LogbookConfig
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
CONFIG_SCHEMA = vol.Schema(
|
||||||
{DOMAIN: INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA}, extra=vol.ALLOW_EXTRA
|
{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:
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
"""Logbook setup."""
|
"""Logbook setup."""
|
||||||
hass.data[DOMAIN] = {}
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def log_message(service: ServiceCall) -> None:
|
def log_message(service: ServiceCall) -> None:
|
||||||
|
@ -134,8 +131,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
else:
|
else:
|
||||||
filters = None
|
filters = None
|
||||||
entities_filter = 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)
|
websocket_api.async_setup(hass)
|
||||||
rest_api.async_setup(hass, config, filters, entities_filter)
|
rest_api.async_setup(hass, config, filters, entities_filter)
|
||||||
hass.services.async_register(DOMAIN, "log", log_message, schema=LOG_MESSAGE_SCHEMA)
|
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
|
hass: HomeAssistant, domain: str, platform: Any
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Process a logbook platform."""
|
"""Process a logbook platform."""
|
||||||
|
logbook_config: LogbookConfig = hass.data[DOMAIN]
|
||||||
|
external_events = logbook_config.external_events
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_describe_event(
|
def _async_describe_event(
|
||||||
domain: str,
|
domain: str,
|
||||||
event_name: str,
|
event_name: str,
|
||||||
describe_callback: Callable[[Event], dict[str, Any]],
|
describe_callback: Callable[[LazyEventPartialState], dict[str, Any]],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Teach logbook how to describe a new event."""
|
"""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)
|
platform.async_describe_events(hass, _async_describe_event)
|
||||||
|
|
|
@ -44,6 +44,3 @@ AUTOMATION_EVENTS = {EVENT_AUTOMATION_TRIGGERED, EVENT_SCRIPT_STARTED}
|
||||||
|
|
||||||
# Events that are built-in to the logbook or core
|
# Events that are built-in to the logbook or core
|
||||||
BUILT_IN_EVENTS = {EVENT_LOGBOOK_ENTRY, EVENT_CALL_SERVICE}
|
BUILT_IN_EVENTS = {EVENT_LOGBOOK_ENTRY, EVENT_CALL_SERVICE}
|
||||||
|
|
||||||
LOGBOOK_FILTERS = "logbook_filters"
|
|
||||||
LOGBOOK_ENTITIES_FILTER = "entities_filter"
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ from homeassistant.helpers.entityfilter import EntityFilter
|
||||||
from homeassistant.helpers.event import async_track_state_change_event
|
from homeassistant.helpers.event import async_track_state_change_event
|
||||||
|
|
||||||
from .const import ALWAYS_CONTINUOUS_DOMAINS, AUTOMATION_EVENTS, BUILT_IN_EVENTS, DOMAIN
|
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]:
|
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
|
hass: HomeAssistant, entity_ids: list[str] | None, device_ids: list[str] | None
|
||||||
) -> tuple[str, ...]:
|
) -> tuple[str, ...]:
|
||||||
"""Reduce the event types based on the entity ids and device ids."""
|
"""Reduce the event types based on the entity ids and device ids."""
|
||||||
external_events: dict[
|
logbook_config: LogbookConfig = hass.data[DOMAIN]
|
||||||
str, tuple[str, Callable[[LazyEventPartialState], dict[str, Any]]]
|
external_events = logbook_config.external_events
|
||||||
] = hass.data.get(DOMAIN, {})
|
|
||||||
if not entity_ids and not device_ids:
|
if not entity_ids and not device_ids:
|
||||||
return (*BUILT_IN_EVENTS, *external_events)
|
return (*BUILT_IN_EVENTS, *external_events)
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
"""Event parser and human readable log generator."""
|
"""Event parser and human readable log generator."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
from sqlalchemy.engine.row import Row
|
from sqlalchemy.engine.row import Row
|
||||||
|
|
||||||
|
from homeassistant.components.recorder.filters import Filters
|
||||||
from homeassistant.components.recorder.models import (
|
from homeassistant.components.recorder.models import (
|
||||||
bytes_to_ulid_or_none,
|
bytes_to_ulid_or_none,
|
||||||
bytes_to_uuid_hex_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.const import ATTR_ICON, EVENT_STATE_CHANGED
|
||||||
from homeassistant.core import Context, Event, State, callback
|
from homeassistant.core import Context, Event, State, callback
|
||||||
|
from homeassistant.helpers.entityfilter import EntityFilter
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
from homeassistant.util.json import json_loads
|
from homeassistant.util.json import json_loads
|
||||||
from homeassistant.util.ulid import ulid_to_bytes
|
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:
|
class LazyEventPartialState:
|
||||||
"""A lazy version of core Event with limited State joined in."""
|
"""A lazy version of core Event with limited State joined in."""
|
||||||
|
|
||||||
|
|
|
@ -52,10 +52,9 @@ from .const import (
|
||||||
LOGBOOK_ENTRY_SOURCE,
|
LOGBOOK_ENTRY_SOURCE,
|
||||||
LOGBOOK_ENTRY_STATE,
|
LOGBOOK_ENTRY_STATE,
|
||||||
LOGBOOK_ENTRY_WHEN,
|
LOGBOOK_ENTRY_WHEN,
|
||||||
LOGBOOK_FILTERS,
|
|
||||||
)
|
)
|
||||||
from .helpers import is_sensor_continuous
|
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 import statement_for_request
|
||||||
from .queries.common import PSEUDO_EVENT_STATE_CHANGED
|
from .queries.common import PSEUDO_EVENT_STATE_CHANGED
|
||||||
|
|
||||||
|
@ -97,16 +96,14 @@ class EventProcessor:
|
||||||
self.entity_ids = entity_ids
|
self.entity_ids = entity_ids
|
||||||
self.device_ids = device_ids
|
self.device_ids = device_ids
|
||||||
self.context_id = context_id
|
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 = (
|
format_time = (
|
||||||
_row_time_fired_timestamp if timestamp else _row_time_fired_isoformat
|
_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(
|
self.logbook_run = LogbookRun(
|
||||||
context_lookup=ContextLookup(hass),
|
context_lookup=ContextLookup(hass),
|
||||||
external_events=external_events,
|
external_events=logbook_config.external_events,
|
||||||
event_cache=EventCache({}),
|
event_cache=EventCache({}),
|
||||||
entity_name_cache=EntityNameCache(self.hass),
|
entity_name_cache=EntityNameCache(self.hass),
|
||||||
include_entity_name=include_entity_name,
|
include_entity_name=include_entity_name,
|
||||||
|
|
|
@ -20,13 +20,13 @@ from homeassistant.helpers.event import async_track_point_in_utc_time
|
||||||
from homeassistant.helpers.json import JSON_DUMP
|
from homeassistant.helpers.json import JSON_DUMP
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from .const import LOGBOOK_ENTITIES_FILTER
|
from .const import DOMAIN
|
||||||
from .helpers import (
|
from .helpers import (
|
||||||
async_determine_event_types,
|
async_determine_event_types,
|
||||||
async_filter_entities,
|
async_filter_entities,
|
||||||
async_subscribe_events,
|
async_subscribe_events,
|
||||||
)
|
)
|
||||||
from .models import async_event_to_row
|
from .models import LogbookConfig, async_event_to_row
|
||||||
from .processor import EventProcessor
|
from .processor import EventProcessor
|
||||||
|
|
||||||
MAX_PENDING_LOGBOOK_EVENTS = 2048
|
MAX_PENDING_LOGBOOK_EVENTS = 2048
|
||||||
|
@ -361,7 +361,8 @@ async def ws_event_stream(
|
||||||
|
|
||||||
entities_filter: EntityFilter | None = None
|
entities_filter: EntityFilter | None = None
|
||||||
if not event_processor.limited_select:
|
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(
|
async_subscribe_events(
|
||||||
hass,
|
hass,
|
||||||
|
|
|
@ -6,6 +6,7 @@ from typing import Any
|
||||||
|
|
||||||
from homeassistant.components import logbook
|
from homeassistant.components import logbook
|
||||||
from homeassistant.components.logbook import processor
|
from homeassistant.components.logbook import processor
|
||||||
|
from homeassistant.components.logbook.models import LogbookConfig
|
||||||
from homeassistant.components.recorder.models import (
|
from homeassistant.components.recorder.models import (
|
||||||
process_timestamp_to_utc_isoformat,
|
process_timestamp_to_utc_isoformat,
|
||||||
ulid_to_bytes_or_none,
|
ulid_to_bytes_or_none,
|
||||||
|
@ -64,7 +65,8 @@ def mock_humanify(hass_, rows):
|
||||||
ent_reg = er.async_get(hass_)
|
ent_reg = er.async_get(hass_)
|
||||||
event_cache = processor.EventCache({})
|
event_cache = processor.EventCache({})
|
||||||
context_lookup = processor.ContextLookup(hass_)
|
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(
|
logbook_run = processor.LogbookRun(
|
||||||
context_lookup,
|
context_lookup,
|
||||||
external_events,
|
external_events,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue