Home Assistant Unofficial Reference 2024.12.1
entity.py
Go to the documentation of this file.
1 """Base ScreenLogicEntity definitions."""
2 
3 from collections.abc import Callable
4 from dataclasses import dataclass
5 from datetime import datetime
6 import logging
7 from typing import Any
8 
9 from screenlogicpy import ScreenLogicGateway
10 from screenlogicpy.const.common import (
11  ON_OFF,
12  ScreenLogicCommunicationError,
13  ScreenLogicError,
14 )
15 from screenlogicpy.const.data import ATTR
16 from screenlogicpy.const.msg import CODE
17 
18 from homeassistant.core import callback
19 from homeassistant.exceptions import HomeAssistantError
20 from homeassistant.helpers import device_registry as dr
21 from homeassistant.helpers.device_registry import DeviceInfo
22 from homeassistant.helpers.entity import EntityDescription
23 from homeassistant.helpers.update_coordinator import CoordinatorEntity
24 
25 from .const import ScreenLogicDataPath
26 from .coordinator import ScreenlogicDataUpdateCoordinator
27 from .util import generate_unique_id
28 
29 _LOGGER = logging.getLogger(__name__)
30 
31 
32 @dataclass(frozen=True, kw_only=True)
34  """Base class for a ScreenLogic entity description."""
35 
36  data_root: ScreenLogicDataPath
37  enabled_lambda: Callable[..., bool] | None = None
38 
39 
40 class ScreenLogicEntity(CoordinatorEntity[ScreenlogicDataUpdateCoordinator]):
41  """Base class for all ScreenLogic entities."""
42 
43  entity_description: ScreenLogicEntityDescription
44  _attr_has_entity_name = True
45 
46  def __init__(
47  self,
48  coordinator: ScreenlogicDataUpdateCoordinator,
49  entity_description: ScreenLogicEntityDescription,
50  ) -> None:
51  """Initialize of the entity."""
52  super().__init__(coordinator)
53  self.entity_descriptionentity_description = entity_description
54  self._data_key_data_key = self.entity_descriptionentity_description.key
55  self._data_path_data_path = (*self.entity_descriptionentity_description.data_root, self._data_key_data_key)
56  mac = self.macmac
57  self._attr_unique_id_attr_unique_id = f"{mac}_{generate_unique_id(*self._data_path)}"
58  self._attr_name_attr_name = self.entity_dataentity_data[ATTR.NAME]
59  assert mac is not None
60  self._attr_device_info_attr_device_info = DeviceInfo(
61  connections={(dr.CONNECTION_NETWORK_MAC, mac)},
62  manufacturer="Pentair",
63  model=self.gatewaygatewaygateway.controller_model,
64  name=self.gatewaygatewaygateway.name,
65  sw_version=self.gatewaygatewaygateway.version,
66  )
67 
68  @property
69  def mac(self) -> str | None:
70  """Mac address."""
71  assert self.coordinator.config_entry is not None
72  return self.coordinator.config_entry.unique_id
73 
74  @property
75  def gateway(self) -> ScreenLogicGateway:
76  """Return the gateway."""
77  return self.coordinator.gateway
78 
79  async def _async_refresh(self) -> None:
80  """Refresh the data from the gateway."""
81  await self.coordinator.async_refresh()
82  # Second debounced refresh to catch any secondary
83  # changes in the device
84  await self.coordinator.async_request_refresh()
85 
86  async def _async_refresh_timed(self, now: datetime) -> None:
87  """Refresh from a timed called."""
88  await self.coordinator.async_request_refresh()
89 
90  @property
91  def entity_data(self) -> dict:
92  """Shortcut to the data for this entity."""
93  try:
94  return self.gatewaygatewaygateway.get_data(*self._data_path_data_path, strict=True)
95  except KeyError as ke:
96  raise HomeAssistantError(f"Data not found: {self._data_path}") from ke
97 
98 
99 @dataclass(frozen=True, kw_only=True)
101  """Base class for a ScreenLogic push entity description."""
102 
103  subscription_code: CODE
104 
105 
107  """Base class for all ScreenLogic push entities."""
108 
109  entity_description: ScreenLogicPushEntityDescription
110 
111  def __init__(
112  self,
113  coordinator: ScreenlogicDataUpdateCoordinator,
114  entity_description: ScreenLogicPushEntityDescription,
115  ) -> None:
116  """Initialize of the entity."""
117  super().__init__(coordinator, entity_description)
118  self._subscription_code_subscription_code = entity_description.subscription_code
119  self._last_update_success_last_update_success = True
120 
121  @callback
122  def _async_data_updated(self) -> None:
123  """Handle data updates."""
124  self._last_update_success_last_update_success = self.coordinator.last_update_success
125  self.async_write_ha_state()
126 
127  async def async_added_to_hass(self) -> None:
128  """When entity is added to hass."""
129  await super().async_added_to_hass()
130  self.async_on_remove(
131  await self.gatewaygatewaygateway.async_subscribe_client(
132  self._async_data_updated_async_data_updated,
133  self._subscription_code_subscription_code,
134  )
135  )
136 
137  @callback
138  def _handle_coordinator_update(self) -> None:
139  """Handle updated data from the coordinator."""
140  # For push entities, only take updates from the coordinator if availability changes.
141  if self.coordinator.last_update_success != self._last_update_success_last_update_success:
142  self._async_data_updated_async_data_updated()
143 
144 
146  """Base class for all switchable entities."""
147 
148  @property
149  def is_on(self) -> bool:
150  """Get whether the switch is in on state."""
151  return self.entity_dataentity_data[ATTR.VALUE] == ON_OFF.ON
152 
153  async def async_turn_on(self, **kwargs: Any) -> None:
154  """Send the ON command."""
155  await self._async_set_state_async_set_state(ON_OFF.ON)
156 
157  async def async_turn_off(self, **kwargs: Any) -> None:
158  """Send the OFF command."""
159  await self._async_set_state_async_set_state(ON_OFF.OFF)
160 
161  async def _async_set_state(self, state: ON_OFF) -> None:
162  raise NotImplementedError
163 
164 
166  """Base class for all ScreenLogic circuit switch and light entities."""
167 
168  async def _async_set_state(self, state: ON_OFF) -> None:
169  try:
170  await self.gatewaygatewaygateway.async_set_circuit(self._data_key_data_key, state.value)
171  except (ScreenLogicCommunicationError, ScreenLogicError) as sle:
172  raise HomeAssistantError(
173  f"Failed to set_circuit {self._data_key} {state.value}: {sle.msg}"
174  ) from sle
175  _LOGGER.debug("Set circuit %s %s", self._data_key_data_key, state.value)
None __init__(self, ScreenlogicDataUpdateCoordinator coordinator, ScreenLogicEntityDescription entity_description)
Definition: entity.py:50
None __init__(self, ScreenlogicDataUpdateCoordinator coordinator, ScreenLogicPushEntityDescription entity_description)
Definition: entity.py:115