mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Handle more Sonos snapshot restore scenarios (#53277)
This commit is contained in:
parent
b2528e97b6
commit
0707792bec
@ -14,7 +14,7 @@ import async_timeout
|
|||||||
from pysonos.core import MUSIC_SRC_LINE_IN, MUSIC_SRC_RADIO, MUSIC_SRC_TV, SoCo
|
from pysonos.core import MUSIC_SRC_LINE_IN, MUSIC_SRC_RADIO, MUSIC_SRC_TV, SoCo
|
||||||
from pysonos.data_structures import DidlAudioBroadcast, DidlPlaylistContainer
|
from pysonos.data_structures import DidlAudioBroadcast, DidlPlaylistContainer
|
||||||
from pysonos.events_base import Event as SonosEvent, SubscriptionBase
|
from pysonos.events_base import Event as SonosEvent, SubscriptionBase
|
||||||
from pysonos.exceptions import SoCoException
|
from pysonos.exceptions import SoCoException, SoCoUPnPException
|
||||||
from pysonos.music_library import MusicLibrary
|
from pysonos.music_library import MusicLibrary
|
||||||
from pysonos.plugins.sharelink import ShareLinkPlugin
|
from pysonos.plugins.sharelink import ShareLinkPlugin
|
||||||
from pysonos.snapshot import Snapshot
|
from pysonos.snapshot import Snapshot
|
||||||
@ -25,6 +25,7 @@ from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
|
|||||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers import entity_registry as ent_reg
|
from homeassistant.helpers import entity_registry as ent_reg
|
||||||
from homeassistant.helpers.dispatcher import (
|
from homeassistant.helpers.dispatcher import (
|
||||||
async_dispatcher_send,
|
async_dispatcher_send,
|
||||||
@ -802,25 +803,56 @@ class SonosSpeaker:
|
|||||||
"""Restore snapshots for all the speakers."""
|
"""Restore snapshots for all the speakers."""
|
||||||
|
|
||||||
def _restore_groups(
|
def _restore_groups(
|
||||||
speakers: list[SonosSpeaker], with_group: bool
|
speakers: set[SonosSpeaker], with_group: bool
|
||||||
) -> list[list[SonosSpeaker]]:
|
) -> list[list[SonosSpeaker]]:
|
||||||
"""Pause all current coordinators and restore groups."""
|
"""Pause all current coordinators and restore groups."""
|
||||||
for speaker in (s for s in speakers if s.is_coordinator):
|
for speaker in (s for s in speakers if s.is_coordinator):
|
||||||
if speaker.media.playback_status == SONOS_STATE_PLAYING:
|
if (
|
||||||
|
speaker.media.playback_status == SONOS_STATE_PLAYING
|
||||||
|
and "Pause" in speaker.soco.available_actions
|
||||||
|
):
|
||||||
|
try:
|
||||||
speaker.soco.pause()
|
speaker.soco.pause()
|
||||||
|
except SoCoUPnPException as exc:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Pause failed during restore of %s: %s",
|
||||||
|
speaker.zone_name,
|
||||||
|
speaker.soco.available_actions,
|
||||||
|
exc_info=exc,
|
||||||
|
)
|
||||||
|
|
||||||
groups = []
|
groups = []
|
||||||
|
if not with_group:
|
||||||
|
return groups
|
||||||
|
|
||||||
if with_group:
|
# Unjoin non-coordinator speakers not contained in the desired snapshot group
|
||||||
# Unjoin slaves first to prevent inheritance of queues
|
#
|
||||||
for speaker in [s for s in speakers if not s.is_coordinator]:
|
# If a coordinator is unjoined from its group, another speaker from the group
|
||||||
if speaker.snapshot_group != speaker.sonos_group:
|
# will inherit the coordinator's playqueue and its own playqueue will be lost
|
||||||
|
speakers_to_unjoin = set()
|
||||||
|
for speaker in speakers:
|
||||||
|
if speaker.sonos_group == speaker.snapshot_group:
|
||||||
|
continue
|
||||||
|
|
||||||
|
speakers_to_unjoin.update(
|
||||||
|
{
|
||||||
|
s
|
||||||
|
for s in speaker.sonos_group[1:]
|
||||||
|
if s not in speaker.snapshot_group
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for speaker in speakers_to_unjoin:
|
||||||
speaker.unjoin()
|
speaker.unjoin()
|
||||||
|
|
||||||
# Bring back the original group topology
|
# Bring back the original group topology
|
||||||
for speaker in (s for s in speakers if s.snapshot_group):
|
for speaker in (s for s in speakers if s.snapshot_group):
|
||||||
assert speaker.snapshot_group is not None
|
assert speaker.snapshot_group is not None
|
||||||
if speaker.snapshot_group[0] == speaker:
|
if speaker.snapshot_group[0] == speaker:
|
||||||
|
if (
|
||||||
|
speaker.snapshot_group != speaker.sonos_group
|
||||||
|
and speaker.snapshot_group != [speaker]
|
||||||
|
):
|
||||||
speaker.join(speaker.snapshot_group)
|
speaker.join(speaker.snapshot_group)
|
||||||
groups.append(speaker.snapshot_group.copy())
|
groups.append(speaker.snapshot_group.copy())
|
||||||
|
|
||||||
@ -836,6 +868,11 @@ class SonosSpeaker:
|
|||||||
|
|
||||||
# Find all affected players
|
# Find all affected players
|
||||||
speakers_set = {s for s in speakers if s.soco_snapshot}
|
speakers_set = {s for s in speakers if s.soco_snapshot}
|
||||||
|
if missing_snapshots := set(speakers) - speakers_set:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
f"Restore failed, speakers are missing snapshots: {[s.zone_name for s in missing_snapshots]}"
|
||||||
|
)
|
||||||
|
|
||||||
if with_group:
|
if with_group:
|
||||||
for speaker in [s for s in speakers_set if s.snapshot_group]:
|
for speaker in [s for s in speakers_set if s.snapshot_group]:
|
||||||
assert speaker.snapshot_group is not None
|
assert speaker.snapshot_group is not None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user