Home Assistant Unofficial Reference 2024.12.1
fan.py
Go to the documentation of this file.
1 """Support for WeMo humidifier."""
2 
3 from __future__ import annotations
4 
5 from datetime import timedelta
6 import math
7 from typing import Any
8 
9 from pywemo import DesiredHumidity, FanMode, Humidifier
10 import voluptuous as vol
11 
12 from homeassistant.components.fan import FanEntity, FanEntityFeature
13 from homeassistant.config_entries import ConfigEntry
14 from homeassistant.core import HomeAssistant, callback
15 from homeassistant.helpers import entity_platform
16 from homeassistant.helpers.entity_platform import AddEntitiesCallback
17 from homeassistant.helpers.typing import VolDictType
19  percentage_to_ranged_value,
20  ranged_value_to_percentage,
21 )
22 from homeassistant.util.scaling import int_states_in_range
23 
24 from . import async_wemo_dispatcher_connect
25 from .const import SERVICE_RESET_FILTER_LIFE, SERVICE_SET_HUMIDITY
26 from .coordinator import DeviceCoordinator
27 from .entity import WemoBinaryStateEntity
28 
29 SCAN_INTERVAL = timedelta(seconds=10)
30 PARALLEL_UPDATES = 0
31 
32 ATTR_CURRENT_HUMIDITY = "current_humidity"
33 ATTR_TARGET_HUMIDITY = "target_humidity"
34 ATTR_FAN_MODE = "fan_mode"
35 ATTR_FILTER_LIFE = "filter_life"
36 ATTR_FILTER_EXPIRED = "filter_expired"
37 ATTR_WATER_LEVEL = "water_level"
38 
39 SPEED_RANGE = (FanMode.Minimum, FanMode.Maximum) # off is not included
40 
41 SET_HUMIDITY_SCHEMA: VolDictType = {
42  vol.Required(ATTR_TARGET_HUMIDITY): vol.All(
43  vol.Coerce(float), vol.Range(min=0, max=100)
44  ),
45 }
46 
47 
49  hass: HomeAssistant,
50  _config_entry: ConfigEntry,
51  async_add_entities: AddEntitiesCallback,
52 ) -> None:
53  """Set up WeMo binary sensors."""
54 
55  async def _discovered_wemo(coordinator: DeviceCoordinator) -> None:
56  """Handle a discovered Wemo device."""
57  async_add_entities([WemoHumidifier(coordinator)])
58 
59  await async_wemo_dispatcher_connect(hass, _discovered_wemo)
60 
61  platform = entity_platform.async_get_current_platform()
62 
63  # This will call WemoHumidifier.set_humidity(target_humidity=VALUE)
64  platform.async_register_entity_service(
65  SERVICE_SET_HUMIDITY, SET_HUMIDITY_SCHEMA, WemoHumidifier.set_humidity.__name__
66  )
67 
68  # This will call WemoHumidifier.reset_filter_life()
69  platform.async_register_entity_service(
70  SERVICE_RESET_FILTER_LIFE, None, WemoHumidifier.reset_filter_life.__name__
71  )
72 
73 
75  """Representation of a WeMo humidifier."""
76 
77  _attr_supported_features = (
78  FanEntityFeature.SET_SPEED
79  | FanEntityFeature.TURN_OFF
80  | FanEntityFeature.TURN_ON
81  )
82  wemo: Humidifier
83  _last_fan_on_mode: FanMode
84  _enable_turn_on_off_backwards_compatibility = False
85 
86  def __init__(self, coordinator: DeviceCoordinator) -> None:
87  """Initialize the WeMo switch."""
88  super().__init__(coordinator)
89  if self.wemowemowemo.fan_mode != FanMode.Off:
90  self._last_fan_on_mode_last_fan_on_mode = self.wemowemowemo.fan_mode
91  else:
92  self._last_fan_on_mode_last_fan_on_mode = FanMode.High
93 
94  @property
95  def icon(self) -> str:
96  """Return the icon of device based on its type."""
97  return "mdi:water-percent"
98 
99  @property
100  def extra_state_attributes(self) -> dict[str, Any]:
101  """Return device specific state attributes."""
102  return {
103  ATTR_CURRENT_HUMIDITY: self.wemowemowemo.current_humidity_percent,
104  ATTR_TARGET_HUMIDITY: self.wemowemowemo.desired_humidity_percent,
105  ATTR_FAN_MODE: self.wemowemowemo.fan_mode_string,
106  ATTR_WATER_LEVEL: self.wemowemowemo.water_level_string,
107  ATTR_FILTER_LIFE: self.wemowemowemo.filter_life_percent,
108  ATTR_FILTER_EXPIRED: self.wemowemowemo.filter_expired,
109  }
110 
111  @property
112  def percentage(self) -> int:
113  """Return the current speed percentage."""
114  return ranged_value_to_percentage(SPEED_RANGE, self.wemowemowemo.fan_mode)
115 
116  @property
117  def speed_count(self) -> int:
118  """Return the number of speeds the fan supports."""
119  return int_states_in_range(SPEED_RANGE)
120 
121  @callback
122  def _handle_coordinator_update(self) -> None:
123  """Handle updated data from the coordinator."""
124  if self.wemowemowemo.fan_mode != FanMode.Off:
125  self._last_fan_on_mode_last_fan_on_mode = self.wemowemowemo.fan_mode
127 
128  def turn_on(
129  self,
130  percentage: int | None = None,
131  preset_mode: str | None = None,
132  **kwargs: Any,
133  ) -> None:
134  """Turn the fan on."""
135  self._set_percentage_set_percentage(percentage)
136 
137  def turn_off(self, **kwargs: Any) -> None:
138  """Turn the switch off."""
139  with self._wemo_call_wrapper_wemo_call_wrapper("turn off"):
140  self.wemowemowemo.set_state(FanMode.Off)
141 
142  def set_percentage(self, percentage: int) -> None:
143  """Set the fan_mode of the Humidifier."""
144  self._set_percentage_set_percentage(percentage)
145 
146  def _set_percentage(self, percentage: int | None) -> None:
147  if percentage is None:
148  named_speed = self._last_fan_on_mode_last_fan_on_mode
149  elif percentage == 0:
150  named_speed = FanMode.Off
151  else:
152  named_speed = FanMode(
153  math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage))
154  )
155 
156  with self._wemo_call_wrapper_wemo_call_wrapper("set speed"):
157  self.wemowemowemo.set_state(named_speed)
158 
159  def set_humidity(self, target_humidity: float) -> None:
160  """Set the target humidity level for the Humidifier."""
161  if target_humidity < 50:
162  pywemo_humidity = DesiredHumidity.FortyFivePercent
163  elif 50 <= target_humidity < 55:
164  pywemo_humidity = DesiredHumidity.FiftyPercent
165  elif 55 <= target_humidity < 60:
166  pywemo_humidity = DesiredHumidity.FiftyFivePercent
167  elif 60 <= target_humidity < 100:
168  pywemo_humidity = DesiredHumidity.SixtyPercent
169  elif target_humidity >= 100:
170  pywemo_humidity = DesiredHumidity.OneHundredPercent
171 
172  with self._wemo_call_wrapper_wemo_call_wrapper("set humidity"):
173  self.wemowemowemo.set_humidity(pywemo_humidity)
174 
175  def reset_filter_life(self) -> None:
176  """Reset the filter life to 100%."""
177  with self._wemo_call_wrapper_wemo_call_wrapper("reset filter life"):
178  self.wemowemowemo.reset_filter_life()
Generator[None] _wemo_call_wrapper(self, str message)
Definition: entity.py:68
None __init__(self, DeviceCoordinator coordinator)
Definition: fan.py:86
None set_percentage(self, int percentage)
Definition: fan.py:142
None turn_off(self, **Any kwargs)
Definition: fan.py:137
None turn_on(self, int|None percentage=None, str|None preset_mode=None, **Any kwargs)
Definition: fan.py:133
None set_humidity(self, float target_humidity)
Definition: fan.py:159
dict[str, Any] extra_state_attributes(self)
Definition: fan.py:100
None _set_percentage(self, int|None percentage)
Definition: fan.py:146
None async_setup_entry(HomeAssistant hass, ConfigEntry _config_entry, AddEntitiesCallback async_add_entities)
Definition: fan.py:52
None async_wemo_dispatcher_connect(HomeAssistant hass, DispatchCallback dispatch)
Definition: __init__.py:159
float percentage_to_ranged_value(tuple[float, float] low_high_range, float percentage)
Definition: percentage.py:81
int ranged_value_to_percentage(tuple[float, float] low_high_range, float value)
Definition: percentage.py:64
int int_states_in_range(tuple[float, float] low_high_range)
Definition: scaling.py:61