Home Assistant Unofficial Reference 2024.12.1
event.py
Go to the documentation of this file.
1 """Platform providing event entities for UniFi Protect."""
2 
3 from __future__ import annotations
4 
5 import dataclasses
6 
7 from uiprotect.data import Camera, EventType, ProtectAdoptableDeviceModel
8 
10  EventDeviceClass,
11  EventEntity,
12  EventEntityDescription,
13 )
14 from homeassistant.core import HomeAssistant, callback
15 from homeassistant.helpers.entity_platform import AddEntitiesCallback
16 
17 from .const import (
18  ATTR_EVENT_ID,
19  EVENT_TYPE_DOORBELL_RING,
20  EVENT_TYPE_FINGERPRINT_IDENTIFIED,
21  EVENT_TYPE_FINGERPRINT_NOT_IDENTIFIED,
22  EVENT_TYPE_NFC_SCANNED,
23 )
24 from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
25 from .entity import EventEntityMixin, ProtectDeviceEntity, ProtectEventMixin
26 
27 
28 @dataclasses.dataclass(frozen=True, kw_only=True)
30  """Describes UniFi Protect event entity."""
31 
32  entity_class: type[ProtectDeviceEntity]
33 
34 
36  """A UniFi Protect event entity."""
37 
38  entity_description: ProtectEventEntityDescription
39 
40  @callback
41  def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
42  description = self.entity_descriptionentity_description
43 
44  prev_event = self._event_event
45  prev_event_end = self._event_end_event_end
46  super()._async_update_device_from_protect(device)
47  if event := description.get_event_obj(device):
48  self._event_event = event
49  self._event_end_event_end = event.end if event else None
50 
51  if (
52  event
53  and not self._event_already_ended_event_already_ended(prev_event, prev_event_end)
54  and event.type is EventType.RING
55  ):
56  self._trigger_event_trigger_event(EVENT_TYPE_DOORBELL_RING, {ATTR_EVENT_ID: event.id})
57  self.async_write_ha_stateasync_write_ha_state()
58 
59 
61  """A UniFi Protect NFC event entity."""
62 
63  entity_description: ProtectEventEntityDescription
64 
65  @callback
66  def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
67  description = self.entity_descriptionentity_description
68 
69  prev_event = self._event_event
70  prev_event_end = self._event_end_event_end
71  super()._async_update_device_from_protect(device)
72  if event := description.get_event_obj(device):
73  self._event_event = event
74  self._event_end_event_end = event.end if event else None
75 
76  if (
77  event
78  and not self._event_already_ended_event_already_ended(prev_event, prev_event_end)
79  and event.type is EventType.NFC_CARD_SCANNED
80  ):
81  event_data = {ATTR_EVENT_ID: event.id}
82  if event.metadata and event.metadata.nfc and event.metadata.nfc.nfc_id:
83  event_data["nfc_id"] = event.metadata.nfc.nfc_id
84 
85  self._trigger_event_trigger_event(EVENT_TYPE_NFC_SCANNED, event_data)
86  self.async_write_ha_stateasync_write_ha_state()
87 
88 
90  EventEntityMixin, ProtectDeviceEntity, EventEntity
91 ):
92  """A UniFi Protect fingerprint event entity."""
93 
94  entity_description: ProtectEventEntityDescription
95 
96  @callback
97  def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
98  description = self.entity_descriptionentity_description
99 
100  prev_event = self._event_event
101  prev_event_end = self._event_end_event_end
102  super()._async_update_device_from_protect(device)
103  if event := description.get_event_obj(device):
104  self._event_event = event
105  self._event_end_event_end = event.end if event else None
106 
107  if (
108  event
109  and not self._event_already_ended_event_already_ended(prev_event, prev_event_end)
110  and event.type is EventType.FINGERPRINT_IDENTIFIED
111  ):
112  event_data = {ATTR_EVENT_ID: event.id}
113  if (
114  event.metadata
115  and event.metadata.fingerprint
116  and event.metadata.fingerprint.ulp_id
117  ):
118  event_data["ulp_id"] = event.metadata.fingerprint.ulp_id
119  event_identified = EVENT_TYPE_FINGERPRINT_IDENTIFIED
120  else:
121  event_data["ulp_id"] = ""
122  event_identified = EVENT_TYPE_FINGERPRINT_NOT_IDENTIFIED
123 
124  self._trigger_event_trigger_event(event_identified, event_data)
125  self.async_write_ha_stateasync_write_ha_state()
126 
127 
128 EVENT_DESCRIPTIONS: tuple[ProtectEventEntityDescription, ...] = (
130  key="doorbell",
131  translation_key="doorbell",
132  device_class=EventDeviceClass.DOORBELL,
133  icon="mdi:doorbell-video",
134  ufp_required_field="feature_flags.is_doorbell",
135  ufp_event_obj="last_ring_event",
136  event_types=[EVENT_TYPE_DOORBELL_RING],
137  entity_class=ProtectDeviceRingEventEntity,
138  ),
140  key="nfc",
141  translation_key="nfc",
142  device_class=EventDeviceClass.DOORBELL,
143  icon="mdi:nfc",
144  ufp_required_field="feature_flags.support_nfc",
145  ufp_event_obj="last_nfc_card_scanned_event",
146  event_types=[EVENT_TYPE_NFC_SCANNED],
147  entity_class=ProtectDeviceNFCEventEntity,
148  ),
150  key="fingerprint",
151  translation_key="fingerprint",
152  device_class=EventDeviceClass.DOORBELL,
153  icon="mdi:fingerprint",
154  ufp_required_field="feature_flags.has_fingerprint_sensor",
155  ufp_event_obj="last_fingerprint_identified_event",
156  event_types=[
157  EVENT_TYPE_FINGERPRINT_IDENTIFIED,
158  EVENT_TYPE_FINGERPRINT_NOT_IDENTIFIED,
159  ],
160  entity_class=ProtectDeviceFingerprintEventEntity,
161  ),
162 )
163 
164 
165 @callback
167  data: ProtectData,
168  ufp_device: ProtectAdoptableDeviceModel | None = None,
169 ) -> list[ProtectDeviceEntity]:
170  return [
171  description.entity_class(data, device, description)
172  for device in (data.get_cameras() if ufp_device is None else [ufp_device])
173  for description in EVENT_DESCRIPTIONS
174  if description.has_required(device)
175  ]
176 
177 
179  hass: HomeAssistant,
180  entry: UFPConfigEntry,
181  async_add_entities: AddEntitiesCallback,
182 ) -> None:
183  """Set up event entities for UniFi Protect integration."""
184  data = entry.runtime_data
185 
186  @callback
187  def _add_new_device(device: ProtectAdoptableDeviceModel) -> None:
188  if device.is_adopted and isinstance(device, Camera):
189  async_add_entities(_async_event_entities(data, ufp_device=device))
190 
191  data.async_subscribe_adopt(_add_new_device)
None _trigger_event(self, str event_type, dict[str, Any]|None event_attributes=None)
Definition: __init__.py:148
bool _event_already_ended(self, Event|None prev_event, datetime|None prev_event_end)
Definition: entity.py:359
None _async_update_device_from_protect(self, ProtectDeviceType device)
Definition: event.py:66
None _async_update_device_from_protect(self, ProtectDeviceType device)
Definition: event.py:41
list[ProtectDeviceEntity] _async_event_entities(ProtectData data, ProtectAdoptableDeviceModel|None ufp_device=None)
Definition: event.py:169
None async_setup_entry(HomeAssistant hass, UFPConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: event.py:182