Fix Sonos missing group member race condition on startup (#55158)

pull/55181/head
jjlawren 2021-08-24 14:13:18 -05:00 committed by GitHub
parent 2932a3d6a7
commit 6cf312f3c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 1 deletions

View File

@ -142,6 +142,7 @@ SONOS_ENTITY_CREATED = "sonos_entity_created"
SONOS_POLL_UPDATE = "sonos_poll_update" SONOS_POLL_UPDATE = "sonos_poll_update"
SONOS_ALARMS_UPDATED = "sonos_alarms_updated" SONOS_ALARMS_UPDATED = "sonos_alarms_updated"
SONOS_FAVORITES_UPDATED = "sonos_favorites_updated" SONOS_FAVORITES_UPDATED = "sonos_favorites_updated"
SONOS_SPEAKER_ADDED = "sonos_speaker_added"
SONOS_STATE_UPDATED = "sonos_state_updated" SONOS_STATE_UPDATED = "sonos_state_updated"
SONOS_REBOOTED = "sonos_rebooted" SONOS_REBOOTED = "sonos_rebooted"
SONOS_SEEN = "sonos_seen" SONOS_SEEN = "sonos_seen"

View File

@ -50,6 +50,7 @@ from .const import (
SONOS_POLL_UPDATE, SONOS_POLL_UPDATE,
SONOS_REBOOTED, SONOS_REBOOTED,
SONOS_SEEN, SONOS_SEEN,
SONOS_SPEAKER_ADDED,
SONOS_STATE_PLAYING, SONOS_STATE_PLAYING,
SONOS_STATE_TRANSITIONING, SONOS_STATE_TRANSITIONING,
SONOS_STATE_UPDATED, SONOS_STATE_UPDATED,
@ -196,6 +197,7 @@ class SonosSpeaker:
self.sonos_group_entities: list[str] = [] self.sonos_group_entities: list[str] = []
self.soco_snapshot: Snapshot | None = None self.soco_snapshot: Snapshot | None = None
self.snapshot_group: list[SonosSpeaker] | None = None self.snapshot_group: list[SonosSpeaker] | None = None
self._group_members_missing: set[str] = set()
def setup(self) -> None: def setup(self) -> None:
"""Run initial setup of the speaker.""" """Run initial setup of the speaker."""
@ -212,6 +214,11 @@ class SonosSpeaker:
self._reboot_dispatcher = dispatcher_connect( self._reboot_dispatcher = dispatcher_connect(
self.hass, f"{SONOS_REBOOTED}-{self.soco.uid}", self.async_rebooted self.hass, f"{SONOS_REBOOTED}-{self.soco.uid}", self.async_rebooted
) )
self._group_dispatcher = dispatcher_connect(
self.hass,
SONOS_SPEAKER_ADDED,
self.update_group_for_uid,
)
if battery_info := fetch_battery_info_or_none(self.soco): if battery_info := fetch_battery_info_or_none(self.soco):
self.battery_info = battery_info self.battery_info = battery_info
@ -240,6 +247,7 @@ class SonosSpeaker:
} }
dispatcher_send(self.hass, SONOS_CREATE_MEDIA_PLAYER, self) dispatcher_send(self.hass, SONOS_CREATE_MEDIA_PLAYER, self)
dispatcher_send(self.hass, SONOS_SPEAKER_ADDED, self.soco.uid)
# #
# Entity management # Entity management
@ -637,6 +645,16 @@ class SonosSpeaker:
"""Update group topology when polling.""" """Update group topology when polling."""
self.hass.add_job(self.create_update_groups_coro()) self.hass.add_job(self.create_update_groups_coro())
def update_group_for_uid(self, uid: str) -> None:
"""Update group topology if uid is missing."""
if uid not in self._group_members_missing:
return
missing_zone = self.hass.data[DATA_SONOS].discovered[uid].zone_name
_LOGGER.debug(
"%s was missing, adding to %s group", missing_zone, self.zone_name
)
self.update_groups()
@callback @callback
def async_update_groups(self, event: SonosEvent) -> None: def async_update_groups(self, event: SonosEvent) -> None:
"""Handle callback for topology change event.""" """Handle callback for topology change event."""
@ -658,7 +676,7 @@ class SonosSpeaker:
slave_uids = [ slave_uids = [
p.uid p.uid
for p in self.soco.group.members for p in self.soco.group.members
if p.uid != coordinator_uid if p.uid != coordinator_uid and p.is_visible
] ]
return [coordinator_uid] + slave_uids return [coordinator_uid] + slave_uids
@ -690,11 +708,19 @@ class SonosSpeaker:
for uid in group: for uid in group:
speaker = self.hass.data[DATA_SONOS].discovered.get(uid) speaker = self.hass.data[DATA_SONOS].discovered.get(uid)
if speaker: if speaker:
self._group_members_missing.discard(uid)
sonos_group.append(speaker) sonos_group.append(speaker)
entity_id = entity_registry.async_get_entity_id( entity_id = entity_registry.async_get_entity_id(
MP_DOMAIN, DOMAIN, uid MP_DOMAIN, DOMAIN, uid
) )
sonos_group_entities.append(entity_id) sonos_group_entities.append(entity_id)
else:
self._group_members_missing.add(uid)
_LOGGER.debug(
"%s group member unavailable (%s), will try again",
self.zone_name,
uid,
)
if self.sonos_group_entities == sonos_group_entities: if self.sonos_group_entities == sonos_group_entities:
# Useful in polling mode for speakers with stereo pairs or surrounds # Useful in polling mode for speakers with stereo pairs or surrounds