"""Midea Water Heater entries.""" import functools as ft import logging from typing import Any, ClassVar, cast from homeassistant.components.water_heater import ( WaterHeaterEntity, WaterHeaterEntityFeature, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_TEMPERATURE, CONF_DEVICE_ID, CONF_SWITCHES, PRECISION_HALVES, PRECISION_WHOLE, STATE_OFF, STATE_ON, Platform, UnitOfTemperature, ) from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from midealocal.device import DeviceType from midealocal.devices.c3 import DeviceAttributes as C3Attributes from midealocal.devices.c3 import MideaC3Device from midealocal.devices.cd import DeviceAttributes as CDAttributes from midealocal.devices.cd import MideaCDDevice from midealocal.devices.e2 import DeviceAttributes as E2Attributes from midealocal.devices.e2 import MideaE2Device from midealocal.devices.e3 import MideaE3Device from midealocal.devices.e6 import DeviceAttributes as E6Attributes from midealocal.devices.e6 import MideaE6Device from .const import DEVICES, DOMAIN from .midea_devices import MIDEA_DEVICES from .midea_entity import MideaEntity _LOGGER = logging.getLogger(__name__) E2_TEMPERATURE_MAX = 75 E2_TEMPERATURE_MIN = 30 E3_TEMPERATURE_MAX = 65 E3_TEMPERATURE_MIN = 35 async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up water heater entries.""" 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: list[ MideaE2WaterHeater | MideaE3WaterHeater | MideaE6WaterHeater | MideaC3WaterHeater | MideaCDWaterHeater ] = [] for entity_key, config in cast( "dict", MIDEA_DEVICES[device.device_type]["entities"], ).items(): if config["type"] == Platform.WATER_HEATER and ( config.get("default") or entity_key in extra_switches ): if device.device_type == DeviceType.E2: devs.append(MideaE2WaterHeater(device, entity_key)) elif device.device_type == DeviceType.E3: devs.append(MideaE3WaterHeater(device, entity_key)) elif device.device_type == DeviceType.E6: devs.append(MideaE6WaterHeater(device, entity_key, config["use"])) elif device.device_type == DeviceType.C3: devs.append(MideaC3WaterHeater(device, entity_key)) elif device.device_type == DeviceType.CD: devs.append(MideaCDWaterHeater(device, entity_key)) async_add_entities(devs) type MideaWaterHeaterDevice = ( MideaE2Device | MideaE3Device | MideaC3Device | MideaE6Device | MideaCDDevice ) class MideaWaterHeater(MideaEntity, WaterHeaterEntity): """Midea Water Heater Entries Base Class.""" _device: MideaWaterHeaterDevice def __init__(self, device: MideaWaterHeaterDevice, entity_key: str) -> None: """Midea Water Heater entity init.""" super().__init__(device, entity_key) self._operations: list[str] = [] @property def supported_features(self) -> WaterHeaterEntityFeature: """Midea Water Heater supported features.""" return WaterHeaterEntityFeature.TARGET_TEMPERATURE @property def extra_state_attributes(self) -> dict[str, Any]: """Midea Water Heater extra state attributes.""" attrs: dict[str, Any] = self._device.attributes if hasattr(self._device, "temperature_step"): attrs["target_temperature_step"] = self._device.temperature_step return attrs @property def min_temp(self) -> float: """Midea Water Heater min temperature.""" raise NotImplementedError @property def max_temp(self) -> float: """Midea Water Heater max temperature.""" raise NotImplementedError @property def precision(self) -> float: """Midea Water Heater precision.""" return float(PRECISION_WHOLE) @property def temperature_unit(self) -> UnitOfTemperature: """Midea Water Heater temperature unix.""" return UnitOfTemperature.CELSIUS @property def current_operation(self) -> str | None: """Midea Water Heater current operation.""" return cast( "str", ( self._device.get_attribute("mode") if self._device.get_attribute("power") else STATE_OFF ), ) @property def current_temperature(self) -> float: """Midea Water Heater current temperature.""" return cast("float", self._device.get_attribute("current_temperature")) @property def target_temperature(self) -> float: """Midea Water Heater target temperature.""" return cast("float", self._device.get_attribute("target_temperature")) def set_temperature(self, **kwargs: Any) -> None: # ruff:ignore[any-type] """Midea Water Heater set temperature.""" if ATTR_TEMPERATURE not in kwargs: return # input target_temperature should be float temperature = float(kwargs[ATTR_TEMPERATURE]) self._device.set_attribute("target_temperature", temperature) def set_operation_mode(self, operation_mode: str) -> None: """Midea Water Heater set operation mode.""" self._device.set_attribute(attr="mode", value=operation_mode) @property def operation_list(self) -> list[str] | None: """Midea Water Heater operation list.""" if not hasattr(self._device, "preset_modes"): return None return cast("list", self._device.preset_modes) def turn_on(self, **kwargs: Any) -> None: # ruff:ignore[any-type, unused-method-argument] """Midea Water Heater turn on.""" self._device.set_attribute(attr="power", value=True) def turn_off(self, **kwargs: Any) -> None: # ruff:ignore[any-type, unused-method-argument] """Midea Water Heater turn off.""" self._device.set_attribute(attr="power", value=False) async def async_turn_on(self, **kwargs: Any) -> None: # ruff:ignore[any-type] """Midea Water Heater async turn on.""" await self.hass.async_add_executor_job(ft.partial(self.turn_on, **kwargs)) async def async_turn_off(self, **kwargs: Any) -> None: # ruff:ignore[any-type] """Midea Water Heater async off.""" await self.hass.async_add_executor_job(ft.partial(self.turn_off, **kwargs)) def update_state(self, status: Any) -> None: # ruff:ignore[any-type, unused-method-argument] """Midea Water Heater update state.""" if not self.hass: _LOGGER.warning( "Water update_state skipped for %s [%s]: HASS is None", self.name, type(self), ) return self.schedule_update_if_running() class MideaE2WaterHeater(MideaWaterHeater): """Midea E2 Water Heater Entries.""" _device: MideaE2Device def __init__(self, device: MideaE2Device, entity_key: str) -> None: """Midea E2 Water Heater entity init.""" super().__init__(device, entity_key) @property def current_operation(self) -> str: """Midea E2 Water Heater current operation.""" return str( STATE_ON if self._device.get_attribute(E2Attributes.power) else STATE_OFF, ) @property def min_temp(self) -> float: """Midea E2 Water Heater min temperature.""" return E2_TEMPERATURE_MIN @property def max_temp(self) -> float: """Midea E2 Water Heater max temperature.""" return E2_TEMPERATURE_MAX @property def supported_features(self) -> WaterHeaterEntityFeature: """Midea E2 Water Heater supported features.""" return ( WaterHeaterEntityFeature.TARGET_TEMPERATURE | WaterHeaterEntityFeature.ON_OFF ) class MideaE3WaterHeater(MideaWaterHeater): """Midea E3 Water Heater Entries.""" _device: MideaE3Device def __init__(self, device: MideaE3Device, entity_key: str) -> None: """Midea E3 Water Heater entity init.""" super().__init__(device, entity_key) @property def min_temp(self) -> float: """Midea E3 Water Heater min temperature.""" return E3_TEMPERATURE_MIN @property def max_temp(self) -> float: """Midea E3 Water Heater max temperature.""" return E3_TEMPERATURE_MAX @property def precision(self) -> float: """Midea E3 Water Heater precision.""" return float( PRECISION_HALVES if self._device.precision_halves else PRECISION_WHOLE, ) @property def current_operation(self) -> str: """Midea E3 Water Heater current operation.""" return str( STATE_ON if self._device.get_attribute("power") else STATE_OFF, ) class MideaC3WaterHeater(MideaWaterHeater): """Midea C3 Water Heater Entries.""" _device: MideaC3Device def __init__(self, device: MideaC3Device, entity_key: str) -> None: """Midea C3 Water Heater entity init.""" super().__init__(device, entity_key) @property def current_operation(self) -> str: """Midea C3 Water Heater current operation.""" return str( ( STATE_ON if self._device.get_attribute(C3Attributes.dhw_power) else STATE_OFF ), ) @property def current_temperature(self) -> float: """Midea C3 Water Heater current temperature.""" return cast( "float", self._device.get_attribute(C3Attributes.tank_actual_temperature), ) @property def target_temperature(self) -> float: """Midea C3 Water Heater target temperature.""" return cast("float", self._device.get_attribute(C3Attributes.dhw_target_temp)) def set_temperature(self, **kwargs: Any) -> None: # ruff:ignore[any-type] """Midea C3 Water Heater set temperature.""" if ATTR_TEMPERATURE not in kwargs: return temperature = float(kwargs[ATTR_TEMPERATURE]) self._device.set_attribute(C3Attributes.dhw_target_temp, temperature) @property def min_temp(self) -> float: """Midea C3 Water Heater min temperature.""" return cast("float", self._device.get_attribute(C3Attributes.dhw_temp_min)) @property def max_temp(self) -> float: """Midea C3 Water Heater max temperature.""" return cast("float", self._device.get_attribute(C3Attributes.dhw_temp_max)) def turn_on(self, **kwargs: Any) -> None: # ruff:ignore[any-type, unused-method-argument] """Midea C3 Water Heater turn on.""" self._device.set_attribute(attr=C3Attributes.dhw_power, value=True) def turn_off(self, **kwargs: Any) -> None: # ruff:ignore[any-type, unused-method-argument] """Midea C3 Water Heater turn off.""" self._device.set_attribute(attr=C3Attributes.dhw_power, value=False) class MideaE6WaterHeater(MideaWaterHeater): """Midea E6 Water Heater Entries.""" _device: MideaE6Device _powers: ClassVar[list[E6Attributes]] = [ E6Attributes.heating_power, E6Attributes.main_power, ] _current_temperatures: ClassVar[list[E6Attributes]] = [ E6Attributes.heating_leaving_temperature, E6Attributes.bathing_leaving_temperature, ] _target_temperatures: ClassVar[list[E6Attributes]] = [ E6Attributes.heating_temperature, E6Attributes.bathing_temperature, ] def __init__(self, device: MideaE6Device, entity_key: str, use: int) -> None: """Midea E6 Water Heater entity init.""" super().__init__(device, entity_key) self._use = use self._power_attr = MideaE6WaterHeater._powers[self._use] self._current_temperature_attr = MideaE6WaterHeater._current_temperatures[ self._use ] self._target_temperature_attr = MideaE6WaterHeater._target_temperatures[ self._use ] @property def current_operation(self) -> str: """Midea E6 Water Heater current operation.""" if self._use == 0: # for heating return str( ( STATE_ON if self._device.get_attribute(E6Attributes.main_power) and self._device.get_attribute(E6Attributes.heating_power) else STATE_OFF ), ) # for bathing return str( ( STATE_ON if self._device.get_attribute(E6Attributes.main_power) else STATE_OFF ), ) @property def current_temperature(self) -> float: """Midea E6 Water Heater current temperature.""" return cast("float", self._device.get_attribute(self._current_temperature_attr)) @property def target_temperature(self) -> float: """Midea E6 Water Heater target temperature.""" return cast("float", self._device.get_attribute(self._target_temperature_attr)) def set_temperature(self, **kwargs: Any) -> None: # ruff:ignore[any-type] """Midea E6 Water Heater set temperature.""" if ATTR_TEMPERATURE not in kwargs: return temperature = float(kwargs[ATTR_TEMPERATURE]) self._device.set_attribute(self._target_temperature_attr, temperature) @property def min_temp(self) -> float: """Midea E6 Water Heater min temperature.""" min_temperature = cast( "list[str]", self._device.get_attribute(E6Attributes.temperature_min), ) return cast( "float", min_temperature[self._use], ) @property def max_temp(self) -> float: """Midea E6 Water Heater max temperature.""" max_temperature = cast( "list[str]", self._device.get_attribute(E6Attributes.temperature_max), ) return cast( "float", max_temperature[self._use], ) def turn_on(self, **kwargs: Any) -> None: # ruff:ignore[any-type, unused-method-argument] """Midea E6 Water Heater turn on.""" self._device.set_attribute(attr=self._power_attr, value=True) def turn_off(self, **kwargs: Any) -> None: # ruff:ignore[any-type, unused-method-argument] """Midea E6 Water Heater turn off.""" self._device.set_attribute(attr=self._power_attr, value=False) class MideaCDWaterHeater(MideaWaterHeater): """Midea CD Water Heater Entries.""" _device: MideaCDDevice def __init__(self, device: MideaCDDevice, entity_key: str) -> None: """Midea CD Water Heater entity init.""" super().__init__(device, entity_key) @property def supported_features(self) -> WaterHeaterEntityFeature: """Midea CD Water Heater supported features.""" return ( WaterHeaterEntityFeature.TARGET_TEMPERATURE | WaterHeaterEntityFeature.OPERATION_MODE ) @property def min_temp(self) -> float: """Midea CD Water Heater min temperature.""" return cast("float", self._device.get_attribute(CDAttributes.min_temperature)) @property def max_temp(self) -> float: """Midea CD Water Heater max temperature.""" return cast("float", self._device.get_attribute(CDAttributes.max_temperature))