1 """Offer event listening automation rules."""
3 from __future__
import annotations
5 from collections.abc
import ItemsView, Mapping
8 import voluptuous
as vol
17 CONF_EVENT_TYPE =
"event_type"
18 CONF_EVENT_CONTEXT =
"context"
22 """Validate the event types.
24 If the event types are templated, we check when attaching the trigger.
26 templates: list[template.Template] = value
27 if any(tpl.is_static
and tpl.template == EVENT_STATE_REPORTED
for tpl
in templates):
28 raise vol.Invalid(f
"Can't listen to {EVENT_STATE_REPORTED} in event trigger")
32 TRIGGER_SCHEMA = cv.TRIGGER_BASE_SCHEMA.extend(
34 vol.Required(CONF_PLATFORM):
"event",
35 vol.Required(CONF_EVENT_TYPE): vol.All(
36 cv.ensure_list, [cv.template], _validate_event_types
38 vol.Optional(CONF_EVENT_DATA): vol.All(dict, cv.template_complex),
39 vol.Optional(CONF_EVENT_CONTEXT): vol.All(dict, cv.template_complex),
45 if isinstance(value, list):
54 action: TriggerActionType,
55 trigger_info: TriggerInfo,
57 platform_type: str =
"event",
59 """Listen for events based on configuration."""
60 trigger_data = trigger_info[
"trigger_data"]
61 variables = trigger_info[
"variables"]
63 event_types = template.render_complex(
64 config[CONF_EVENT_TYPE], variables, limited=
True
66 if EVENT_STATE_REPORTED
in event_types:
68 f
"Can't listen to {EVENT_STATE_REPORTED} in event trigger"
70 event_data_schema: vol.Schema |
None =
None
71 event_data_items: ItemsView |
None =
None
72 if CONF_EVENT_DATA
in config:
76 template.render_complex(config[CONF_EVENT_DATA], variables, limited=
True)
82 if any(isinstance(value, dict)
for value
in event_data.values()):
83 event_data_schema = vol.Schema(
84 {vol.Required(key): value
for key, value
in event_data.items()},
85 extra=vol.ALLOW_EXTRA,
89 event_data_items = event_data.items()
91 event_context_schema: vol.Schema |
None =
None
92 event_context_items: ItemsView |
None =
None
93 if CONF_EVENT_CONTEXT
in config:
97 template.render_complex(config[CONF_EVENT_CONTEXT], variables, limited=
True)
105 if any(isinstance(value, list)
for value
in event_context.values()):
106 event_context_schema = vol.Schema(
109 for key, value
in event_context.items()
111 extra=vol.ALLOW_EXTRA,
115 event_context_items = event_context.items()
117 job =
HassJob(action, f
"event trigger {trigger_info}")
120 def filter_event(event_data: Mapping[str, Any]) -> bool:
127 if not (event_data.items() >= event_data_items):
129 elif event_data_schema:
131 event_data_schema(event_data)
138 def handle_event(event: Event) ->
None:
139 """Listen for events and calls the action when data matches."""
140 if event_context_items:
143 if not (event.context._as_dict.items() >= event_context_items):
145 elif event_context_schema:
149 event_context_schema(
dict(event.context._as_dict))
155 hass.async_run_hass_job,
160 "platform": platform_type,
162 "description": f
"event '{event.event_type}'",
168 event_filter = filter_event
if event_data_items
or event_data_schema
else None
170 hass.bus.async_listen(event_type, handle_event, event_filter=event_filter)
171 for event_type
in event_types
175 def remove_listen_events() -> None:
176 """Remove event listeners."""
177 for remove
in removes:
180 return remove_listen_events
bool remove(self, _T matcher)
Any _validate_event_types(Any value)
CALLBACK_TYPE async_attach_trigger(HomeAssistant hass, ConfigType config, TriggerActionType action, TriggerInfo trigger_info, *str platform_type="event")
Any _schema_value(Any value)