core/homeassistant/components/wemo/fan.py

183 lines
6.0 KiB
Python

"""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:
"""Set the fan_mode of the Humidifier."""
self._set_percentage(percentage)
def _set_percentage(self, percentage: int | None) -> None:
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()