This commit is contained in:
Home Assistant Version Control
2026-09-28 14:45:59 +00:00
parent ae38d6b234
commit cd65be7a07
35 changed files with 5212 additions and 133 deletions
+127 -2
View File
@@ -44,6 +44,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from midealan.device import DeviceType
from midealan.devices.ac import DeviceAttributes as ACAttributes
from midealan.devices.ac import MideaACDevice
from midealan.devices.c1 import DeviceAttributes as C1Attributes
from midealan.devices.c1 import MideaC1Device
from midealan.devices.c3 import DeviceAttributes as C3Attributes
from midealan.devices.c3 import MideaC3Device
from midealan.devices.cc import DeviceAttributes as CCAttributes
@@ -83,6 +85,7 @@ async def async_setup_entry(
| MideaCCClimate
| MideaCFClimate
| MideaC3Climate
| MideaC1Climate
| MideaFBClimate
| MideaEDTeaBarClimate
] = []
@@ -104,6 +107,8 @@ async def async_setup_entry(
devs.append(MideaCFClimate(device, entity_key))
elif device.device_type == DeviceType.C3:
devs.append(MideaC3Climate(device, entity_key, config["zone"]))
elif device.device_type == DeviceType.C1:
devs.append(MideaC1Climate(device, entity_key))
elif device.device_type == DeviceType.FB:
devs.append(MideaFBClimate(device, entity_key))
elif device.device_type == DeviceType.ED:
@@ -111,9 +116,10 @@ async def async_setup_entry(
async_add_entities(devs)
type MideaClimateDevice = (
type MideaSetTemperatureDevice = (
MideaACDevice | MideaCCDevice | MideaCFDevice | MideaC3Device | MideaFBDevice
)
type MideaClimateDevice = MideaSetTemperatureDevice | MideaC1Device
class MideaClimate(MideaEntity, ClimateEntity):
@@ -211,7 +217,8 @@ class MideaClimate(MideaEntity, ClimateEntity):
else:
try:
mode = self.hvac_modes.index(hvac_mode.lower()) if hvac_mode else None
self._device.set_target_temperature(
target_device = cast("MideaSetTemperatureDevice", self._device)
target_device.set_target_temperature(
target_temperature=temperature,
mode=mode,
zone=None,
@@ -1019,6 +1026,124 @@ class MideaC3Climate(MideaClimate):
self._device.set_mode(self._zone, self.hvac_modes.index(hvac_mode))
class MideaC1Climate(MideaClimate):
"""Midea C1 electric wall-hung boiler (space heating as climate)."""
_device: MideaC1Device
_attr_max_temp: float = 60
_attr_min_temp: float = 30
_attr_target_temperature_high: float | None = 60
_attr_target_temperature_low: float | None = 30
_attr_target_temperature_step: float | None = PRECISION_WHOLE
def __init__(self, device: MideaC1Device, entity_key: str) -> None:
"""Midea C1 climate entity init."""
super().__init__(device, entity_key)
self._attr_hvac_modes = [HVACMode.OFF, HVACMode.HEAT]
self._attr_preset_modes: list[str] = self._device.heating_modes
@property
def supported_features(self) -> ClimateEntityFeature:
"""Midea C1 climate supported features."""
features = (
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
)
if (MAJOR_VERSION, MINOR_VERSION) >= (2024, 2):
features |= ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON
return features
@property
def hvac_mode(self) -> HVACMode:
"""Midea C1 climate hvac mode."""
return (
HVACMode.HEAT
if self._device.get_attribute(C1Attributes.power)
else HVACMode.OFF
)
@property
def preset_mode(self) -> str:
"""Midea C1 climate preset mode (comfort / activity / sleep)."""
mode = cast("str", self._device.get_attribute(C1Attributes.heating_mode))
if mode == "unknown" and self._attr_preset_modes:
return self._attr_preset_modes[0]
return mode
@property
def current_temperature(self) -> float | None:
"""Midea C1 climate current temperature."""
raw = self._device.get_attribute(C1Attributes.current_temperature)
if isinstance(raw, int | float):
return float(raw)
return None
@property
def target_temperature(self) -> float:
"""Midea C1 climate heating target setpoint."""
raw = self._device.get_attribute(C1Attributes.heating_target_temperature)
if isinstance(raw, int | float):
return float(raw)
return float(self.min_temp)
def set_temperature(self, **kwargs: Any) -> None: # ruff:ignore[any-type]
"""Midea C1 climate set heating target temperature."""
if ATTR_TEMPERATURE not in kwargs:
return
temperature = float(round(float(kwargs[ATTR_TEMPERATURE])))
hvac_mode = kwargs.get(ATTR_HVAC_MODE)
if hvac_mode == HVACMode.OFF:
self.turn_off()
return
# Writing heating_target_temperature only sends MessageSetHeating, not a
# power-on command. When the service call carries an explicit non-OFF
# mode, turn the boiler on first so a combined change on an off device
# actually starts heating instead of silently staying off.
if hvac_mode is not None:
self.turn_on()
self._device.set_attribute(
attr=C1Attributes.heating_target_temperature,
value=temperature,
)
def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Midea C1 climate set hvac mode."""
if hvac_mode == HVACMode.OFF:
self.turn_off()
else:
self.turn_on()
def set_preset_mode(self, preset_mode: str) -> None:
"""Midea C1 climate set heating schedule mode.
Send the requested preset's own stored setpoint together with the mode
change. The device library's plain ``heating_mode`` setter re-applies
the cached general ``heating_target_temperature`` under the new mode, so
switching presets would otherwise carry over the previous mode's target
instead of that preset's per-mode setpoint. Fall back to the plain mode
change when the per-mode setpoint has not been reported yet.
"""
# Lua mode codes: user=1, activity=2, sleep=3 (see midealan c1.message).
per_mode = {
"user": (1, C1Attributes.user_mode_target_temperature),
"activity": (2, C1Attributes.activity_mode_target_temperature),
"sleep": (3, C1Attributes.sleep_mode_target_temperature),
}.get(preset_mode)
if per_mode is not None:
mode_code, per_mode_attr = per_mode
raw = self._device.get_attribute(per_mode_attr)
if isinstance(raw, int | float):
self._device.set_heating_target_temperature(
float(raw),
heating_mode=mode_code,
)
return
self._device.set_attribute(
attr=C1Attributes.heating_mode,
value=preset_mode,
)
class MideaFBClimate(MideaClimate):
"""Midea FB Climate Entries."""