Files

240 lines
8.6 KiB
Python

"""Select platform for IronOS integration."""
from collections.abc import Callable
from dataclasses import dataclass
from enum import Enum, StrEnum
from typing import override
from pynecil import (
AnimationSpeed,
AutostartMode,
BatteryType,
CharSetting,
LockingMode,
LogoDuration,
ScreenOrientationMode,
ScrollSpeed,
SettingsDataResponse,
TempUnit,
TipType,
USBPDMode,
)
from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import IronOSConfigEntry
from .coordinator import IronOSCoordinators
from .entity import IronOSBaseEntity
PARALLEL_UPDATES = 0
@dataclass(frozen=True, kw_only=True)
class IronOSSelectEntityDescription(SelectEntityDescription):
"""Describes IronOS select entity."""
value_fn: Callable[[SettingsDataResponse], str | None]
characteristic: CharSetting
raw_value_fn: Callable[[str], Enum]
class PinecilSelect(StrEnum):
"""Select controls for Pinecil device."""
MIN_DC_VOLTAGE_CELLS = "min_dc_voltage_cells"
ORIENTATION_MODE = "orientation_mode"
ANIMATION_SPEED = "animation_speed"
AUTOSTART_MODE = "autostart_mode"
TEMP_UNIT = "temp_unit"
DESC_SCROLL_SPEED = "desc_scroll_speed"
LOCKING_MODE = "locking_mode"
LOGO_DURATION = "logo_duration"
USB_PD_MODE = "usb_pd_mode"
TIP_TYPE = "tip_type"
def enum_to_str(enum: Enum | None) -> str | None:
"""Convert enum name to lower-case string."""
return enum.name.lower() if isinstance(enum, Enum) else None
PINECIL_SELECT_DESCRIPTIONS: tuple[IronOSSelectEntityDescription, ...] = (
IronOSSelectEntityDescription(
key=PinecilSelect.MIN_DC_VOLTAGE_CELLS,
translation_key=PinecilSelect.MIN_DC_VOLTAGE_CELLS,
characteristic=CharSetting.MIN_DC_VOLTAGE_CELLS,
value_fn=lambda x: enum_to_str(x.get("min_dc_voltage_cells")),
raw_value_fn=lambda value: BatteryType[value.upper()],
options=[x.name.lower() for x in BatteryType],
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
),
IronOSSelectEntityDescription(
key=PinecilSelect.ORIENTATION_MODE,
translation_key=PinecilSelect.ORIENTATION_MODE,
characteristic=CharSetting.ORIENTATION_MODE,
value_fn=lambda x: enum_to_str(x.get("orientation_mode")),
raw_value_fn=lambda value: ScreenOrientationMode[value.upper()],
options=[x.name.lower() for x in ScreenOrientationMode],
entity_category=EntityCategory.CONFIG,
),
IronOSSelectEntityDescription(
key=PinecilSelect.ANIMATION_SPEED,
translation_key=PinecilSelect.ANIMATION_SPEED,
characteristic=CharSetting.ANIMATION_SPEED,
value_fn=lambda x: enum_to_str(x.get("animation_speed")),
raw_value_fn=lambda value: AnimationSpeed[value.upper()],
options=[x.name.lower() for x in AnimationSpeed],
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
),
IronOSSelectEntityDescription(
key=PinecilSelect.AUTOSTART_MODE,
translation_key=PinecilSelect.AUTOSTART_MODE,
characteristic=CharSetting.AUTOSTART_MODE,
value_fn=lambda x: enum_to_str(x.get("autostart_mode")),
raw_value_fn=lambda value: AutostartMode[value.upper()],
options=[x.name.lower() for x in AutostartMode],
entity_category=EntityCategory.CONFIG,
),
IronOSSelectEntityDescription(
key=PinecilSelect.TEMP_UNIT,
translation_key=PinecilSelect.TEMP_UNIT,
characteristic=CharSetting.TEMP_UNIT,
value_fn=lambda x: enum_to_str(x.get("temp_unit")),
raw_value_fn=lambda value: TempUnit[value.upper()],
options=[x.name.lower() for x in TempUnit],
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
),
IronOSSelectEntityDescription(
key=PinecilSelect.DESC_SCROLL_SPEED,
translation_key=PinecilSelect.DESC_SCROLL_SPEED,
characteristic=CharSetting.DESC_SCROLL_SPEED,
value_fn=lambda x: enum_to_str(x.get("desc_scroll_speed")),
raw_value_fn=lambda value: ScrollSpeed[value.upper()],
options=[x.name.lower() for x in ScrollSpeed],
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
),
IronOSSelectEntityDescription(
key=PinecilSelect.LOCKING_MODE,
translation_key=PinecilSelect.LOCKING_MODE,
characteristic=CharSetting.LOCKING_MODE,
value_fn=lambda x: enum_to_str(x.get("locking_mode")),
raw_value_fn=lambda value: LockingMode[value.upper()],
options=[x.name.lower() for x in LockingMode],
entity_category=EntityCategory.CONFIG,
),
IronOSSelectEntityDescription(
key=PinecilSelect.LOGO_DURATION,
translation_key=PinecilSelect.LOGO_DURATION,
characteristic=CharSetting.LOGO_DURATION,
value_fn=lambda x: enum_to_str(x.get("logo_duration")),
raw_value_fn=lambda value: LogoDuration[value.upper()],
options=[x.name.lower() for x in LogoDuration],
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
),
)
PINECIL_SELECT_DESCRIPTIONS_V222: tuple[IronOSSelectEntityDescription, ...] = (
IronOSSelectEntityDescription(
key=PinecilSelect.USB_PD_MODE,
translation_key=PinecilSelect.USB_PD_MODE,
characteristic=CharSetting.USB_PD_MODE,
value_fn=lambda x: enum_to_str(x.get("usb_pd_mode")),
raw_value_fn=lambda value: USBPDMode[value.upper()],
options=["off", "on"],
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
),
)
PINECIL_SELECT_DESCRIPTIONS_V223: tuple[IronOSSelectEntityDescription, ...] = (
IronOSSelectEntityDescription(
key=PinecilSelect.USB_PD_MODE,
translation_key=PinecilSelect.USB_PD_MODE,
characteristic=CharSetting.USB_PD_MODE,
value_fn=lambda x: enum_to_str(x.get("usb_pd_mode")),
raw_value_fn=lambda value: USBPDMode[value.upper()],
options=[x.name.lower() for x in USBPDMode],
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
),
IronOSSelectEntityDescription(
key=PinecilSelect.TIP_TYPE,
translation_key=PinecilSelect.TIP_TYPE,
characteristic=CharSetting.TIP_TYPE,
value_fn=lambda x: enum_to_str(x.get("tip_type")),
raw_value_fn=lambda value: TipType[value.upper()],
options=[x.name.lower() for x in TipType],
entity_category=EntityCategory.CONFIG,
),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: IronOSConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up select entities from a config entry."""
coordinators = entry.runtime_data
descriptions = PINECIL_SELECT_DESCRIPTIONS
descriptions += (
PINECIL_SELECT_DESCRIPTIONS_V223
if coordinators.live_data.v223_features
else PINECIL_SELECT_DESCRIPTIONS_V222
)
async_add_entities(
IronOSSelectEntity(coordinators, description) for description in descriptions
)
class IronOSSelectEntity(IronOSBaseEntity, SelectEntity):
"""Implementation of a IronOS select entity."""
entity_description: IronOSSelectEntityDescription
def __init__(
self,
coordinators: IronOSCoordinators,
entity_description: IronOSSelectEntityDescription,
) -> None:
"""Initialize the select entity."""
super().__init__(coordinators.live_data, entity_description)
self.settings = coordinators.settings
@property
@override
def current_option(self) -> str | None:
"""Return the selected entity option to represent the entity state."""
return self.entity_description.value_fn(self.settings.data)
@override
async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
await self.settings.write(
self.entity_description.characteristic,
self.entity_description.raw_value_fn(option),
)
@override
async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
self.async_on_remove(
self.settings.async_add_listener(
self._handle_coordinator_update, self.entity_description.characteristic
)
)
await self.settings.async_request_refresh()