Fix Sonos updating when entities are disabled (#62456)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
cceedf766a
commit
4475e88707
7 changed files with 24 additions and 32 deletions
|
@ -1,6 +1,7 @@
|
|||
"""Entity representing a Sonos power sensor."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
|
@ -16,11 +17,14 @@ from .speaker import SonosSpeaker
|
|||
|
||||
ATTR_BATTERY_POWER_SOURCE = "power_source"
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up Sonos from a config entry."""
|
||||
|
||||
async def _async_create_entity(speaker: SonosSpeaker) -> None:
|
||||
_LOGGER.debug("Creating battery binary_sensor on %s", speaker.zone_name)
|
||||
entity = SonosPowerEntity(speaker)
|
||||
async_add_entities([entity])
|
||||
|
||||
|
|
|
@ -149,7 +149,6 @@ SONOS_CREATE_BATTERY = "sonos_create_battery"
|
|||
SONOS_CREATE_SWITCHES = "sonos_create_switches"
|
||||
SONOS_CREATE_LEVELS = "sonos_create_levels"
|
||||
SONOS_CREATE_MEDIA_PLAYER = "sonos_create_media_player"
|
||||
SONOS_ENTITY_CREATED = "sonos_entity_created"
|
||||
SONOS_POLL_UPDATE = "sonos_poll_update"
|
||||
SONOS_ALARMS_UPDATED = "sonos_alarms_updated"
|
||||
SONOS_FAVORITES_UPDATED = "sonos_favorites_updated"
|
||||
|
|
|
@ -10,15 +10,11 @@ from soco.core import SoCo
|
|||
from soco.exceptions import SoCoException
|
||||
|
||||
import homeassistant.helpers.device_registry as dr
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
async_dispatcher_send,
|
||||
)
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
SONOS_ENTITY_CREATED,
|
||||
SONOS_FAVORITES_UPDATED,
|
||||
SONOS_POLL_UPDATE,
|
||||
SONOS_STATE_UPDATED,
|
||||
|
@ -60,9 +56,6 @@ class SonosEntity(Entity):
|
|||
self.async_write_ha_state,
|
||||
)
|
||||
)
|
||||
async_dispatcher_send(
|
||||
self.hass, f"{SONOS_ENTITY_CREATED}-{self.soco.uid}", self.platform.domain
|
||||
)
|
||||
|
||||
async def async_poll(self, now: datetime.datetime) -> None:
|
||||
"""Poll the entity if subscriptions fail."""
|
||||
|
|
|
@ -132,6 +132,7 @@ async def async_setup_entry(
|
|||
@callback
|
||||
def async_create_entities(speaker: SonosSpeaker) -> None:
|
||||
"""Handle device discovery and create entities."""
|
||||
_LOGGER.debug("Creating media_player on %s", speaker.zone_name)
|
||||
async_add_entities([SonosMediaPlayerEntity(speaker)])
|
||||
|
||||
@service.verify_domain_control(hass, SONOS_DOMAIN)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""Entity representing a Sonos number control."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from homeassistant.components.number import NumberEntity
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
@ -13,6 +15,8 @@ from .speaker import SonosSpeaker
|
|||
|
||||
LEVEL_TYPES = ("bass", "treble")
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up the Sonos number platform from a config entry."""
|
||||
|
@ -21,6 +25,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
def _async_create_entities(speaker: SonosSpeaker) -> None:
|
||||
entities = []
|
||||
for level_type in LEVEL_TYPES:
|
||||
_LOGGER.debug(
|
||||
"Creating %s number control on %s", level_type, speaker.zone_name
|
||||
)
|
||||
entities.append(SonosLevelEntity(speaker, level_type))
|
||||
async_add_entities(entities)
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""Entity representing a Sonos battery level."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
|
||||
from homeassistant.const import PERCENTAGE
|
||||
from homeassistant.core import callback
|
||||
|
@ -11,6 +13,8 @@ from .const import SONOS_CREATE_AUDIO_FORMAT_SENSOR, SONOS_CREATE_BATTERY
|
|||
from .entity import SonosEntity
|
||||
from .speaker import SonosSpeaker
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up Sonos from a config entry."""
|
||||
|
@ -19,11 +23,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
def _async_create_audio_format_entity(
|
||||
speaker: SonosSpeaker, audio_format: str
|
||||
) -> None:
|
||||
_LOGGER.debug("Creating audio input format sensor on %s", speaker.zone_name)
|
||||
entity = SonosAudioInputFormatSensorEntity(speaker, audio_format)
|
||||
async_add_entities([entity])
|
||||
|
||||
@callback
|
||||
def _async_create_battery_sensor(speaker: SonosSpeaker) -> None:
|
||||
_LOGGER.debug("Creating battery level sensor on %s", speaker.zone_name)
|
||||
entity = SonosBatteryEntity(speaker)
|
||||
async_add_entities([entity])
|
||||
|
||||
|
|
|
@ -20,10 +20,7 @@ from soco.music_library import MusicLibrary
|
|||
from soco.plugins.sharelink import ShareLinkPlugin
|
||||
from soco.snapshot import Snapshot
|
||||
|
||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
||||
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
@ -42,7 +39,6 @@ from .const import (
|
|||
BATTERY_SCAN_INTERVAL,
|
||||
DATA_SONOS,
|
||||
DOMAIN,
|
||||
PLATFORMS,
|
||||
SCAN_INTERVAL,
|
||||
SONOS_CHECK_ACTIVITY,
|
||||
SONOS_CREATE_ALARM,
|
||||
|
@ -51,7 +47,6 @@ from .const import (
|
|||
SONOS_CREATE_LEVELS,
|
||||
SONOS_CREATE_MEDIA_PLAYER,
|
||||
SONOS_CREATE_SWITCHES,
|
||||
SONOS_ENTITY_CREATED,
|
||||
SONOS_POLL_UPDATE,
|
||||
SONOS_REBOOTED,
|
||||
SONOS_SPEAKER_ACTIVITY,
|
||||
|
@ -161,9 +156,6 @@ class SonosSpeaker:
|
|||
self._share_link_plugin: ShareLinkPlugin | None = None
|
||||
self.available = True
|
||||
|
||||
# Synchronization helpers
|
||||
self._platforms_ready: set[str] = set()
|
||||
|
||||
# Subscriptions and events
|
||||
self.subscriptions_failed: bool = False
|
||||
self._subscriptions: list[SubscriptionBase] = []
|
||||
|
@ -217,7 +209,6 @@ class SonosSpeaker:
|
|||
dispatch_pairs = (
|
||||
(SONOS_CHECK_ACTIVITY, self.async_check_activity),
|
||||
(SONOS_SPEAKER_ADDED, self.update_group_for_uid),
|
||||
(f"{SONOS_ENTITY_CREATED}-{self.soco.uid}", self.async_handle_new_entity),
|
||||
(f"{SONOS_REBOOTED}-{self.soco.uid}", self.async_rebooted),
|
||||
(f"{SONOS_SPEAKER_ACTIVITY}-{self.soco.uid}", self.speaker_activity),
|
||||
)
|
||||
|
@ -253,15 +244,11 @@ class SonosSpeaker:
|
|||
self.hass, self.async_poll_battery, BATTERY_SCAN_INTERVAL
|
||||
)
|
||||
dispatcher_send(self.hass, SONOS_CREATE_BATTERY, self)
|
||||
else:
|
||||
self._platforms_ready.update({BINARY_SENSOR_DOMAIN, SENSOR_DOMAIN})
|
||||
|
||||
if new_alarms := [
|
||||
alarm.alarm_id for alarm in self.alarms if alarm.zone.uid == self.soco.uid
|
||||
]:
|
||||
dispatcher_send(self.hass, SONOS_CREATE_ALARM, self, new_alarms)
|
||||
else:
|
||||
self._platforms_ready.add(SWITCH_DOMAIN)
|
||||
|
||||
dispatcher_send(self.hass, SONOS_CREATE_SWITCHES, self)
|
||||
|
||||
|
@ -277,19 +264,11 @@ class SonosSpeaker:
|
|||
dispatcher_send(self.hass, SONOS_CREATE_MEDIA_PLAYER, self)
|
||||
dispatcher_send(self.hass, SONOS_SPEAKER_ADDED, self.soco.uid)
|
||||
|
||||
self.hass.create_task(self.async_subscribe())
|
||||
|
||||
#
|
||||
# Entity management
|
||||
#
|
||||
async def async_handle_new_entity(self, entity_type: str) -> None:
|
||||
"""Listen to new entities to trigger first subscription."""
|
||||
if self._platforms_ready == PLATFORMS:
|
||||
return
|
||||
|
||||
self._platforms_ready.add(entity_type)
|
||||
if self._platforms_ready == PLATFORMS:
|
||||
self._resubscription_lock = asyncio.Lock()
|
||||
await self.async_subscribe()
|
||||
|
||||
def write_entity_states(self) -> None:
|
||||
"""Write states for associated SonosEntity instances."""
|
||||
dispatcher_send(self.hass, f"{SONOS_STATE_UPDATED}-{self.soco.uid}")
|
||||
|
@ -405,6 +384,9 @@ class SonosSpeaker:
|
|||
|
||||
async def async_resubscribe(self, exception: Exception) -> None:
|
||||
"""Attempt to resubscribe when a renewal failure is detected."""
|
||||
if not self._resubscription_lock:
|
||||
self._resubscription_lock = asyncio.Lock()
|
||||
|
||||
async with self._resubscription_lock:
|
||||
if not self.available:
|
||||
return
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue