Cleanup implementation of new Sonos sensors (#49716)
parent
9e7d83b2d5
commit
dc50524f32
|
@ -3,7 +3,6 @@ from __future__ import annotations
|
|||
|
||||
import asyncio
|
||||
import datetime
|
||||
from functools import partial
|
||||
import logging
|
||||
import socket
|
||||
|
||||
|
@ -64,14 +63,13 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
class SonosData:
|
||||
"""Storage class for platform global data."""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""Initialize the data."""
|
||||
self.discovered = {}
|
||||
self.discovered: dict[str, SonosSpeaker] = {}
|
||||
self.media_player_entities = {}
|
||||
self.topology_condition = asyncio.Condition()
|
||||
self.discovery_thread = None
|
||||
self.hosts_heartbeat = None
|
||||
self.platforms_ready = set()
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
|
@ -90,7 +88,7 @@ async def async_setup(hass, config):
|
|||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Sonos from a config entry."""
|
||||
pysonos.config.EVENTS_MODULE = events_asyncio
|
||||
|
||||
|
@ -168,25 +166,24 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|||
def _async_signal_update_groups(event):
|
||||
async_dispatcher_send(hass, SONOS_GROUP_UPDATE)
|
||||
|
||||
@callback
|
||||
def start_discovery():
|
||||
async def setup_platforms_and_discovery():
|
||||
await asyncio.gather(
|
||||
*[
|
||||
hass.config_entries.async_forward_entry_setup(entry, platform)
|
||||
for platform in PLATFORMS
|
||||
]
|
||||
)
|
||||
entry.async_on_unload(
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _stop_discovery)
|
||||
)
|
||||
entry.async_on_unload(
|
||||
hass.bus.async_listen_once(
|
||||
EVENT_HOMEASSISTANT_START, _async_signal_update_groups
|
||||
)
|
||||
)
|
||||
_LOGGER.debug("Adding discovery job")
|
||||
hass.async_add_executor_job(_discovery)
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _stop_discovery)
|
||||
hass.bus.async_listen_once(
|
||||
EVENT_HOMEASSISTANT_START, _async_signal_update_groups
|
||||
)
|
||||
await hass.async_add_executor_job(_discovery)
|
||||
|
||||
@callback
|
||||
def platform_ready(platform, _):
|
||||
hass.data[DATA_SONOS].platforms_ready.add(platform)
|
||||
if hass.data[DATA_SONOS].platforms_ready == PLATFORMS:
|
||||
start_discovery()
|
||||
|
||||
for platform in PLATFORMS:
|
||||
task = hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(entry, platform)
|
||||
)
|
||||
task.add_done_callback(partial(platform_ready, platform))
|
||||
hass.async_create_task(setup_platforms_and_discovery())
|
||||
|
||||
return True
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
import pysonos
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_entry_flow
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
|
||||
async def _async_has_devices(hass):
|
||||
async def _async_has_devices(hass: HomeAssistant) -> bool:
|
||||
"""Return if there are devices that can be discovered."""
|
||||
return await hass.async_add_executor_job(pysonos.discover)
|
||||
result = await hass.async_add_executor_job(pysonos.discover)
|
||||
return bool(result)
|
||||
|
||||
|
||||
config_entry_flow.register_discovery_flow(
|
||||
|
|
|
@ -6,7 +6,6 @@ from typing import Any
|
|||
|
||||
from pysonos.core import SoCo
|
||||
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.device_registry as dr
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
@ -21,7 +20,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||
class SonosEntity(Entity):
|
||||
"""Representation of a Sonos entity."""
|
||||
|
||||
def __init__(self, speaker: SonosSpeaker, sonos_data: SonosData):
|
||||
def __init__(self, speaker: SonosSpeaker, sonos_data: SonosData) -> None:
|
||||
"""Initialize a SonosEntity."""
|
||||
self.speaker = speaker
|
||||
self.data = sonos_data
|
||||
|
@ -41,7 +40,7 @@ class SonosEntity(Entity):
|
|||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
f"{SONOS_STATE_UPDATED}-{self.soco.uid}",
|
||||
self.async_write_state,
|
||||
self.async_write_ha_state,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -72,8 +71,3 @@ class SonosEntity(Entity):
|
|||
def should_poll(self) -> bool:
|
||||
"""Return that we should not be polled (we handle that internally)."""
|
||||
return False
|
||||
|
||||
@callback
|
||||
def async_write_state(self) -> None:
|
||||
"""Flush the current entity state."""
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -10,14 +10,12 @@ from pysonos.core import SoCo
|
|||
from pysonos.events_base import Event as SonosEvent
|
||||
from pysonos.exceptions import SoCoException
|
||||
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN, SensorEntity
|
||||
from homeassistant.const import DEVICE_CLASS_BATTERY, PERCENTAGE, STATE_UNKNOWN
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
async_dispatcher_send,
|
||||
)
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.icon import icon_for_battery_level
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import SonosData
|
||||
|
@ -51,6 +49,7 @@ def fetch_battery_info_or_none(soco: SoCo) -> dict[str, Any] | None:
|
|||
"""
|
||||
with contextlib.suppress(ConnectionError, TimeoutError, SoCoException):
|
||||
return soco.get_battery_info()
|
||||
return None
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
|
@ -76,16 +75,16 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
async_dispatcher_connect(hass, SONOS_DISCOVERY_UPDATE, _async_create_entities)
|
||||
|
||||
|
||||
class SonosBatteryEntity(SonosEntity, Entity):
|
||||
class SonosBatteryEntity(SonosEntity, SensorEntity):
|
||||
"""Representation of a Sonos Battery entity."""
|
||||
|
||||
def __init__(
|
||||
self, speaker: SonosSpeaker, sonos_data: SonosData, battery_info: dict[str, Any]
|
||||
):
|
||||
) -> None:
|
||||
"""Initialize a SonosBatteryEntity."""
|
||||
super().__init__(speaker, sonos_data)
|
||||
self._battery_info: dict[str, Any] = battery_info
|
||||
self._last_event: datetime.datetime = None
|
||||
self._last_event: datetime.datetime | None = None
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register polling callback when added to hass."""
|
||||
|
@ -185,11 +184,6 @@ class SonosBatteryEntity(SonosEntity, Entity):
|
|||
"""Return the charging status of this battery."""
|
||||
return self.power_source not in ("BATTERY", STATE_UNKNOWN)
|
||||
|
||||
@property
|
||||
def icon(self) -> str:
|
||||
"""Return the icon of the sensor."""
|
||||
return icon_for_battery_level(self.battery_level, self.charging)
|
||||
|
||||
@property
|
||||
def state(self) -> int | None:
|
||||
"""Return the state of the sensor."""
|
||||
|
|
|
@ -40,7 +40,9 @@ _LOGGER = logging.getLogger(__name__)
|
|||
class SonosSpeaker:
|
||||
"""Representation of a Sonos speaker."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, soco: SoCo, speaker_info: dict[str, Any]):
|
||||
def __init__(
|
||||
self, hass: HomeAssistant, soco: SoCo, speaker_info: dict[str, Any]
|
||||
) -> None:
|
||||
"""Initialize a SonosSpeaker."""
|
||||
self._is_ready: bool = False
|
||||
self._subscriptions: list[SubscriptionBase] = []
|
||||
|
@ -78,7 +80,7 @@ class SonosSpeaker:
|
|||
self._is_ready = True
|
||||
|
||||
@callback
|
||||
def async_write_entity_states(self) -> bool:
|
||||
def async_write_entity_states(self) -> None:
|
||||
"""Write states for associated SonosEntity instances."""
|
||||
async_dispatcher_send(self.hass, f"{SONOS_STATE_UPDATED}-{self.soco.uid}")
|
||||
|
||||
|
|
|
@ -57,6 +57,5 @@ async def test_battery_attributes(hass, config_entry, config, soco):
|
|||
# confirm initial state from conftest
|
||||
assert battery_state.state == "100"
|
||||
assert battery_state.attributes.get("unit_of_measurement") == "%"
|
||||
assert battery_state.attributes.get("icon") == "mdi:battery-charging-100"
|
||||
assert battery_state.attributes.get("charging")
|
||||
assert battery_state.attributes.get("power_source") == "SONOS_CHARGING_RING"
|
||||
|
|
Loading…
Reference in New Issue