1
0
mirror of https://github.com/home-assistant/core.git synced 2026-07-14 18:14:35 +01:00
Files
2026-07-07 15:55:09 +02:00

160 lines
5.4 KiB
Python

"""Vistapool Select entities."""
from dataclasses import dataclass
from typing import Any, override
from aioaquarite import AquariteError
from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import VistapoolConfigEntry
from .const import DOMAIN, SIGNAL_NEW_POOL
from .coordinator import VistapoolDataUpdateCoordinator
from .entity import VistapoolEntity
PARALLEL_UPDATES = 1
_PUMP_MODE_OPTIONS = ["manual", "auto", "heat", "smart", "intel"]
_PUMP_SPEED_OPTIONS = ["slow", "medium", "high"]
@dataclass(frozen=True, kw_only=True)
class VistapoolSelectEntityDescription(SelectEntityDescription):
"""Describes a Vistapool select entity."""
value_path: str
exists_path: str | tuple[str, ...] | None = None
translation_placeholders: dict[str, str] | None = None
SELECT_DESCRIPTIONS: tuple[VistapoolSelectEntityDescription, ...] = (
VistapoolSelectEntityDescription(
key="pump_mode",
translation_key="pump_mode",
entity_category=EntityCategory.CONFIG,
options=_PUMP_MODE_OPTIONS,
value_path="filtration.mode",
),
VistapoolSelectEntityDescription(
key="pump_speed",
translation_key="pump_speed",
entity_category=EntityCategory.CONFIG,
options=_PUMP_SPEED_OPTIONS,
value_path="filtration.manVel",
),
*(
VistapoolSelectEntityDescription(
key=f"filtration_timer_speed_{i}",
translation_key="filtration_timer_speed",
translation_placeholders={"number": str(i)},
entity_category=EntityCategory.CONFIG,
options=_PUMP_SPEED_OPTIONS,
value_path=f"filtration.timerVel{i}",
)
for i in (1, 2, 3)
),
)
def _build_select_entities(
coordinator: VistapoolDataUpdateCoordinator,
) -> list[SelectEntity]:
"""Build the select entities for a single pool."""
entities: list[SelectEntity] = []
for description in SELECT_DESCRIPTIONS:
if description.exists_path is not None:
required = (
(description.exists_path,)
if isinstance(description.exists_path, str)
else description.exists_path
)
if not all(coordinator.get_value(path) for path in required):
continue
entities.append(VistapoolSelect(coordinator, description))
return entities
async def async_setup_entry(
hass: HomeAssistant,
entry: VistapoolConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up Vistapool select entities for every pool on the account."""
entities: list[SelectEntity] = []
for coordinator in entry.runtime_data.coordinators.values():
entities.extend(_build_select_entities(coordinator))
async_add_entities(entities)
@callback
def _async_add_pool(coordinator: VistapoolDataUpdateCoordinator) -> None:
async_add_entities(_build_select_entities(coordinator))
entry.async_on_unload(
async_dispatcher_connect(
hass, f"{SIGNAL_NEW_POOL}_{entry.entry_id}", _async_add_pool
)
)
def _to_index(raw: Any) -> int | None:
"""Convert a coordinator value into an options-list index, or None if not possible."""
if raw is None:
return None
try:
return int(raw)
except TypeError, ValueError:
return None
class VistapoolSelect(VistapoolEntity, SelectEntity):
"""Generic Vistapool select driven by an entity description."""
entity_description: VistapoolSelectEntityDescription
def __init__(
self,
coordinator: VistapoolDataUpdateCoordinator,
description: VistapoolSelectEntityDescription,
) -> None:
"""Initialize the select entity."""
super().__init__(coordinator)
self.entity_description = description
self._attr_unique_id = self.build_unique_id(description.key)
if description.translation_placeholders is not None:
self._attr_translation_placeholders = description.translation_placeholders
@property
@override
def current_option(self) -> str | None:
"""Return the option that maps to the current API value."""
index = _to_index(
self.coordinator.get_value(self.entity_description.value_path)
)
options = self.entity_description.options or []
if index is None or not 0 <= index < len(options):
return None
return options[index]
@override
async def async_select_option(self, option: str) -> None:
"""Send the index of the chosen option to the controller."""
assert self.entity_description.options is not None
index = self.entity_description.options.index(option)
try:
await self.coordinator.api.set_value(
self.coordinator.pool_id,
self.entity_description.value_path,
index,
)
except AquariteError as err:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="set_failed",
translation_placeholders={"entity": self.entity_id},
) from err