From a2fbc4218de269b545e59dde338a8d4afb7a30d9 Mon Sep 17 00:00:00 2001 From: jjlawren Date: Tue, 20 Jul 2021 13:21:48 -0500 Subject: [PATCH] Cleanup regroup handling in Sonos (#53241) Check event before creating coroutine Remove unnecessary regrouping dispatcher Update typing to reflect actual behavior Add optimizations for polling mode --- homeassistant/components/sonos/__init__.py | 16 +------- homeassistant/components/sonos/const.py | 1 - homeassistant/components/sonos/speaker.py | 44 +++++++++++----------- 3 files changed, 22 insertions(+), 39 deletions(-) diff --git a/homeassistant/components/sonos/__init__.py b/homeassistant/components/sonos/__init__.py index ec26373c44e..26541db5fd8 100644 --- a/homeassistant/components/sonos/__init__.py +++ b/homeassistant/components/sonos/__init__.py @@ -19,11 +19,7 @@ from homeassistant import config_entries from homeassistant.components import ssdp from homeassistant.components.media_player import DOMAIN as MP_DOMAIN from homeassistant.config_entries import ConfigEntry -from homeassistant.const import ( - CONF_HOSTS, - EVENT_HOMEASSISTANT_START, - EVENT_HOMEASSISTANT_STOP, -) +from homeassistant.const import CONF_HOSTS, EVENT_HOMEASSISTANT_STOP from homeassistant.core import Event, HomeAssistant, callback from homeassistant.helpers import config_validation as cv from homeassistant.helpers.dispatcher import async_dispatcher_send, dispatcher_send @@ -35,7 +31,6 @@ from .const import ( DISCOVERY_INTERVAL, DOMAIN, PLATFORMS, - SONOS_GROUP_UPDATE, SONOS_REBOOTED, SONOS_SEEN, UPNP_ST, @@ -226,10 +221,6 @@ class SonosDiscoveryManager: DISCOVERY_INTERVAL.total_seconds(), self._manual_hosts ) - @callback - def _async_signal_update_groups(self, _event): - async_dispatcher_send(self.hass, SONOS_GROUP_UPDATE) - def _discovered_ip(self, ip_address): soco = _create_soco(ip_address, SoCoCreationSource.DISCOVERED) if soco and soco.is_visible: @@ -290,11 +281,6 @@ class SonosDiscoveryManager: for platform in PLATFORMS ) ) - self.entry.async_on_unload( - self.hass.bus.async_listen_once( - EVENT_HOMEASSISTANT_START, self._async_signal_update_groups - ) - ) self.entry.async_on_unload( self.hass.bus.async_listen_once( EVENT_HOMEASSISTANT_STOP, self._async_stop_event_listener diff --git a/homeassistant/components/sonos/const.py b/homeassistant/components/sonos/const.py index aca4b9b39ae..88b71066486 100644 --- a/homeassistant/components/sonos/const.py +++ b/homeassistant/components/sonos/const.py @@ -140,7 +140,6 @@ SONOS_CREATE_BATTERY = "sonos_create_battery" SONOS_CREATE_MEDIA_PLAYER = "sonos_create_media_player" SONOS_ENTITY_CREATED = "sonos_entity_created" SONOS_POLL_UPDATE = "sonos_poll_update" -SONOS_GROUP_UPDATE = "sonos_group_update" SONOS_ALARMS_UPDATED = "sonos_alarms_updated" SONOS_FAVORITES_UPDATED = "sonos_favorites_updated" SONOS_STATE_UPDATED = "sonos_state_updated" diff --git a/homeassistant/components/sonos/speaker.py b/homeassistant/components/sonos/speaker.py index 7522f72b20b..3ff6627bb8a 100644 --- a/homeassistant/components/sonos/speaker.py +++ b/homeassistant/components/sonos/speaker.py @@ -46,7 +46,6 @@ from .const import ( SONOS_CREATE_BATTERY, SONOS_CREATE_MEDIA_PLAYER, SONOS_ENTITY_CREATED, - SONOS_GROUP_UPDATE, SONOS_POLL_UPDATE, SONOS_REBOOTED, SONOS_SEEN, @@ -206,11 +205,6 @@ class SonosSpeaker: f"{SONOS_ENTITY_CREATED}-{self.soco.uid}", self.async_handle_new_entity, ) - self._group_dispatcher = dispatcher_connect( - self.hass, - SONOS_GROUP_UPDATE, - self.async_update_groups, - ) self._seen_dispatcher = dispatcher_connect( self.hass, f"{SONOS_SEEN}-{self.soco.uid}", self.async_seen ) @@ -612,22 +606,18 @@ class SonosSpeaker: # # Group management # - def update_groups(self, event: SonosEvent | None = None) -> None: - """Handle callback for topology change event.""" - coro = self.create_update_groups_coro(event) - if coro: - self.hass.add_job(coro) # type: ignore + def update_groups(self) -> None: + """Update group topology when polling.""" + self.hass.add_job(self.create_update_groups_coro()) @callback - def async_update_groups(self, event: SonosEvent | None = None) -> None: + def async_update_groups(self, event: SonosEvent) -> None: """Handle callback for topology change event.""" - coro = self.create_update_groups_coro(event) - if coro: - self.hass.async_add_job(coro) # type: ignore + if not hasattr(event, "zone_player_uui_ds_in_group"): + return None + self.hass.async_add_job(self.create_update_groups_coro(event)) - def create_update_groups_coro( - self, event: SonosEvent | None = None - ) -> Coroutine | None: + def create_update_groups_coro(self, event: SonosEvent | None = None) -> Coroutine: """Handle callback for topology change event.""" def _get_soco_group() -> list[str]: @@ -646,7 +636,7 @@ class SonosSpeaker: return [coordinator_uid] + slave_uids - async def _async_extract_group(event: SonosEvent) -> list[str]: + async def _async_extract_group(event: SonosEvent | None) -> list[str]: """Extract group layout from a topology event.""" group = event and event.zone_player_uui_ds_in_group if group: @@ -658,6 +648,10 @@ class SonosSpeaker: @callback def _async_regroup(group: list[str]) -> None: """Rebuild internal group layout.""" + if group == [self.soco.uid] and self.sonos_group == [self]: + # Skip updating existing single speakers in polling mode + return + entity_registry = ent_reg.async_get(self.hass) sonos_group = [] sonos_group_entities = [] @@ -671,6 +665,11 @@ class SonosSpeaker: ) sonos_group_entities.append(entity_id) + if self.sonos_group_entities == sonos_group_entities: + # Useful in polling mode for speakers with stereo pairs or surrounds + # as those "invisible" speakers will bypass the single speaker check + return + self.coordinator = None self.sonos_group = sonos_group self.sonos_group_entities = sonos_group_entities @@ -684,7 +683,9 @@ class SonosSpeaker: slave.sonos_group_entities = sonos_group_entities slave.async_write_entity_states() - async def _async_handle_group_event(event: SonosEvent) -> None: + _LOGGER.debug("Regrouped %s: %s", self.zone_name, self.sonos_group_entities) + + async def _async_handle_group_event(event: SonosEvent | None) -> None: """Get async lock and handle event.""" async with self.hass.data[DATA_SONOS].topology_condition: @@ -695,9 +696,6 @@ class SonosSpeaker: self.hass.data[DATA_SONOS].topology_condition.notify_all() - if event and not hasattr(event, "zone_player_uui_ds_in_group"): - return None - return _async_handle_group_event(event) @soco_error()