Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Platform for NASweb output."""
2 
3 from __future__ import annotations
4 
5 import logging
6 import time
7 from typing import Any
8 
9 from webio_api import Output as NASwebOutput
10 
11 from homeassistant.components.switch import DOMAIN as DOMAIN_SWITCH, SwitchEntity
12 from homeassistant.core import HomeAssistant, callback
13 from homeassistant.helpers.device_registry import DeviceInfo
14 from homeassistant.helpers.entity_platform import AddEntitiesCallback
16 from homeassistant.helpers.typing import DiscoveryInfoType
18  BaseCoordinatorEntity,
19  BaseDataUpdateCoordinatorProtocol,
20 )
21 
22 from . import NASwebConfigEntry
23 from .const import DOMAIN, STATUS_UPDATE_MAX_TIME_INTERVAL
24 from .coordinator import NASwebCoordinator
25 
26 OUTPUT_TRANSLATION_KEY = "switch_output"
27 
28 _LOGGER = logging.getLogger(__name__)
29 
30 
31 def _get_output(coordinator: NASwebCoordinator, index: int) -> NASwebOutput | None:
32  for out in coordinator.webio_api.outputs:
33  if out.index == index:
34  return out
35  return None
36 
37 
39  hass: HomeAssistant,
40  config: NASwebConfigEntry,
41  async_add_entities: AddEntitiesCallback,
42  discovery_info: DiscoveryInfoType | None = None,
43 ) -> None:
44  """Set up switch platform."""
45  coordinator = config.runtime_data
46  current_outputs: set[int] = set()
47 
48  @callback
49  def _check_entities() -> None:
50  received_outputs = {out.index for out in coordinator.webio_api.outputs}
51  added = {i for i in received_outputs if i not in current_outputs}
52  removed = {i for i in current_outputs if i not in received_outputs}
53  entities_to_add: list[RelaySwitch] = []
54  for index in added:
55  webio_output = _get_output(coordinator, index)
56  if not isinstance(webio_output, NASwebOutput):
57  _LOGGER.error("Cannot create RelaySwitch entity without NASwebOutput")
58  continue
59  new_output = RelaySwitch(coordinator, webio_output)
60  entities_to_add.append(new_output)
61  current_outputs.add(index)
62  async_add_entities(entities_to_add)
63  entity_registry = er.async_get(hass)
64  for index in removed:
65  unique_id = f"{DOMAIN}.{config.unique_id}.relay_switch.{index}"
66  if entity_id := entity_registry.async_get_entity_id(
67  DOMAIN_SWITCH, DOMAIN, unique_id
68  ):
69  entity_registry.async_remove(entity_id)
70  current_outputs.remove(index)
71  else:
72  _LOGGER.warning("Failed to remove old output: no entity_id")
73 
74  coordinator.async_add_listener(_check_entities)
75  _check_entities()
76 
77 
78 class RelaySwitch(SwitchEntity, BaseCoordinatorEntity):
79  """Entity representing NASweb Output."""
80 
81  def __init__(
82  self,
83  coordinator: BaseDataUpdateCoordinatorProtocol,
84  nasweb_output: NASwebOutput,
85  ) -> None:
86  """Initialize RelaySwitch."""
87  super().__init__(coordinator)
88  self._output_output = nasweb_output
89  self._attr_icon_attr_icon = "mdi:export"
90  self._attr_has_entity_name_attr_has_entity_name = True
91  self._attr_translation_key_attr_translation_key = OUTPUT_TRANSLATION_KEY
92  self._attr_translation_placeholders_attr_translation_placeholders = {"index": f"{nasweb_output.index:2d}"}
93  self._attr_unique_id_attr_unique_id = (
94  f"{DOMAIN}.{self._output.webio_serial}.relay_switch.{self._output.index}"
95  )
96  self._attr_device_info_attr_device_info = DeviceInfo(
97  identifiers={(DOMAIN, self._output_output.webio_serial)},
98  )
99 
100  async def async_added_to_hass(self) -> None:
101  """When entity is added to hass."""
102  await super().async_added_to_hass()
103  self._handle_coordinator_update_handle_coordinator_update()
104 
105  @callback
106  def _handle_coordinator_update(self) -> None:
107  """Handle updated data from the coordinator."""
108  self._attr_is_on_attr_is_on = self._output_output.state
109  if (
110  self.coordinator.last_update is None
111  or time.time() - self._output_output.last_update >= STATUS_UPDATE_MAX_TIME_INTERVAL
112  ):
113  self._attr_available_attr_available = False
114  else:
115  self._attr_available_attr_available = (
116  self._output_output.available if self._output_output.available is not None else False
117  )
118  self.async_write_ha_state()
119 
120  async def async_update(self) -> None:
121  """Update the entity.
122 
123  Only used by the generic entity update service.
124  Scheduling updates is not necessary, the coordinator takes care of updates via push notifications.
125  """
126 
127  async def async_turn_on(self, **kwargs: Any) -> None:
128  """Turn On RelaySwitch."""
129  await self._output.turn_on()
130 
131  async def async_turn_off(self, **kwargs: Any) -> None:
132  """Turn Off RelaySwitch."""
133  await self._output_output.turn_off()
None __init__(self, BaseDataUpdateCoordinatorProtocol coordinator, NASwebOutput nasweb_output)
Definition: switch.py:85
None async_setup_entry(HomeAssistant hass, NASwebConfigEntry config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: switch.py:43
NASwebOutput|None _get_output(NASwebCoordinator coordinator, int index)
Definition: switch.py:31