"""Climate device for CCM15 coordinator.""" import logging from typing import Any, override from ccm15 import CCM15DeviceState, CCM15SlaveDevice from homeassistant.components.climate import ( ATTR_HVAC_MODE, FAN_AUTO, FAN_HIGH, FAN_LOW, FAN_MEDIUM, PRECISION_WHOLE, SWING_OFF, SWING_ON, ClimateEntity, ClimateEntityFeature, HVACMode, ) from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature from homeassistant.core import HomeAssistant from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import CONST_CMD_FAN_MAP, CONST_CMD_STATE_MAP, DOMAIN from .coordinator import CCM15ConfigEntry, CCM15Coordinator _LOGGER = logging.getLogger(__name__) async def async_setup_entry( hass: HomeAssistant, config_entry: CCM15ConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up all climate.""" coordinator = config_entry.runtime_data ac_data: CCM15DeviceState = coordinator.data entities = [ CCM15Climate(coordinator.get_host(), ac_index, coordinator) for ac_index in ac_data.devices ] async_add_entities(entities) class CCM15Climate(CoordinatorEntity[CCM15Coordinator], ClimateEntity): """Climate device for CCM15 coordinator.""" _attr_has_entity_name = True _attr_target_temperature_step = PRECISION_WHOLE _attr_hvac_modes = [ HVACMode.OFF, HVACMode.HEAT, HVACMode.COOL, HVACMode.DRY, HVACMode.FAN_ONLY, HVACMode.AUTO, ] _attr_fan_modes = [FAN_AUTO, FAN_LOW, FAN_MEDIUM, FAN_HIGH] _attr_swing_modes = [SWING_OFF, SWING_ON] _attr_supported_features = ( ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE | ClimateEntityFeature.SWING_MODE | ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON ) _attr_name = None def __init__( self, ac_host: str, ac_index: int, coordinator: CCM15Coordinator ) -> None: """Create a climate device managed from a coordinator.""" super().__init__(coordinator) self._ac_index: int = ac_index self._attr_unique_id = f"{ac_host}.{ac_index}" self._attr_device_info = DeviceInfo( identifiers={ # Serial numbers are unique identifiers within a specific domain (DOMAIN, f"{ac_host}.{ac_index}"), }, name=f"Midea {ac_index}", manufacturer="Midea", model="CCM15", ) @property def data(self) -> CCM15SlaveDevice | None: """Return device data.""" return self.coordinator.get_ac_data(self._ac_index) @property @override def temperature_unit(self) -> str: """Return the unit of measurement reported by the device.""" if (data := self.data) is not None and not data.is_celsius: return UnitOfTemperature.FAHRENHEIT return UnitOfTemperature.CELSIUS @property @override def current_temperature(self) -> int | None: """Return current temperature.""" if (data := self.data) is not None: return data.temperature return None @property @override def target_temperature(self) -> int | None: """Return target temperature.""" if (data := self.data) is not None: return data.temperature_setpoint return None @property @override def hvac_mode(self) -> HVACMode | None: """Return hvac mode.""" if (data := self.data) is not None: mode = data.ac_mode return CONST_CMD_STATE_MAP[mode] return None @property @override def fan_mode(self) -> str | None: """Return fan mode.""" if (data := self.data) is not None: mode = data.fan_mode return CONST_CMD_FAN_MAP[mode] return None @property @override def swing_mode(self) -> str | None: """Return swing mode.""" if (data := self.data) is not None: return SWING_ON if data.is_swing_on else SWING_OFF return None @property @override def available(self) -> bool: """Return the availability of the entity.""" return self.data is not None @property @override def extra_state_attributes(self) -> dict[str, Any]: """Return the optional state attributes.""" if (data := self.data) is not None: return {"error_code": data.error_code} return {} @override async def async_set_temperature(self, **kwargs: Any) -> None: """Set the target temperature.""" if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None: data = self.data assert data is not None await self.coordinator.async_set_temperature( self._ac_index, data, temperature, kwargs.get(ATTR_HVAC_MODE) ) @override async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: """Set the hvac mode.""" data = self.data assert data is not None await self.coordinator.async_set_hvac_mode(self._ac_index, data, hvac_mode) @override async def async_set_fan_mode(self, fan_mode: str) -> None: """Set the fan mode.""" data = self.data assert data is not None await self.coordinator.async_set_fan_mode(self._ac_index, data, fan_mode) @override async def async_set_swing_mode(self, swing_mode: str) -> None: """Set the swing mode.""" data = self.data assert data is not None await self.coordinator.async_set_swing_mode(self._ac_index, data, swing_mode) @override async def async_turn_off(self) -> None: """Turn off.""" await self.async_set_hvac_mode(HVACMode.OFF) @override async def async_turn_on(self) -> None: """Turn on.""" await self.async_set_hvac_mode(HVACMode.AUTO)