core/homeassistant/components/lg_thinq/climate.py

347 lines
12 KiB
Python

"""Support for climate entities."""
from __future__ import annotations
import logging
from typing import Any
from thinqconnect import DeviceType
from thinqconnect.integration import ExtendedProperty
from homeassistant.components.climate import (
ATTR_HVAC_MODE,
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
PRESET_NONE,
SWING_OFF,
SWING_ON,
ClimateEntity,
ClimateEntityDescription,
ClimateEntityFeature,
HVACMode,
)
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import ThinqConfigEntry
from .coordinator import DeviceDataUpdateCoordinator
from .entity import ThinQEntity
DEVICE_TYPE_CLIMATE_MAP: dict[DeviceType, tuple[ClimateEntityDescription, ...]] = {
DeviceType.AIR_CONDITIONER: (
ClimateEntityDescription(
key=ExtendedProperty.CLIMATE_AIR_CONDITIONER,
name=None,
translation_key=ExtendedProperty.CLIMATE_AIR_CONDITIONER,
),
),
DeviceType.SYSTEM_BOILER: (
ClimateEntityDescription(
key=ExtendedProperty.CLIMATE_SYSTEM_BOILER,
name=None,
translation_key=ExtendedProperty.CLIMATE_SYSTEM_BOILER,
),
),
}
STR_TO_HVAC: dict[str, HVACMode] = {
"air_dry": HVACMode.DRY,
"auto": HVACMode.AUTO,
"cool": HVACMode.COOL,
"fan": HVACMode.FAN_ONLY,
"heat": HVACMode.HEAT,
}
HVAC_TO_STR = {v: k for k, v in STR_TO_HVAC.items()}
THINQ_PRESET_MODE: list[str] = ["air_clean", "aroma", "energy_saving"]
STR_TO_SWING = {
"true": SWING_ON,
"false": SWING_OFF,
}
SWING_TO_STR = {v: k for k, v in STR_TO_SWING.items()}
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: ThinqConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up an entry for climate platform."""
entities: list[ThinQClimateEntity] = []
for coordinator in entry.runtime_data.coordinators.values():
if (
descriptions := DEVICE_TYPE_CLIMATE_MAP.get(
coordinator.api.device.device_type
)
) is not None:
for description in descriptions:
entities.extend(
ThinQClimateEntity(coordinator, description, property_id)
for property_id in coordinator.api.get_active_idx(description.key)
)
if entities:
async_add_entities(entities)
class ThinQClimateEntity(ThinQEntity, ClimateEntity):
"""Represent a thinq climate platform."""
def __init__(
self,
coordinator: DeviceDataUpdateCoordinator,
entity_description: ClimateEntityDescription,
property_id: str,
) -> None:
"""Initialize a climate entity."""
super().__init__(coordinator, entity_description, property_id)
self._attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE
| ClimateEntityFeature.TURN_ON
| ClimateEntityFeature.TURN_OFF
)
self._attr_hvac_modes = [HVACMode.OFF]
self._attr_hvac_mode = HVACMode.OFF
self._attr_preset_modes = [PRESET_NONE]
self._attr_preset_mode = PRESET_NONE
self._attr_temperature_unit = (
self._get_unit_of_measurement(self.data.unit) or UnitOfTemperature.CELSIUS
)
# Set up HVAC modes.
for mode in self.data.hvac_modes:
if mode in STR_TO_HVAC:
self._attr_hvac_modes.append(STR_TO_HVAC[mode])
elif mode in THINQ_PRESET_MODE:
self._attr_preset_modes.append(mode)
self._attr_supported_features |= ClimateEntityFeature.PRESET_MODE
# Set up fan modes.
self._attr_fan_modes = self.data.fan_modes
if self.fan_modes:
self._attr_supported_features |= ClimateEntityFeature.FAN_MODE
# Supports target temperature range.
if self.data.support_temperature_range:
self._attr_supported_features |= (
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
)
# Supports swing mode.
if self.data.swing_modes:
self._attr_swing_modes = [SWING_ON, SWING_OFF]
self._attr_supported_features |= ClimateEntityFeature.SWING_MODE
if self.data.swing_horizontal_modes:
self._attr_swing_horizontal_modes = [SWING_ON, SWING_OFF]
self._attr_supported_features |= ClimateEntityFeature.SWING_HORIZONTAL_MODE
def _update_status(self) -> None:
"""Update status itself."""
super()._update_status()
# Update fan, hvac and preset mode.
if self.supported_features & ClimateEntityFeature.FAN_MODE:
self._attr_fan_mode = self.data.fan_mode
if self.supported_features & ClimateEntityFeature.SWING_MODE:
self._attr_swing_mode = STR_TO_SWING.get(self.data.swing_mode)
if self.supported_features & ClimateEntityFeature.SWING_HORIZONTAL_MODE:
self._attr_swing_horizontal_mode = STR_TO_SWING.get(
self.data.swing_horizontal_mode
)
if self.data.is_on:
hvac_mode = self.data.hvac_mode
if hvac_mode in STR_TO_HVAC:
self._attr_hvac_mode = STR_TO_HVAC.get(hvac_mode)
self._attr_preset_mode = PRESET_NONE
elif hvac_mode in THINQ_PRESET_MODE:
self._attr_hvac_mode = (
HVACMode.COOL if hvac_mode == "energy_saving" else HVACMode.FAN_ONLY
)
self._attr_preset_mode = hvac_mode
else:
self._attr_hvac_mode = HVACMode.OFF
self._attr_preset_mode = PRESET_NONE
self._attr_current_humidity = self.data.humidity
self._attr_current_temperature = self.data.current_temp
# Update min, max and step.
if self.data.max is not None:
self._attr_max_temp = self.data.max
if self.data.min is not None:
self._attr_min_temp = self.data.min
self._attr_target_temperature_step = self.data.step
# Update target temperatures.
self._attr_target_temperature = self.data.target_temp
self._attr_target_temperature_high = self.data.target_temp_high
self._attr_target_temperature_low = self.data.target_temp_low
# Update unit.
self._attr_temperature_unit = (
self._get_unit_of_measurement(self.data.unit) or UnitOfTemperature.CELSIUS
)
_LOGGER.debug(
"[%s:%s] update status: c:%s, t:%s, l:%s, h:%s, hvac:%s, unit:%s, step:%s",
self.coordinator.device_name,
self.property_id,
self.current_temperature,
self.target_temperature,
self.target_temperature_low,
self.target_temperature_high,
self.hvac_mode,
self.temperature_unit,
self.target_temperature_step,
)
async def async_turn_on(self) -> None:
"""Turn the entity on."""
_LOGGER.debug(
"[%s:%s] async_turn_on", self.coordinator.device_name, self.property_id
)
await self.async_call_api(self.coordinator.api.async_turn_on(self.property_id))
async def async_turn_off(self) -> None:
"""Turn the entity off."""
_LOGGER.debug(
"[%s:%s] async_turn_off", self.coordinator.device_name, self.property_id
)
await self.async_call_api(self.coordinator.api.async_turn_off(self.property_id))
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode."""
if hvac_mode == HVACMode.OFF:
await self.async_turn_off()
return
if hvac_mode == HVACMode.HEAT_COOL:
hvac_mode = HVACMode.AUTO
# If device is off, turn on first.
if not self.data.is_on:
await self.async_turn_on()
_LOGGER.debug(
"[%s:%s] async_set_hvac_mode: %s",
self.coordinator.device_name,
self.property_id,
hvac_mode,
)
await self.async_call_api(
self.coordinator.api.async_set_hvac_mode(
self.property_id, HVAC_TO_STR.get(hvac_mode)
)
)
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set new preset mode."""
_LOGGER.debug(
"[%s:%s] async_set_preset_mode: %s",
self.coordinator.device_name,
self.property_id,
preset_mode,
)
if preset_mode == PRESET_NONE:
preset_mode = "cool" if self.preset_mode == "energy_saving" else "fan"
await self.async_call_api(
self.coordinator.api.async_set_hvac_mode(self.property_id, preset_mode)
)
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set new target fan mode."""
_LOGGER.debug(
"[%s:%s] async_set_fan_mode: %s",
self.coordinator.device_name,
self.property_id,
fan_mode,
)
await self.async_call_api(
self.coordinator.api.async_set_fan_mode(self.property_id, fan_mode)
)
async def async_set_swing_mode(self, swing_mode: str) -> None:
"""Set new swing mode."""
_LOGGER.debug(
"[%s:%s] async_set_swing_mode: %s",
self.coordinator.device_name,
self.property_id,
swing_mode,
)
await self.async_call_api(
self.coordinator.api.async_set_swing_mode(
self.property_id, SWING_TO_STR.get(swing_mode)
)
)
async def async_set_swing_horizontal_mode(self, swing_horizontal_mode: str) -> None:
"""Set new swing horizontal mode."""
_LOGGER.debug(
"[%s:%s] async_set_swing_horizontal_mode: %s",
self.coordinator.device_name,
self.property_id,
swing_horizontal_mode,
)
await self.async_call_api(
self.coordinator.api.async_set_swing_horizontal_mode(
self.property_id, SWING_TO_STR.get(swing_horizontal_mode)
)
)
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
if hvac_mode := kwargs.get(ATTR_HVAC_MODE):
if hvac_mode == HVACMode.OFF:
await self.async_turn_off()
return
if hvac_mode == HVACMode.HEAT_COOL:
hvac_mode = HVACMode.AUTO
# If device is off, turn on first.
if not self.data.is_on:
await self.async_turn_on()
if hvac_mode and hvac_mode != self.hvac_mode:
await self.async_set_hvac_mode(HVACMode(hvac_mode))
_LOGGER.debug(
"[%s:%s] async_set_temperature: %s",
self.coordinator.device_name,
self.property_id,
kwargs,
)
if temperature := kwargs.get(ATTR_TEMPERATURE):
if self.data.step >= 1:
temperature = int(temperature)
if temperature != self.target_temperature:
await self.async_call_api(
self.coordinator.api.async_set_target_temperature(
self.property_id,
temperature,
)
)
if (temperature_low := kwargs.get(ATTR_TARGET_TEMP_LOW)) and (
temperature_high := kwargs.get(ATTR_TARGET_TEMP_HIGH)
):
if self.data.step >= 1:
temperature_low = int(temperature_low)
temperature_high = int(temperature_high)
await self.async_call_api(
self.coordinator.api.async_set_target_temperature_low_high(
self.property_id,
temperature_low,
temperature_high,
)
)