495 lines
17 KiB
Python
495 lines
17 KiB
Python
|
from homeassistant.components.climate import *
|
||
|
from homeassistant.components.climate.const import *
|
||
|
from homeassistant.const import (
|
||
|
Platform,
|
||
|
TEMP_CELSIUS,
|
||
|
PRECISION_WHOLE,
|
||
|
PRECISION_HALVES,
|
||
|
ATTR_TEMPERATURE,
|
||
|
CONF_DEVICE_ID,
|
||
|
CONF_SWITCHES
|
||
|
)
|
||
|
|
||
|
from .const import (
|
||
|
DOMAIN,
|
||
|
DEVICES,
|
||
|
)
|
||
|
from .midea.devices.ac.device import DeviceAttributes as ACAttributes
|
||
|
from .midea.devices.c3.device import DeviceAttributes as C3Attributes
|
||
|
from .midea.devices.cc.device import DeviceAttributes as CCAttributes
|
||
|
from .midea.devices.cf.device import DeviceAttributes as CFAttributes
|
||
|
from .midea.devices.fb.device import DeviceAttributes as FBAttributes
|
||
|
from .midea_devices import MIDEA_DEVICES
|
||
|
from .midea_entity import MideaEntity
|
||
|
|
||
|
_LOGGER = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
TEMPERATURE_MAX = 30
|
||
|
TEMPERATURE_MIN = 17
|
||
|
|
||
|
FAN_SILENT = "Silent"
|
||
|
FAN_FULL_SPEED = "Full"
|
||
|
|
||
|
|
||
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||
|
device_id = config_entry.data.get(CONF_DEVICE_ID)
|
||
|
device = hass.data[DOMAIN][DEVICES].get(device_id)
|
||
|
extra_switches = config_entry.options.get(
|
||
|
CONF_SWITCHES, []
|
||
|
)
|
||
|
devs = []
|
||
|
for entity_key, config in MIDEA_DEVICES[device.device_type]["entities"].items():
|
||
|
if config["type"] == Platform.CLIMATE and (config.get("default") or entity_key in extra_switches):
|
||
|
if device.device_type == 0xAC:
|
||
|
devs.append(MideaACClimate(device, entity_key))
|
||
|
elif device.device_type == 0xCC:
|
||
|
devs.append(MideaCCClimate(device, entity_key))
|
||
|
elif device.device_type == 0xCF:
|
||
|
devs.append(MideaCFClimate(device, entity_key))
|
||
|
elif device.device_type == 0xC3:
|
||
|
devs.append(MideaC3Climate(device, entity_key, config["zone"]))
|
||
|
elif device.device_type == 0xFB:
|
||
|
devs.append(MideaFBClimate(device, entity_key))
|
||
|
async_add_entities(devs)
|
||
|
|
||
|
|
||
|
class MideaClimate(MideaEntity, ClimateEntity):
|
||
|
def __init__(self, device, entity_key):
|
||
|
super().__init__(device, entity_key)
|
||
|
|
||
|
@property
|
||
|
def state(self):
|
||
|
return self.hvac_mode
|
||
|
|
||
|
@property
|
||
|
def supported_features(self):
|
||
|
return ClimateEntityFeature.TARGET_TEMPERATURE | \
|
||
|
ClimateEntityFeature.FAN_MODE | \
|
||
|
ClimateEntityFeature.PRESET_MODE | \
|
||
|
ClimateEntityFeature.SWING_MODE | \
|
||
|
ClimateEntityFeature.AUX_HEAT
|
||
|
|
||
|
@property
|
||
|
def min_temp(self):
|
||
|
return TEMPERATURE_MIN
|
||
|
|
||
|
@property
|
||
|
def max_temp(self):
|
||
|
return TEMPERATURE_MAX
|
||
|
|
||
|
@property
|
||
|
def temperature_unit(self):
|
||
|
return TEMP_CELSIUS
|
||
|
|
||
|
@property
|
||
|
def target_temperature_low(self):
|
||
|
return TEMPERATURE_MIN
|
||
|
|
||
|
@property
|
||
|
def target_temperature_high(self):
|
||
|
return TEMPERATURE_MAX
|
||
|
|
||
|
@property
|
||
|
def hvac_modes(self):
|
||
|
return self._modes
|
||
|
|
||
|
@property
|
||
|
def swing_modes(self):
|
||
|
return self._swing_modes
|
||
|
|
||
|
@property
|
||
|
def is_on(self) -> bool:
|
||
|
return self.hvac_mode != HVACMode.OFF
|
||
|
|
||
|
@property
|
||
|
def hvac_mode(self) -> str:
|
||
|
if self._device.get_attribute("power"):
|
||
|
return self._modes[self._device.get_attribute("mode")]
|
||
|
else:
|
||
|
return HVACMode.OFF
|
||
|
|
||
|
@property
|
||
|
def target_temperature(self):
|
||
|
return self._device.get_attribute("target_temperature")
|
||
|
|
||
|
@property
|
||
|
def current_temperature(self):
|
||
|
return self._device.get_attribute("indoor_temperature")
|
||
|
|
||
|
@property
|
||
|
def is_aux_heat(self):
|
||
|
return self._device.get_attribute("aux_heating")
|
||
|
|
||
|
@property
|
||
|
def preset_modes(self):
|
||
|
return self._preset_modes
|
||
|
|
||
|
@property
|
||
|
def preset_mode(self):
|
||
|
if self._device.get_attribute("comfort_mode"):
|
||
|
mode = PRESET_COMFORT
|
||
|
elif self._device.get_attribute("eco_mode"):
|
||
|
mode = PRESET_ECO
|
||
|
elif self._device.get_attribute("boost_mode"):
|
||
|
mode = PRESET_BOOST
|
||
|
elif self._device.get_attribute("sleep_mode"):
|
||
|
mode = PRESET_SLEEP
|
||
|
elif self._device.get_attribute("frost_protect"):
|
||
|
mode = PRESET_AWAY
|
||
|
else:
|
||
|
mode = PRESET_NONE
|
||
|
return mode
|
||
|
|
||
|
@property
|
||
|
def extra_state_attributes(self) -> dict:
|
||
|
return self._device.attributes
|
||
|
|
||
|
def turn_on(self):
|
||
|
self._device.set_attribute(attr="power", value=True)
|
||
|
|
||
|
def turn_off(self):
|
||
|
self._device.set_attribute(attr="power", value=False)
|
||
|
|
||
|
def set_temperature(self, **kwargs) -> None:
|
||
|
if ATTR_TEMPERATURE not in kwargs:
|
||
|
return
|
||
|
temperature = float(int((float(kwargs.get(ATTR_TEMPERATURE)) * 2) + 0.5)) / 2
|
||
|
hvac_mode = kwargs.get(ATTR_HVAC_MODE)
|
||
|
if hvac_mode == HVACMode.OFF:
|
||
|
self.turn_off()
|
||
|
else:
|
||
|
try:
|
||
|
mode = self._modes.index(hvac_mode.lower()) if hvac_mode else None
|
||
|
self._device.set_target_temperature(
|
||
|
target_temperature=temperature, mode=mode)
|
||
|
except ValueError as e:
|
||
|
_LOGGER.error(f"set_temperature {e}, kwargs = {kwargs}")
|
||
|
|
||
|
def set_hvac_mode(self, hvac_mode: str) -> None:
|
||
|
hvac_mode = hvac_mode.lower()
|
||
|
if hvac_mode == HVACMode.OFF:
|
||
|
self.turn_off()
|
||
|
else:
|
||
|
self._device.set_attribute(attr="mode", value=self._modes.index(hvac_mode))
|
||
|
|
||
|
def set_preset_mode(self, preset_mode: str) -> None:
|
||
|
old_mode = self.preset_mode
|
||
|
preset_mode = preset_mode.lower()
|
||
|
if preset_mode == PRESET_AWAY:
|
||
|
self._device.set_attribute(attr="frost_protect", value=True)
|
||
|
elif preset_mode == PRESET_COMFORT:
|
||
|
self._device.set_attribute(attr="comfort_mode", value=True)
|
||
|
elif preset_mode == PRESET_SLEEP:
|
||
|
self._device.set_attribute(attr="sleep_mode", value=True)
|
||
|
elif preset_mode == PRESET_ECO:
|
||
|
self._device.set_attribute(attr="eco_mode", value=True)
|
||
|
elif preset_mode == PRESET_BOOST:
|
||
|
self._device.set_attribute(attr="boost_mode", value=True)
|
||
|
elif old_mode == PRESET_AWAY:
|
||
|
self._device.set_attribute(attr="frost_protect", value=False)
|
||
|
elif old_mode == PRESET_COMFORT:
|
||
|
self._device.set_attribute(attr="comfort_mode", value=False)
|
||
|
elif old_mode == PRESET_SLEEP:
|
||
|
self._device.set_attribute(attr="sleep_mode", value=False)
|
||
|
elif old_mode == PRESET_ECO:
|
||
|
self._device.set_attribute(attr="eco_mode", value=False)
|
||
|
elif old_mode == PRESET_BOOST:
|
||
|
self._device.set_attribute(attr="boost_mode", value=False)
|
||
|
|
||
|
def update_state(self, status):
|
||
|
try:
|
||
|
self.schedule_update_ha_state()
|
||
|
except Exception as e:
|
||
|
_LOGGER.debug(f"Entity {self.entity_id} update_state {repr(e)}, status = {status}")
|
||
|
|
||
|
def turn_aux_heat_on(self) -> None:
|
||
|
self._device.set_attribute(attr="aux_heating", value=True)
|
||
|
|
||
|
def turn_aux_heat_off(self) -> None:
|
||
|
self._device.set_attribute(attr="aux_heating", value=False)
|
||
|
|
||
|
|
||
|
class MideaACClimate(MideaClimate):
|
||
|
def __init__(self, device, entity_key):
|
||
|
super().__init__(device, entity_key)
|
||
|
self._modes = [HVACMode.OFF, HVACMode.AUTO, HVACMode.COOL, HVACMode.DRY, HVACMode.HEAT, HVACMode.FAN_ONLY]
|
||
|
self._fan_speeds = {
|
||
|
FAN_SILENT.capitalize(): 20,
|
||
|
FAN_LOW.capitalize(): 40,
|
||
|
FAN_MEDIUM.capitalize(): 60,
|
||
|
FAN_HIGH.capitalize(): 80,
|
||
|
FAN_FULL_SPEED.capitalize(): 100,
|
||
|
FAN_AUTO.capitalize(): 102
|
||
|
}
|
||
|
self._swing_modes = [
|
||
|
SWING_OFF.capitalize(),
|
||
|
SWING_VERTICAL.capitalize(),
|
||
|
SWING_HORIZONTAL.capitalize(),
|
||
|
SWING_BOTH.capitalize()
|
||
|
]
|
||
|
self._preset_modes = [PRESET_NONE, PRESET_COMFORT, PRESET_ECO, PRESET_BOOST, PRESET_SLEEP, PRESET_AWAY]
|
||
|
|
||
|
@property
|
||
|
def fan_modes(self):
|
||
|
return list(self._fan_speeds.keys())
|
||
|
|
||
|
@property
|
||
|
def fan_mode(self) -> str:
|
||
|
fan_speed = self._device.get_attribute(ACAttributes.fan_speed)
|
||
|
if fan_speed > 100:
|
||
|
return FAN_AUTO.capitalize()
|
||
|
elif fan_speed > 80:
|
||
|
return FAN_FULL_SPEED.capitalize()
|
||
|
elif fan_speed > 60:
|
||
|
return FAN_HIGH.capitalize()
|
||
|
elif fan_speed > 40:
|
||
|
return FAN_MEDIUM.capitalize()
|
||
|
elif fan_speed > 20:
|
||
|
return FAN_LOW.capitalize()
|
||
|
else:
|
||
|
return FAN_SILENT.capitalize()
|
||
|
|
||
|
@property
|
||
|
def target_temperature_step(self):
|
||
|
return PRECISION_WHOLE if self._device.temperature_step == 1 else PRECISION_HALVES
|
||
|
|
||
|
@property
|
||
|
def swing_mode(self):
|
||
|
swing_mode = (1 if self._device.get_attribute(ACAttributes.swing_vertical) else 0) + \
|
||
|
(2 if self._device.get_attribute(ACAttributes.swing_horizontal) else 0)
|
||
|
return self._swing_modes[swing_mode]
|
||
|
|
||
|
@property
|
||
|
def outdoor_temperature(self):
|
||
|
return self._device.get_attribute(ACAttributes.outdoor_temperature)
|
||
|
|
||
|
def set_fan_mode(self, fan_mode: str) -> None:
|
||
|
fan_speed = self._fan_speeds.get(fan_mode.capitalize())
|
||
|
if fan_speed:
|
||
|
self._device.set_attribute(attr=ACAttributes.fan_speed, value=fan_speed)
|
||
|
|
||
|
def set_swing_mode(self, swing_mode: str) -> None:
|
||
|
swing = self._swing_modes.index(swing_mode.capitalize())
|
||
|
swing_vertical = swing & 1 > 0
|
||
|
swing_horizontal = swing & 2 > 0
|
||
|
self._device.set_swing(swing_vertical=swing_vertical, swing_horizontal=swing_horizontal)
|
||
|
|
||
|
|
||
|
class MideaCCClimate(MideaClimate):
|
||
|
def __init__(self, device, entity_key):
|
||
|
super().__init__(device, entity_key)
|
||
|
self._modes = [HVACMode.OFF, HVACMode.FAN_ONLY, HVACMode.DRY, HVACMode.HEAT, HVACMode.COOL, HVACMode.AUTO]
|
||
|
self._swing_modes = [
|
||
|
SWING_OFF.capitalize(),
|
||
|
SWING_ON.capitalize()
|
||
|
]
|
||
|
self._preset_modes = [PRESET_NONE, PRESET_SLEEP, PRESET_ECO]
|
||
|
|
||
|
@property
|
||
|
def fan_modes(self):
|
||
|
return self._device.fan_modes
|
||
|
|
||
|
@property
|
||
|
def fan_mode(self) -> str:
|
||
|
return self._device.get_attribute(CCAttributes.fan_speed)
|
||
|
|
||
|
@property
|
||
|
def target_temperature_step(self):
|
||
|
return self._device.get_attribute(CCAttributes.temperature_precision)
|
||
|
|
||
|
@property
|
||
|
def swing_mode(self):
|
||
|
return SWING_ON.capitalize() if self._device.get_attribute(CCAttributes.swing) else SWING_OFF.capitalize()
|
||
|
|
||
|
def set_fan_mode(self, fan_mode: str) -> None:
|
||
|
self._device.set_attribute(attr=CCAttributes.fan_speed, value=fan_mode)
|
||
|
|
||
|
def set_swing_mode(self, swing_mode: str) -> None:
|
||
|
self._device.set_attribute(
|
||
|
attr=CCAttributes.swing,
|
||
|
value=swing_mode.capitalize() == SWING_ON.capitalize()
|
||
|
)
|
||
|
|
||
|
|
||
|
class MideaCFClimate(MideaClimate):
|
||
|
def __init__(self, device, entity_key):
|
||
|
super().__init__(device, entity_key)
|
||
|
self._modes = [HVACMode.OFF, HVACMode.AUTO, HVACMode.COOL, HVACMode.HEAT]
|
||
|
|
||
|
@property
|
||
|
def supported_features(self):
|
||
|
return ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.AUX_HEAT
|
||
|
|
||
|
@property
|
||
|
def target_temperature_step(self):
|
||
|
return PRECISION_WHOLE
|
||
|
|
||
|
@property
|
||
|
def min_temp(self):
|
||
|
return self._device.get_attribute(CFAttributes.min_temperature)
|
||
|
|
||
|
@property
|
||
|
def max_temp(self):
|
||
|
return self._device.get_attribute(CFAttributes.max_temperature)
|
||
|
|
||
|
@property
|
||
|
def target_temperature_low(self):
|
||
|
return self._device.get_attribute(CFAttributes.min_temperature)
|
||
|
|
||
|
@property
|
||
|
def target_temperature_high(self):
|
||
|
return self._device.get_attribute(CFAttributes.max_temperature)
|
||
|
|
||
|
@property
|
||
|
def current_temperature(self):
|
||
|
return self._device.get_attribute(CFAttributes.current_temperature)
|
||
|
|
||
|
|
||
|
class MideaC3Climate(MideaClimate):
|
||
|
_powers = [
|
||
|
C3Attributes.zone1_power,
|
||
|
C3Attributes.zone2_power,
|
||
|
]
|
||
|
|
||
|
def __init__(self, device, entity_key, zone):
|
||
|
super().__init__(device, entity_key)
|
||
|
self._zone = zone
|
||
|
self._modes = [HVACMode.OFF, HVACMode.AUTO, HVACMode.COOL, HVACMode.HEAT]
|
||
|
self._power_attr = MideaC3Climate._powers[self._zone]
|
||
|
|
||
|
@property
|
||
|
def supported_features(self):
|
||
|
return ClimateEntityFeature.TARGET_TEMPERATURE
|
||
|
|
||
|
@property
|
||
|
def target_temperature_step(self):
|
||
|
return PRECISION_WHOLE if \
|
||
|
self._device.get_attribute(C3Attributes.zone_temp_type)[self._zone] else PRECISION_HALVES
|
||
|
|
||
|
@property
|
||
|
def min_temp(self):
|
||
|
return self._device.get_attribute(C3Attributes.temperature_min)[self._zone]
|
||
|
|
||
|
@property
|
||
|
def max_temp(self):
|
||
|
return self._device.get_attribute(C3Attributes.temperature_max)[self._zone]
|
||
|
|
||
|
@property
|
||
|
def target_temperature_low(self):
|
||
|
return self._device.get_attribute(C3Attributes.temperature_min)[self._zone]
|
||
|
|
||
|
@property
|
||
|
def target_temperature_high(self):
|
||
|
return self._device.get_attribute(C3Attributes.temperature_max)[self._zone]
|
||
|
|
||
|
def turn_on(self):
|
||
|
self._device.set_attribute(attr=self._power_attr, value=True)
|
||
|
|
||
|
def turn_off(self):
|
||
|
self._device.set_attribute(attr=self._power_attr, value=False)
|
||
|
|
||
|
@property
|
||
|
def hvac_mode(self) -> str:
|
||
|
if self._device.get_attribute(self._power_attr):
|
||
|
return self._modes[self._device.get_attribute(C3Attributes.mode)]
|
||
|
else:
|
||
|
return HVACMode.OFF
|
||
|
|
||
|
@property
|
||
|
def target_temperature(self):
|
||
|
return self._device.get_attribute(C3Attributes.target_temperature)[self._zone]
|
||
|
|
||
|
@property
|
||
|
def current_temperature(self):
|
||
|
return None
|
||
|
|
||
|
def set_temperature(self, **kwargs) -> None:
|
||
|
if ATTR_TEMPERATURE not in kwargs:
|
||
|
return
|
||
|
temperature = float(int((float(kwargs.get(ATTR_TEMPERATURE)) * 2) + 0.5)) / 2
|
||
|
hvac_mode = kwargs.get(ATTR_HVAC_MODE)
|
||
|
if hvac_mode == HVACMode.OFF:
|
||
|
self.turn_off()
|
||
|
else:
|
||
|
try:
|
||
|
mode = self._modes.index(hvac_mode.lower()) if hvac_mode else None
|
||
|
self._device.set_target_temperature(
|
||
|
zone=self._zone, target_temperature=temperature, mode=mode)
|
||
|
except ValueError as e:
|
||
|
_LOGGER.error(f"set_temperature {e}, kwargs = {kwargs}")
|
||
|
|
||
|
def set_hvac_mode(self, hvac_mode: str) -> None:
|
||
|
hvac_mode = hvac_mode.lower()
|
||
|
if hvac_mode == HVACMode.OFF:
|
||
|
self.turn_off()
|
||
|
else:
|
||
|
self._device.set_mode(self._zone, self._modes.index(hvac_mode))
|
||
|
|
||
|
|
||
|
class MideaFBClimate(MideaClimate):
|
||
|
def __init__(self, device, entity_key):
|
||
|
super().__init__(device, entity_key)
|
||
|
self._modes = [HVACMode.OFF, HVACMode.HEAT]
|
||
|
self._preset_modes = self._device.modes
|
||
|
|
||
|
@property
|
||
|
def supported_features(self):
|
||
|
return ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
|
||
|
|
||
|
@property
|
||
|
def target_temperature_step(self):
|
||
|
return PRECISION_WHOLE
|
||
|
|
||
|
@property
|
||
|
def preset_modes(self):
|
||
|
return self._preset_modes
|
||
|
|
||
|
@property
|
||
|
def preset_mode(self):
|
||
|
return self._device.get_attribute(attr=FBAttributes.mode)
|
||
|
|
||
|
@property
|
||
|
def min_temp(self):
|
||
|
return 5
|
||
|
|
||
|
@property
|
||
|
def max_temp(self):
|
||
|
return 35
|
||
|
|
||
|
@property
|
||
|
def target_temperature_low(self):
|
||
|
return 5
|
||
|
|
||
|
@property
|
||
|
def target_temperature_high(self):
|
||
|
return 35
|
||
|
|
||
|
@property
|
||
|
def hvac_mode(self) -> str:
|
||
|
return HVACMode.HEAT if self._device.get_attribute(attr=FBAttributes.power) else HVACMode.OFF
|
||
|
|
||
|
@property
|
||
|
def current_temperature(self):
|
||
|
return self._device.get_attribute(FBAttributes.current_temperature)
|
||
|
|
||
|
def set_temperature(self, **kwargs) -> None:
|
||
|
if ATTR_TEMPERATURE not in kwargs:
|
||
|
return
|
||
|
temperature = float(int((float(kwargs.get(ATTR_TEMPERATURE)) * 2) + 0.5)) / 2
|
||
|
hvac_mode = kwargs.get(ATTR_HVAC_MODE)
|
||
|
if hvac_mode == HVACMode.OFF:
|
||
|
self.turn_off()
|
||
|
else:
|
||
|
self._device.set_attribute(attr=FBAttributes.target_temperature, value=temperature)
|
||
|
|
||
|
def set_hvac_mode(self, hvac_mode: str) -> None:
|
||
|
hvac_mode = hvac_mode.lower()
|
||
|
if hvac_mode == HVACMode.OFF:
|
||
|
self.turn_off()
|
||
|
else:
|
||
|
self.turn_on()
|
||
|
|
||
|
def set_preset_mode(self, preset_mode: str) -> None:
|
||
|
self._device.set_attribute(attr=FBAttributes.mode,value=preset_mode)
|