core/homeassistant/components/wiz/fan.py

140 lines
4.8 KiB
Python

"""WiZ integration fan platform."""
from __future__ import annotations
import math
from typing import Any, ClassVar
from pywizlight.bulblibrary import BulbType, Features
from homeassistant.components.fan import (
DIRECTION_FORWARD,
DIRECTION_REVERSE,
FanEntity,
FanEntityFeature,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util.percentage import (
percentage_to_ranged_value,
ranged_value_to_percentage,
)
from . import WizConfigEntry
from .entity import WizEntity
from .models import WizData
PRESET_MODE_BREEZE = "breeze"
async def async_setup_entry(
hass: HomeAssistant,
entry: WizConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the WiZ Platform from config_flow."""
if entry.runtime_data.bulb.bulbtype.features.fan:
async_add_entities([WizFanEntity(entry.runtime_data, entry.title)])
class WizFanEntity(WizEntity, FanEntity):
"""Representation of WiZ Light bulb."""
_attr_name = None
# We want the implementation of is_on to be the same as in ToggleEntity,
# but it is being overridden in FanEntity, so we need to restore it here.
is_on: ClassVar = ToggleEntity.is_on
def __init__(self, wiz_data: WizData, name: str) -> None:
"""Initialize a WiZ fan."""
super().__init__(wiz_data, name)
bulb_type: BulbType = self._device.bulbtype
features: Features = bulb_type.features
supported_features = (
FanEntityFeature.TURN_ON
| FanEntityFeature.TURN_OFF
| FanEntityFeature.SET_SPEED
)
if features.fan_reverse:
supported_features |= FanEntityFeature.DIRECTION
if features.fan_breeze_mode:
supported_features |= FanEntityFeature.PRESET_MODE
self._attr_preset_modes = [PRESET_MODE_BREEZE]
self._attr_supported_features = supported_features
self._attr_speed_count = bulb_type.fan_speed_range
self._async_update_attrs()
@callback
def _async_update_attrs(self) -> None:
"""Handle updating _attr values."""
state = self._device.state
self._attr_is_on = state.get_fan_state() > 0
self._attr_percentage = ranged_value_to_percentage(
(1, self.speed_count), state.get_fan_speed()
)
if FanEntityFeature.PRESET_MODE in self.supported_features:
fan_mode = state.get_fan_mode()
self._attr_preset_mode = PRESET_MODE_BREEZE if fan_mode == 2 else None
if FanEntityFeature.DIRECTION in self.supported_features:
fan_reverse = state.get_fan_reverse()
self._attr_current_direction = None
if fan_reverse == 0:
self._attr_current_direction = DIRECTION_FORWARD
elif fan_reverse == 1:
self._attr_current_direction = DIRECTION_REVERSE
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set the preset mode of the fan."""
# preset_mode == PRESET_MODE_BREEZE
await self._device.fan_set_state(mode=2)
await self.coordinator.async_request_refresh()
async def async_set_percentage(self, percentage: int) -> None:
"""Set the speed percentage of the fan."""
if percentage == 0:
await self.async_turn_off()
return
speed = math.ceil(percentage_to_ranged_value((1, self.speed_count), percentage))
await self._device.fan_set_state(mode=1, speed=speed)
await self.coordinator.async_request_refresh()
async def async_turn_on(
self,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs: Any,
) -> None:
"""Turn on the fan."""
mode: int | None = None
speed: int | None = None
if preset_mode is not None:
self._valid_preset_mode_or_raise(preset_mode)
if preset_mode == PRESET_MODE_BREEZE:
mode = 2
if percentage is not None:
speed = math.ceil(
percentage_to_ranged_value((1, self.speed_count), percentage)
)
if mode is None:
mode = 1
await self._device.fan_turn_on(mode=mode, speed=speed)
await self.coordinator.async_request_refresh()
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the fan."""
await self._device.fan_turn_off(**kwargs)
await self.coordinator.async_request_refresh()
async def async_set_direction(self, direction: str) -> None:
"""Set the direction of the fan."""
reverse = 1 if direction == DIRECTION_REVERSE else 0
await self._device.fan_set_state(reverse=reverse)
await self.coordinator.async_request_refresh()