mirror of
https://github.com/home-assistant/core
synced 2024-09-03 08:14:07 +02:00
![jjlawren](/assets/img/avatar_default.png)
* Refactor Sonos polling Explicitly rename fallback polling Catch soco exceptions centrally where possible Create SonosPollingEntity subclass Remove unnecessary soco_error fixture argument Remove unnecessary polling in update_volume() Adjust log levels and wording Set explicit timeout on library * Adjust logging to use raised exceptions * Simplify availabiliity checks when using built-in poller * Fix typing for return values
79 lines
2.5 KiB
Python
79 lines
2.5 KiB
Python
"""Class representing a Sonos household storage helper."""
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from collections.abc import Callable, Coroutine
|
|
import logging
|
|
|
|
from soco import SoCo
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.debounce import Debouncer
|
|
|
|
from .const import DATA_SONOS
|
|
from .exception import SonosUpdateError
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
class SonosHouseholdCoordinator:
|
|
"""Base class for Sonos household-level storage."""
|
|
|
|
def __init__(self, hass: HomeAssistant, household_id: str) -> None:
|
|
"""Initialize the data."""
|
|
self.hass = hass
|
|
self.household_id = household_id
|
|
self.async_poll: Callable[[], Coroutine[None, None, None]] | None = None
|
|
self.last_processed_event_id: int | None = None
|
|
self.cache_update_lock: asyncio.Lock | None = None
|
|
|
|
def setup(self, soco: SoCo) -> None:
|
|
"""Set up the SonosAlarm instance."""
|
|
self.update_cache(soco)
|
|
self.hass.add_job(self._async_setup)
|
|
|
|
async def _async_setup(self) -> None:
|
|
"""Finish setup in async context."""
|
|
self.cache_update_lock = asyncio.Lock()
|
|
self.async_poll = Debouncer(
|
|
self.hass,
|
|
_LOGGER,
|
|
cooldown=3,
|
|
immediate=False,
|
|
function=self._async_poll,
|
|
).async_call
|
|
|
|
@property
|
|
def class_type(self) -> str:
|
|
"""Return the class type of this instance."""
|
|
return type(self).__name__
|
|
|
|
async def _async_poll(self) -> None:
|
|
"""Poll any known speaker."""
|
|
discovered = self.hass.data[DATA_SONOS].discovered
|
|
|
|
for uid, speaker in discovered.items():
|
|
_LOGGER.debug("Polling %s using %s", self.class_type, speaker.soco)
|
|
try:
|
|
await self.async_update_entities(speaker.soco)
|
|
except SonosUpdateError as err:
|
|
_LOGGER.error(
|
|
"Could not refresh %s: %s",
|
|
self.class_type,
|
|
err,
|
|
)
|
|
else:
|
|
# Prefer this SoCo instance next update
|
|
discovered.move_to_end(uid, last=False)
|
|
break
|
|
|
|
async def async_update_entities(
|
|
self, soco: SoCo, update_id: int | None = None
|
|
) -> None:
|
|
"""Update the cache and update entities."""
|
|
raise NotImplementedError()
|
|
|
|
def update_cache(self, soco: SoCo, update_id: int | None = None) -> bool:
|
|
"""Update the cache of the household-level feature and return if cache has changed."""
|
|
raise NotImplementedError()
|