Home Assistant Unofficial Reference 2024.12.1
coordinator.py
Go to the documentation of this file.
1 """YoLink DataUpdateCoordinator."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from datetime import UTC, datetime, timedelta
7 import logging
8 
9 from yolink.device import YoLinkDevice
10 from yolink.exception import YoLinkAuthFailError, YoLinkClientError
11 
12 from homeassistant.core import HomeAssistant
13 from homeassistant.exceptions import ConfigEntryAuthFailed
14 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
15 
16 from .const import ATTR_DEVICE_STATE, DOMAIN, YOLINK_OFFLINE_TIME
17 
18 _LOGGER = logging.getLogger(__name__)
19 
20 
22  """YoLink DataUpdateCoordinator."""
23 
24  def __init__(
25  self,
26  hass: HomeAssistant,
27  device: YoLinkDevice,
28  paired_device: YoLinkDevice | None = None,
29  ) -> None:
30  """Init YoLink DataUpdateCoordinator.
31 
32  fetch state every 30 minutes base on yolink device heartbeat interval
33  data is None before the first successful update, but we need to use
34  data at first update
35  """
36  super().__init__(
37  hass, _LOGGER, name=DOMAIN, update_interval=timedelta(minutes=30)
38  )
39  self.devicedevice = device
40  self.paired_devicepaired_device = paired_device
41  self.dev_onlinedev_online = True
42 
43  async def _async_update_data(self) -> dict:
44  """Fetch device state."""
45  try:
46  async with asyncio.timeout(10):
47  device_state_resp = await self.devicedevice.fetch_state()
48  device_state = device_state_resp.data.get(ATTR_DEVICE_STATE)
49  device_reporttime = device_state_resp.data.get("reportAt")
50  if device_reporttime is not None:
51  rpt_time_delta = (
52  datetime.now(tz=UTC).replace(tzinfo=None)
53  - datetime.strptime(device_reporttime, "%Y-%m-%dT%H:%M:%S.%fZ")
54  ).total_seconds()
55  self.dev_onlinedev_online = rpt_time_delta < YOLINK_OFFLINE_TIME
56  if self.paired_devicepaired_device is not None and device_state is not None:
57  paried_device_state_resp = await self.paired_devicepaired_device.fetch_state()
58  paried_device_state = paried_device_state_resp.data.get(
59  ATTR_DEVICE_STATE
60  )
61  if (
62  paried_device_state is not None
63  and ATTR_DEVICE_STATE in paried_device_state
64  ):
65  device_state[ATTR_DEVICE_STATE] = paried_device_state[
66  ATTR_DEVICE_STATE
67  ]
68  except YoLinkAuthFailError as yl_auth_err:
69  raise ConfigEntryAuthFailed from yl_auth_err
70  except YoLinkClientError as yl_client_err:
71  raise UpdateFailed from yl_client_err
72  if device_state is not None:
73  return device_state
74  return {}