"""Support for HomeKit Controller humidifier.""" from __future__ import annotations from typing import Any from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import Service, ServicesTypes from homeassistant.components.humidifier import HumidifierDeviceClass, HumidifierEntity from homeassistant.components.humidifier.const import ( MODE_AUTO, MODE_NORMAL, SUPPORT_MODES, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import KNOWN_DEVICES, HomeKitEntity SUPPORT_FLAGS = 0 HK_MODE_TO_HA = { 0: "off", 1: MODE_AUTO, 2: "humidifying", 3: "dehumidifying", } HA_MODE_TO_HK = { MODE_AUTO: 0, "humidifying": 1, "dehumidifying": 2, } class HomeKitHumidifier(HomeKitEntity, HumidifierEntity): """Representation of a HomeKit Controller Humidifier.""" _attr_device_class = HumidifierDeviceClass.HUMIDIFIER def get_characteristic_types(self) -> list[str]: """Define the homekit characteristics the entity cares about.""" return [ CharacteristicsTypes.ACTIVE, CharacteristicsTypes.CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE, CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE, CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD, ] @property def supported_features(self) -> int: """Return the list of supported features.""" return SUPPORT_FLAGS | SUPPORT_MODES @property def is_on(self) -> bool: """Return true if device is on.""" return self.service.value(CharacteristicsTypes.ACTIVE) async def async_turn_on(self, **kwargs: Any) -> None: """Turn the specified valve on.""" await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: True}) async def async_turn_off(self, **kwargs: Any) -> None: """Turn the specified valve off.""" await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: False}) @property def target_humidity(self) -> int | None: """Return the humidity we try to reach.""" return self.service.value( CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD ) @property def mode(self) -> str | None: """Return the current mode, e.g., home, auto, baby. Requires SUPPORT_MODES. """ mode = self.service.value( CharacteristicsTypes.CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE ) return MODE_AUTO if mode == 1 else MODE_NORMAL @property def available_modes(self) -> list[str] | None: """Return a list of available modes. Requires SUPPORT_MODES. """ available_modes = [ MODE_NORMAL, MODE_AUTO, ] return available_modes async def async_set_humidity(self, humidity: int) -> None: """Set new target humidity.""" await self.async_put_characteristics( {CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD: humidity} ) async def async_set_mode(self, mode: str) -> None: """Set new mode.""" if mode == MODE_AUTO: await self.async_put_characteristics( { CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE: 0, CharacteristicsTypes.ACTIVE: True, } ) else: await self.async_put_characteristics( { CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE: 1, CharacteristicsTypes.ACTIVE: True, } ) @property def min_humidity(self) -> int: """Return the minimum humidity.""" return self.service[ CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD ].minValue @property def max_humidity(self) -> int: """Return the maximum humidity.""" return self.service[ CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD ].maxValue class HomeKitDehumidifier(HomeKitEntity, HumidifierEntity): """Representation of a HomeKit Controller Humidifier.""" _attr_device_class = HumidifierDeviceClass.DEHUMIDIFIER def get_characteristic_types(self) -> list[str]: """Define the homekit characteristics the entity cares about.""" return [ CharacteristicsTypes.ACTIVE, CharacteristicsTypes.CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE, CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE, CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD, CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD, ] @property def supported_features(self) -> int: """Return the list of supported features.""" return SUPPORT_FLAGS | SUPPORT_MODES @property def is_on(self) -> bool: """Return true if device is on.""" return self.service.value(CharacteristicsTypes.ACTIVE) async def async_turn_on(self, **kwargs: Any) -> None: """Turn the specified valve on.""" await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: True}) async def async_turn_off(self, **kwargs: Any) -> None: """Turn the specified valve off.""" await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: False}) @property def target_humidity(self) -> int | None: """Return the humidity we try to reach.""" return self.service.value( CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD ) @property def mode(self) -> str | None: """Return the current mode, e.g., home, auto, baby. Requires SUPPORT_MODES. """ mode = self.service.value( CharacteristicsTypes.CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE ) return MODE_AUTO if mode == 1 else MODE_NORMAL @property def available_modes(self) -> list[str] | None: """Return a list of available modes. Requires SUPPORT_MODES. """ available_modes = [ MODE_NORMAL, MODE_AUTO, ] return available_modes async def async_set_humidity(self, humidity: int) -> None: """Set new target humidity.""" await self.async_put_characteristics( {CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD: humidity} ) async def async_set_mode(self, mode: str) -> None: """Set new mode.""" if mode == MODE_AUTO: await self.async_put_characteristics( { CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE: 0, CharacteristicsTypes.ACTIVE: True, } ) else: await self.async_put_characteristics( { CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE: 2, CharacteristicsTypes.ACTIVE: True, } ) @property def min_humidity(self) -> int: """Return the minimum humidity.""" return self.service[ CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD ].minValue @property def max_humidity(self) -> int: """Return the maximum humidity.""" return self.service[ CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD ].maxValue @property def unique_id(self) -> str: """Return the ID of this device.""" serial = self.accessory_info.value(CharacteristicsTypes.SERIAL_NUMBER) return f"homekit-{serial}-{self._iid}-{self.device_class}" async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit humidifer.""" hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_service(service: Service) -> bool: if service.type != ServicesTypes.HUMIDIFIER_DEHUMIDIFIER: return False info = {"aid": service.accessory.aid, "iid": service.iid} entities: list[HumidifierEntity] = [] if service.has(CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD): entities.append(HomeKitHumidifier(conn, info)) if service.has(CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD): entities.append(HomeKitDehumidifier(conn, info)) async_add_entities(entities, True) return True conn.add_listener(async_add_service)