mirror of
https://github.com/home-assistant/core.git
synced 2025-10-17 23:59:38 +00:00
260 lines
8.3 KiB
Python
260 lines
8.3 KiB
Python
"""Climate platform for Actron Air integration."""
|
|
|
|
from typing import Any
|
|
|
|
from actron_neo_api import ActronAirNeoStatus, ActronAirNeoZone
|
|
|
|
from homeassistant.components.climate import (
|
|
FAN_AUTO,
|
|
FAN_HIGH,
|
|
FAN_LOW,
|
|
FAN_MEDIUM,
|
|
ClimateEntity,
|
|
ClimateEntityFeature,
|
|
HVACMode,
|
|
)
|
|
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.device_registry import DeviceInfo
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
|
|
|
from .const import DOMAIN
|
|
from .coordinator import ActronAirConfigEntry, ActronAirSystemCoordinator
|
|
|
|
PARALLEL_UPDATES = 0
|
|
|
|
FAN_MODE_MAPPING_ACTRONAIR_TO_HA = {
|
|
"AUTO": FAN_AUTO,
|
|
"LOW": FAN_LOW,
|
|
"MED": FAN_MEDIUM,
|
|
"HIGH": FAN_HIGH,
|
|
}
|
|
FAN_MODE_MAPPING_HA_TO_ACTRONAIR = {
|
|
v: k for k, v in FAN_MODE_MAPPING_ACTRONAIR_TO_HA.items()
|
|
}
|
|
HVAC_MODE_MAPPING_ACTRONAIR_TO_HA = {
|
|
"COOL": HVACMode.COOL,
|
|
"HEAT": HVACMode.HEAT,
|
|
"FAN": HVACMode.FAN_ONLY,
|
|
"AUTO": HVACMode.AUTO,
|
|
"OFF": HVACMode.OFF,
|
|
}
|
|
HVAC_MODE_MAPPING_HA_TO_ACTRONAIR = {
|
|
v: k for k, v in HVAC_MODE_MAPPING_ACTRONAIR_TO_HA.items()
|
|
}
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: ActronAirConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up Actron Air climate entities."""
|
|
system_coordinators = entry.runtime_data.system_coordinators
|
|
entities: list[ClimateEntity] = []
|
|
|
|
for coordinator in system_coordinators.values():
|
|
status = coordinator.data
|
|
name = status.ac_system.system_name
|
|
entities.append(ActronSystemClimate(coordinator, name))
|
|
|
|
entities.extend(
|
|
ActronZoneClimate(coordinator, zone)
|
|
for zone in status.remote_zone_info
|
|
if zone.exists
|
|
)
|
|
|
|
async_add_entities(entities)
|
|
|
|
|
|
class BaseClimateEntity(CoordinatorEntity[ActronAirSystemCoordinator], ClimateEntity):
|
|
"""Base class for Actron Air climate entities."""
|
|
|
|
_attr_has_entity_name = True
|
|
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
|
_attr_supported_features = (
|
|
ClimateEntityFeature.TARGET_TEMPERATURE
|
|
| ClimateEntityFeature.FAN_MODE
|
|
| ClimateEntityFeature.TURN_ON
|
|
| ClimateEntityFeature.TURN_OFF
|
|
)
|
|
_attr_name = None
|
|
_attr_fan_modes = list(FAN_MODE_MAPPING_ACTRONAIR_TO_HA.values())
|
|
_attr_hvac_modes = list(HVAC_MODE_MAPPING_ACTRONAIR_TO_HA.values())
|
|
|
|
def __init__(
|
|
self,
|
|
coordinator: ActronAirSystemCoordinator,
|
|
name: str,
|
|
) -> None:
|
|
"""Initialize an Actron Air unit."""
|
|
super().__init__(coordinator)
|
|
self._serial_number = coordinator.serial_number
|
|
|
|
|
|
class ActronSystemClimate(BaseClimateEntity):
|
|
"""Representation of the Actron Air system."""
|
|
|
|
_attr_supported_features = (
|
|
ClimateEntityFeature.TARGET_TEMPERATURE
|
|
| ClimateEntityFeature.FAN_MODE
|
|
| ClimateEntityFeature.TURN_ON
|
|
| ClimateEntityFeature.TURN_OFF
|
|
)
|
|
|
|
def __init__(
|
|
self,
|
|
coordinator: ActronAirSystemCoordinator,
|
|
name: str,
|
|
) -> None:
|
|
"""Initialize an Actron Air unit."""
|
|
super().__init__(coordinator, name)
|
|
serial_number = coordinator.serial_number
|
|
self._attr_unique_id = serial_number
|
|
self._attr_device_info = DeviceInfo(
|
|
identifiers={(DOMAIN, serial_number)},
|
|
name=self._status.ac_system.system_name,
|
|
manufacturer="Actron Air",
|
|
model_id=self._status.ac_system.master_wc_model,
|
|
sw_version=self._status.ac_system.master_wc_firmware_version,
|
|
serial_number=serial_number,
|
|
)
|
|
|
|
@property
|
|
def min_temp(self) -> float:
|
|
"""Return the minimum temperature that can be set."""
|
|
return self._status.min_temp
|
|
|
|
@property
|
|
def max_temp(self) -> float:
|
|
"""Return the maximum temperature that can be set."""
|
|
return self._status.max_temp
|
|
|
|
@property
|
|
def _status(self) -> ActronAirNeoStatus:
|
|
"""Get the current status from the coordinator."""
|
|
return self.coordinator.data
|
|
|
|
@property
|
|
def hvac_mode(self) -> HVACMode | None:
|
|
"""Return the current HVAC mode."""
|
|
if not self._status.user_aircon_settings.is_on:
|
|
return HVACMode.OFF
|
|
|
|
mode = self._status.user_aircon_settings.mode
|
|
return HVAC_MODE_MAPPING_ACTRONAIR_TO_HA.get(mode)
|
|
|
|
@property
|
|
def fan_mode(self) -> str | None:
|
|
"""Return the current fan mode."""
|
|
fan_mode = self._status.user_aircon_settings.fan_mode
|
|
return FAN_MODE_MAPPING_ACTRONAIR_TO_HA.get(fan_mode)
|
|
|
|
@property
|
|
def current_humidity(self) -> float:
|
|
"""Return the current humidity."""
|
|
return self._status.master_info.live_humidity_pc
|
|
|
|
@property
|
|
def current_temperature(self) -> float:
|
|
"""Return the current temperature."""
|
|
return self._status.master_info.live_temp_c
|
|
|
|
@property
|
|
def target_temperature(self) -> float:
|
|
"""Return the target temperature."""
|
|
return self._status.user_aircon_settings.temperature_setpoint_cool_c
|
|
|
|
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
|
"""Set a new fan mode."""
|
|
api_fan_mode = FAN_MODE_MAPPING_HA_TO_ACTRONAIR.get(fan_mode.lower())
|
|
await self._status.user_aircon_settings.set_fan_mode(api_fan_mode)
|
|
|
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
"""Set the HVAC mode."""
|
|
ac_mode = HVAC_MODE_MAPPING_HA_TO_ACTRONAIR.get(hvac_mode)
|
|
await self._status.ac_system.set_system_mode(ac_mode)
|
|
|
|
async def async_set_temperature(self, **kwargs: Any) -> None:
|
|
"""Set the temperature."""
|
|
temp = kwargs.get(ATTR_TEMPERATURE)
|
|
await self._status.user_aircon_settings.set_temperature(temperature=temp)
|
|
|
|
|
|
class ActronZoneClimate(BaseClimateEntity):
|
|
"""Representation of a zone within the Actron Air system."""
|
|
|
|
_attr_supported_features = (
|
|
ClimateEntityFeature.TARGET_TEMPERATURE
|
|
| ClimateEntityFeature.TURN_ON
|
|
| ClimateEntityFeature.TURN_OFF
|
|
)
|
|
|
|
def __init__(
|
|
self,
|
|
coordinator: ActronAirSystemCoordinator,
|
|
zone: ActronAirNeoZone,
|
|
) -> None:
|
|
"""Initialize an Actron Air unit."""
|
|
super().__init__(coordinator, zone.title)
|
|
serial_number = coordinator.serial_number
|
|
self._zone_id: int = zone.zone_id
|
|
self._attr_unique_id: str = f"{serial_number}_zone_{zone.zone_id}"
|
|
self._attr_device_info: DeviceInfo = DeviceInfo(
|
|
identifiers={(DOMAIN, self._attr_unique_id)},
|
|
name=zone.title,
|
|
manufacturer="Actron Air",
|
|
model="Zone",
|
|
suggested_area=zone.title,
|
|
via_device=(DOMAIN, serial_number),
|
|
)
|
|
|
|
@property
|
|
def min_temp(self) -> float:
|
|
"""Return the minimum temperature that can be set."""
|
|
return self._zone.min_temp
|
|
|
|
@property
|
|
def max_temp(self) -> float:
|
|
"""Return the maximum temperature that can be set."""
|
|
return self._zone.max_temp
|
|
|
|
@property
|
|
def _zone(self) -> ActronAirNeoZone:
|
|
"""Get the current zone data from the coordinator."""
|
|
status = self.coordinator.data
|
|
return status.zones[self._zone_id]
|
|
|
|
@property
|
|
def hvac_mode(self) -> HVACMode | None:
|
|
"""Return the current HVAC mode."""
|
|
if self._zone.is_active:
|
|
mode = self._zone.hvac_mode
|
|
return HVAC_MODE_MAPPING_ACTRONAIR_TO_HA.get(mode)
|
|
return HVACMode.OFF
|
|
|
|
@property
|
|
def current_humidity(self) -> float | None:
|
|
"""Return the current humidity."""
|
|
return self._zone.humidity
|
|
|
|
@property
|
|
def current_temperature(self) -> float | None:
|
|
"""Return the current temperature."""
|
|
return self._zone.live_temp_c
|
|
|
|
@property
|
|
def target_temperature(self) -> float | None:
|
|
"""Return the target temperature."""
|
|
return self._zone.temperature_setpoint_cool_c
|
|
|
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
"""Set the HVAC mode."""
|
|
is_enabled = hvac_mode != HVACMode.OFF
|
|
await self._zone.enable(is_enabled)
|
|
|
|
async def async_set_temperature(self, **kwargs: Any) -> None:
|
|
"""Set the temperature."""
|
|
await self._zone.set_temperature(temperature=kwargs["temperature"])
|