Home Assistant Unofficial Reference 2024.12.1
coordinator.py
Go to the documentation of this file.
1 """Data UpdateCoordinator for the Husqvarna Automower integration."""
2 
3 import asyncio
4 from datetime import timedelta
5 import logging
6 
7 from aioautomower.exceptions import (
8  ApiException,
9  AuthException,
10  HusqvarnaWSServerHandshakeError,
11  TimeoutException,
12 )
13 from aioautomower.model import MowerAttributes
14 from aioautomower.session import AutomowerSession
15 
16 from homeassistant.config_entries import ConfigEntry
17 from homeassistant.core import HomeAssistant, callback
18 from homeassistant.exceptions import ConfigEntryAuthFailed
19 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
20 
21 from .const import DOMAIN
22 
23 _LOGGER = logging.getLogger(__name__)
24 MAX_WS_RECONNECT_TIME = 600
25 SCAN_INTERVAL = timedelta(minutes=8)
26 DEFAULT_RECONNECT_TIME = 2 # Define a default reconnect time
27 
28 
29 class AutomowerDataUpdateCoordinator(DataUpdateCoordinator[dict[str, MowerAttributes]]):
30  """Class to manage fetching Husqvarna data."""
31 
32  config_entry: ConfigEntry
33 
34  def __init__(
35  self, hass: HomeAssistant, api: AutomowerSession, entry: ConfigEntry
36  ) -> None:
37  """Initialize data updater."""
38  super().__init__(
39  hass,
40  _LOGGER,
41  name=DOMAIN,
42  update_interval=SCAN_INTERVAL,
43  )
44  self.apiapi = api
45  self.ws_connectedws_connected: bool = False
46  self.reconnect_timereconnect_time = DEFAULT_RECONNECT_TIME
47 
48  async def _async_update_data(self) -> dict[str, MowerAttributes]:
49  """Subscribe for websocket and poll data from the API."""
50  if not self.ws_connectedws_connected:
51  await self.apiapi.connect()
52  self.apiapi.register_data_callback(self.callbackcallback)
53  self.ws_connectedws_connected = True
54  try:
55  return await self.apiapi.get_status()
56  except ApiException as err:
57  raise UpdateFailed(err) from err
58  except AuthException as err:
59  raise ConfigEntryAuthFailed(err) from err
60 
61  @callback
62  def callback(self, ws_data: dict[str, MowerAttributes]) -> None:
63  """Process websocket callbacks and write them to the DataUpdateCoordinator."""
64  self.async_set_updated_dataasync_set_updated_data(ws_data)
65 
66  async def client_listen(
67  self,
68  hass: HomeAssistant,
69  entry: ConfigEntry,
70  automower_client: AutomowerSession,
71  ) -> None:
72  """Listen with the client."""
73  try:
74  await automower_client.auth.websocket_connect()
75  # Reset reconnect time after successful connection
76  self.reconnect_timereconnect_time = DEFAULT_RECONNECT_TIME
77  await automower_client.start_listening()
78  except HusqvarnaWSServerHandshakeError as err:
79  _LOGGER.debug(
80  "Failed to connect to websocket. Trying to reconnect: %s",
81  err,
82  )
83  except TimeoutException as err:
84  _LOGGER.debug(
85  "Failed to listen to websocket. Trying to reconnect: %s",
86  err,
87  )
88  if not hass.is_stopping:
89  await asyncio.sleep(self.reconnect_timereconnect_time)
90  self.reconnect_timereconnect_time = min(self.reconnect_timereconnect_time * 2, MAX_WS_RECONNECT_TIME)
91  entry.async_create_background_task(
92  hass,
93  self.client_listenclient_listen(hass, entry, automower_client),
94  "reconnect_task",
95  )
None client_listen(self, HomeAssistant hass, ConfigEntry entry, AutomowerSession automower_client)
Definition: coordinator.py:71
None __init__(self, HomeAssistant hass, AutomowerSession api, ConfigEntry entry)
Definition: coordinator.py:36
def get_status(hass, host, port)
Definition: panel.py:387