Cleanup implementation of new Sonos sensors (#49716)

pull/49733/head
jjlawren 2021-04-26 16:59:04 -05:00 committed by GitHub
parent 9e7d83b2d5
commit dc50524f32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 35 additions and 47 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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