core/homeassistant/components/hunterdouglas_powerview/select.py

122 lines
3.9 KiB
Python

"""Support for hunterdouglass_powerview settings."""
from __future__ import annotations
from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from typing import Any, Final
from aiopvapi.resources.shade import BaseShade, factory as PvShade
from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import (
ATTR_BATTERY_KIND,
DOMAIN,
POWER_SUPPLY_TYPE_MAP,
POWER_SUPPLY_TYPE_REVERSE_MAP,
ROOM_ID_IN_SHADE,
ROOM_NAME_UNICODE,
SHADE_BATTERY_LEVEL,
)
from .coordinator import PowerviewShadeUpdateCoordinator
from .entity import ShadeEntity
from .model import PowerviewDeviceInfo, PowerviewEntryData
@dataclass
class PowerviewSelectDescriptionMixin:
"""Mixin to describe a select entity."""
current_fn: Callable[[BaseShade], Any]
select_fn: Callable[[BaseShade, str], Coroutine[Any, Any, bool]]
@dataclass
class PowerviewSelectDescription(
SelectEntityDescription, PowerviewSelectDescriptionMixin
):
"""A class that describes select entities."""
entity_category: EntityCategory = EntityCategory.CONFIG
DROPDOWNS: Final = [
PowerviewSelectDescription(
key="powersource",
name="Power Source",
icon="mdi:power-plug-outline",
current_fn=lambda shade: POWER_SUPPLY_TYPE_MAP.get(
shade.raw_data.get(ATTR_BATTERY_KIND), None
),
options=list(POWER_SUPPLY_TYPE_MAP.values()),
select_fn=lambda shade, option: shade.set_power_source(
POWER_SUPPLY_TYPE_REVERSE_MAP.get(option)
),
),
]
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the hunter douglas select entities."""
pv_entry: PowerviewEntryData = hass.data[DOMAIN][entry.entry_id]
entities = []
for raw_shade in pv_entry.shade_data.values():
shade: BaseShade = PvShade(raw_shade, pv_entry.api)
if SHADE_BATTERY_LEVEL not in shade.raw_data:
continue
name_before_refresh = shade.name
room_id = shade.raw_data.get(ROOM_ID_IN_SHADE)
room_name = pv_entry.room_data.get(room_id, {}).get(ROOM_NAME_UNICODE, "")
for description in DROPDOWNS:
entities.append(
PowerViewSelect(
pv_entry.coordinator,
pv_entry.device_info,
room_name,
shade,
name_before_refresh,
description,
)
)
async_add_entities(entities)
class PowerViewSelect(ShadeEntity, SelectEntity):
"""Representation of a select entity."""
def __init__(
self,
coordinator: PowerviewShadeUpdateCoordinator,
device_info: PowerviewDeviceInfo,
room_name: str,
shade: BaseShade,
name: str,
description: PowerviewSelectDescription,
) -> None:
"""Initialize the select entity."""
super().__init__(coordinator, device_info, room_name, shade, name)
self.entity_description: PowerviewSelectDescription = description
self._attr_name = f"{self._shade_name} {description.name}"
self._attr_unique_id = f"{self._attr_unique_id}_{description.key}"
@property
def current_option(self) -> str | None:
"""Return the selected entity option to represent the entity state."""
return self.entity_description.current_fn(self._shade)
async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
await self.entity_description.select_fn(self._shade, option)
await self._shade.refresh() # force update data to ensure new info is in coordinator
self.async_write_ha_state()