mirror of
https://github.com/home-assistant/core.git
synced 2025-07-20 03:37:07 +00:00
Reorganize SonosSpeaker class for readability (#51222)
This commit is contained in:
parent
27b9d7fed0
commit
3d2f696d73
@ -146,36 +146,43 @@ class SonosSpeaker:
|
|||||||
self.household_id: str = soco.household_id
|
self.household_id: str = soco.household_id
|
||||||
self.media = SonosMedia(soco)
|
self.media = SonosMedia(soco)
|
||||||
|
|
||||||
|
# Synchronization helpers
|
||||||
self.is_first_poll: bool = True
|
self.is_first_poll: bool = True
|
||||||
self._is_ready: bool = False
|
self._is_ready: bool = False
|
||||||
|
self._platforms_ready: set[str] = set()
|
||||||
|
|
||||||
# Subscriptions and events
|
# Subscriptions and events
|
||||||
self._subscriptions: list[SubscriptionBase] = []
|
self._subscriptions: list[SubscriptionBase] = []
|
||||||
self._resubscription_lock: asyncio.Lock | None = None
|
self._resubscription_lock: asyncio.Lock | None = None
|
||||||
self._event_dispatchers: dict[str, Callable] = {}
|
self._event_dispatchers: dict[str, Callable] = {}
|
||||||
|
|
||||||
|
# Scheduled callback handles
|
||||||
self._poll_timer: Callable | None = None
|
self._poll_timer: Callable | None = None
|
||||||
self._seen_timer: Callable | None = None
|
self._seen_timer: Callable | None = None
|
||||||
self._platforms_ready: set[str] = set()
|
|
||||||
|
|
||||||
|
# Dispatcher handles
|
||||||
self._entity_creation_dispatcher: Callable | None = None
|
self._entity_creation_dispatcher: Callable | None = None
|
||||||
self._group_dispatcher: Callable | None = None
|
self._group_dispatcher: Callable | None = None
|
||||||
self._seen_dispatcher: Callable | None = None
|
self._seen_dispatcher: Callable | None = None
|
||||||
|
|
||||||
|
# Device information
|
||||||
self.mac_address = speaker_info["mac_address"]
|
self.mac_address = speaker_info["mac_address"]
|
||||||
self.model_name = speaker_info["model_name"]
|
self.model_name = speaker_info["model_name"]
|
||||||
self.version = speaker_info["display_version"]
|
self.version = speaker_info["display_version"]
|
||||||
self.zone_name = speaker_info["zone_name"]
|
self.zone_name = speaker_info["zone_name"]
|
||||||
|
|
||||||
|
# Battery
|
||||||
self.battery_info: dict[str, Any] | None = None
|
self.battery_info: dict[str, Any] | None = None
|
||||||
self._last_battery_event: datetime.datetime | None = None
|
self._last_battery_event: datetime.datetime | None = None
|
||||||
self._battery_poll_timer: Callable | None = None
|
self._battery_poll_timer: Callable | None = None
|
||||||
|
|
||||||
|
# Volume / Sound
|
||||||
self.volume: int | None = None
|
self.volume: int | None = None
|
||||||
self.muted: bool | None = None
|
self.muted: bool | None = None
|
||||||
self.night_mode: bool | None = None
|
self.night_mode: bool | None = None
|
||||||
self.dialog_mode: bool | None = None
|
self.dialog_mode: bool | None = None
|
||||||
|
|
||||||
|
# Grouping
|
||||||
self.coordinator: SonosSpeaker | None = None
|
self.coordinator: SonosSpeaker | None = None
|
||||||
self.sonos_group: list[SonosSpeaker] = [self]
|
self.sonos_group: list[SonosSpeaker] = [self]
|
||||||
self.sonos_group_entities: list[str] = []
|
self.sonos_group_entities: list[str] = []
|
||||||
@ -232,6 +239,9 @@ class SonosSpeaker:
|
|||||||
|
|
||||||
dispatcher_send(self.hass, SONOS_CREATE_MEDIA_PLAYER, self)
|
dispatcher_send(self.hass, SONOS_CREATE_MEDIA_PLAYER, self)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Entity management
|
||||||
|
#
|
||||||
async def async_handle_new_entity(self, entity_type: str) -> None:
|
async def async_handle_new_entity(self, entity_type: str) -> None:
|
||||||
"""Listen to new entities to trigger first subscription."""
|
"""Listen to new entities to trigger first subscription."""
|
||||||
self._platforms_ready.add(entity_type)
|
self._platforms_ready.add(entity_type)
|
||||||
@ -254,11 +264,32 @@ class SonosSpeaker:
|
|||||||
self.media.play_mode = self.soco.play_mode
|
self.media.play_mode = self.soco.play_mode
|
||||||
self.update_volume()
|
self.update_volume()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Properties
|
||||||
|
#
|
||||||
@property
|
@property
|
||||||
def available(self) -> bool:
|
def available(self) -> bool:
|
||||||
"""Return whether this speaker is available."""
|
"""Return whether this speaker is available."""
|
||||||
return self._seen_timer is not None
|
return self._seen_timer is not None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def favorites(self) -> SonosFavorites:
|
||||||
|
"""Return the SonosFavorites instance for this household."""
|
||||||
|
return self.hass.data[DATA_SONOS].favorites[self.household_id]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_coordinator(self) -> bool:
|
||||||
|
"""Return true if player is a coordinator."""
|
||||||
|
return self.coordinator is None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def subscription_address(self) -> str | None:
|
||||||
|
"""Return the current subscription callback address if any."""
|
||||||
|
if self._subscriptions:
|
||||||
|
addr, port = self._subscriptions[0].event_listener.address
|
||||||
|
return ":".join([addr, str(port)])
|
||||||
|
return None
|
||||||
|
|
||||||
#
|
#
|
||||||
# Subscription handling and event dispatchers
|
# Subscription handling and event dispatchers
|
||||||
#
|
#
|
||||||
@ -295,6 +326,30 @@ class SonosSpeaker:
|
|||||||
subscription.auto_renew_fail = self.async_renew_failed
|
subscription.auto_renew_fail = self.async_renew_failed
|
||||||
self._subscriptions.append(subscription)
|
self._subscriptions.append(subscription)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_renew_failed(self, exception: Exception) -> None:
|
||||||
|
"""Handle a failed subscription renewal."""
|
||||||
|
self.hass.async_create_task(self.async_resubscribe(exception))
|
||||||
|
|
||||||
|
async def async_resubscribe(self, exception: Exception) -> None:
|
||||||
|
"""Attempt to resubscribe when a renewal failure is detected."""
|
||||||
|
async with self._resubscription_lock:
|
||||||
|
if not self.available:
|
||||||
|
return
|
||||||
|
|
||||||
|
if getattr(exception, "status", None) == 412:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Subscriptions for %s failed, speaker may have lost power",
|
||||||
|
self.zone_name,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Subscription renewals for %s failed",
|
||||||
|
self.zone_name,
|
||||||
|
exc_info=exception,
|
||||||
|
)
|
||||||
|
await self.async_unseen()
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_dispatch_event(self, event: SonosEvent) -> None:
|
def async_dispatch_event(self, event: SonosEvent) -> None:
|
||||||
"""Handle callback event and route as needed."""
|
"""Handle callback event and route as needed."""
|
||||||
@ -349,6 +404,9 @@ class SonosSpeaker:
|
|||||||
|
|
||||||
self.async_write_entity_states()
|
self.async_write_entity_states()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Speaker availability methods
|
||||||
|
#
|
||||||
async def async_seen(self, soco: SoCo | None = None) -> None:
|
async def async_seen(self, soco: SoCo | None = None) -> None:
|
||||||
"""Record that this speaker was seen right now."""
|
"""Record that this speaker was seen right now."""
|
||||||
if soco is not None:
|
if soco is not None:
|
||||||
@ -386,28 +444,6 @@ class SonosSpeaker:
|
|||||||
|
|
||||||
self.async_write_entity_states()
|
self.async_write_entity_states()
|
||||||
|
|
||||||
async def async_resubscribe(self, exception: Exception) -> None:
|
|
||||||
"""Attempt to resubscribe when a renewal failure is detected."""
|
|
||||||
async with self._resubscription_lock:
|
|
||||||
if self.available:
|
|
||||||
if getattr(exception, "status", None) == 412:
|
|
||||||
_LOGGER.warning(
|
|
||||||
"Subscriptions for %s failed, speaker may have lost power",
|
|
||||||
self.zone_name,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_LOGGER.error(
|
|
||||||
"Subscription renewals for %s failed",
|
|
||||||
self.zone_name,
|
|
||||||
exc_info=exception,
|
|
||||||
)
|
|
||||||
await self.async_unseen()
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_renew_failed(self, exception: Exception) -> None:
|
|
||||||
"""Handle a failed subscription renewal."""
|
|
||||||
self.hass.async_create_task(self.async_resubscribe(exception))
|
|
||||||
|
|
||||||
async def async_unseen(self, now: datetime.datetime | None = None) -> None:
|
async def async_unseen(self, now: datetime.datetime | None = None) -> None:
|
||||||
"""Make this player unavailable when it was not seen recently."""
|
"""Make this player unavailable when it was not seen recently."""
|
||||||
self.async_write_entity_states()
|
self.async_write_entity_states()
|
||||||
@ -425,6 +461,9 @@ class SonosSpeaker:
|
|||||||
|
|
||||||
self._subscriptions = []
|
self._subscriptions = []
|
||||||
|
|
||||||
|
#
|
||||||
|
# Alarm management
|
||||||
|
#
|
||||||
def update_alarms_for_speaker(self) -> set[str]:
|
def update_alarms_for_speaker(self) -> set[str]:
|
||||||
"""Update current alarm instances.
|
"""Update current alarm instances.
|
||||||
|
|
||||||
@ -453,6 +492,9 @@ class SonosSpeaker:
|
|||||||
dispatcher_send(self.hass, SONOS_CREATE_ALARM, self, new_alarms)
|
dispatcher_send(self.hass, SONOS_CREATE_ALARM, self, new_alarms)
|
||||||
dispatcher_send(self.hass, SONOS_ALARM_UPDATE)
|
dispatcher_send(self.hass, SONOS_ALARM_UPDATE)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Battery management
|
||||||
|
#
|
||||||
async def async_update_battery_info(self, battery_dict: dict[str, Any]) -> None:
|
async def async_update_battery_info(self, battery_dict: dict[str, Any]) -> None:
|
||||||
"""Update battery info using the decoded SonosEvent."""
|
"""Update battery info using the decoded SonosEvent."""
|
||||||
self._last_battery_event = dt_util.utcnow()
|
self._last_battery_event = dt_util.utcnow()
|
||||||
@ -477,11 +519,6 @@ class SonosSpeaker:
|
|||||||
):
|
):
|
||||||
self.battery_info = battery_info
|
self.battery_info = battery_info
|
||||||
|
|
||||||
@property
|
|
||||||
def is_coordinator(self) -> bool:
|
|
||||||
"""Return true if player is a coordinator."""
|
|
||||||
return self.coordinator is None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def power_source(self) -> str | None:
|
def power_source(self) -> str | None:
|
||||||
"""Return the name of the current power source.
|
"""Return the name of the current power source.
|
||||||
@ -516,6 +553,9 @@ class SonosSpeaker:
|
|||||||
self.battery_info = battery_info
|
self.battery_info = battery_info
|
||||||
self.async_write_entity_states()
|
self.async_write_entity_states()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Group management
|
||||||
|
#
|
||||||
def update_groups(self, event: SonosEvent | None = None) -> None:
|
def update_groups(self, event: SonosEvent | None = None) -> None:
|
||||||
"""Handle callback for topology change event."""
|
"""Handle callback for topology change event."""
|
||||||
coro = self.create_update_groups_coro(event)
|
coro = self.create_update_groups_coro(event)
|
||||||
@ -786,11 +826,9 @@ class SonosSpeaker:
|
|||||||
for speaker in hass.data[DATA_SONOS].discovered.values():
|
for speaker in hass.data[DATA_SONOS].discovered.values():
|
||||||
speaker.soco._zgs_cache.clear() # pylint: disable=protected-access
|
speaker.soco._zgs_cache.clear() # pylint: disable=protected-access
|
||||||
|
|
||||||
@property
|
#
|
||||||
def favorites(self) -> SonosFavorites:
|
# Media and playback state handlers
|
||||||
"""Return the SonosFavorites instance for this household."""
|
#
|
||||||
return self.hass.data[DATA_SONOS].favorites[self.household_id]
|
|
||||||
|
|
||||||
def update_volume(self) -> None:
|
def update_volume(self) -> None:
|
||||||
"""Update information about current volume settings."""
|
"""Update information about current volume settings."""
|
||||||
self.volume = self.soco.volume
|
self.volume = self.soco.volume
|
||||||
@ -951,11 +989,3 @@ class SonosSpeaker:
|
|||||||
elif update_media_position:
|
elif update_media_position:
|
||||||
self.media.position = current_position
|
self.media.position = current_position
|
||||||
self.media.position_updated_at = dt_util.utcnow()
|
self.media.position_updated_at = dt_util.utcnow()
|
||||||
|
|
||||||
@property
|
|
||||||
def subscription_address(self) -> str | None:
|
|
||||||
"""Return the current subscription callback address if any."""
|
|
||||||
if self._subscriptions:
|
|
||||||
addr, port = self._subscriptions[0].event_listener.address
|
|
||||||
return ":".join([addr, str(port)])
|
|
||||||
return None
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user