core/homeassistant/components/wled/select.py

169 lines
5.6 KiB
Python

"""Support for LED selects."""
from __future__ import annotations
from functools import partial
from wled import Playlist, Preset
from homeassistant.components.select import SelectEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .coordinator import WLEDDataUpdateCoordinator
from .helpers import wled_exception_handler
from .models import WLEDEntity
PARALLEL_UPDATES = 1
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up WLED select based on a config entry."""
coordinator: WLEDDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities([WLEDPlaylistSelect(coordinator), WLEDPresetSelect(coordinator)])
update_segments = partial(
async_update_segments,
coordinator,
set(),
async_add_entities,
)
coordinator.async_add_listener(update_segments)
update_segments()
class WLEDPresetSelect(WLEDEntity, SelectEntity):
"""Defined a WLED Preset select."""
_attr_icon = "mdi:playlist-play"
def __init__(self, coordinator: WLEDDataUpdateCoordinator) -> None:
"""Initialize WLED ."""
super().__init__(coordinator=coordinator)
self._attr_name = f"{coordinator.data.info.name} Preset"
self._attr_unique_id = f"{coordinator.data.info.mac_address}_preset"
self._attr_options = [preset.name for preset in self.coordinator.data.presets]
@property
def available(self) -> bool:
"""Return True if entity is available."""
return len(self.coordinator.data.presets) > 0 and super().available
@property
def current_option(self) -> str | None:
"""Return the current selected preset."""
if not isinstance(self.coordinator.data.state.preset, Preset):
return None
return self.coordinator.data.state.preset.name
@wled_exception_handler
async def async_select_option(self, option: str) -> None:
"""Set WLED segment to the selected preset."""
await self.coordinator.wled.preset(preset=option)
class WLEDPlaylistSelect(WLEDEntity, SelectEntity):
"""Define a WLED Playlist select."""
_attr_icon = "mdi:play-speed"
def __init__(self, coordinator: WLEDDataUpdateCoordinator) -> None:
"""Initialize WLED playlist."""
super().__init__(coordinator=coordinator)
self._attr_name = f"{coordinator.data.info.name} Playlist"
self._attr_unique_id = f"{coordinator.data.info.mac_address}_playlist"
self._attr_options = [
playlist.name for playlist in self.coordinator.data.playlists
]
@property
def available(self) -> bool:
"""Return True if entity is available."""
return len(self.coordinator.data.playlists) > 0 and super().available
@property
def current_option(self) -> str | None:
"""Return the currently selected playlist."""
if not isinstance(self.coordinator.data.state.playlist, Playlist):
return None
return self.coordinator.data.state.playlist.name
@wled_exception_handler
async def async_select_option(self, option: str) -> None:
"""Set WLED segment to the selected playlist."""
await self.coordinator.wled.playlist(playlist=option)
class WLEDPaletteSelect(WLEDEntity, SelectEntity):
"""Defines a WLED Palette select."""
_attr_icon = "mdi:palette-outline"
_segment: int
_attr_entity_registry_enabled_default = False
def __init__(self, coordinator: WLEDDataUpdateCoordinator, segment: int) -> None:
"""Initialize WLED ."""
super().__init__(coordinator=coordinator)
# Segment 0 uses a simpler name, which is more natural for when using
# a single segment / using WLED with one big LED strip.
self._attr_name = (
f"{coordinator.data.info.name} Segment {segment} Color Palette"
)
if segment == 0:
self._attr_name = f"{coordinator.data.info.name} Color Palette"
self._attr_unique_id = f"{coordinator.data.info.mac_address}_palette_{segment}"
self._attr_options = [
palette.name for palette in self.coordinator.data.palettes
]
self._segment = segment
@property
def available(self) -> bool:
"""Return True if entity is available."""
try:
self.coordinator.data.state.segments[self._segment]
except IndexError:
return False
return super().available
@property
def current_option(self) -> str | None:
"""Return the current selected color palette."""
return self.coordinator.data.state.segments[self._segment].palette.name
@wled_exception_handler
async def async_select_option(self, option: str) -> None:
"""Set WLED segment to the selected color palette."""
await self.coordinator.wled.segment(segment_id=self._segment, palette=option)
@callback
def async_update_segments(
coordinator: WLEDDataUpdateCoordinator,
current_ids: set[int],
async_add_entities,
) -> None:
"""Update segments."""
segment_ids = {segment.segment_id for segment in coordinator.data.state.segments}
new_entities = []
# Process new segments, add them to Home Assistant
for segment_id in segment_ids - current_ids:
current_ids.add(segment_id)
new_entities.append(WLEDPaletteSelect(coordinator, segment_id))
if new_entities:
async_add_entities(new_entities)