Home Assistant Unofficial Reference 2024.12.1
event.py
Go to the documentation of this file.
1 """Support for bthome event entities."""
2 
3 from __future__ import annotations
4 
5 from dataclasses import replace
6 
8  EventDeviceClass,
9  EventEntity,
10  EventEntityDescription,
11 )
12 from homeassistant.core import HomeAssistant, callback
13 from homeassistant.helpers import device_registry as dr, entity_registry as er
14 from homeassistant.helpers.dispatcher import async_dispatcher_connect
15 from homeassistant.helpers.entity_platform import AddEntitiesCallback
16 
17 from . import format_discovered_event_class, format_event_dispatcher_name
18 from .const import (
19  DOMAIN,
20  EVENT_CLASS_BUTTON,
21  EVENT_CLASS_DIMMER,
22  EVENT_PROPERTIES,
23  EVENT_TYPE,
24  BTHomeBleEvent,
25 )
26 from .types import BTHomeConfigEntry
27 
28 DESCRIPTIONS_BY_EVENT_CLASS = {
29  EVENT_CLASS_BUTTON: EventEntityDescription(
30  key=EVENT_CLASS_BUTTON,
31  translation_key="button",
32  event_types=[
33  "press",
34  "double_press",
35  "triple_press",
36  "long_press",
37  "long_double_press",
38  "long_triple_press",
39  ],
40  device_class=EventDeviceClass.BUTTON,
41  ),
42  EVENT_CLASS_DIMMER: EventEntityDescription(
43  key=EVENT_CLASS_DIMMER,
44  translation_key="dimmer",
45  event_types=["rotate_left", "rotate_right"],
46  ),
47 }
48 
49 
51  """Representation of a BTHome event entity."""
52 
53  _attr_should_poll = False
54  _attr_has_entity_name = True
55 
56  def __init__(
57  self,
58  address: str,
59  event_class: str,
60  event: BTHomeBleEvent | None,
61  ) -> None:
62  """Initialise a BTHome event entity."""
63  self._update_signal_update_signal = format_event_dispatcher_name(address, event_class)
64  # event_class is something like "button" or "dimmer"
65  # and it maybe postfixed with "_1", "_2", "_3", etc
66  # If there is only one button then it will be "button"
67  base_event_class, _, postfix = event_class.partition("_")
68  base_description = DESCRIPTIONS_BY_EVENT_CLASS[base_event_class]
69  self.entity_descriptionentity_description = replace(base_description, key=event_class)
70  postfix_name = f" {postfix}" if postfix else ""
71  self._attr_name_attr_name = f"{base_event_class.title()}{postfix_name}"
72  # Matches logic in PassiveBluetoothProcessorEntity
73  self._attr_device_info_attr_device_info = dr.DeviceInfo(
74  identifiers={(DOMAIN, address)},
75  connections={(dr.CONNECTION_BLUETOOTH, address)},
76  )
77  self._attr_unique_id_attr_unique_id = f"{address}-{event_class}"
78  # If the event is provided then we can set the initial state
79  # since the event itself is likely what triggered the creation
80  # of this entity. We have to do this at creation time since
81  # entities are created dynamically and would otherwise miss
82  # the initial state.
83  if event:
84  self._trigger_event_trigger_event(event[EVENT_TYPE], event[EVENT_PROPERTIES])
85 
86  async def async_added_to_hass(self) -> None:
87  """Entity added to hass."""
88  await super().async_added_to_hass()
89  self.async_on_removeasync_on_remove(
91  self.hasshass,
92  self._update_signal_update_signal,
93  self._async_handle_event_async_handle_event,
94  )
95  )
96 
97  @callback
98  def _async_handle_event(self, event: BTHomeBleEvent) -> None:
99  self._trigger_event_trigger_event(event[EVENT_TYPE], event[EVENT_PROPERTIES])
100  self.async_write_ha_stateasync_write_ha_state()
101 
102 
104  hass: HomeAssistant,
105  entry: BTHomeConfigEntry,
106  async_add_entities: AddEntitiesCallback,
107 ) -> None:
108  """Set up BTHome event."""
109  coordinator = entry.runtime_data
110  address = coordinator.address
111  ent_reg = er.async_get(hass)
113  # Matches logic in PassiveBluetoothProcessorEntity
114  BTHomeEventEntity(address_event_class[0], address_event_class[2], None)
115  for ent_reg_entry in er.async_entries_for_config_entry(ent_reg, entry.entry_id)
116  if ent_reg_entry.domain == "event"
117  and (address_event_class := ent_reg_entry.unique_id.partition("-"))
118  )
119 
120  @callback
121  def _async_discovered_event_class(event_class: str, event: BTHomeBleEvent) -> None:
122  """Handle a newly discovered event class with or without a postfix."""
123  async_add_entities([BTHomeEventEntity(address, event_class, event)])
124 
125  entry.async_on_unload(
127  hass,
129  _async_discovered_event_class,
130  )
131  )
None __init__(self, str address, str event_class, BTHomeBleEvent|None event)
Definition: event.py:61
None _async_handle_event(self, BTHomeBleEvent event)
Definition: event.py:98
None _trigger_event(self, str event_type, dict[str, Any]|None event_attributes=None)
Definition: __init__.py:148
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
None async_setup_entry(HomeAssistant hass, BTHomeConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: event.py:107
SignalType[BTHomeBleEvent] format_event_dispatcher_name(str address, str event_class)
Definition: __init__.py:109
SignalType[str, BTHomeBleEvent] format_discovered_event_class(str address)
Definition: __init__.py:114
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103