1 """Support for Tuya Fan."""
3 from __future__
import annotations
7 from tuya_sharing
import CustomerDevice, Manager
19 ordered_list_item_to_percentage,
20 percentage_to_ordered_list_item,
23 from .
import TuyaConfigEntry
24 from .const
import TUYA_DISCOVERY_NEW, DPCode, DPType
25 from .entity
import EnumTypeData, IntegerTypeData, TuyaEntity
37 hass: HomeAssistant, entry: TuyaConfigEntry, async_add_entities: AddEntitiesCallback
39 """Set up tuya fan dynamically through tuya discovery."""
40 hass_data = entry.runtime_data
44 """Discover and add a discovered tuya fan."""
45 entities: list[TuyaFanEntity] = []
46 for device_id
in device_ids:
47 device = hass_data.manager.device_map[device_id]
48 if device
and device.category
in TUYA_SUPPORT_TYPE:
54 entry.async_on_unload(
60 """Tuya Fan Device."""
62 _direction: EnumTypeData |
None =
None
63 _oscillate: DPCode |
None =
None
64 _presets: EnumTypeData |
None =
None
65 _speed: IntegerTypeData |
None =
None
66 _speeds: EnumTypeData |
None =
None
67 _switch: DPCode |
None =
None
69 _enable_turn_on_off_backwards_compatibility =
False
73 device: CustomerDevice,
74 device_manager: Manager,
76 """Init Tuya Fan Device."""
77 super().
__init__(device, device_manager)
80 (DPCode.SWITCH_FAN, DPCode.FAN_SWITCH, DPCode.SWITCH), prefer_function=
True
85 (DPCode.FAN_MODE, DPCode.MODE), dptype=DPType.ENUM, prefer_function=
True
88 self._attr_supported_features |= FanEntityFeature.PRESET_MODE
93 DPCode.FAN_SPEED_PERCENT,
96 DPCode.FAN_SPEED_ENUM,
99 dpcodes, dptype=DPType.INTEGER, prefer_function=
True
101 self._attr_supported_features |= FanEntityFeature.SET_SPEED
104 dpcodes, dptype=DPType.ENUM, prefer_function=
True
106 self._attr_supported_features |= FanEntityFeature.SET_SPEED
110 (DPCode.SWITCH_HORIZONTAL, DPCode.SWITCH_VERTICAL), prefer_function=
True
113 self._attr_supported_features |= FanEntityFeature.OSCILLATE
116 DPCode.FAN_DIRECTION, dptype=DPType.ENUM, prefer_function=
True
119 self._attr_supported_features |= FanEntityFeature.DIRECTION
120 if self.
_switch_switch
is not None:
121 self._attr_supported_features |= (
122 FanEntityFeature.TURN_ON | FanEntityFeature.TURN_OFF
126 """Set the preset mode of the fan."""
132 """Set the direction of the fan."""
138 """Set the speed of the fan, as a percentage."""
139 if self.
_speed_speed
is not None:
143 "code": self.
_speed_speed.dpcode,
144 "value":
int(self.
_speed_speed.remap_value_from(percentage, 1, 100)),
150 if self.
_speeds_speeds
is not None:
154 "code": self.
_speeds_speeds.dpcode,
155 "value": percentage_to_ordered_list_item(
156 self.
_speeds_speeds.range, percentage
163 """Turn the fan off."""
168 percentage: int |
None =
None,
169 preset_mode: str |
None =
None,
172 """Turn on the fan."""
173 if self.
_switch_switch
is None:
176 commands: list[dict[str, str | bool | int]] = [
177 {
"code": self.
_switch_switch,
"value":
True}
180 if percentage
is not None and self.
_speed_speed
is not None:
183 "code": self.
_speed_speed.dpcode,
184 "value":
int(self.
_speed_speed.remap_value_from(percentage, 1, 100)),
188 if percentage
is not None and self.
_speeds_speeds
is not None:
191 "code": self.
_speeds_speeds.dpcode,
192 "value": percentage_to_ordered_list_item(
193 self.
_speeds_speeds.range, percentage
198 if preset_mode
is not None and self.
_presets_presets
is not None:
199 commands.append({
"code": self.
_presets_presets.dpcode,
"value": preset_mode})
204 """Oscillate the fan."""
211 """Return true if fan is on."""
212 if self.
_switch_switch
is None:
218 """Return the current direction of the fan."""
221 or (value := self.
devicedevice.status.get(self.
_direction_direction.dpcode))
is None
225 if value.lower() == DIRECTION_FORWARD:
226 return DIRECTION_FORWARD
228 if value.lower() == DIRECTION_REVERSE:
229 return DIRECTION_REVERSE
235 """Return true if the fan is oscillating."""
242 """Return the current preset_mode."""
249 """Return the current speed."""
250 if self.
_speed_speed
is not None:
251 if (value := self.
devicedevice.status.get(self.
_speed_speed.dpcode))
is None:
253 return int(self.
_speed_speed.remap_value_to(value, 1, 100))
255 if self.
_speeds_speeds
is not None:
256 if (value := self.
devicedevice.status.get(self.
_speeds_speeds.dpcode))
is None:
258 return ordered_list_item_to_percentage(self.
_speeds_speeds.range, value)
264 """Return the number of speeds the fan supports."""
265 if self.
_speeds_speeds
is not None:
266 return len(self.
_speeds_speeds.range)
None _send_command(self, list[dict[str, Any]] commands)
DPCode|EnumTypeData|IntegerTypeData|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False, DPType|None dptype=None)
IntegerTypeData|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False, Literal[DPType.INTEGER] dptype)
DPCode|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False)
EnumTypeData|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False, Literal[DPType.ENUM] dptype)
bool|None oscillating(self)
None set_preset_mode(self, str preset_mode)
None oscillate(self, bool oscillating)
None turn_off(self, **Any kwargs)
str|None preset_mode(self)
None __init__(self, CustomerDevice device, Manager device_manager)
None set_percentage(self, int percentage)
int|None percentage(self)
None set_direction(self, str direction)
None turn_on(self, int|None percentage=None, str|None preset_mode=None, **Any kwargs)
str|None current_direction(self)
ElkSystem|None async_discover_device(HomeAssistant hass, str host)
None async_setup_entry(HomeAssistant hass, TuyaConfigEntry entry, AddEntitiesCallback async_add_entities)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)