Files
2026-03-07 17:28:59 +00:00

255 lines
7.9 KiB
Python

"""Adds climate entity for each air conditioner appliance."""
import logging
from typing import Final
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
ATTR_FAN_MODE,
ATTR_HVAC_MODE,
ATTR_SWING_MODE,
FAN_AUTO,
FAN_HIGH,
FAN_LOW,
FAN_MEDIUM,
PRESET_BOOST,
PRESET_ECO,
PRESET_NONE,
PRESET_SLEEP,
PRESET_AWAY,
PRESET_COMFORT,
ClimateEntityFeature,
SWING_BOTH,
SWING_HORIZONTAL,
SWING_OFF,
SWING_VERTICAL,
HVACAction,
HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_HALVES, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from custom_components.midea_dehumidifier_lan.appliance_coordinator import (
ApplianceEntity,
)
from custom_components.midea_dehumidifier_lan.const import (
ATTR_RUNNING,
DOMAIN,
MAX_TARGET_TEMPERATURE,
MIN_TARGET_TEMPERATURE,
)
from custom_components.midea_dehumidifier_lan.hub import Hub
_LOGGER = logging.getLogger(__name__)
FAN_SILENT = "Silent"
FAN_FULL = "Full"
HVAC_MODES: Final = [
HVACMode.OFF,
HVACMode.AUTO,
HVACMode.COOL,
HVACMode.HEAT,
HVACMode.DRY,
HVACMode.FAN_ONLY,
]
FAN_MODES: Final = [
FAN_SILENT,
FAN_LOW,
FAN_MEDIUM,
FAN_HIGH,
FAN_FULL,
FAN_AUTO,
]
SWING_MODES: Final = [SWING_OFF, SWING_HORIZONTAL, SWING_VERTICAL, SWING_BOTH]
PRESET_MODES: Final = [PRESET_NONE, PRESET_ECO, PRESET_BOOST, PRESET_SLEEP, PRESET_AWAY, PRESET_COMFORT]
_FAN_SPEEDS = {
FAN_AUTO: 102,
FAN_FULL: 100,
FAN_HIGH: 80,
FAN_MEDIUM: 60,
FAN_LOW: 40,
FAN_SILENT: 20,
}
_MODES_TO_MIDEA = {
HVACMode.AUTO: 1,
HVACMode.COOL: 2,
HVACMode.DRY: 3,
HVACMode.HEAT: 4,
HVACMode.FAN_ONLY: 5,
}
_MIDEA_TO_MODES = {
1: HVACMode.AUTO,
2: HVACMode.COOL,
3: HVACMode.DRY,
4: HVACMode.HEAT,
5: HVACMode.FAN_ONLY,
}
_HVAC_ACTIONS = {
HVACMode.OFF: HVACAction.OFF,
HVACMode.AUTO: None,
HVACMode.COOL: HVACAction.COOLING,
HVACMode.DRY: HVACAction.DRYING,
HVACMode.HEAT: HVACAction.HEATING,
HVACMode.FAN_ONLY: HVACAction.FAN,
}
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Sets up air conditioner entites"""
hub: Hub = hass.data[DOMAIN][config_entry.entry_id]
async_add_entities(
AirConditionerEntity(c) for c in hub.coordinators if c.is_climate()
)
class AirConditionerEntity(ApplianceEntity, ClimateEntity):
"""Climate entity for Midea air conditioner"""
_attr_hvac_modes = HVAC_MODES
_attr_fan_modes = FAN_MODES
_attr_preset_modes = PRESET_MODES
_attr_swing_modes = SWING_MODES
_attr_max_temp = MAX_TARGET_TEMPERATURE
_attr_min_temp = MIN_TARGET_TEMPERATURE
_attr_precision = PRECISION_HALVES
_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE
| ClimateEntityFeature.FAN_MODE
| ClimateEntityFeature.SWING_MODE
| ClimateEntityFeature.PRESET_MODE
| ClimateEntityFeature.TURN_ON
| ClimateEntityFeature.TURN_OFF
)
_name_suffix = ""
_add_extra_attrs = True
def on_update(self) -> None:
aircon = self.airconditioner()
self._attr_current_temperature = aircon.indoor_temperature
self._attr_target_temperature = aircon.target_temperature
self._attr_fan_mode = self._fan_mode()
self._attr_preset_mode = self._preset_mode()
self._attr_swing_mode = self._swing_mode()
self._attr_hvac_mode = self._hvac_mode()
self._attr_hvac_action = _HVAC_ACTIONS.get(self._attr_hvac_mode)
super().on_update()
def _fan_mode(self) -> str:
fan_speed = self.airconditioner().fan_speed
for mode, mode_speed in _FAN_SPEEDS.items():
if fan_speed <= mode_speed:
return mode
return FAN_AUTO
def _preset_mode(self) -> str:
if self.airconditioner().turbo:
return PRESET_BOOST
if self.airconditioner().eco_mode:
return PRESET_ECO
if self.airconditioner().comfort_sleep:
return PRESET_SLEEP
if self.airconditioner().frost_protect:
return PRESET_AWAY
if self.airconditioner().comfort_mode:
return PRESET_COMFORT
return PRESET_NONE
def _swing_mode(self) -> str:
if self.airconditioner().vertical_swing:
if self.airconditioner().horizontal_swing:
return SWING_BOTH
return SWING_VERTICAL
if self.airconditioner().horizontal_swing:
return SWING_HORIZONTAL
return SWING_OFF
def _hvac_mode(self) -> str:
if not self.airconditioner().running:
return HVACMode.OFF
curr_mode = self.airconditioner().mode
mode = _MIDEA_TO_MODES.get(curr_mode)
if mode is None:
mode = HVACMode.AUTO
_LOGGER.warning("Unknown mode %d, reporting %s", curr_mode, mode)
return mode
def turn_on(self, **kwargs) -> None: # pylint: disable=unused-argument
"""Turn the entity on."""
self.apply(ATTR_RUNNING, True)
def turn_off(self, **kwargs) -> None: # pylint: disable=unused-argument
"""Turn the entity off."""
self.apply(ATTR_RUNNING, False)
def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode."""
if hvac_mode == HVACMode.OFF:
self.turn_off()
return
midea_mode = _MODES_TO_MIDEA.get(hvac_mode)
if midea_mode is None:
_LOGGER.warning("Unsupported climate mode %s", hvac_mode)
return
# Make sure we are running
if not self.airconditioner().running:
self.turn_on()
self.apply("mode", midea_mode)
def set_temperature(self, **kwargs) -> None:
"""Set new target temperature."""
if kwargs.get(ATTR_TEMPERATURE):
self.apply("target_temperature", kwargs.get(ATTR_TEMPERATURE))
if kwargs.get(ATTR_HVAC_MODE):
self.set_hvac_mode(kwargs.get(ATTR_HVAC_MODE))
if kwargs.get(ATTR_SWING_MODE):
self.set_swing_mode(kwargs.get(ATTR_SWING_MODE))
if kwargs.get(ATTR_FAN_MODE):
self.set_fan_mode(kwargs.get(ATTR_FAN_MODE))
def set_swing_mode(self, swing_mode: str) -> None:
if swing_mode == SWING_VERTICAL:
self.apply(vertical_swing=True, horizontal_swing=False)
elif swing_mode == SWING_HORIZONTAL:
self.apply(vertical_swing=False, horizontal_swing=True)
elif swing_mode == SWING_BOTH:
self.apply(vertical_swing=True, horizontal_swing=True)
else:
self.apply(vertical_swing=False, horizontal_swing=False)
def set_fan_mode(self, fan_mode: str) -> None:
self.apply(fan_speed=_FAN_SPEEDS.get(fan_mode, 20))
def set_preset_mode(self, preset_mode: str) -> None:
if preset_mode == PRESET_BOOST:
self.apply(turbo=True, eco_mode=False, comfort_sleep=False, frost_protect=False, comfort_mode=False)
elif preset_mode == PRESET_ECO:
self.apply(turbo=False, eco_mode=True, comfort_sleep=False, frost_protect=False, comfort_mode=False)
elif preset_mode == PRESET_SLEEP:
self.apply(turbo=False, eco_mode=False, comfort_sleep=True, frost_protect=False, comfort_mode=False)
elif preset_mode == PRESET_AWAY:
self.apply(turbo=False, eco_mode=False, comfort_sleep=False, frost_protect=True, comfort_mode=False)
elif preset_mode == PRESET_SLEEP:
self.apply(turbo=False, eco_mode=False, comfort_sleep=False, frost_protect=False, comfort_mode=True)
else:
self.apply(turbo=False, eco_mode=False, comfort_sleep=False, frost_protect=False, comfort_mode=False)