156 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			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.const import EntityCategory
 | 
						|
from homeassistant.core import HomeAssistant, callback
 | 
						|
from homeassistant.exceptions import HomeAssistantError
 | 
						|
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]
 |