Fix Sonos missing group member race condition on startup (#55158)
parent
2932a3d6a7
commit
6cf312f3c8
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue