diff --git a/homeassistant/components/sonos/binary_sensor.py b/homeassistant/components/sonos/binary_sensor.py index bab153175e8..e3545552bee 100644 --- a/homeassistant/components/sonos/binary_sensor.py +++ b/homeassistant/components/sonos/binary_sensor.py @@ -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]) diff --git a/homeassistant/components/sonos/const.py b/homeassistant/components/sonos/const.py index 523ac9f561b..bffc6425928 100644 --- a/homeassistant/components/sonos/const.py +++ b/homeassistant/components/sonos/const.py @@ -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" diff --git a/homeassistant/components/sonos/entity.py b/homeassistant/components/sonos/entity.py index d8196ffdfa6..65f73eaf3f0 100644 --- a/homeassistant/components/sonos/entity.py +++ b/homeassistant/components/sonos/entity.py @@ -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.""" diff --git a/homeassistant/components/sonos/media_player.py b/homeassistant/components/sonos/media_player.py index 90c33d7a4e6..f4dbf8f87d0 100644 --- a/homeassistant/components/sonos/media_player.py +++ b/homeassistant/components/sonos/media_player.py @@ -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) diff --git a/homeassistant/components/sonos/number.py b/homeassistant/components/sonos/number.py index c1b0ffcfd3b..afe7effed53 100644 --- a/homeassistant/components/sonos/number.py +++ b/homeassistant/components/sonos/number.py @@ -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) diff --git a/homeassistant/components/sonos/sensor.py b/homeassistant/components/sonos/sensor.py index 6a1162a6aa6..d735a7be1e3 100644 --- a/homeassistant/components/sonos/sensor.py +++ b/homeassistant/components/sonos/sensor.py @@ -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]) diff --git a/homeassistant/components/sonos/speaker.py b/homeassistant/components/sonos/speaker.py index 30b240c9fd7..8cd2abcf2b2 100644 --- a/homeassistant/components/sonos/speaker.py +++ b/homeassistant/components/sonos/speaker.py @@ -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