Home Assistant Unofficial Reference 2024.12.1
coordinator.py
Go to the documentation of this file.
1 """The Fjäråskupan data update coordinator."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import AsyncIterator
6 from contextlib import asynccontextmanager, contextmanager
7 from datetime import timedelta
8 import logging
9 
10 from fjaraskupan import (
11  Device,
12  FjaraskupanConnectionError,
13  FjaraskupanError,
14  FjaraskupanReadError,
15  FjaraskupanWriteError,
16  State,
17 )
18 
20  BluetoothServiceInfoBleak,
21  async_address_present,
22  async_ble_device_from_address,
23 )
24 from homeassistant.core import HomeAssistant
25 from homeassistant.exceptions import HomeAssistantError
26 from homeassistant.helpers.device_registry import DeviceInfo
27 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
28 
29 from .const import DOMAIN
30 
31 _LOGGER = logging.getLogger(__name__)
32 
33 
34 @contextmanager
36  """Convert exception so home assistant translated ones."""
37 
38  try:
39  yield
40  except FjaraskupanWriteError as exception:
41  raise HomeAssistantError(
42  translation_domain=DOMAIN, translation_key="write_error"
43  ) from exception
44  except FjaraskupanReadError as exception:
45  raise HomeAssistantError(
46  translation_domain=DOMAIN, translation_key="read_error"
47  ) from exception
48  except FjaraskupanConnectionError as exception:
49  raise HomeAssistantError(
50  translation_domain=DOMAIN, translation_key="connection_error"
51  ) from exception
52  except FjaraskupanError as exception:
53  raise HomeAssistantError(
54  translation_domain=DOMAIN,
55  translation_key="unexpected_error",
56  translation_placeholders={"msg": str(exception)},
57  ) from exception
58 
59 
61  """Exception to indicate that we cannot connect to device."""
62 
63 
64 class FjaraskupanCoordinator(DataUpdateCoordinator[State]):
65  """Update coordinator for each device."""
66 
67  def __init__(
68  self, hass: HomeAssistant, device: Device, device_info: DeviceInfo
69  ) -> None:
70  """Initialize the coordinator."""
71  self.devicedevice = device
72  self.device_infodevice_info = device_info
73  self._refresh_was_scheduled_refresh_was_scheduled = False
74 
75  super().__init__(
76  hass, _LOGGER, name="Fjäråskupan", update_interval=timedelta(seconds=120)
77  )
78 
79  async def _async_refresh(
80  self,
81  log_failures: bool = True,
82  raise_on_auth_failed: bool = False,
83  scheduled: bool = False,
84  raise_on_entry_error: bool = False,
85  ) -> None:
86  self._refresh_was_scheduled_refresh_was_scheduled = scheduled
87  await super()._async_refresh(
88  log_failures=log_failures,
89  raise_on_auth_failed=raise_on_auth_failed,
90  scheduled=scheduled,
91  raise_on_entry_error=raise_on_entry_error,
92  )
93 
94  async def _async_update_data(self) -> State:
95  """Handle an explicit update request."""
96  if self._refresh_was_scheduled_refresh_was_scheduled:
97  if async_address_present(self.hasshass, self.devicedevice.address, False):
98  return self.devicedevice.state
99  raise UpdateFailed(
100  "No data received within schedule, and device is no longer present"
101  )
102 
103  if (
104  ble_device := async_ble_device_from_address(
105  self.hasshass, self.devicedevice.address, True
106  )
107  ) is None:
108  raise UpdateFailed("No connectable path to device")
109 
110  with exception_converter():
111  async with self.devicedevice.connect(ble_device) as device:
112  await device.update()
113 
114  return self.devicedevice.state
115 
116  def detection_callback(self, service_info: BluetoothServiceInfoBleak) -> None:
117  """Handle a new announcement of data."""
118  self.devicedevice.detection_callback(service_info.device, service_info.advertisement)
119  self.async_set_updated_dataasync_set_updated_data(self.devicedevice.state)
120 
121  @asynccontextmanager
122  async def async_connect_and_update(self) -> AsyncIterator[Device]:
123  """Provide an up-to-date device for use during connections."""
124  if (
125  ble_device := async_ble_device_from_address(
126  self.hasshass, self.devicedevice.address, True
127  )
128  ) is None:
129  raise UnableToConnect("No connectable path to device")
130 
131  with exception_converter():
132  async with self.devicedevice.connect(ble_device) as device:
133  yield device
134 
135  self.async_set_updated_dataasync_set_updated_data(self.devicedevice.state)
None _async_refresh(self, bool log_failures=True, bool raise_on_auth_failed=False, bool scheduled=False, bool raise_on_entry_error=False)
Definition: coordinator.py:85
None detection_callback(self, BluetoothServiceInfoBleak service_info)
Definition: coordinator.py:116
None __init__(self, HomeAssistant hass, Device device, DeviceInfo device_info)
Definition: coordinator.py:69
BLEDevice|None async_ble_device_from_address(HomeAssistant hass, str address, bool connectable=True)
Definition: api.py:88
bool async_address_present(HomeAssistant hass, str address, bool connectable=True)
Definition: api.py:104