Home Assistant Unofficial Reference 2024.12.1
coordinator.py
Go to the documentation of this file.
1 """DataUpdateCoordinator for the Squeezebox integration."""
2 
3 from asyncio import timeout
4 from collections.abc import Callable
5 from datetime import timedelta
6 import logging
7 import re
8 from typing import Any
9 
10 from pysqueezebox import Player, Server
11 
12 from homeassistant.core import HomeAssistant, callback
13 from homeassistant.helpers.dispatcher import async_dispatcher_connect
14 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
15 from homeassistant.util import dt as dt_util
16 
17 from .const import (
18  PLAYER_UPDATE_INTERVAL,
19  SENSOR_UPDATE_INTERVAL,
20  SIGNAL_PLAYER_REDISCOVERED,
21  STATUS_API_TIMEOUT,
22  STATUS_SENSOR_LASTSCAN,
23  STATUS_SENSOR_NEEDSRESTART,
24  STATUS_SENSOR_RESCAN,
25 )
26 
27 _LOGGER = logging.getLogger(__name__)
28 
29 
31  """LMS Status custom coordinator."""
32 
33  def __init__(self, hass: HomeAssistant, lms: Server) -> None:
34  """Initialize my coordinator."""
35  super().__init__(
36  hass,
37  _LOGGER,
38  name=lms.name,
39  update_interval=timedelta(seconds=SENSOR_UPDATE_INTERVAL),
40  always_update=False,
41  )
42  self.lmslms = lms
43  self.newversion_regexnewversion_regex = re.compile("<.*$")
44 
45  async def _async_update_data(self) -> dict:
46  """Fetch data from LMS status call.
47 
48  Then we process only a subset to make then nice for HA
49  """
50  async with timeout(STATUS_API_TIMEOUT):
51  data = await self.lmslms.async_status()
52 
53  if not data:
54  raise UpdateFailed("No data from status poll")
55  _LOGGER.debug("Raw serverstatus %s=%s", self.lmslms.name, data)
56 
57  return self._prepare_status_data_prepare_status_data(data)
58 
59  def _prepare_status_data(self, data: dict) -> dict:
60  """Sensors that need the data changing for HA presentation."""
61 
62  # Binary sensors
63  # rescan bool are we rescanning alter poll not present if false
64  data[STATUS_SENSOR_RESCAN] = STATUS_SENSOR_RESCAN in data
65  # needsrestart bool pending lms plugin updates not present if false
66  data[STATUS_SENSOR_NEEDSRESTART] = STATUS_SENSOR_NEEDSRESTART in data
67 
68  # Sensors that need special handling
69  # 'lastscan': '1718431678', epoc -> ISO 8601 not always present
70  data[STATUS_SENSOR_LASTSCAN] = (
71  dt_util.utc_from_timestamp(int(data[STATUS_SENSOR_LASTSCAN]))
72  if STATUS_SENSOR_LASTSCAN in data
73  else None
74  )
75 
76  _LOGGER.debug("Processed serverstatus %s=%s", self.lmslms.name, data)
77  return data
78 
79 
81  """Coordinator for Squeezebox players."""
82 
83  def __init__(self, hass: HomeAssistant, player: Player, server_uuid: str) -> None:
84  """Initialize the coordinator."""
85  super().__init__(
86  hass,
87  _LOGGER,
88  name=player.name,
89  update_interval=timedelta(seconds=PLAYER_UPDATE_INTERVAL),
90  always_update=True,
91  )
92  self.playerplayer = player
93  self.availableavailable = True
94  self._remove_dispatcher_remove_dispatcher: Callable | None = None
95  self.server_uuidserver_uuid = server_uuid
96 
97  async def _async_update_data(self) -> dict[str, Any]:
98  """Update Player if available, or listen for rediscovery if not."""
99  if self.availableavailable:
100  # Only update players available at last update, unavailable players are rediscovered instead
101  await self.playerplayer.async_update()
102 
103  if self.playerplayer.connected is False:
104  _LOGGER.debug("Player %s is not available", self.namename)
105  self.availableavailable = False
106 
107  # start listening for restored players
109  self.hasshass, SIGNAL_PLAYER_REDISCOVERED, self.rediscoveredrediscovered
110  )
111  return {}
112 
113  @callback
114  def rediscovered(self, unique_id: str, connected: bool) -> None:
115  """Make a player available again."""
116  if unique_id == self.playerplayer.player_id and connected:
117  self.availableavailable = True
118  _LOGGER.debug("Player %s is available again", self.namename)
119  if self._remove_dispatcher_remove_dispatcher:
120  self._remove_dispatcher_remove_dispatcher()
None __init__(self, HomeAssistant hass, Player player, str server_uuid)
Definition: coordinator.py:83
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103