mirror of
https://github.com/home-assistant/core.git
synced 2026-08-16 10:13:55 +01:00
714 lines
22 KiB
Python
714 lines
22 KiB
Python
"""Midea Climate entries."""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any, cast, override
|
|
|
|
from midealocal.const import DeviceType
|
|
from midealocal.devices.ac import DeviceAttributes as ACAttributes, MideaACDevice
|
|
from midealocal.devices.c3 import MideaC3Device
|
|
from midealocal.devices.c3.const import DeviceAttributes as C3Attributes
|
|
from midealocal.devices.cc import DeviceAttributes as CCAttributes, MideaCCDevice
|
|
from midealocal.devices.cf import DeviceAttributes as CFAttributes, MideaCFDevice
|
|
from midealocal.devices.fb import DeviceAttributes as FBAttributes, MideaFBDevice
|
|
|
|
from homeassistant.components.climate import (
|
|
ATTR_HVAC_MODE,
|
|
FAN_AUTO,
|
|
FAN_HIGH,
|
|
FAN_LOW,
|
|
FAN_MEDIUM,
|
|
PRESET_AWAY,
|
|
PRESET_BOOST,
|
|
PRESET_COMFORT,
|
|
PRESET_ECO,
|
|
PRESET_NONE,
|
|
PRESET_SLEEP,
|
|
SWING_BOTH,
|
|
SWING_HORIZONTAL,
|
|
SWING_OFF,
|
|
SWING_ON,
|
|
SWING_VERTICAL,
|
|
ClimateEntity,
|
|
ClimateEntityDescription,
|
|
ClimateEntityFeature,
|
|
HVACMode,
|
|
)
|
|
from homeassistant.const import (
|
|
ATTR_TEMPERATURE,
|
|
PRECISION_HALVES,
|
|
PRECISION_WHOLE,
|
|
UnitOfTemperature,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import ServiceValidationError
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
|
|
from .const import DOMAIN, FanSpeed
|
|
from .entity import MideaConfigEntry, MideaEntity
|
|
|
|
PARALLEL_UPDATES = 0
|
|
|
|
|
|
TEMPERATURE_MAX = 30
|
|
TEMPERATURE_MIN = 16
|
|
|
|
TEMPERATURE_MAX_C3 = 60
|
|
TEMPERATURE_MIN_C3 = 5
|
|
|
|
FAN_SILENT = "silent"
|
|
FAN_FULL_SPEED = "full"
|
|
|
|
FEATURES_TARGET_AND_POWER = (
|
|
ClimateEntityFeature.TARGET_TEMPERATURE
|
|
| ClimateEntityFeature.TURN_OFF
|
|
| ClimateEntityFeature.TURN_ON
|
|
)
|
|
|
|
type MideaClimateDevice = (
|
|
MideaACDevice | MideaCCDevice | MideaCFDevice | MideaC3Device | MideaFBDevice
|
|
)
|
|
|
|
|
|
@dataclass(kw_only=True, frozen=True)
|
|
class MideaClimateEntityDescription(ClimateEntityDescription):
|
|
"""Description for a Midea climate entity."""
|
|
|
|
models: list[DeviceType]
|
|
zone: int | None = None
|
|
|
|
|
|
CLIMATE_ENTITIES: list[MideaClimateEntityDescription] = [
|
|
MideaClimateEntityDescription(
|
|
key="climate",
|
|
models=[DeviceType.AC, DeviceType.CC, DeviceType.CF, DeviceType.FB],
|
|
),
|
|
MideaClimateEntityDescription(
|
|
key="climate_zone1",
|
|
models=[DeviceType.C3],
|
|
translation_key="climate_zone1",
|
|
zone=0,
|
|
),
|
|
MideaClimateEntityDescription(
|
|
key="climate_zone2",
|
|
models=[DeviceType.C3],
|
|
translation_key="climate_zone2",
|
|
zone=1,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
]
|
|
|
|
_PRESET_TO_ATTR: dict[str, str] = {
|
|
PRESET_AWAY: "frost_protect",
|
|
PRESET_COMFORT: "comfort_mode",
|
|
PRESET_SLEEP: "sleep_mode",
|
|
PRESET_ECO: "eco_mode",
|
|
PRESET_BOOST: "boost_mode",
|
|
}
|
|
|
|
_ATTR_TO_PRESET: dict[str, str] = {v: k for k, v in _PRESET_TO_ATTR.items()}
|
|
|
|
_SWING_MODE_MAP: dict[str, tuple[bool, bool]] = {
|
|
SWING_OFF: (False, False),
|
|
SWING_VERTICAL: (True, False),
|
|
SWING_HORIZONTAL: (False, True),
|
|
SWING_BOTH: (True, True),
|
|
}
|
|
|
|
_SWING_STATE_MAP: dict[tuple[bool, bool], str] = {
|
|
v: k for k, v in _SWING_MODE_MAP.items()
|
|
}
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: MideaConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up climate entries."""
|
|
device = config_entry.runtime_data
|
|
|
|
entities: list[MideaClimate] = []
|
|
for description in CLIMATE_ENTITIES:
|
|
if device.device_type not in description.models:
|
|
continue
|
|
if device.device_type == DeviceType.AC:
|
|
entities.append(MideaACClimate(cast(MideaACDevice, device), description))
|
|
elif device.device_type == DeviceType.CC:
|
|
entities.append(MideaCCClimate(cast(MideaCCDevice, device), description))
|
|
elif device.device_type == DeviceType.CF:
|
|
entities.append(MideaCFClimate(cast(MideaCFDevice, device), description))
|
|
elif device.device_type == DeviceType.C3 and description.zone is not None:
|
|
entities.append(
|
|
MideaC3Climate(
|
|
cast(MideaC3Device, device), description, description.zone
|
|
)
|
|
)
|
|
elif device.device_type == DeviceType.FB:
|
|
entities.append(MideaFBClimate(cast(MideaFBDevice, device), description))
|
|
async_add_entities(entities)
|
|
|
|
|
|
class MideaClimate(MideaEntity, ClimateEntity):
|
|
"""Midea Climate Entries Base Class."""
|
|
|
|
_device: MideaClimateDevice
|
|
|
|
_attr_supported_features = (
|
|
ClimateEntityFeature.TARGET_TEMPERATURE
|
|
| ClimateEntityFeature.FAN_MODE
|
|
| ClimateEntityFeature.PRESET_MODE
|
|
| ClimateEntityFeature.SWING_MODE
|
|
| ClimateEntityFeature.TURN_OFF
|
|
| ClimateEntityFeature.TURN_ON
|
|
)
|
|
_attr_max_temp = TEMPERATURE_MAX
|
|
_attr_min_temp = TEMPERATURE_MIN
|
|
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
|
_zone: int | None = None
|
|
|
|
def _float_attribute(self, attr: str) -> float | None:
|
|
"""Return a device attribute as float, if convertible."""
|
|
value = self._device.get_attribute(attr)
|
|
if not isinstance(value, (int, float, str)):
|
|
return None
|
|
return float(value)
|
|
|
|
@property
|
|
@override
|
|
def hvac_mode(self) -> HVACMode | None:
|
|
"""Midea Climate hvac mode."""
|
|
power = self._device.get_attribute(attr="power")
|
|
if not isinstance(power, bool):
|
|
return None
|
|
if not power:
|
|
return HVACMode.OFF
|
|
|
|
mode = self._device.get_attribute("mode")
|
|
if isinstance(mode, int):
|
|
return self._protocol_mode_to_hvac(mode)
|
|
return None
|
|
|
|
def _protocol_mode_to_hvac(self, mode: int) -> HVACMode | None:
|
|
"""Convert protocol mode value to Home Assistant HVAC mode."""
|
|
if 1 <= mode < len(self.hvac_modes):
|
|
return self.hvac_modes[mode]
|
|
return None
|
|
|
|
def _hvac_to_protocol_mode(self, hvac_mode: HVACMode) -> int:
|
|
"""Convert Home Assistant HVAC mode to protocol mode value."""
|
|
return self.hvac_modes.index(hvac_mode)
|
|
|
|
@property
|
|
@override
|
|
def target_temperature(self) -> float | None:
|
|
"""Midea Climate target temperature."""
|
|
return self._float_attribute("target_temperature")
|
|
|
|
@property
|
|
@override
|
|
def current_temperature(self) -> float | None:
|
|
"""Midea Climate current temperature."""
|
|
return self._float_attribute("indoor_temperature")
|
|
|
|
@property
|
|
@override
|
|
def preset_mode(self) -> str | None:
|
|
"""Midea Climate preset mode."""
|
|
for attr, preset in _ATTR_TO_PRESET.items():
|
|
if self._device.get_attribute(attr):
|
|
return preset
|
|
|
|
return PRESET_NONE
|
|
|
|
@override
|
|
def turn_on(self, **kwargs: Any) -> None:
|
|
"""Midea Climate turn on."""
|
|
self._device.set_attribute(attr="power", value=True)
|
|
|
|
@override
|
|
def turn_off(self, **kwargs: Any) -> None:
|
|
"""Midea Climate turn off."""
|
|
self._device.set_attribute(attr="power", value=False)
|
|
|
|
@override
|
|
def set_temperature(self, **kwargs: Any) -> None:
|
|
"""Midea Climate set temperature."""
|
|
if ATTR_TEMPERATURE not in kwargs:
|
|
return
|
|
temperature = kwargs[ATTR_TEMPERATURE]
|
|
hvac_mode = kwargs.get(ATTR_HVAC_MODE)
|
|
if hvac_mode == HVACMode.OFF:
|
|
self.turn_off()
|
|
else:
|
|
mode = None
|
|
if hvac_mode:
|
|
if hvac_mode not in self.hvac_modes:
|
|
raise ServiceValidationError(
|
|
translation_domain=DOMAIN,
|
|
translation_key="unsupported_hvac_mode",
|
|
translation_placeholders={"hvac_mode": hvac_mode},
|
|
)
|
|
mode = self.hvac_modes.index(hvac_mode)
|
|
self._device.set_target_temperature(
|
|
target_temperature=temperature,
|
|
mode=mode,
|
|
zone=self._zone,
|
|
)
|
|
|
|
@override
|
|
def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
"""Midea Climate set hvac mode."""
|
|
if hvac_mode == HVACMode.OFF:
|
|
self.turn_off()
|
|
else:
|
|
self._device.set_attribute(
|
|
attr="mode",
|
|
value=self._hvac_to_protocol_mode(hvac_mode),
|
|
)
|
|
|
|
@override
|
|
def set_preset_mode(self, preset_mode: str) -> None:
|
|
"""Midea Climate set preset mode."""
|
|
if new_attr := _PRESET_TO_ATTR.get(preset_mode):
|
|
self._device.set_attribute(attr=new_attr, value=True)
|
|
return
|
|
old_mode = self.preset_mode
|
|
old_attr = _PRESET_TO_ATTR.get(old_mode) if isinstance(old_mode, str) else None
|
|
if old_attr:
|
|
self._device.set_attribute(attr=old_attr, value=False)
|
|
|
|
|
|
class MideaACClimate(MideaClimate):
|
|
"""Midea AC Climate Entries."""
|
|
|
|
_device: MideaACDevice
|
|
|
|
_fan_thresholds: tuple[tuple[int, str], ...] = (
|
|
(FanSpeed.AUTO, FAN_AUTO),
|
|
(FanSpeed.FULL_SPEED, FAN_FULL_SPEED),
|
|
(FanSpeed.HIGH, FAN_HIGH),
|
|
(FanSpeed.MEDIUM, FAN_MEDIUM),
|
|
(FanSpeed.LOW, FAN_LOW),
|
|
)
|
|
|
|
_fan_speeds: dict[str, int] = {
|
|
FAN_SILENT: 20,
|
|
FAN_LOW: 40,
|
|
FAN_MEDIUM: 60,
|
|
FAN_HIGH: 80,
|
|
FAN_FULL_SPEED: 100,
|
|
FAN_AUTO: 102,
|
|
}
|
|
_attr_fan_modes: list[str] = [
|
|
FAN_SILENT,
|
|
FAN_LOW,
|
|
FAN_MEDIUM,
|
|
FAN_HIGH,
|
|
FAN_FULL_SPEED,
|
|
FAN_AUTO,
|
|
]
|
|
|
|
_attr_hvac_modes = [
|
|
HVACMode.OFF,
|
|
HVACMode.AUTO,
|
|
HVACMode.COOL,
|
|
HVACMode.DRY,
|
|
HVACMode.HEAT,
|
|
HVACMode.FAN_ONLY,
|
|
]
|
|
_attr_swing_modes: list[str] = [
|
|
SWING_OFF,
|
|
SWING_VERTICAL,
|
|
SWING_HORIZONTAL,
|
|
SWING_BOTH,
|
|
]
|
|
_attr_preset_modes = [
|
|
PRESET_NONE,
|
|
PRESET_COMFORT,
|
|
PRESET_ECO,
|
|
PRESET_BOOST,
|
|
PRESET_SLEEP,
|
|
PRESET_AWAY,
|
|
]
|
|
|
|
def __init__(
|
|
self,
|
|
device: MideaACDevice,
|
|
description: MideaClimateEntityDescription,
|
|
) -> None:
|
|
"""Midea AC Climate entity init."""
|
|
super().__init__(device, description)
|
|
self._attr_target_temperature_step = float(
|
|
PRECISION_WHOLE if self._device.temperature_step == 1 else PRECISION_HALVES,
|
|
)
|
|
|
|
@property
|
|
@override
|
|
def min_temp(self) -> float:
|
|
"""Midea AC Climate min temperature."""
|
|
min_temperature = self._float_attribute(ACAttributes.min_temperature)
|
|
if min_temperature is None:
|
|
return float(TEMPERATURE_MIN)
|
|
return min_temperature
|
|
|
|
@property
|
|
@override
|
|
def max_temp(self) -> float:
|
|
"""Midea AC Climate max temperature."""
|
|
max_temperature = self._float_attribute(ACAttributes.max_temperature)
|
|
if max_temperature is None:
|
|
return float(TEMPERATURE_MAX)
|
|
return max_temperature
|
|
|
|
@property
|
|
@override
|
|
def fan_mode(self) -> str | None:
|
|
"""Midea AC Climate fan mode."""
|
|
fan_speed = self._device.get_attribute(ACAttributes.fan_speed)
|
|
if not isinstance(fan_speed, int):
|
|
return None
|
|
for threshold, mode in self._fan_thresholds:
|
|
if fan_speed > threshold:
|
|
return mode
|
|
return FAN_SILENT
|
|
|
|
@property
|
|
@override
|
|
def swing_mode(self) -> str | None:
|
|
"""Midea AC Climate swing mode."""
|
|
vertical = bool(self._device.get_attribute(ACAttributes.swing_vertical))
|
|
horizontal = bool(self._device.get_attribute(ACAttributes.swing_horizontal))
|
|
return _SWING_STATE_MAP.get((vertical, horizontal))
|
|
|
|
@property
|
|
@override
|
|
def current_humidity(self) -> float | None:
|
|
"""Return the current indoor humidity, or None if unavailable."""
|
|
raw = self._device.get_attribute(ACAttributes.indoor_humidity)
|
|
# Some devices report invalid values (0 or 0xFF) for this sensor
|
|
# so filter those out and return None instead.
|
|
if isinstance(raw, (int, float)) and raw not in {0, 0xFF}:
|
|
return float(raw)
|
|
return None
|
|
|
|
@override
|
|
def set_fan_mode(self, fan_mode: str) -> None:
|
|
"""Midea AC Climate set fan mode."""
|
|
fan_speed = self._fan_speeds[fan_mode]
|
|
self._device.set_attribute(attr=ACAttributes.fan_speed, value=fan_speed)
|
|
|
|
@override
|
|
def set_swing_mode(self, swing_mode: str) -> None:
|
|
"""Midea AC Climate set swing mode."""
|
|
swing_vertical, swing_horizontal = _SWING_MODE_MAP.get(
|
|
swing_mode, (False, False)
|
|
)
|
|
self._device.set_swing(
|
|
swing_vertical=swing_vertical,
|
|
swing_horizontal=swing_horizontal,
|
|
)
|
|
|
|
|
|
class MideaCCClimate(MideaClimate):
|
|
"""Midea CC Climate Entries."""
|
|
|
|
_device: MideaCCDevice
|
|
|
|
_attr_hvac_modes = [
|
|
HVACMode.OFF,
|
|
HVACMode.FAN_ONLY,
|
|
HVACMode.DRY,
|
|
HVACMode.HEAT,
|
|
HVACMode.COOL,
|
|
HVACMode.AUTO,
|
|
]
|
|
_attr_swing_modes = [SWING_OFF, SWING_ON]
|
|
_attr_preset_modes = [PRESET_NONE, PRESET_SLEEP, PRESET_ECO]
|
|
|
|
@property
|
|
@override
|
|
def fan_modes(self) -> list[str] | None:
|
|
"""Midea CC Climate fan modes."""
|
|
return self._device.fan_modes
|
|
|
|
@property
|
|
@override
|
|
def fan_mode(self) -> str | None:
|
|
"""Midea CC Climate fan mode."""
|
|
fan_mode = self._device.get_attribute(CCAttributes.fan_speed)
|
|
if not isinstance(fan_mode, str):
|
|
return None
|
|
return fan_mode
|
|
|
|
@property
|
|
@override
|
|
def target_temperature_step(self) -> float | None:
|
|
"""Midea CC Climate target temperature step."""
|
|
return self._float_attribute(CCAttributes.temperature_precision)
|
|
|
|
@property
|
|
@override
|
|
def swing_mode(self) -> str | None:
|
|
"""Midea CC Climate swing mode."""
|
|
swing = self._device.get_attribute(CCAttributes.swing)
|
|
if not isinstance(swing, bool):
|
|
return None
|
|
return SWING_ON if swing else SWING_OFF
|
|
|
|
@override
|
|
def set_fan_mode(self, fan_mode: str) -> None:
|
|
"""Midea CC Climate set fan mode."""
|
|
self._device.set_attribute(attr=CCAttributes.fan_speed, value=fan_mode)
|
|
|
|
@override
|
|
def set_swing_mode(self, swing_mode: str) -> None:
|
|
"""Midea CC Climate set swing mode."""
|
|
self._device.set_attribute(
|
|
attr=CCAttributes.swing,
|
|
value=swing_mode == SWING_ON,
|
|
)
|
|
|
|
|
|
class MideaCFClimate(MideaClimate):
|
|
"""Midea CF Climate Entries."""
|
|
|
|
_device: MideaCFDevice
|
|
|
|
_attr_hvac_modes = [
|
|
HVACMode.OFF,
|
|
HVACMode.AUTO,
|
|
HVACMode.COOL,
|
|
HVACMode.HEAT,
|
|
]
|
|
_attr_target_temperature_step: float | None = PRECISION_WHOLE
|
|
|
|
_attr_supported_features = FEATURES_TARGET_AND_POWER
|
|
|
|
@override
|
|
def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
"""Midea CF Climate set hvac mode."""
|
|
if hvac_mode == HVACMode.OFF:
|
|
self.turn_off()
|
|
else:
|
|
target_temperature = self.target_temperature or self.min_temp
|
|
self._device.set_target_temperature(
|
|
target_temperature=target_temperature,
|
|
mode=self._hvac_to_protocol_mode(hvac_mode),
|
|
)
|
|
|
|
@property
|
|
@override
|
|
def min_temp(self) -> float:
|
|
"""Midea CF Climate min temperature."""
|
|
min_temperature = self._float_attribute(CFAttributes.min_temperature)
|
|
if min_temperature is None:
|
|
return float(TEMPERATURE_MIN)
|
|
return min_temperature
|
|
|
|
@property
|
|
@override
|
|
def max_temp(self) -> float:
|
|
"""Midea CF Climate max temperature."""
|
|
max_temperature = self._float_attribute(CFAttributes.max_temperature)
|
|
if max_temperature is None:
|
|
return float(TEMPERATURE_MAX)
|
|
return max_temperature
|
|
|
|
@property
|
|
@override
|
|
def current_temperature(self) -> float | None:
|
|
"""Midea CF Climate current temperature."""
|
|
return self._float_attribute(CFAttributes.current_temperature)
|
|
|
|
|
|
class MideaC3Climate(MideaClimate):
|
|
"""Midea C3 Climate Entries."""
|
|
|
|
_device: MideaC3Device
|
|
_zone: int
|
|
|
|
_powers: tuple[C3Attributes, ...] = (
|
|
C3Attributes.zone1_power,
|
|
C3Attributes.zone2_power,
|
|
)
|
|
_attr_hvac_modes = [
|
|
HVACMode.OFF,
|
|
HVACMode.AUTO,
|
|
HVACMode.COOL,
|
|
HVACMode.HEAT,
|
|
]
|
|
|
|
def __init__(
|
|
self,
|
|
device: MideaC3Device,
|
|
description: MideaClimateEntityDescription,
|
|
zone: int,
|
|
) -> None:
|
|
"""Midea C3 Climate entity init."""
|
|
super().__init__(device, description)
|
|
self._zone = zone
|
|
self._power_attr = MideaC3Climate._powers[zone]
|
|
|
|
def _temperature(self, *, minimum: bool) -> list[float]:
|
|
"""Midea C3 Climate temperature."""
|
|
value = (
|
|
C3Attributes.temperature_min if minimum else C3Attributes.temperature_max
|
|
)
|
|
temperatures = self._device.get_attribute(value)
|
|
fallback = float(TEMPERATURE_MIN_C3 if minimum else TEMPERATURE_MAX_C3)
|
|
if not isinstance(temperatures, list):
|
|
return [fallback, fallback]
|
|
parsed_temperatures = [float(temperature) for temperature in temperatures]
|
|
if len(parsed_temperatures) < 2:
|
|
return [fallback, fallback]
|
|
return [
|
|
fallback if temperature == 0.0 else temperature
|
|
for temperature in parsed_temperatures
|
|
]
|
|
|
|
_attr_supported_features = FEATURES_TARGET_AND_POWER
|
|
|
|
@property
|
|
@override
|
|
def target_temperature_step(self) -> float:
|
|
"""Midea C3 Climate target temperature step."""
|
|
zone_temp_type = self._device.get_attribute(C3Attributes.zone_temp_type)
|
|
if not isinstance(zone_temp_type, list) or len(zone_temp_type) <= self._zone:
|
|
return float(PRECISION_HALVES)
|
|
return float(
|
|
PRECISION_WHOLE if zone_temp_type[self._zone] else PRECISION_HALVES,
|
|
)
|
|
|
|
@property
|
|
@override
|
|
def min_temp(self) -> float:
|
|
"""Midea C3 Climate min temperature."""
|
|
return self._temperature(minimum=True)[self._zone]
|
|
|
|
@property
|
|
@override
|
|
def max_temp(self) -> float:
|
|
"""Midea C3 Climate max temperature."""
|
|
return self._temperature(minimum=False)[self._zone]
|
|
|
|
@override
|
|
def turn_on(self, **kwargs: Any) -> None:
|
|
"""Midea C3 Climate turn on."""
|
|
self._device.set_attribute(attr=self._power_attr, value=True)
|
|
|
|
@override
|
|
def turn_off(self, **kwargs: Any) -> None:
|
|
"""Midea C3 Climate turn off."""
|
|
self._device.set_attribute(attr=self._power_attr, value=False)
|
|
|
|
@property
|
|
@override
|
|
def hvac_mode(self) -> HVACMode | None:
|
|
"""Midea C3 Climate hvac mode."""
|
|
power = self._device.get_attribute(self._power_attr)
|
|
if not isinstance(power, bool):
|
|
return None
|
|
if not power:
|
|
return HVACMode.OFF
|
|
mode = self._device.get_attribute(C3Attributes.mode)
|
|
if isinstance(mode, int):
|
|
return self._protocol_mode_to_hvac(mode)
|
|
return None
|
|
|
|
@property
|
|
@override
|
|
def target_temperature(self) -> float | None:
|
|
"""Midea C3 Climate target temperature."""
|
|
target_temperature = self._device.get_attribute(C3Attributes.target_temperature)
|
|
if (
|
|
not isinstance(target_temperature, list)
|
|
or len(target_temperature) <= self._zone
|
|
):
|
|
return None
|
|
return float(target_temperature[self._zone])
|
|
|
|
@property
|
|
@override
|
|
def current_temperature(self) -> float | None:
|
|
"""Midea C3 Climate current temperature."""
|
|
return self._float_attribute(C3Attributes.temp_tw_out)
|
|
|
|
@override
|
|
def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
"""Midea C3 Climate set hvac mode."""
|
|
if hvac_mode == HVACMode.OFF:
|
|
self.turn_off()
|
|
else:
|
|
self._device.set_mode(self._zone, self._hvac_to_protocol_mode(hvac_mode))
|
|
|
|
|
|
class MideaFBClimate(MideaClimate):
|
|
"""Midea FB Climate Entries."""
|
|
|
|
_device: MideaFBDevice
|
|
|
|
_attr_hvac_modes = [HVACMode.OFF, HVACMode.HEAT]
|
|
_attr_max_temp = 35
|
|
_attr_min_temp = 5
|
|
_attr_supported_features = (
|
|
ClimateEntityFeature.TARGET_TEMPERATURE
|
|
| ClimateEntityFeature.PRESET_MODE
|
|
| ClimateEntityFeature.TURN_OFF
|
|
| ClimateEntityFeature.TURN_ON
|
|
)
|
|
_attr_target_temperature_step = PRECISION_WHOLE
|
|
|
|
def __init__(
|
|
self,
|
|
device: MideaFBDevice,
|
|
description: MideaClimateEntityDescription,
|
|
) -> None:
|
|
"""Midea FB Climate entity init."""
|
|
super().__init__(device, description)
|
|
self._attr_preset_modes: list[str] = self._device.modes
|
|
|
|
@property
|
|
@override
|
|
def preset_mode(self) -> str | None:
|
|
"""Midea FB Climate preset mode."""
|
|
preset_mode = self._device.get_attribute(attr=FBAttributes.mode)
|
|
if not isinstance(preset_mode, str):
|
|
return None
|
|
return preset_mode
|
|
|
|
@property
|
|
@override
|
|
def hvac_mode(self) -> HVACMode | None:
|
|
"""Midea FB Climate hvac mode."""
|
|
hvac_mode = self._device.get_attribute(attr=FBAttributes.power)
|
|
if not isinstance(hvac_mode, bool):
|
|
return None
|
|
return HVACMode.HEAT if hvac_mode else HVACMode.OFF
|
|
|
|
@property
|
|
@override
|
|
def current_temperature(self) -> float | None:
|
|
"""Midea FB Climate current temperature."""
|
|
return self._float_attribute(FBAttributes.current_temperature)
|
|
|
|
@override
|
|
def set_temperature(self, **kwargs: Any) -> None:
|
|
"""Midea FB Climate set temperature."""
|
|
wants_heat = kwargs.get(ATTR_HVAC_MODE) == HVACMode.HEAT
|
|
if wants_heat and self.hvac_mode == HVACMode.OFF:
|
|
self.turn_on()
|
|
super().set_temperature(**kwargs)
|
|
|
|
@override
|
|
def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
"""Midea FB Climate set hvac mode."""
|
|
if hvac_mode == HVACMode.OFF:
|
|
self.turn_off()
|
|
else:
|
|
self.turn_on()
|
|
|
|
@override
|
|
def set_preset_mode(self, preset_mode: str) -> None:
|
|
"""Midea FB Climate set preset mode."""
|
|
self._device.set_attribute(attr=FBAttributes.mode, value=preset_mode)
|