Home Assistant Unofficial Reference 2024.12.1
entity.py
Go to the documentation of this file.
1 """Base entity for Russound RIO integration."""
2 
3 from collections.abc import Awaitable, Callable, Coroutine
4 from functools import wraps
5 from typing import Any, Concatenate
6 
7 from aiorussound import Controller, RussoundClient, RussoundTcpConnectionHandler
8 from aiorussound.models import CallbackType
9 
10 from homeassistant.exceptions import HomeAssistantError
11 from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
12 from homeassistant.helpers.entity import Entity
13 
14 from .const import DOMAIN, RUSSOUND_RIO_EXCEPTIONS
15 
16 
17 def command[_EntityT: RussoundBaseEntity, **_P](
18  func: Callable[Concatenate[_EntityT, _P], Awaitable[None]],
19 ) -> Callable[Concatenate[_EntityT, _P], Coroutine[Any, Any, None]]:
20  """Wrap async calls to raise on request error."""
21 
22  @wraps(func)
23  async def decorator(self: _EntityT, *args: _P.args, **kwargs: _P.kwargs) -> None:
24  """Wrap all command methods."""
25  try:
26  await func(self, *args, **kwargs)
27  except RUSSOUND_RIO_EXCEPTIONS as exc:
28  raise HomeAssistantError(
29  translation_domain=DOMAIN,
30  translation_key="command_error",
31  translation_placeholders={
32  "function_name": func.__name__,
33  "entity_id": self.entity_id,
34  },
35  ) from exc
36 
37  return decorator
38 
39 
41  """Russound Base Entity."""
42 
43  _attr_has_entity_name = True
44  _attr_should_poll = False
45 
46  def __init__(
47  self,
48  controller: Controller,
49  ) -> None:
50  """Initialize the entity."""
51  self._client_client = controller.client
52  self._controller_controller = controller
53  self._primary_mac_address_primary_mac_address = (
54  controller.mac_address or self._client_client.controllers[1].mac_address
55  )
56  self._device_identifier_device_identifier = (
57  self._controller_controller.mac_address
58  or f"{self._primary_mac_address}-{self._controller.controller_id}"
59  )
60  self._attr_device_info_attr_device_info = DeviceInfo(
61  # Use MAC address of Russound device as identifier
62  identifiers={(DOMAIN, self._device_identifier_device_identifier)},
63  manufacturer="Russound",
64  name=controller.controller_type,
65  model=controller.controller_type,
66  sw_version=controller.firmware_version,
67  )
68  if isinstance(self._client_client.connection_handler, RussoundTcpConnectionHandler):
69  self._attr_device_info_attr_device_info["configuration_url"] = (
70  f"http://{self._client.connection_handler.host}"
71  )
72  if controller.controller_id != 1:
73  assert self._client_client.controllers[1].mac_address
74  self._attr_device_info_attr_device_info["via_device"] = (
75  DOMAIN,
76  self._client_client.controllers[1].mac_address,
77  )
78  else:
79  assert controller.mac_address
80  self._attr_device_info_attr_device_info["connections"] = {
81  (CONNECTION_NETWORK_MAC, controller.mac_address)
82  }
83 
85  self, _client: RussoundClient, _callback_type: CallbackType
86  ) -> None:
87  """Call when the device is notified of changes."""
88  if _callback_type == CallbackType.CONNECTION:
89  self._attr_available_attr_available = _client.is_connected()
90  self._controller_controller = _client.controllers[self._controller_controller.controller_id]
91  self.async_write_ha_stateasync_write_ha_state()
92 
93  async def async_added_to_hass(self) -> None:
94  """Register callback handlers."""
95  await self._client_client.register_state_update_callbacks(self._state_update_callback_state_update_callback)
96 
97  async def async_will_remove_from_hass(self) -> None:
98  """Remove callbacks."""
99  self._client_client.unregister_state_update_callbacks(self._state_update_callback_state_update_callback)
None _state_update_callback(self, RussoundClient _client, CallbackType _callback_type)
Definition: entity.py:86