Handle failures during initial Sonos subscription (#73456)

This commit is contained in:
jjlawren 2022-06-22 10:56:17 -05:00 committed by GitHub
parent 143e6a7adc
commit 86fde1a644
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 14 deletions

View file

@ -57,7 +57,7 @@ from .const import (
SONOS_VANISHED,
SUBSCRIPTION_TIMEOUT,
)
from .exception import S1BatteryMissing, SonosUpdateError
from .exception import S1BatteryMissing, SonosSubscriptionsFailed, SonosUpdateError
from .favorites import SonosFavorites
from .helpers import soco_error
from .media import SonosMedia
@ -324,12 +324,29 @@ class SonosSpeaker:
async with self._subscription_lock:
if self._subscriptions:
return
await self._async_subscribe()
try:
await self._async_subscribe()
except SonosSubscriptionsFailed:
_LOGGER.warning("Creating subscriptions failed for %s", self.zone_name)
await self._async_offline()
async def _async_subscribe(self) -> None:
"""Create event subscriptions."""
_LOGGER.debug("Creating subscriptions for %s", self.zone_name)
subscriptions = [
self._subscribe(getattr(self.soco, service), self.async_dispatch_event)
for service in SUBSCRIPTION_SERVICES
]
results = await asyncio.gather(*subscriptions, return_exceptions=True)
for result in results:
self.log_subscription_result(
result, "Creating subscription", logging.WARNING
)
if any(isinstance(result, Exception) for result in results):
raise SonosSubscriptionsFailed
# Create a polling task in case subscriptions fail or callback events do not arrive
if not self._poll_timer:
self._poll_timer = async_track_time_interval(
@ -342,16 +359,6 @@ class SonosSpeaker:
SCAN_INTERVAL,
)
subscriptions = [
self._subscribe(getattr(self.soco, service), self.async_dispatch_event)
for service in SUBSCRIPTION_SERVICES
]
results = await asyncio.gather(*subscriptions, return_exceptions=True)
for result in results:
self.log_subscription_result(
result, "Creating subscription", logging.WARNING
)
async def _subscribe(
self, target: SubscriptionBase, sub_callback: Callable
) -> None:
@ -585,6 +592,11 @@ class SonosSpeaker:
await self.async_offline()
async def async_offline(self) -> None:
"""Handle removal of speaker when unavailable."""
async with self._subscription_lock:
await self._async_offline()
async def _async_offline(self) -> None:
"""Handle removal of speaker when unavailable."""
if not self.available:
return
@ -602,8 +614,7 @@ class SonosSpeaker:
self._poll_timer()
self._poll_timer = None
async with self._subscription_lock:
await self.async_unsubscribe()
await self.async_unsubscribe()
self.hass.data[DATA_SONOS].discovery_known.discard(self.soco.uid)