Home Assistant Unofficial Reference 2024.12.1
button.py
Go to the documentation of this file.
1 """Support for Ubiquiti's UniFi Protect NVR."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Sequence
6 from dataclasses import dataclass
7 from functools import partial
8 import logging
9 from typing import TYPE_CHECKING, Final
10 
11 from uiprotect.data import ModelType, ProtectAdoptableDeviceModel
12 
14  ButtonDeviceClass,
15  ButtonEntity,
16  ButtonEntityDescription,
17 )
18 from homeassistant.const import Platform
19 from homeassistant.core import HomeAssistant, callback
20 from homeassistant.helpers import entity_registry as er
21 from homeassistant.helpers.dispatcher import async_dispatcher_connect
22 from homeassistant.helpers.entity_platform import AddEntitiesCallback
23 
24 from .const import DEVICES_THAT_ADOPT, DOMAIN
25 from .data import ProtectDeviceType, UFPConfigEntry
26 from .entity import (
27  PermRequired,
28  ProtectDeviceEntity,
29  ProtectEntityDescription,
30  ProtectSetableKeysMixin,
31  T,
32  async_all_device_entities,
33 )
34 
35 _LOGGER = logging.getLogger(__name__)
36 
37 
38 @dataclass(frozen=True, kw_only=True)
40  ProtectSetableKeysMixin[T], ButtonEntityDescription
41 ):
42  """Describes UniFi Protect Button entity."""
43 
44  ufp_press: str | None = None
45 
46 
47 DEVICE_CLASS_CHIME_BUTTON: Final = "unifiprotect__chime_button"
48 
49 
50 ALL_DEVICE_BUTTONS: tuple[ProtectButtonEntityDescription, ...] = (
52  key="reboot",
53  entity_registry_enabled_default=False,
54  device_class=ButtonDeviceClass.RESTART,
55  name="Reboot device",
56  ufp_press="reboot",
57  ufp_perm=PermRequired.WRITE,
58  ),
60  key="unadopt",
61  entity_registry_enabled_default=False,
62  name="Unadopt device",
63  icon="mdi:delete",
64  ufp_press="unadopt",
65  ufp_perm=PermRequired.DELETE,
66  ),
67 )
68 
69 ADOPT_BUTTON = ProtectButtonEntityDescription[ProtectAdoptableDeviceModel](
70  key="adopt",
71  name="Adopt device",
72  icon="mdi:plus-circle",
73  ufp_press="adopt",
74 )
75 
76 SENSOR_BUTTONS: tuple[ProtectButtonEntityDescription, ...] = (
78  key="clear_tamper",
79  name="Clear tamper",
80  icon="mdi:notification-clear-all",
81  ufp_press="clear_tamper",
82  ufp_perm=PermRequired.WRITE,
83  ),
84 )
85 
86 CHIME_BUTTONS: tuple[ProtectButtonEntityDescription, ...] = (
88  key="play",
89  name="Play chime",
90  device_class=DEVICE_CLASS_CHIME_BUTTON,
91  icon="mdi:play",
92  ufp_press="play",
93  ),
95  key="play_buzzer",
96  name="Play buzzer",
97  icon="mdi:play",
98  ufp_press="play_buzzer",
99  ),
100 )
101 
102 
103 _MODEL_DESCRIPTIONS: dict[ModelType, Sequence[ProtectEntityDescription]] = {
104  ModelType.CHIME: CHIME_BUTTONS,
105  ModelType.SENSOR: SENSOR_BUTTONS,
106 }
107 
108 
109 @callback
111  hass: HomeAssistant, device: ProtectAdoptableDeviceModel
112 ) -> None:
113  entity_registry = er.async_get(hass)
114  if entity_id := entity_registry.async_get_entity_id(
115  Platform.BUTTON, DOMAIN, f"{device.mac}_adopt"
116  ):
117  entity_registry.async_remove(entity_id)
118 
119 
121  hass: HomeAssistant,
122  entry: UFPConfigEntry,
123  async_add_entities: AddEntitiesCallback,
124 ) -> None:
125  """Discover devices on a UniFi Protect NVR."""
126  data = entry.runtime_data
127 
128  adopt_entities = partial(
129  async_all_device_entities,
130  data,
131  ProtectAdoptButton,
132  unadopted_descs=[ADOPT_BUTTON],
133  )
134  base_entities = partial(
135  async_all_device_entities,
136  data,
137  ProtectButton,
138  all_descs=ALL_DEVICE_BUTTONS,
139  model_descriptions=_MODEL_DESCRIPTIONS,
140  )
141 
142  @callback
143  def _add_new_device(device: ProtectAdoptableDeviceModel) -> None:
145  [*base_entities(ufp_device=device), *adopt_entities(ufp_device=device)]
146  )
147  _async_remove_adopt_button(hass, device)
148 
149  @callback
150  def _async_add_unadopted_device(device: ProtectAdoptableDeviceModel) -> None:
151  if not device.can_adopt or not device.can_create(data.api.bootstrap.auth_user):
152  _LOGGER.debug("Device is not adoptable: %s", device.id)
153  return
154  async_add_entities(adopt_entities(ufp_device=device))
155 
156  data.async_subscribe_adopt(_add_new_device)
157  entry.async_on_unload(
158  async_dispatcher_connect(hass, data.add_signal, _async_add_unadopted_device)
159  )
160  async_add_entities([*base_entities(), *adopt_entities()])
161 
162  for device in data.get_by_types(DEVICES_THAT_ADOPT):
163  _async_remove_adopt_button(hass, device)
164 
165 
167  """A Ubiquiti UniFi Protect Reboot button."""
168 
169  entity_description: ProtectButtonEntityDescription
170 
171  async def async_press(self) -> None:
172  """Press the button."""
173  if self.entity_descriptionentity_description.ufp_press is not None:
174  await getattr(self.devicedevice, self.entity_descriptionentity_description.ufp_press)()
175 
176 
178  """A Ubiquiti UniFi Protect Adopt button."""
179 
180  @callback
181  def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
182  super()._async_update_device_from_protect(device)
183  if TYPE_CHECKING:
184  assert isinstance(device, ProtectAdoptableDeviceModel)
185  self._attr_available_attr_available_attr_available = device.can_adopt and device.can_create(
186  self.datadata.api.bootstrap.auth_user
187  )
None _async_update_device_from_protect(self, ProtectDeviceType device)
Definition: button.py:181
None _async_remove_adopt_button(HomeAssistant hass, ProtectAdoptableDeviceModel device)
Definition: button.py:112
None async_setup_entry(HomeAssistant hass, UFPConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: button.py:124
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103