Fix sonos overloading the executor when there are many devices (#112482)

This commit is contained in:
J. Nick Koston 2024-03-06 08:55:47 -10:00 committed by GitHub
parent 7096701cab
commit 0f3838e7a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -8,7 +8,7 @@ import datetime
from functools import partial from functools import partial
import logging import logging
import time import time
from typing import Any, cast from typing import TYPE_CHECKING, Any, cast
import defusedxml.ElementTree as ET import defusedxml.ElementTree as ET
from soco.core import SoCo from soco.core import SoCo
@ -64,6 +64,9 @@ from .helpers import soco_error
from .media import SonosMedia from .media import SonosMedia
from .statistics import ActivityStatistics, EventStatistics from .statistics import ActivityStatistics, EventStatistics
if TYPE_CHECKING:
from . import SonosData
NEVER_TIME = -1200.0 NEVER_TIME = -1200.0
RESUB_COOLDOWN_SECONDS = 10.0 RESUB_COOLDOWN_SECONDS = 10.0
EVENT_CHARGING = { EVENT_CHARGING = {
@ -97,6 +100,7 @@ class SonosSpeaker:
) -> None: ) -> None:
"""Initialize a SonosSpeaker.""" """Initialize a SonosSpeaker."""
self.hass = hass self.hass = hass
self.data: SonosData = hass.data[DATA_SONOS]
self.soco = soco self.soco = soco
self.websocket: SonosWebsocket | None = None self.websocket: SonosWebsocket | None = None
self.household_id: str = soco.household_id self.household_id: str = soco.household_id
@ -183,7 +187,7 @@ class SonosSpeaker:
) )
dispatch_pairs: tuple[tuple[str, Callable[..., Any]], ...] = ( dispatch_pairs: tuple[tuple[str, Callable[..., Any]], ...] = (
(SONOS_CHECK_ACTIVITY, self.async_check_activity), (SONOS_CHECK_ACTIVITY, self.async_check_activity),
(SONOS_SPEAKER_ADDED, self.update_group_for_uid), (SONOS_SPEAKER_ADDED, self.async_update_group_for_uid),
(f"{SONOS_REBOOTED}-{self.soco.uid}", self.async_rebooted), (f"{SONOS_REBOOTED}-{self.soco.uid}", self.async_rebooted),
(f"{SONOS_SPEAKER_ACTIVITY}-{self.soco.uid}", self.speaker_activity), (f"{SONOS_SPEAKER_ACTIVITY}-{self.soco.uid}", self.speaker_activity),
(f"{SONOS_VANISHED}-{self.soco.uid}", self.async_vanished), (f"{SONOS_VANISHED}-{self.soco.uid}", self.async_vanished),
@ -272,12 +276,12 @@ class SonosSpeaker:
@property @property
def alarms(self) -> SonosAlarms: def alarms(self) -> SonosAlarms:
"""Return the SonosAlarms instance for this household.""" """Return the SonosAlarms instance for this household."""
return self.hass.data[DATA_SONOS].alarms[self.household_id] return self.data.alarms[self.household_id]
@property @property
def favorites(self) -> SonosFavorites: def favorites(self) -> SonosFavorites:
"""Return the SonosFavorites instance for this household.""" """Return the SonosFavorites instance for this household."""
return self.hass.data[DATA_SONOS].favorites[self.household_id] return self.data.favorites[self.household_id]
@property @property
def is_coordinator(self) -> bool: def is_coordinator(self) -> bool:
@ -496,9 +500,7 @@ class SonosSpeaker:
"x-rincon:" "x-rincon:"
): ):
new_coordinator_uid = av_transport_uri.split(":")[-1] new_coordinator_uid = av_transport_uri.split(":")[-1]
if new_coordinator_speaker := self.hass.data[DATA_SONOS].discovered.get( if new_coordinator_speaker := self.data.discovered.get(new_coordinator_uid):
new_coordinator_uid
):
_LOGGER.debug( _LOGGER.debug(
"Media update coordinator (%s) received for %s", "Media update coordinator (%s) received for %s",
new_coordinator_speaker.zone_name, new_coordinator_speaker.zone_name,
@ -657,7 +659,7 @@ class SonosSpeaker:
await self.async_unsubscribe() await self.async_unsubscribe()
self.hass.data[DATA_SONOS].discovery_known.discard(self.soco.uid) self.data.discovery_known.discard(self.soco.uid)
async def async_vanished(self, reason: str) -> None: async def async_vanished(self, reason: str) -> None:
"""Handle removal of speaker when marked as vanished.""" """Handle removal of speaker when marked as vanished."""
@ -784,15 +786,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: @callback
def async_update_group_for_uid(self, uid: str) -> None:
"""Update group topology if uid is missing.""" """Update group topology if uid is missing."""
if uid not in self._group_members_missing: if uid not in self._group_members_missing:
return return
missing_zone = self.hass.data[DATA_SONOS].discovered[uid].zone_name missing_zone = self.data.discovered[uid].zone_name
_LOGGER.debug( _LOGGER.debug(
"%s was missing, adding to %s group", missing_zone, self.zone_name "%s was missing, adding to %s group", missing_zone, self.zone_name
) )
self.update_groups() self.hass.async_create_task(self.create_update_groups_coro(), eager_start=True)
@callback @callback
def async_update_groups(self, event: SonosEvent) -> None: def async_update_groups(self, event: SonosEvent) -> None:
@ -866,7 +869,7 @@ class SonosSpeaker:
sonos_group_entities = [] sonos_group_entities = []
for uid in group: for uid in group:
speaker = self.hass.data[DATA_SONOS].discovered.get(uid) speaker = self.data.discovered.get(uid)
if speaker: if speaker:
self._group_members_missing.discard(uid) self._group_members_missing.discard(uid)
sonos_group.append(speaker) sonos_group.append(speaker)
@ -894,10 +897,7 @@ class SonosSpeaker:
self.async_write_entity_states() self.async_write_entity_states()
for joined_uid in group[1:]: for joined_uid in group[1:]:
joined_speaker: SonosSpeaker = self.hass.data[ if joined_speaker := self.data.discovered.get(joined_uid):
DATA_SONOS
].discovered.get(joined_uid)
if joined_speaker:
joined_speaker.coordinator = self joined_speaker.coordinator = self
joined_speaker.sonos_group = sonos_group joined_speaker.sonos_group = sonos_group
joined_speaker.sonos_group_entities = sonos_group_entities joined_speaker.sonos_group_entities = sonos_group_entities
@ -908,13 +908,13 @@ class SonosSpeaker:
async def _async_handle_group_event(event: SonosEvent | None) -> None: async def _async_handle_group_event(event: SonosEvent | None) -> None:
"""Get async lock and handle event.""" """Get async lock and handle event."""
async with self.hass.data[DATA_SONOS].topology_condition: async with self.data.topology_condition:
group = await _async_extract_group(event) group = await _async_extract_group(event)
if self.soco.uid == group[0]: if self.soco.uid == group[0]:
_async_regroup(group) _async_regroup(group)
self.hass.data[DATA_SONOS].topology_condition.notify_all() self.data.topology_condition.notify_all()
return _async_handle_group_event(event) return _async_handle_group_event(event)