Refactor Sonos polling (#65722)
* 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
This commit is contained in:
parent
4efebcb86c
commit
a7fd477c64
14 changed files with 89 additions and 85 deletions
|
@ -7,7 +7,6 @@ import logging
|
|||
|
||||
import soco.config as soco_config
|
||||
from soco.core import SoCo
|
||||
from soco.exceptions import SoCoException
|
||||
|
||||
from homeassistant.components import persistent_notification
|
||||
import homeassistant.helpers.device_registry as dr
|
||||
|
@ -17,10 +16,11 @@ from homeassistant.helpers.entity import DeviceInfo, Entity
|
|||
from .const import (
|
||||
DATA_SONOS,
|
||||
DOMAIN,
|
||||
SONOS_FALLBACK_POLL,
|
||||
SONOS_FAVORITES_UPDATED,
|
||||
SONOS_POLL_UPDATE,
|
||||
SONOS_STATE_UPDATED,
|
||||
)
|
||||
from .exception import SonosUpdateError
|
||||
from .speaker import SonosSpeaker
|
||||
|
||||
SUB_FAIL_URL = "https://www.home-assistant.io/integrations/sonos/#network-requirements"
|
||||
|
@ -43,8 +43,8 @@ class SonosEntity(Entity):
|
|||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
f"{SONOS_POLL_UPDATE}-{self.soco.uid}",
|
||||
self.async_poll,
|
||||
f"{SONOS_FALLBACK_POLL}-{self.soco.uid}",
|
||||
self.async_fallback_poll,
|
||||
)
|
||||
)
|
||||
self.async_on_remove(
|
||||
|
@ -66,7 +66,7 @@ class SonosEntity(Entity):
|
|||
"""Clean up when entity is removed."""
|
||||
del self.hass.data[DATA_SONOS].entity_id_mappings[self.entity_id]
|
||||
|
||||
async def async_poll(self, now: datetime.datetime) -> None:
|
||||
async def async_fallback_poll(self, now: datetime.datetime) -> None:
|
||||
"""Poll the entity if subscriptions fail."""
|
||||
if not self.speaker.subscriptions_failed:
|
||||
if soco_config.EVENT_ADVERTISE_IP:
|
||||
|
@ -86,13 +86,16 @@ class SonosEntity(Entity):
|
|||
self.speaker.subscriptions_failed = True
|
||||
await self.speaker.async_unsubscribe()
|
||||
try:
|
||||
await self._async_poll()
|
||||
except (OSError, SoCoException) as ex:
|
||||
_LOGGER.debug("Error connecting to %s: %s", self.entity_id, ex)
|
||||
await self._async_fallback_poll()
|
||||
except SonosUpdateError as err:
|
||||
_LOGGER.debug("Could not fallback poll: %s", err)
|
||||
|
||||
@abstractmethod
|
||||
async def _async_poll(self) -> None:
|
||||
"""Poll the specific functionality. Should be implemented by platforms if needed."""
|
||||
async def _async_fallback_poll(self) -> None:
|
||||
"""Poll the specific functionality if subscriptions fail.
|
||||
|
||||
Should be implemented by platforms if needed.
|
||||
"""
|
||||
|
||||
@property
|
||||
def soco(self) -> SoCo:
|
||||
|
@ -120,3 +123,20 @@ class SonosEntity(Entity):
|
|||
def available(self) -> bool:
|
||||
"""Return whether this device is available."""
|
||||
return self.speaker.available
|
||||
|
||||
|
||||
class SonosPollingEntity(SonosEntity):
|
||||
"""Representation of a Sonos entity which may not support updating by subscriptions."""
|
||||
|
||||
@abstractmethod
|
||||
def poll_state(self) -> None:
|
||||
"""Poll the device for the current state."""
|
||||
|
||||
def update(self) -> None:
|
||||
"""Update the state using the built-in entity poller."""
|
||||
if not self.available:
|
||||
return
|
||||
try:
|
||||
self.poll_state()
|
||||
except SonosUpdateError as err:
|
||||
_LOGGER.debug("Could not poll: %s", err)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue