Home Assistant Unofficial Reference 2024.12.1
entity.py
Go to the documentation of this file.
1 """Ecovacs mqtt entity module."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Coroutine
6 from dataclasses import dataclass
7 from typing import Any, Generic, TypeVar
8 
9 from deebot_client.capabilities import Capabilities
10 from deebot_client.device import Device
11 from deebot_client.events import AvailabilityEvent
12 from deebot_client.events.base import Event
13 from sucks import EventListener, VacBot
14 
15 from homeassistant.helpers import device_registry as dr
16 from homeassistant.helpers.device_registry import DeviceInfo
17 from homeassistant.helpers.entity import Entity, EntityDescription
18 
19 from .const import DOMAIN
20 
21 CapabilityEntity = TypeVar("CapabilityEntity")
22 EventT = TypeVar("EventT", bound=Event)
23 
24 
25 class EcovacsEntity(Entity, Generic[CapabilityEntity]):
26  """Ecovacs entity."""
27 
28  _attr_should_poll = False
29  _attr_has_entity_name = True
30  _always_available: bool = False
31 
32  def __init__(
33  self,
34  device: Device,
35  capability: CapabilityEntity,
36  **kwargs: Any,
37  ) -> None:
38  """Initialize entity."""
39  super().__init__(**kwargs)
40  self._attr_unique_id_attr_unique_id = (
41  f"{device.device_info['did']}_{self.entity_description.key}"
42  )
43 
44  self._device_device = device
45  self._capability_capability = capability
46  self._subscribed_events: set[type[Event]] = set()
47 
48  @property
49  def device_info(self) -> DeviceInfo | None:
50  """Return device specific attributes."""
51  device_info = self._device_device.device_info
52  info = DeviceInfo(
53  identifiers={(DOMAIN, device_info["did"])},
54  manufacturer="Ecovacs",
55  sw_version=self._device_device.fw_version,
56  serial_number=device_info["name"],
57  model_id=device_info["class"],
58  )
59 
60  if nick := device_info.get("nick"):
61  info["name"] = nick
62 
63  if model := device_info.get("deviceName"):
64  info["model"] = model
65 
66  if mac := self._device_device.mac:
67  info["connections"] = {(dr.CONNECTION_NETWORK_MAC, mac)}
68 
69  return info
70 
71  async def async_added_to_hass(self) -> None:
72  """Set up the event listeners now that hass is ready."""
73  await super().async_added_to_hass()
74 
75  if not self._always_available:
76 
77  async def on_available(event: AvailabilityEvent) -> None:
78  self._attr_available_attr_available = event.available
79  self.async_write_ha_stateasync_write_ha_state()
80 
81  self._subscribe_subscribe(AvailabilityEvent, on_available)
82 
84  self,
85  event_type: type[EventT],
86  callback: Callable[[EventT], Coroutine[Any, Any, None]],
87  ) -> None:
88  """Subscribe to events."""
89  self._subscribed_events.add(event_type)
90  self.async_on_removeasync_on_remove(self._device_device.events.subscribe(event_type, callback))
91 
92  async def async_update(self) -> None:
93  """Update the entity.
94 
95  Only used by the generic entity update service.
96  """
97  for event_type in self._subscribed_events:
98  self._device_device.events.request_refresh(event_type)
99 
100 
101 class EcovacsDescriptionEntity(EcovacsEntity[CapabilityEntity]):
102  """Ecovacs entity."""
103 
104  def __init__(
105  self,
106  device: Device,
107  capability: CapabilityEntity,
108  entity_description: EntityDescription,
109  **kwargs: Any,
110  ) -> None:
111  """Initialize entity."""
112  self.entity_descriptionentity_description = entity_description
113  super().__init__(device, capability, **kwargs)
114 
115 
116 @dataclass(kw_only=True, frozen=True)
118  EntityDescription,
119  Generic[CapabilityEntity],
120 ):
121  """Ecovacs entity description."""
122 
123  capability_fn: Callable[[Capabilities], CapabilityEntity | None]
124 
125 
127  """Ecovacs legacy bot entity."""
128 
129  _attr_has_entity_name = True
130  _attr_should_poll = False
131 
132  def __init__(self, device: VacBot) -> None:
133  """Initialize the legacy Ecovacs entity."""
134  self.devicedevice = device
135  vacuum = device.vacuum
136 
137  self.error: str | None = None
138  self._attr_unique_id_attr_unique_id = vacuum["did"]
139 
140  if (name := vacuum.get("nick")) is None:
141  name = vacuum["did"]
142 
143  self._attr_device_info_attr_device_info = DeviceInfo(
144  identifiers={(DOMAIN, vacuum["did"])},
145  manufacturer="Ecovacs",
146  model=vacuum.get("deviceName"),
147  name=name,
148  serial_number=vacuum["did"],
149  )
150 
151  self._event_listeners: list[EventListener] = []
152 
153  @property
154  def available(self) -> bool:
155  """Return True if the entity is available."""
156  return super().available and self.statestate is not None
157 
158  async def async_will_remove_from_hass(self) -> None:
159  """Remove event listeners on entity remove."""
160  for listener in self._event_listeners:
161  listener.unsubscribe()
None __init__(self, Device device, CapabilityEntity capability, EntityDescription entity_description, **Any kwargs)
Definition: entity.py:110
None __init__(self, Device device, CapabilityEntity capability, **Any kwargs)
Definition: entity.py:37
None _subscribe(self, type[EventT] event_type, Callable[[EventT], Coroutine[Any, Any, None]] callback)
Definition: entity.py:87
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
bool add(self, _T matcher)
Definition: match.py:185