Home Assistant Unofficial Reference 2024.12.1
siren.py
Go to the documentation of this file.
1 """Component providing HA Siren support for Ring Chimes."""
2 
3 from collections.abc import Callable, Coroutine
4 from dataclasses import dataclass
5 import logging
6 from typing import Any, Generic, cast
7 
8 from ring_doorbell import (
9  RingCapability,
10  RingChime,
11  RingEventKind,
12  RingGeneric,
13  RingStickUpCam,
14 )
15 
17  ATTR_TONE,
18  SirenEntity,
19  SirenEntityDescription,
20  SirenEntityFeature,
21  SirenTurnOnServiceParameters,
22 )
23 from homeassistant.const import Platform
24 from homeassistant.core import HomeAssistant, callback
25 from homeassistant.helpers.entity_platform import AddEntitiesCallback
26 
27 from . import RingConfigEntry
28 from .coordinator import RingDataCoordinator
29 from .entity import (
30  RingDeviceT,
31  RingEntity,
32  RingEntityDescription,
33  async_check_create_deprecated,
34  refresh_after,
35 )
36 
37 _LOGGER = logging.getLogger(__name__)
38 
39 
40 @dataclass(frozen=True, kw_only=True)
42  SirenEntityDescription, RingEntityDescription, Generic[RingDeviceT]
43 ):
44  """Describes a Ring siren entity."""
45 
46  exists_fn: Callable[[RingGeneric], bool]
47  unique_id_fn: Callable[[RingDeviceT], str] = lambda device: str(
48  device.device_api_id
49  )
50  is_on_fn: Callable[[RingDeviceT], bool] | None = None
51  turn_on_fn: (
52  Callable[[RingDeviceT, SirenTurnOnServiceParameters], Coroutine[Any, Any, Any]]
53  | None
54  ) = None
55  turn_off_fn: Callable[[RingDeviceT], Coroutine[Any, Any, None]] | None = None
56 
57 
58 SIRENS: tuple[RingSirenEntityDescription[Any], ...] = (
59  RingSirenEntityDescription[RingChime](
60  key="siren",
61  translation_key="siren",
62  available_tones=[RingEventKind.DING.value, RingEventKind.MOTION.value],
63  # Historically the chime siren entity has appended `siren` to the unique id
64  unique_id_fn=lambda device: f"{device.device_api_id}-siren",
65  exists_fn=lambda device: isinstance(device, RingChime),
66  turn_on_fn=lambda device, kwargs: device.async_test_sound(
67  kind=str(kwargs.get(ATTR_TONE) or "") or RingEventKind.DING.value
68  ),
69  ),
70  RingSirenEntityDescription[RingStickUpCam](
71  key="siren",
72  translation_key="siren",
73  exists_fn=lambda device: device.has_capability(RingCapability.SIREN),
74  is_on_fn=lambda device: device.siren > 0,
75  turn_on_fn=lambda device, _: device.async_set_siren(1),
76  turn_off_fn=lambda device: device.async_set_siren(0),
77  ),
78 )
79 
80 
82  hass: HomeAssistant,
83  entry: RingConfigEntry,
84  async_add_entities: AddEntitiesCallback,
85 ) -> None:
86  """Create the sirens for the Ring devices."""
87  ring_data = entry.runtime_data
88  devices_coordinator = ring_data.devices_coordinator
89 
91  RingSiren(device, devices_coordinator, description)
92  for device in ring_data.devices.all_devices
93  for description in SIRENS
94  if description.exists_fn(device)
96  hass,
97  Platform.SIREN,
98  description.unique_id_fn(device),
99  description,
100  )
101  )
102 
103 
104 class RingSiren(RingEntity[RingDeviceT], SirenEntity):
105  """Creates a siren to play the test chimes of a Chime device."""
106 
107  entity_description: RingSirenEntityDescription[RingDeviceT]
108 
109  def __init__(
110  self,
111  device: RingDeviceT,
112  coordinator: RingDataCoordinator,
113  description: RingSirenEntityDescription[RingDeviceT],
114  ) -> None:
115  """Initialize a Ring Chime siren."""
116  super().__init__(device, coordinator)
117  self.entity_descriptionentity_description = description
118  self._attr_unique_id_attr_unique_id = description.unique_id_fn(device)
119  if description.is_on_fn:
120  self._attr_is_on_attr_is_on = description.is_on_fn(self._device_device_device_device)
121  features = SirenEntityFeature(0)
122  if description.turn_on_fn:
123  features = features | SirenEntityFeature.TURN_ON
124  if description.turn_off_fn:
125  features = features | SirenEntityFeature.TURN_OFF
126  if description.available_tones:
127  features = features | SirenEntityFeature.TONES
128  self._attr_supported_features_attr_supported_features = features
129 
130  async def _async_set_siren(self, siren_on: bool, **kwargs: Any) -> None:
131  if siren_on and self.entity_descriptionentity_description.turn_on_fn:
132  turn_on_params = cast(SirenTurnOnServiceParameters, kwargs)
133  await self.entity_descriptionentity_description.turn_on_fn(self._device_device_device_device, turn_on_params)
134  elif not siren_on and self.entity_descriptionentity_description.turn_off_fn:
135  await self.entity_descriptionentity_description.turn_off_fn(self._device_device_device_device)
136 
137  if self.entity_descriptionentity_description.is_on_fn:
138  self._attr_is_on_attr_is_on = siren_on
139  self.async_write_ha_stateasync_write_ha_state()
140 
141  @refresh_after
142  async def async_turn_on(self, **kwargs: Any) -> None:
143  """Turn on the siren."""
144  await self._async_set_siren_async_set_siren(True, **kwargs)
145 
146  @refresh_after
147  async def async_turn_off(self, **kwargs: Any) -> None:
148  """Turn off the siren."""
149  await self._async_set_siren_async_set_siren(False)
150 
151  @callback
152  def _handle_coordinator_update(self) -> None:
153  """Call update method."""
154  if not self.entity_descriptionentity_description.is_on_fn:
155  return
156  self._device_device_device_device = cast(
157  RingDeviceT,
158  self._get_coordinator_data_get_coordinator_data().get_device(self._device_device_device_device.device_api_id),
159  )
160  self._attr_is_on_attr_is_on = self.entity_descriptionentity_description.is_on_fn(self._device_device_device_device)
None __init__(self, RingDeviceT device, RingDataCoordinator coordinator, RingSirenEntityDescription[RingDeviceT] description)
Definition: siren.py:114
None _async_set_siren(self, bool siren_on, **Any kwargs)
Definition: siren.py:130
None async_turn_on(self, **Any kwargs)
Definition: siren.py:142
None async_turn_off(self, **Any kwargs)
Definition: siren.py:147
DeviceEntry get_device(HomeAssistant hass, str unique_id)
Definition: util.py:12
bool async_check_create_deprecated(HomeAssistant hass, Platform platform, str unique_id, RingEntityDescription entity_description)
Definition: entity.py:97
None async_setup_entry(HomeAssistant hass, RingConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: siren.py:85