Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Component providing HA switch support for Ring Door Bell/Chimes."""
2 
3 from collections.abc import Callable, Coroutine, Sequence
4 from dataclasses import dataclass
5 import logging
6 from typing import Any, Generic, Self, cast
7 
8 from ring_doorbell import RingCapability, RingDoorBell, RingStickUpCam
9 from ring_doorbell.const import DOORBELL_EXISTING_TYPE
10 
11 from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
12 from homeassistant.const import Platform
13 from homeassistant.core import HomeAssistant, callback
14 from homeassistant.helpers.entity_platform import AddEntitiesCallback
15 import homeassistant.util.dt as dt_util
16 
17 from . import RingConfigEntry
18 from .coordinator import RingDataCoordinator
19 from .entity import (
20  DeprecatedInfo,
21  RingDeviceT,
22  RingEntity,
23  RingEntityDescription,
24  async_check_create_deprecated,
25  refresh_after,
26 )
27 
28 _LOGGER = logging.getLogger(__name__)
29 
30 IN_HOME_CHIME_IS_PRESENT = {v for k, v in DOORBELL_EXISTING_TYPE.items() if k != 2}
31 
32 
33 @dataclass(frozen=True, kw_only=True)
35  SwitchEntityDescription, RingEntityDescription, Generic[RingDeviceT]
36 ):
37  """Describes a Ring switch entity."""
38 
39  exists_fn: Callable[[RingDeviceT], bool]
40  unique_id_fn: Callable[[Self, RingDeviceT], str] = (
41  lambda self, device: f"{device.device_api_id}-{self.key}"
42  )
43  is_on_fn: Callable[[RingDeviceT], bool]
44  turn_on_fn: Callable[[RingDeviceT], Coroutine[Any, Any, None]]
45  turn_off_fn: Callable[[RingDeviceT], Coroutine[Any, Any, None]]
46 
47 
48 SWITCHES: Sequence[RingSwitchEntityDescription[Any]] = (
49  RingSwitchEntityDescription[RingStickUpCam](
50  key="siren",
51  translation_key="siren",
52  exists_fn=lambda device: device.has_capability(RingCapability.SIREN),
53  is_on_fn=lambda device: device.siren > 0,
54  turn_on_fn=lambda device: device.async_set_siren(1),
55  turn_off_fn=lambda device: device.async_set_siren(0),
56  deprecated_info=DeprecatedInfo(
57  new_platform=Platform.SIREN, breaks_in_ha_version="2025.4.0"
58  ),
59  ),
60  RingSwitchEntityDescription[RingDoorBell](
61  key="in_home_chime",
62  translation_key="in_home_chime",
63  exists_fn=lambda device: device.family == "doorbots"
64  and device.existing_doorbell_type in IN_HOME_CHIME_IS_PRESENT,
65  is_on_fn=lambda device: device.existing_doorbell_type_enabled or False,
66  turn_on_fn=lambda device: device.async_set_existing_doorbell_type_enabled(True),
67  turn_off_fn=lambda device: device.async_set_existing_doorbell_type_enabled(
68  False
69  ),
70  ),
71  RingSwitchEntityDescription[RingDoorBell](
72  key="motion_detection",
73  translation_key="motion_detection",
74  exists_fn=lambda device: device.has_capability(RingCapability.MOTION_DETECTION),
75  is_on_fn=lambda device: device.motion_detection,
76  turn_on_fn=lambda device: device.async_set_motion_detection(True),
77  turn_off_fn=lambda device: device.async_set_motion_detection(False),
78  ),
79 )
80 
81 
83  hass: HomeAssistant,
84  entry: RingConfigEntry,
85  async_add_entities: AddEntitiesCallback,
86 ) -> None:
87  """Create the switches for the Ring devices."""
88  ring_data = entry.runtime_data
89  devices_coordinator = ring_data.devices_coordinator
90 
92  RingSwitch(device, devices_coordinator, description)
93  for description in SWITCHES
94  for device in ring_data.devices.all_devices
95  if description.exists_fn(device)
97  hass,
98  Platform.SWITCH,
99  description.unique_id_fn(description, device),
100  description,
101  )
102  )
103 
104 
105 class RingSwitch(RingEntity[RingDeviceT], SwitchEntity):
106  """Represents a switch for controlling an aspect of a ring device."""
107 
108  entity_description: RingSwitchEntityDescription[RingDeviceT]
109 
110  def __init__(
111  self,
112  device: RingDeviceT,
113  coordinator: RingDataCoordinator,
114  description: RingSwitchEntityDescription[RingDeviceT],
115  ) -> None:
116  """Initialize the switch."""
117  super().__init__(device, coordinator)
118  self.entity_descriptionentity_description = description
119  self._no_updates_until_no_updates_until = dt_util.utcnow()
120  self._attr_unique_id_attr_unique_id = description.unique_id_fn(description, device)
121  self._attr_is_on_attr_is_on = description.is_on_fn(device)
122 
123  @callback
124  def _handle_coordinator_update(self) -> None:
125  """Call update method."""
126  self._device_device_device_device = cast(
127  RingDeviceT,
128  self._get_coordinator_data_get_coordinator_data().get_device(self._device_device_device_device.device_api_id),
129  )
130  self._attr_is_on_attr_is_on = self.entity_descriptionentity_description.is_on_fn(self._device_device_device_device)
132 
133  @refresh_after
134  async def _async_set_switch(self, switch_on: bool) -> None:
135  """Update switch state, and causes Home Assistant to correctly update."""
136  if switch_on:
137  await self.entity_descriptionentity_description.turn_on_fn(self._device_device_device_device)
138  else:
139  await self.entity_descriptionentity_description.turn_off_fn(self._device_device_device_device)
140 
141  self._attr_is_on_attr_is_on = switch_on
142  self.async_write_ha_stateasync_write_ha_state()
143 
144  async def async_turn_on(self, **kwargs: Any) -> None:
145  """Turn the siren on for 30 seconds."""
146  await self._async_set_switch_async_set_switch(True)
147 
148  async def async_turn_off(self, **kwargs: Any) -> None:
149  """Turn the siren off."""
150  await self._async_set_switch_async_set_switch(False)
None _async_set_switch(self, bool switch_on)
Definition: switch.py:134
None async_turn_off(self, **Any kwargs)
Definition: switch.py:148
None async_turn_on(self, **Any kwargs)
Definition: switch.py:144
None __init__(self, RingDeviceT device, RingDataCoordinator coordinator, RingSwitchEntityDescription[RingDeviceT] description)
Definition: switch.py:115
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: switch.py:86