1 """Support for ESPHome fans."""
3 from __future__
import annotations
5 from functools
import partial
9 from aioesphomeapi
import EntityInfo, FanDirection, FanInfo, FanSpeed, FanState
19 ordered_list_item_to_percentage,
20 percentage_to_ordered_list_item,
21 percentage_to_ranged_value,
22 ranged_value_to_percentage,
27 convert_api_error_ha_error,
28 esphome_state_property,
29 platform_async_setup_entry,
31 from .enum_mapper
import EsphomeEnumMapper
33 ORDERED_NAMED_FAN_SPEEDS = [FanSpeed.LOW, FanSpeed.MEDIUM, FanSpeed.HIGH]
38 FanDirection.FORWARD: DIRECTION_FORWARD,
39 FanDirection.REVERSE: DIRECTION_REVERSE,
45 """A fan implementation for ESPHome."""
47 _supports_speed_levels: bool =
True
48 _enable_turn_on_off_backwards_compatibility =
False
51 """Set the speed percentage of the fan."""
54 @convert_api_error_ha_error
60 data: dict[str, Any] = {
"key": self.
_key_key,
"state":
True}
61 if percentage
is not None:
63 data[
"speed_level"] = math.ceil(
65 (1, self.
_static_info_static_info.supported_speed_levels), percentage
69 named_speed = percentage_to_ordered_list_item(
70 ORDERED_NAMED_FAN_SPEEDS, percentage
72 data[
"speed"] = named_speed
73 self.
_client_client.fan_command(**data)
77 percentage: int |
None =
None,
78 preset_mode: str |
None =
None,
81 """Turn on the fan."""
84 @convert_api_error_ha_error
86 """Turn off the fan."""
87 self.
_client_client.fan_command(key=self.
_key_key, state=
False)
89 @convert_api_error_ha_error
91 """Oscillate the fan."""
92 self.
_client_client.fan_command(key=self.
_key_key, oscillating=oscillating)
94 @convert_api_error_ha_error
96 """Set direction of the fan."""
97 self.
_client_client.fan_command(
98 key=self.
_key_key, direction=_FAN_DIRECTIONS.from_hass(direction)
101 @convert_api_error_ha_error
103 """Set the preset mode of the fan."""
104 self.
_client_client.fan_command(key=self.
_key_key, preset_mode=preset_mode)
107 @esphome_state_property
109 """Return true if the entity is on."""
110 return self.
_state_state.state
113 @esphome_state_property
115 """Return the current speed percentage."""
117 return ordered_list_item_to_percentage(
118 ORDERED_NAMED_FAN_SPEEDS,
123 (1, self.
_static_info_static_info.supported_speed_levels), self.
_state_state.speed_level
127 @esphome_state_property
129 """Return the oscillation state."""
130 return self.
_state_state.oscillating
133 @esphome_state_property
135 """Return the current fan direction."""
136 return _FAN_DIRECTIONS.from_esphome(self.
_state_state.direction)
139 @esphome_state_property
141 """Return the current fan preset mode."""
142 return self.
_state_state.preset_mode
146 """Set attrs from static info."""
150 supports_speed_levels = api_version.major == 1
and api_version.minor > 3
152 flags = FanEntityFeature.TURN_OFF | FanEntityFeature.TURN_ON
153 if static_info.supports_oscillation:
154 flags |= FanEntityFeature.OSCILLATE
155 if static_info.supports_speed:
156 flags |= FanEntityFeature.SET_SPEED
157 if static_info.supports_direction:
158 flags |= FanEntityFeature.DIRECTION
159 if static_info.supported_preset_modes:
160 flags |= FanEntityFeature.PRESET_MODE
163 if not supports_speed_levels:
169 async_setup_entry = partial(
170 platform_async_setup_entry,
172 entity_type=EsphomeFan,
int|None percentage(self)
bool|None oscillating(self)
None async_set_percentage(self, int percentage)
None async_oscillate(self, bool oscillating)
None _async_set_percentage(self, int|None percentage)
None async_set_direction(self, str direction)
str|None current_direction(self)
None _on_static_info_update(self, EntityInfo static_info)
None async_set_preset_mode(self, str preset_mode)
None async_turn_on(self, int|None percentage=None, str|None preset_mode=None, **Any kwargs)
None async_turn_off(self, **Any kwargs)
str|None preset_mode(self)
None async_turn_off(self, **Any kwargs)
float percentage_to_ranged_value(tuple[float, float] low_high_range, float percentage)
int ranged_value_to_percentage(tuple[float, float] low_high_range, float value)