From e86c82e6750a036a9b9b8bb7ede9f40647f87174 Mon Sep 17 00:00:00 2001 From: jjlawren Date: Thu, 10 Feb 2022 14:11:47 -0600 Subject: [PATCH] Tweak Sonos activity monitoring (#66207) * Tweak Sonos activity monitoring * Support new 'sleeping' vanish reason * Check availability before last-ditch check * Use short-timeout call for last-ditch check * Adjust reboot logging message and severity * Simplify activity check failure --- homeassistant/components/sonos/speaker.py | 39 +++++++++++++---------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/sonos/speaker.py b/homeassistant/components/sonos/speaker.py index ed530704550..16ca58448e2 100644 --- a/homeassistant/components/sonos/speaker.py +++ b/homeassistant/components/sonos/speaker.py @@ -79,6 +79,7 @@ SUBSCRIPTION_SERVICES = [ "renderingControl", "zoneGroupTopology", ] +SUPPORTED_VANISH_REASONS = ("sleeping", "upgrade") UNAVAILABLE_VALUES = {"", "NOT_IMPLEMENTED", None} UNUSED_DEVICE_KEYS = ["SPID", "TargetRoomName"] @@ -553,25 +554,29 @@ class SonosSpeaker: async def async_check_activity(self, now: datetime.datetime) -> None: """Validate availability of the speaker based on recent activity.""" + if not self.available: + return if time.monotonic() - self._last_activity < AVAILABILITY_TIMEOUT: return try: - _ = await self.hass.async_add_executor_job(getattr, self.soco, "volume") - except (OSError, SoCoException): - pass + # Make a short-timeout call as a final check + # before marking this speaker as unavailable + await self.hass.async_add_executor_job( + partial( + self.soco.renderingControl.GetVolume, + [("InstanceID", 0), ("Channel", "Master")], + timeout=1, + ) + ) + except OSError: + _LOGGER.warning( + "No recent activity and cannot reach %s, marking unavailable", + self.zone_name, + ) + await self.async_offline() else: self.speaker_activity("timeout poll") - return - - if not self.available: - return - - _LOGGER.warning( - "No recent activity and cannot reach %s, marking unavailable", - self.zone_name, - ) - await self.async_offline() async def async_offline(self) -> None: """Handle removal of speaker when unavailable.""" @@ -603,8 +608,8 @@ class SonosSpeaker: async def async_rebooted(self, soco: SoCo) -> None: """Handle a detected speaker reboot.""" - _LOGGER.warning( - "%s rebooted or lost network connectivity, reconnecting with %s", + _LOGGER.debug( + "%s rebooted, reconnecting with %s", self.zone_name, soco, ) @@ -717,7 +722,9 @@ class SonosSpeaker: if xml := event.variables.get("zone_group_state"): zgs = ET.fromstring(xml) for vanished_device in zgs.find("VanishedDevices") or []: - if (reason := vanished_device.get("Reason")) != "sleeping": + if ( + reason := vanished_device.get("Reason") + ) not in SUPPORTED_VANISH_REASONS: _LOGGER.debug( "Ignoring %s marked %s as vanished with reason: %s", self.zone_name,