core/homeassistant/components/bond/fan.py

158 lines
4.7 KiB
Python
Raw Normal View History

"""Support for Bond fans."""
2021-03-17 22:34:25 +00:00
from __future__ import annotations
import logging
import math
from typing import Any
from bond_api import Action, BPUPSubscriptions, DeviceType, Direction
from homeassistant.components.fan import (
DIRECTION_FORWARD,
DIRECTION_REVERSE,
SUPPORT_DIRECTION,
SUPPORT_SET_SPEED,
FanEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
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 BPUP_SUBS, DOMAIN, HUB
from .entity import BondEntity
from .utils import BondDevice, BondHub
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Bond fan devices."""
data = hass.data[DOMAIN][entry.entry_id]
hub: BondHub = data[HUB]
bpup_subs: BPUPSubscriptions = data[BPUP_SUBS]
2021-03-17 22:34:25 +00:00
fans: list[Entity] = [
BondFan(hub, device, bpup_subs)
for device in hub.devices
if DeviceType.is_fan(device.type)
]
async_add_entities(fans, True)
class BondFan(BondEntity, FanEntity):
"""Representation of a Bond fan."""
def __init__(
self, hub: BondHub, device: BondDevice, bpup_subs: BPUPSubscriptions
) -> None:
"""Create HA entity representing Bond fan."""
super().__init__(hub, device, bpup_subs)
2021-03-17 22:34:25 +00:00
self._power: bool | None = None
self._speed: int | None = None
self._direction: int | None = None
def _apply_state(self, state: dict) -> None:
self._power = state.get("power")
self._speed = state.get("speed")
self._direction = state.get("direction")
@property
def supported_features(self) -> int:
"""Flag supported features."""
features = 0
if self._device.supports_speed():
features |= SUPPORT_SET_SPEED
if self._device.supports_direction():
features |= SUPPORT_DIRECTION
return features
@property
2021-03-17 22:34:25 +00:00
def _speed_range(self) -> tuple[int, int]:
"""Return the range of speeds."""
return (1, self._device.props.get("max_speed", 3))
@property
def percentage(self) -> int:
"""Return the current speed percentage for the fan."""
if not self._speed or not self._power:
return 0
return ranged_value_to_percentage(self._speed_range, self._speed)
@property
def speed_count(self) -> int:
"""Return the number of speeds the fan supports."""
return int_states_in_range(self._speed_range)
@property
2021-03-17 22:34:25 +00:00
def current_direction(self) -> str | None:
"""Return fan rotation direction."""
direction = None
if self._direction == Direction.FORWARD:
direction = DIRECTION_FORWARD
elif self._direction == Direction.REVERSE:
direction = DIRECTION_REVERSE
return direction
async def async_set_percentage(self, percentage: int) -> None:
"""Set the desired speed for the fan."""
_LOGGER.debug("async_set_percentage called with percentage %s", percentage)
if percentage == 0:
await self.async_turn_off()
return
bond_speed = math.ceil(
percentage_to_ranged_value(self._speed_range, percentage)
)
_LOGGER.debug(
"async_set_percentage converted percentage %s to bond speed %s",
percentage,
bond_speed,
)
await self._hub.bond.action(
self._device.device_id, Action.set_speed(bond_speed)
)
async def async_turn_on(
self,
2021-03-17 22:34:25 +00:00
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs: Any,
) -> None:
"""Turn on the fan."""
_LOGGER.debug("Fan async_turn_on called with percentage %s", percentage)
if percentage is not None:
await self.async_set_percentage(percentage)
else:
await self._hub.bond.action(self._device.device_id, Action.turn_on())
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the fan off."""
await self._hub.bond.action(self._device.device_id, Action.turn_off())
async def async_set_direction(self, direction: str) -> None:
"""Set fan rotation direction."""
bond_direction = (
Direction.REVERSE if direction == DIRECTION_REVERSE else Direction.FORWARD
)
await self._hub.bond.action(
self._device.device_id, Action.set_direction(bond_direction)
)