Home Assistant Unofficial Reference 2024.12.1
entity.py
Go to the documentation of this file.
1 """Code to handle a Xiaomi Device."""
2 
3 import datetime
4 from enum import Enum
5 from functools import partial
6 import logging
7 from typing import Any
8 
9 from miio import DeviceException
10 
11 from homeassistant.const import ATTR_CONNECTIONS, CONF_MAC, CONF_MODEL
12 from homeassistant.helpers import device_registry as dr
13 from homeassistant.helpers.device_registry import DeviceInfo
14 from homeassistant.helpers.entity import Entity
16  CoordinatorEntity,
17  DataUpdateCoordinator,
18 )
19 
20 from .const import ATTR_AVAILABLE, DOMAIN
21 
22 _LOGGER = logging.getLogger(__name__)
23 
24 
26  """Representation of a base Xiaomi Miio Entity."""
27 
28  def __init__(self, name, device, entry, unique_id):
29  """Initialize the Xiaomi Miio Device."""
30  self._device_device = device
31  self._model_model = entry.data[CONF_MODEL]
32  self._mac_mac = entry.data[CONF_MAC]
33  self._device_id_device_id = entry.unique_id
34  self._unique_id_unique_id = unique_id
35  self._name_name = name
36  self._available_available = None
37 
38  @property
39  def unique_id(self):
40  """Return an unique ID."""
41  return self._unique_id_unique_id
42 
43  @property
44  def name(self):
45  """Return the name of this entity, if any."""
46  return self._name_name
47 
48  @property
49  def device_info(self) -> DeviceInfo:
50  """Return the device info."""
51  device_info = DeviceInfo(
52  identifiers={(DOMAIN, self._device_id_device_id)},
53  manufacturer="Xiaomi",
54  model=self._model_model,
55  name=self._name_name,
56  )
57 
58  if self._mac_mac is not None:
59  device_info[ATTR_CONNECTIONS] = {(dr.CONNECTION_NETWORK_MAC, self._mac_mac)}
60 
61  return device_info
62 
63 
64 class XiaomiCoordinatedMiioEntity[_T: DataUpdateCoordinator[Any]](
65  CoordinatorEntity[_T]
66 ):
67  """Representation of a base a coordinated Xiaomi Miio Entity."""
68 
69  _attr_has_entity_name = True
70 
71  def __init__(self, device, entry, unique_id, coordinator):
72  """Initialize the coordinated Xiaomi Miio Device."""
73  super().__init__(coordinator)
74  self._device = device
75  self._model = entry.data[CONF_MODEL]
76  self._mac = entry.data[CONF_MAC]
77  self._device_id = entry.unique_id
78  self._device_name = entry.title
79  self._unique_id = unique_id
80 
81  @property
82  def unique_id(self):
83  """Return an unique ID."""
84  return self._unique_id
85 
86  @property
87  def device_info(self) -> DeviceInfo:
88  """Return the device info."""
89  device_info = DeviceInfo(
90  identifiers={(DOMAIN, self._device_id)},
91  manufacturer="Xiaomi",
92  model=self._model,
93  name=self._device_name,
94  )
95 
96  if self._mac is not None:
97  device_info[ATTR_CONNECTIONS] = {(dr.CONNECTION_NETWORK_MAC, self._mac)}
98 
99  return device_info
100 
101  async def _try_command(self, mask_error, func, *args, **kwargs):
102  """Call a miio device command handling error messages."""
103  try:
104  result = await self.hass.async_add_executor_job(
105  partial(func, *args, **kwargs)
106  )
107  except DeviceException as exc:
108  if self.available:
109  _LOGGER.error(mask_error, exc)
110 
111  return False
112 
113  _LOGGER.debug("Response received from miio device: %s", result)
114  return True
115 
116  @classmethod
117  def _extract_value_from_attribute(cls, state, attribute):
118  value = getattr(state, attribute)
119  if isinstance(value, Enum):
120  return value.value
121  if isinstance(value, datetime.timedelta):
122  return cls._parse_time_delta(value)
123  if isinstance(value, datetime.time):
124  return cls._parse_datetime_time(value)
125  if isinstance(value, datetime.datetime):
126  return cls._parse_datetime_datetime(value)
127 
128  if value is None:
129  _LOGGER.debug("Attribute %s is None, this is unexpected", attribute)
130 
131  return value
132 
133  @staticmethod
134  def _parse_time_delta(timedelta: datetime.timedelta) -> int:
135  return int(timedelta.total_seconds())
136 
137  @staticmethod
138  def _parse_datetime_time(initial_time: datetime.time) -> str:
139  time = datetime.datetime.now().replace(
140  hour=initial_time.hour, minute=initial_time.minute, second=0, microsecond=0
141  )
142 
143  if time < datetime.datetime.now():
144  time += datetime.timedelta(days=1)
145 
146  return time.isoformat()
147 
148  @staticmethod
149  def _parse_datetime_datetime(time: datetime.datetime) -> str:
150  return time.isoformat()
151 
152 
154  """Representation of a base Xiaomi Gateway Device."""
155 
156  def __init__(self, coordinator, sub_device, entry):
157  """Initialize the Xiaomi Gateway Device."""
158  super().__init__(coordinator)
159  self._sub_device_sub_device = sub_device
160  self._entry_entry = entry
161  self._unique_id_unique_id = sub_device.sid
162  self._name_name = f"{sub_device.name} ({sub_device.sid})"
163 
164  @property
165  def unique_id(self):
166  """Return an unique ID."""
167  return self._unique_id_unique_id
168 
169  @property
170  def name(self):
171  """Return the name of this entity, if any."""
172  return self._name_name
173 
174  @property
175  def device_info(self) -> DeviceInfo:
176  """Return the device info of the gateway."""
177  return DeviceInfo(
178  identifiers={(DOMAIN, self._sub_device_sub_device.sid)},
179  via_device=(DOMAIN, self._entry_entry.unique_id),
180  manufacturer="Xiaomi",
181  name=self._sub_device_sub_device.name,
182  model=self._sub_device_sub_device.model,
183  sw_version=self._sub_device_sub_device.firmware_version,
184  hw_version=self._sub_device_sub_device.zigbee_model,
185  )
186 
187  @property
188  def available(self):
189  """Return if entity is available."""
190  if self.coordinator.data is None:
191  return False
192 
193  return self.coordinator.data[ATTR_AVAILABLE]
def __init__(self, coordinator, sub_device, entry)
Definition: entity.py:156
def __init__(self, name, device, entry, unique_id)
Definition: entity.py:28
str _parse_datetime_time(datetime.time initial_time)
Definition: entity.py:138
int _parse_time_delta(datetime.timedelta timedelta)
Definition: entity.py:134
def _extract_value_from_attribute(cls, state, attribute)
Definition: entity.py:117
def _try_command(self, mask_error, func, *args, **kwargs)
Definition: entity.py:101
def __init__(self, device, entry, unique_id, coordinator)
Definition: entity.py:71
str _parse_datetime_datetime(datetime.datetime time)
Definition: entity.py:149