core/homeassistant/components/rainmachine/select.py

156 lines
4.9 KiB
Python

"""Support for RainMachine selects."""
from __future__ import annotations
from dataclasses import dataclass
from regenmaschine.errors import RainMachineError
from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM, UnitSystem
from . import RainMachineData, RainMachineEntity
from .const import DATA_RESTRICTIONS_UNIVERSAL, DOMAIN
from .model import (
RainMachineEntityDescription,
RainMachineEntityDescriptionMixinDataKey,
)
from .util import key_exists
@dataclass
class RainMachineSelectDescription(
SelectEntityDescription,
RainMachineEntityDescription,
RainMachineEntityDescriptionMixinDataKey,
):
"""Describe a generic RainMachine select."""
@dataclass
class FreezeProtectionSelectOption:
"""Define an option for a freeze selection select."""
api_value: float
imperial_label: str
metric_label: str
@dataclass
class FreezeProtectionTemperatureMixin:
"""Define an entity description mixin to include an options list."""
extended_options: list[FreezeProtectionSelectOption]
@dataclass
class FreezeProtectionSelectDescription(
RainMachineSelectDescription, FreezeProtectionTemperatureMixin
):
"""Describe a freeze protection temperature select."""
TYPE_FREEZE_PROTECTION_TEMPERATURE = "freeze_protection_temperature"
SELECT_DESCRIPTIONS = (
FreezeProtectionSelectDescription(
key=TYPE_FREEZE_PROTECTION_TEMPERATURE,
name="Freeze protection temperature",
icon="mdi:thermometer",
entity_category=EntityCategory.CONFIG,
api_category=DATA_RESTRICTIONS_UNIVERSAL,
data_key="freezeProtectTemp",
extended_options=[
FreezeProtectionSelectOption(
api_value=0.0,
imperial_label="32°F",
metric_label="0°C",
),
FreezeProtectionSelectOption(
api_value=2.0,
imperial_label="35.6°F",
metric_label="2°C",
),
FreezeProtectionSelectOption(
api_value=5.0,
imperial_label="41°F",
metric_label="5°C",
),
FreezeProtectionSelectOption(
api_value=10.0,
imperial_label="50°F",
metric_label="10°C",
),
],
),
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up RainMachine selects based on a config entry."""
data: RainMachineData = hass.data[DOMAIN][entry.entry_id]
entity_map = {
TYPE_FREEZE_PROTECTION_TEMPERATURE: FreezeProtectionTemperatureSelect,
}
async_add_entities(
entity_map[description.key](entry, data, description, hass.config.units)
for description in SELECT_DESCRIPTIONS
if (
(coordinator := data.coordinators[description.api_category]) is not None
and coordinator.data
and key_exists(coordinator.data, description.data_key)
)
)
class FreezeProtectionTemperatureSelect(RainMachineEntity, SelectEntity):
"""Define a RainMachine select."""
entity_description: FreezeProtectionSelectDescription
def __init__(
self,
entry: ConfigEntry,
data: RainMachineData,
description: FreezeProtectionSelectDescription,
unit_system: UnitSystem,
) -> None:
"""Initialize."""
super().__init__(entry, data, description)
self._api_value_to_label_map = {}
self._label_to_api_value_map = {}
for option in description.extended_options:
if unit_system is US_CUSTOMARY_SYSTEM:
label = option.imperial_label
else:
label = option.metric_label
self._api_value_to_label_map[option.api_value] = label
self._label_to_api_value_map[label] = option.api_value
self._attr_options = list(self._label_to_api_value_map)
async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
try:
await self._data.controller.restrictions.set_universal(
{self.entity_description.data_key: self._label_to_api_value_map[option]}
)
except RainMachineError as err:
raise HomeAssistantError(f"Error while setting {self.name}: {err}") from err
@callback
def update_from_latest_data(self) -> None:
"""Update the entity when new data is received."""
raw_value = self.coordinator.data[self.entity_description.data_key]
self._attr_current_option = self._api_value_to_label_map[raw_value]