mirror of
https://github.com/home-assistant/core.git
synced 2025-11-12 12:30:31 +00:00
133 lines
4.4 KiB
Python
133 lines
4.4 KiB
Python
"""Select entities for Sonos."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
import logging
|
|
|
|
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
|
|
from .const import (
|
|
ATTR_DIALOG_LEVEL,
|
|
ATTR_DIALOG_LEVEL_ENUM,
|
|
MODEL_SONOS_ARC_ULTRA,
|
|
SONOS_CREATE_SELECTS,
|
|
SPEECH_DIALOG_LEVEL,
|
|
)
|
|
from .entity import SonosEntity
|
|
from .helpers import SonosConfigEntry, soco_error
|
|
from .speaker import SonosSpeaker
|
|
|
|
|
|
@dataclass(frozen=True, kw_only=True)
|
|
class SonosSelectEntityDescription(SelectEntityDescription):
|
|
"""Describes AirGradient select entity."""
|
|
|
|
soco_attribute: str
|
|
speaker_attribute: str
|
|
speaker_model: str
|
|
|
|
|
|
SELECT_TYPES: list[SonosSelectEntityDescription] = [
|
|
SonosSelectEntityDescription(
|
|
key=SPEECH_DIALOG_LEVEL,
|
|
translation_key=SPEECH_DIALOG_LEVEL,
|
|
soco_attribute=ATTR_DIALOG_LEVEL,
|
|
speaker_attribute=ATTR_DIALOG_LEVEL_ENUM,
|
|
speaker_model=MODEL_SONOS_ARC_ULTRA,
|
|
options=["off", "low", "medium", "high", "max"],
|
|
),
|
|
]
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: SonosConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up the Sonos select platform from a config entry."""
|
|
|
|
def available_soco_attributes(
|
|
speaker: SonosSpeaker,
|
|
) -> list[SonosSelectEntityDescription]:
|
|
features: list[SonosSelectEntityDescription] = []
|
|
for select_data in SELECT_TYPES:
|
|
if select_data.speaker_model == speaker.model_name.upper():
|
|
if (
|
|
speaker.update_soco_int_attribute(
|
|
select_data.soco_attribute, select_data.speaker_attribute
|
|
)
|
|
is not None
|
|
):
|
|
features.append(select_data)
|
|
return features
|
|
|
|
async def _async_create_entities(speaker: SonosSpeaker) -> None:
|
|
available_features = await hass.async_add_executor_job(
|
|
available_soco_attributes, speaker
|
|
)
|
|
async_add_entities(
|
|
SonosSelectEntity(speaker, config_entry, select_data)
|
|
for select_data in available_features
|
|
)
|
|
|
|
config_entry.async_on_unload(
|
|
async_dispatcher_connect(hass, SONOS_CREATE_SELECTS, _async_create_entities)
|
|
)
|
|
|
|
|
|
class SonosSelectEntity(SonosEntity, SelectEntity):
|
|
"""Representation of a Sonos select entity."""
|
|
|
|
def __init__(
|
|
self,
|
|
speaker: SonosSpeaker,
|
|
config_entry: SonosConfigEntry,
|
|
select_data: SonosSelectEntityDescription,
|
|
) -> None:
|
|
"""Initialize the select entity."""
|
|
super().__init__(speaker, config_entry)
|
|
self._attr_unique_id = f"{self.soco.uid}-{select_data.key}"
|
|
self._attr_translation_key = select_data.translation_key
|
|
assert select_data.options is not None
|
|
self._attr_options = select_data.options
|
|
self.speaker_attribute = select_data.speaker_attribute
|
|
self.soco_attribute = select_data.soco_attribute
|
|
|
|
async def _async_fallback_poll(self) -> None:
|
|
"""Poll the value if subscriptions are not working."""
|
|
await self.hass.async_add_executor_job(self.poll_state)
|
|
self.async_write_ha_state()
|
|
|
|
@soco_error()
|
|
def poll_state(self) -> None:
|
|
"""Poll the device for the current state."""
|
|
self.speaker.update_soco_int_attribute(
|
|
self.soco_attribute, self.speaker_attribute
|
|
)
|
|
|
|
@property
|
|
def current_option(self) -> str | None:
|
|
"""Return the current option for the entity."""
|
|
option = getattr(self.speaker, self.speaker_attribute, None)
|
|
if not isinstance(option, int) or not (0 <= option < len(self._attr_options)):
|
|
_LOGGER.error(
|
|
"Invalid option %s for %s on %s",
|
|
option,
|
|
self.soco_attribute,
|
|
self.speaker.zone_name,
|
|
)
|
|
return None
|
|
return self._attr_options[option]
|
|
|
|
@soco_error()
|
|
def select_option(self, option: str) -> None:
|
|
"""Set a new value."""
|
|
dialog_level = self._attr_options.index(option)
|
|
setattr(self.soco, self.soco_attribute, dialog_level)
|