Home Assistant Unofficial Reference 2024.12.1
event.py
Go to the documentation of this file.
1 """Support for MQTT events."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 import logging
7 from typing import Any
8 
9 import voluptuous as vol
10 
11 from homeassistant.components import event
13  ENTITY_ID_FORMAT,
14  EventDeviceClass,
15  EventEntity,
16 )
17 from homeassistant.config_entries import ConfigEntry
18 from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME, CONF_VALUE_TEMPLATE
19 from homeassistant.core import HomeAssistant, callback
21 from homeassistant.helpers.entity_platform import AddEntitiesCallback
22 from homeassistant.helpers.service_info.mqtt import ReceivePayloadType
23 from homeassistant.helpers.typing import ConfigType, VolSchemaType
24 from homeassistant.util.json import JSON_DECODE_EXCEPTIONS, json_loads_object
25 
26 from . import subscription
27 from .config import MQTT_RO_SCHEMA
28 from .const import CONF_STATE_TOPIC, PAYLOAD_EMPTY_JSON, PAYLOAD_NONE
29 from .entity import MqttEntity, async_setup_entity_entry_helper
30 from .models import (
31  DATA_MQTT,
32  MqttValueTemplate,
33  MqttValueTemplateException,
34  PayloadSentinel,
35  ReceiveMessage,
36 )
37 from .schemas import MQTT_ENTITY_COMMON_SCHEMA
38 
39 _LOGGER = logging.getLogger(__name__)
40 
41 PARALLEL_UPDATES = 0
42 
43 CONF_EVENT_TYPES = "event_types"
44 
45 MQTT_EVENT_ATTRIBUTES_BLOCKED = frozenset(
46  {
47  event.ATTR_EVENT_TYPE,
48  event.ATTR_EVENT_TYPES,
49  }
50 )
51 
52 DEFAULT_NAME = "MQTT Event"
53 DEFAULT_FORCE_UPDATE = False
54 DEVICE_CLASS_SCHEMA = vol.All(vol.Lower, vol.Coerce(EventDeviceClass))
55 
56 _PLATFORM_SCHEMA_BASE = MQTT_RO_SCHEMA.extend(
57  {
58  vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASS_SCHEMA,
59  vol.Optional(CONF_NAME): vol.Any(None, cv.string),
60  vol.Required(CONF_EVENT_TYPES): vol.All(cv.ensure_list, [cv.string]),
61  }
62 ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
63 
64 PLATFORM_SCHEMA_MODERN = vol.All(
65  _PLATFORM_SCHEMA_BASE,
66 )
67 
68 DISCOVERY_SCHEMA = vol.All(
69  _PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
70 )
71 
72 
74  hass: HomeAssistant,
75  config_entry: ConfigEntry,
76  async_add_entities: AddEntitiesCallback,
77 ) -> None:
78  """Set up MQTT event through YAML and through MQTT discovery."""
80  hass,
81  config_entry,
82  MqttEvent,
83  event.DOMAIN,
84  async_add_entities,
85  DISCOVERY_SCHEMA,
86  PLATFORM_SCHEMA_MODERN,
87  )
88 
89 
91  """Representation of an event that can be updated using MQTT."""
92 
93  _default_name = DEFAULT_NAME
94  _entity_id_format = ENTITY_ID_FORMAT
95  _attributes_extra_blocked = MQTT_EVENT_ATTRIBUTES_BLOCKED
96  _template: Callable[[ReceivePayloadType, PayloadSentinel], ReceivePayloadType]
97 
98  @staticmethod
99  def config_schema() -> VolSchemaType:
100  """Return the config schema."""
101  return DISCOVERY_SCHEMA
102 
103  def _setup_from_config(self, config: ConfigType) -> None:
104  """(Re)Setup the entity."""
105  self._attr_device_class_attr_device_class = config.get(CONF_DEVICE_CLASS)
106  self._attr_event_types_attr_event_types = config[CONF_EVENT_TYPES]
107  self._template_template = MqttValueTemplate(
108  self._config_config.get(CONF_VALUE_TEMPLATE), entity=self
109  ).async_render_with_possible_json_value
110 
111  @callback
112  def _event_received(self, msg: ReceiveMessage) -> None:
113  """Handle new MQTT messages."""
114  if msg.retain:
115  _LOGGER.debug(
116  "Ignoring event trigger from replayed retained payload '%s' on topic %s",
117  msg.payload,
118  msg.topic,
119  )
120  return
121  event_attributes: dict[str, Any] = {}
122  event_type: str
123  try:
124  payload = self._template_template(msg.payload, PayloadSentinel.DEFAULT)
125  except MqttValueTemplateException as exc:
126  _LOGGER.warning(exc)
127  return
128  if (
129  not payload
130  or payload is PayloadSentinel.DEFAULT
131  or payload in (PAYLOAD_NONE, PAYLOAD_EMPTY_JSON)
132  ):
133  _LOGGER.debug(
134  "Ignoring empty payload '%s' after rendering for topic %s",
135  payload,
136  msg.topic,
137  )
138  return
139  try:
140  event_attributes = json_loads_object(payload)
141  event_type = str(event_attributes.pop(event.ATTR_EVENT_TYPE))
142  _LOGGER.debug(
143  (
144  "JSON event data detected after processing payload '%s' on"
145  " topic %s, type %s, attributes %s"
146  ),
147  payload,
148  msg.topic,
149  event_type,
150  event_attributes,
151  )
152  except KeyError:
153  _LOGGER.warning(
154  ("`event_type` missing in JSON event payload, " " '%s' on topic %s"),
155  payload,
156  msg.topic,
157  )
158  return
159  except JSON_DECODE_EXCEPTIONS:
160  _LOGGER.warning(
161  (
162  "No valid JSON event payload detected, "
163  "value after processing payload"
164  " '%s' on topic %s"
165  ),
166  payload,
167  msg.topic,
168  )
169  return
170  try:
171  self._trigger_event_trigger_event(event_type, event_attributes)
172  except ValueError:
173  _LOGGER.warning(
174  "Invalid event type %s for %s received on topic %s, payload %s",
175  event_type,
176  self.entity_identity_id,
177  msg.topic,
178  payload,
179  )
180  return
181  mqtt_data = self.hasshasshass.data[DATA_MQTT]
182  mqtt_data.state_write_requests.write_state_request(self)
183 
184  @callback
185  def _prepare_subscribe_topics(self) -> None:
186  """(Re)Subscribe to topics."""
187  self.add_subscriptionadd_subscription(CONF_STATE_TOPIC, self._event_received_event_received, None)
188 
189  async def _subscribe_topics(self) -> None:
190  """(Re)Subscribe to topics."""
191  subscription.async_subscribe_topics_internal(self.hasshasshass, self._sub_state_sub_state)
None _trigger_event(self, str event_type, dict[str, Any]|None event_attributes=None)
Definition: __init__.py:148
bool add_subscription(self, str state_topic_config_key, Callable[[ReceiveMessage], None] msg_callback, set[str]|None tracked_attributes, bool disable_encoding=False)
Definition: entity.py:1484
None _event_received(self, ReceiveMessage msg)
Definition: event.py:112
None _setup_from_config(self, ConfigType config)
Definition: event.py:103
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None async_setup_entity_entry_helper(HomeAssistant hass, ConfigEntry entry, type[MqttEntity]|None entity_class, str domain, AddEntitiesCallback async_add_entities, VolSchemaType discovery_schema, VolSchemaType platform_schema_modern, dict[str, type[MqttEntity]]|None schema_class_mapping=None)
Definition: entity.py:245
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: event.py:77
JsonObjectType json_loads_object(bytes|bytearray|memoryview|str obj)
Definition: json.py:54