Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion homeassistant/components/airzone/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@
from .const import DOMAIN
from .coordinator import AirzoneUpdateCoordinator

PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.CLIMATE, Platform.SENSOR]
PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR,
Platform.CLIMATE,
Platform.SELECT,
Platform.SENSOR,
]

_LOGGER = logging.getLogger(__name__)

Expand Down
24 changes: 0 additions & 24 deletions homeassistant/components/airzone/climate.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
"""Support for the Airzone climate."""
from __future__ import annotations

import logging
from typing import Any, Final

from aioairzone.common import OperationMode
from aioairzone.const import (
API_MODE,
API_ON,
API_SET_POINT,
API_SYSTEM_ID,
API_ZONE_ID,
AZD_DEMAND,
AZD_HUMIDITY,
AZD_MASTER,
Expand All @@ -25,7 +22,6 @@
AZD_TEMP_UNIT,
AZD_ZONES,
)
from aioairzone.exceptions import AirzoneError

from homeassistant.components.climate import (
ClimateEntity,
Expand All @@ -43,9 +39,6 @@
from .coordinator import AirzoneUpdateCoordinator
from .entity import AirzoneZoneEntity

_LOGGER = logging.getLogger(__name__)


HVAC_ACTION_LIB_TO_HASS: Final[dict[OperationMode, HVACAction]] = {
OperationMode.STOP: HVACAction.OFF,
OperationMode.COOLING: HVACAction.COOLING,
Expand Down Expand Up @@ -114,23 +107,6 @@ def __init__(
]
self._async_update_attrs()

async def _async_update_hvac_params(self, params: dict[str, Any]) -> None:
"""Send HVAC parameters to API."""
_params = {
API_SYSTEM_ID: self.system_id,
API_ZONE_ID: self.zone_id,
**params,
}
_LOGGER.debug("update_hvac_params=%s", _params)
try:
await self.coordinator.airzone.set_hvac_parameters(_params)
except AirzoneError as error:
raise HomeAssistantError(
f"Failed to set zone {self.name}: {error}"
) from error
else:
self.coordinator.async_set_updated_data(self.coordinator.airzone.data())

async def async_turn_on(self) -> None:
"""Turn the entity on."""
params = {
Expand Down
24 changes: 24 additions & 0 deletions homeassistant/components/airzone/entity.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
"""Entity classes for the Airzone integration."""
from __future__ import annotations

import logging
from typing import Any

from aioairzone.const import (
API_SYSTEM_ID,
API_ZONE_ID,
AZD_FIRMWARE,
AZD_FULL_NAME,
AZD_ID,
Expand All @@ -17,15 +20,19 @@
AZD_WEBSERVER,
AZD_ZONES,
)
from aioairzone.exceptions import AirzoneError

from homeassistant.config_entries import ConfigEntry
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .const import DOMAIN, MANUFACTURER
from .coordinator import AirzoneUpdateCoordinator

_LOGGER = logging.getLogger(__name__)


class AirzoneEntity(CoordinatorEntity[AirzoneUpdateCoordinator]):
"""Define an Airzone entity."""
Expand Down Expand Up @@ -130,3 +137,20 @@ def get_airzone_value(self, key: str) -> Any:
if key in zone:
value = zone[key]
return value

async def _async_update_hvac_params(self, params: dict[str, Any]) -> None:
"""Send HVAC parameters to API."""
_params = {
API_SYSTEM_ID: self.system_id,
API_ZONE_ID: self.zone_id,
**params,
}
_LOGGER.debug("update_hvac_params=%s", _params)
try:
await self.coordinator.airzone.set_hvac_parameters(_params)
except AirzoneError as error:
raise HomeAssistantError(
f"Failed to set zone {self.name}: {error}"
) from error
else:
self.coordinator.async_set_updated_data(self.coordinator.airzone.data())
160 changes: 160 additions & 0 deletions homeassistant/components/airzone/select.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
"""Support for the Airzone sensors."""
from __future__ import annotations

from dataclasses import dataclass, replace
from typing import Any, Final

from aioairzone.common import GrilleAngle, SleepTimeout
from aioairzone.const import (
API_COLD_ANGLE,
API_HEAT_ANGLE,
API_SLEEP,
AZD_COLD_ANGLE,
AZD_HEAT_ANGLE,
AZD_NAME,
AZD_SLEEP,
AZD_ZONES,
)

from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import DOMAIN
from .coordinator import AirzoneUpdateCoordinator
from .entity import AirzoneEntity, AirzoneZoneEntity


@dataclass
class AirzoneSelectDescriptionMixin:
"""Define an entity description mixin for select entities."""

api_param: str
options_dict: dict[str, int]


@dataclass
class AirzoneSelectDescription(SelectEntityDescription, AirzoneSelectDescriptionMixin):
"""Class to describe an Airzone select entity."""


GRILLE_ANGLE_DICT: Final[dict[str, int]] = {
Comment thread
Noltari marked this conversation as resolved.
"90º": GrilleAngle.DEG_90,
"50º": GrilleAngle.DEG_50,
"45º": GrilleAngle.DEG_45,
"40º": GrilleAngle.DEG_40,
}

SLEEP_DICT: Final[dict[str, int]] = {
"Off": SleepTimeout.SLEEP_OFF,
"30m": SleepTimeout.SLEEP_30,
"60m": SleepTimeout.SLEEP_60,
"90m": SleepTimeout.SLEEP_90,
}


ZONE_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = (
AirzoneSelectDescription(
api_param=API_COLD_ANGLE,
entity_category=EntityCategory.CONFIG,
key=AZD_COLD_ANGLE,
name="Cold Angle",
options_dict=GRILLE_ANGLE_DICT,
),
AirzoneSelectDescription(
api_param=API_HEAT_ANGLE,
entity_category=EntityCategory.CONFIG,
key=AZD_HEAT_ANGLE,
name="Heat Angle",
options_dict=GRILLE_ANGLE_DICT,
),
AirzoneSelectDescription(
api_param=API_SLEEP,
entity_category=EntityCategory.CONFIG,
key=AZD_SLEEP,
name="Sleep",
options_dict=SLEEP_DICT,
),
)


async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Add Airzone sensors from a config_entry."""
coordinator = hass.data[DOMAIN][entry.entry_id]

entities: list[AirzoneBaseSelect] = []

for system_zone_id, zone_data in coordinator.data[AZD_ZONES].items():
for description in ZONE_SELECT_TYPES:
if description.key in zone_data:
_desc = replace(
description,
options=list(description.options_dict.keys()),
Comment thread
Noltari marked this conversation as resolved.
)
entities.append(
AirzoneZoneSelect(
coordinator,
_desc,
entry,
system_zone_id,
zone_data,
)
)

async_add_entities(entities)


class AirzoneBaseSelect(AirzoneEntity, SelectEntity):
"""Define an Airzone select."""

entity_description: AirzoneSelectDescription
values_dict: dict[int, str]

@callback
def _handle_coordinator_update(self) -> None:
"""Update attributes when the coordinator updates."""
self._async_update_attrs()
super()._handle_coordinator_update()

def _get_current_option(self) -> str | None:
value = self.get_airzone_value(self.entity_description.key)
return self.values_dict.get(value)

@callback
def _async_update_attrs(self) -> None:
"""Update select attributes."""
self._attr_current_option = self._get_current_option()


class AirzoneZoneSelect(AirzoneZoneEntity, AirzoneBaseSelect):
"""Define an Airzone Zone select."""

def __init__(
self,
coordinator: AirzoneUpdateCoordinator,
description: AirzoneSelectDescription,
entry: ConfigEntry,
system_zone_id: str,
zone_data: dict[str, Any],
) -> None:
"""Initialize."""
super().__init__(coordinator, entry, system_zone_id, zone_data)

self._attr_name = f"{zone_data[AZD_NAME]} {description.name}"
self._attr_unique_id = (
f"{self._attr_unique_id}_{system_zone_id}_{description.key}"
)
self.entity_description = description
self.values_dict = {v: k for k, v in description.options_dict.items()}

self._async_update_attrs()

async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
param = self.entity_description.api_param
value = self.entity_description.options_dict[option]
await self._async_update_hvac_params({param: value})
Loading