"""Support for WeMo humidifier.""" from __future__ import annotations import asyncio from datetime import timedelta import math from typing import Any from pywemo import DesiredHumidity, FanMode, Humidifier import voluptuous as vol from homeassistant.components.fan import FanEntity, FanEntityFeature from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import entity_platform from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.percentage import ( int_states_in_range, percentage_to_ranged_value, ranged_value_to_percentage, ) from .const import ( DOMAIN as WEMO_DOMAIN, SERVICE_RESET_FILTER_LIFE, SERVICE_SET_HUMIDITY, ) from .entity import WemoBinaryStateEntity from .wemo_device import DeviceCoordinator SCAN_INTERVAL = timedelta(seconds=10) PARALLEL_UPDATES = 0 ATTR_CURRENT_HUMIDITY = "current_humidity" ATTR_TARGET_HUMIDITY = "target_humidity" ATTR_FAN_MODE = "fan_mode" ATTR_FILTER_LIFE = "filter_life" ATTR_FILTER_EXPIRED = "filter_expired" ATTR_WATER_LEVEL = "water_level" SPEED_RANGE = (FanMode.Minimum, FanMode.Maximum) # off is not included SET_HUMIDITY_SCHEMA = { vol.Required(ATTR_TARGET_HUMIDITY): vol.All( vol.Coerce(float), vol.Range(min=0, max=100) ), } async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up WeMo binary sensors.""" async def _discovered_wemo(coordinator: DeviceCoordinator) -> None: """Handle a discovered Wemo device.""" async_add_entities([WemoHumidifier(coordinator)]) async_dispatcher_connect(hass, f"{WEMO_DOMAIN}.fan", _discovered_wemo) await asyncio.gather( *( _discovered_wemo(coordinator) for coordinator in hass.data[WEMO_DOMAIN]["pending"].pop("fan") ) ) platform = entity_platform.async_get_current_platform() # This will call WemoHumidifier.set_humidity(target_humidity=VALUE) platform.async_register_entity_service( SERVICE_SET_HUMIDITY, SET_HUMIDITY_SCHEMA, WemoHumidifier.set_humidity.__name__ ) # This will call WemoHumidifier.reset_filter_life() platform.async_register_entity_service( SERVICE_RESET_FILTER_LIFE, {}, WemoHumidifier.reset_filter_life.__name__ ) class WemoHumidifier(WemoBinaryStateEntity, FanEntity): """Representation of a WeMo humidifier.""" _attr_supported_features = FanEntityFeature.SET_SPEED wemo: Humidifier def __init__(self, coordinator: DeviceCoordinator) -> None: """Initialize the WeMo switch.""" super().__init__(coordinator) if self.wemo.fan_mode != FanMode.Off: self._last_fan_on_mode = self.wemo.fan_mode else: self._last_fan_on_mode = FanMode.High @property def icon(self) -> str: """Return the icon of device based on its type.""" return "mdi:water-percent" @property def extra_state_attributes(self) -> dict[str, Any]: """Return device specific state attributes.""" return { ATTR_CURRENT_HUMIDITY: self.wemo.current_humidity_percent, ATTR_TARGET_HUMIDITY: self.wemo.desired_humidity_percent, ATTR_FAN_MODE: self.wemo.fan_mode_string, ATTR_WATER_LEVEL: self.wemo.water_level_string, ATTR_FILTER_LIFE: self.wemo.filter_life_percent, ATTR_FILTER_EXPIRED: self.wemo.filter_expired, } @property def percentage(self) -> int: """Return the current speed percentage.""" return ranged_value_to_percentage(SPEED_RANGE, self.wemo.fan_mode) @property def speed_count(self) -> int: """Return the number of speeds the fan supports.""" return int_states_in_range(SPEED_RANGE) @callback def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" if self.wemo.fan_mode != FanMode.Off: self._last_fan_on_mode = self.wemo.fan_mode super()._handle_coordinator_update() def turn_on( self, percentage: int | None = None, preset_mode: str | None = None, **kwargs: Any, ) -> None: """Turn the fan on.""" self.set_percentage(percentage) def turn_off(self, **kwargs: Any) -> None: """Turn the switch off.""" with self._wemo_call_wrapper("turn off"): self.wemo.set_state(FanMode.Off) def set_percentage(self, percentage: int | None) -> None: """Set the fan_mode of the Humidifier.""" if percentage is None: named_speed = self._last_fan_on_mode elif percentage == 0: named_speed = FanMode.Off else: named_speed = FanMode( math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage)) ) with self._wemo_call_wrapper("set speed"): self.wemo.set_state(named_speed) def set_humidity(self, target_humidity: float) -> None: """Set the target humidity level for the Humidifier.""" if target_humidity < 50: pywemo_humidity = DesiredHumidity.FortyFivePercent elif 50 <= target_humidity < 55: pywemo_humidity = DesiredHumidity.FiftyPercent elif 55 <= target_humidity < 60: pywemo_humidity = DesiredHumidity.FiftyFivePercent elif 60 <= target_humidity < 100: pywemo_humidity = DesiredHumidity.SixtyPercent elif target_humidity >= 100: pywemo_humidity = DesiredHumidity.OneHundredPercent with self._wemo_call_wrapper("set humidity"): self.wemo.set_humidity(pywemo_humidity) def reset_filter_life(self) -> None: """Reset the filter life to 100%.""" with self._wemo_call_wrapper("reset filter life"): self.wemo.reset_filter_life()