Fix Sonos updating when entities are disabled (#62456)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
jjlawren 2021-12-21 23:36:12 -05:00 committed by GitHub
parent cceedf766a
commit 4475e88707
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 24 additions and 32 deletions

View file

@ -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])

View file

@ -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"

View file

@ -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."""

View file

@ -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)

View file

@ -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)

View file

@ -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])

View file

@ -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