1
mirror of https://github.com/home-assistant/core synced 2024-08-28 03:36:46 +02:00
ha-core/homeassistant/components/roku/select.py
Erik Montnemery 0c2485bc03
Freeze integration entity descriptions (#105984)
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-12-18 16:28:13 -10:00

171 lines
4.7 KiB
Python

"""Support for Roku selects."""
from __future__ import annotations
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from rokuecp import Roku
from rokuecp.models import Device as RokuDevice
from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .coordinator import RokuDataUpdateCoordinator
from .entity import RokuEntity
from .helpers import format_channel_name, roku_exception_handler
@dataclass(frozen=True)
class RokuSelectEntityDescriptionMixin:
"""Mixin for required keys."""
options_fn: Callable[[RokuDevice], list[str]]
value_fn: Callable[[RokuDevice], str | None]
set_fn: Callable[[RokuDevice, Roku, str], Awaitable[None]]
def _get_application_name(device: RokuDevice) -> str | None:
if device.app is None or device.app.name is None:
return None
if device.app.name == "Roku":
return "Home"
return device.app.name
def _get_applications(device: RokuDevice) -> list[str]:
return ["Home"] + sorted(app.name for app in device.apps if app.name is not None)
def _get_channel_name(device: RokuDevice) -> str | None:
if device.channel is None:
return None
return format_channel_name(device.channel.number, device.channel.name)
def _get_channels(device: RokuDevice) -> list[str]:
return sorted(
format_channel_name(channel.number, channel.name) for channel in device.channels
)
async def _launch_application(device: RokuDevice, roku: Roku, value: str) -> None:
if value == "Home":
await roku.remote("home")
appl = next(
(app for app in device.apps if value == app.name),
None,
)
if appl is not None and appl.app_id is not None:
await roku.launch(appl.app_id)
async def _tune_channel(device: RokuDevice, roku: Roku, value: str) -> None:
_channel = next(
(
channel
for channel in device.channels
if (
channel.name is not None
and value == format_channel_name(channel.number, channel.name)
)
or value == channel.number
),
None,
)
if _channel is not None:
await roku.tune(_channel.number)
@dataclass(frozen=True)
class RokuSelectEntityDescription(
SelectEntityDescription, RokuSelectEntityDescriptionMixin
):
"""Describes Roku select entity."""
ENTITIES: tuple[RokuSelectEntityDescription, ...] = (
RokuSelectEntityDescription(
key="application",
translation_key="application",
icon="mdi:application",
set_fn=_launch_application,
value_fn=_get_application_name,
options_fn=_get_applications,
entity_registry_enabled_default=False,
),
)
CHANNEL_ENTITY = RokuSelectEntityDescription(
key="channel",
translation_key="channel",
icon="mdi:television",
set_fn=_tune_channel,
value_fn=_get_channel_name,
options_fn=_get_channels,
)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Roku select based on a config entry."""
coordinator: RokuDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
device: RokuDevice = coordinator.data
entities: list[RokuSelectEntity] = []
for description in ENTITIES:
entities.append(
RokuSelectEntity(
coordinator=coordinator,
description=description,
)
)
if len(device.channels) > 0:
entities.append(
RokuSelectEntity(
coordinator=coordinator,
description=CHANNEL_ENTITY,
)
)
async_add_entities(entities)
class RokuSelectEntity(RokuEntity, SelectEntity):
"""Defines a Roku select entity."""
entity_description: RokuSelectEntityDescription
@property
def current_option(self) -> str | None:
"""Return the current value."""
return self.entity_description.value_fn(self.coordinator.data)
@property
def options(self) -> list[str]:
"""Return a set of selectable options."""
return self.entity_description.options_fn(self.coordinator.data)
@roku_exception_handler()
async def async_select_option(self, option: str) -> None:
"""Set the option."""
await self.entity_description.set_fn(
self.coordinator.data,
self.coordinator.roku,
option,
)
await self.coordinator.async_request_refresh()