1 """Event parser and human readable log generator."""
3 from __future__
import annotations
5 from collections.abc
import Callable
8 import voluptuous
as vol
13 extract_include_exclude_filter_conf,
14 merge_include_exclude_filters,
15 sqlalchemy_filter_from_include_exclude_conf,
26 INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA,
27 convert_include_exclude_filter,
30 async_process_integration_platforms,
36 from .
import rest_api, websocket_api
40 LOGBOOK_ENTRY_CONTEXT_ID,
42 LOGBOOK_ENTRY_ENTITY_ID,
44 LOGBOOK_ENTRY_MESSAGE,
48 from .models
import LazyEventPartialState, LogbookConfig
50 CONFIG_SCHEMA = vol.Schema(
51 {DOMAIN: INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA}, extra=vol.ALLOW_EXTRA
55 LOG_MESSAGE_SCHEMA = vol.Schema(
57 vol.Required(ATTR_NAME): cv.string,
58 vol.Required(ATTR_MESSAGE): cv.string,
59 vol.Optional(ATTR_DOMAIN): cv.slug,
60 vol.Optional(ATTR_ENTITY_ID): cv.entity_id,
70 domain: str |
None =
None,
71 entity_id: str |
None =
None,
72 context: Context |
None =
None,
74 """Add an entry to the logbook."""
75 hass.add_job(async_log_entry, hass, name, message, domain, entity_id, context)
84 domain: str |
None =
None,
85 entity_id: str |
None =
None,
86 context: Context |
None =
None,
88 """Add an entry to the logbook."""
89 data = {LOGBOOK_ENTRY_NAME: name, LOGBOOK_ENTRY_MESSAGE: message}
91 if domain
is not None:
92 data[LOGBOOK_ENTRY_DOMAIN] = domain
93 if entity_id
is not None:
94 data[LOGBOOK_ENTRY_ENTITY_ID] = entity_id
95 hass.bus.async_fire(EVENT_LOGBOOK_ENTRY, data, context=context)
98 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
103 """Handle sending notification message service calls."""
104 message = service.data[ATTR_MESSAGE]
105 name = service.data[ATTR_NAME]
106 domain = service.data.get(ATTR_DOMAIN)
107 entity_id = service.data.get(ATTR_ENTITY_ID)
109 if entity_id
is None and domain
is None:
115 async_log_entry(hass, name, message, domain, entity_id, service.context)
117 frontend.async_register_built_in_panel(
118 hass,
"logbook",
"logbook",
"hass:format-list-bulleted-type"
121 recorder_conf = config.get(RECORDER_DOMAIN, {})
122 logbook_conf = config.get(DOMAIN, {})
128 if not possible_merged_entities_filter.empty_filter:
130 entities_filter = possible_merged_entities_filter.get_filter()
133 entities_filter =
None
135 external_events: dict[
136 EventType[Any] | str,
137 tuple[str, Callable[[LazyEventPartialState], dict[str, Any]]],
139 hass.data[DOMAIN] =
LogbookConfig(external_events, filters, entities_filter)
140 websocket_api.async_setup(hass)
141 rest_api.async_setup(hass, config, filters, entities_filter)
142 hass.services.async_register(DOMAIN,
"log", log_message, schema=LOG_MESSAGE_SCHEMA)
151 """Process a logbook platform."""
152 logbook_config: LogbookConfig = hass.data[DOMAIN]
153 external_events = logbook_config.external_events
156 def _async_describe_event(
159 describe_callback: Callable[[LazyEventPartialState], dict[str, Any]],
161 """Teach logbook how to describe a new event."""
162 external_events[event_name] = (domain, describe_callback)
164 platform.async_describe_events(hass, _async_describe_event)
None log_entry(HomeAssistant hass, str name, str message, str|None domain=None, str|None entity_id=None, Context|None context=None)
bool async_setup(HomeAssistant hass, ConfigType config)
None async_log_entry(HomeAssistant hass, str name, str message, str|None domain=None, str|None entity_id=None, Context|None context=None)
None _process_logbook_platform(HomeAssistant hass, str domain, Any platform)
None log_message(HomeAssistant hass, str entity_id, str topic, PublishPayloadType payload, int qos, bool retain)
dict[str, Any] merge_include_exclude_filters(dict[str, Any] base_filter, dict[str, Any] add_filter)
dict[str, Any] extract_include_exclude_filter_conf(ConfigType conf)
Filters|None sqlalchemy_filter_from_include_exclude_conf(ConfigType conf)
EntityFilter convert_include_exclude_filter(dict[str, dict[str, list[str]]] config)