Update bond to use new fan entity model (#45534)

This commit is contained in:
J. Nick Koston 2021-01-28 03:23:12 -06:00 committed by GitHub
parent 0693d8a064
commit 85e463d507
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 45 deletions

View file

@ -1,17 +1,13 @@
"""Support for Bond fans."""
import logging
import math
from typing import Any, Callable, List, Optional
from typing import Any, Callable, List, Optional, Tuple
from bond_api import Action, DeviceType, Direction
from homeassistant.components.fan import (
DIRECTION_FORWARD,
DIRECTION_REVERSE,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_DIRECTION,
SUPPORT_SET_SPEED,
FanEntity,
@ -19,6 +15,10 @@ from homeassistant.components.fan import (
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
from homeassistant.util.percentage import (
percentage_to_ranged_value,
ranged_value_to_percentage,
)
from .const import DOMAIN
from .entity import BondEntity
@ -70,22 +70,16 @@ class BondFan(BondEntity, FanEntity):
return features
@property
def speed(self) -> Optional[str]:
"""Return the current speed."""
if self._power == 0:
return SPEED_OFF
if not self._power or not self._speed:
return None
# map 1..max_speed Bond speed to 1..3 HA speed
max_speed = max(self._device.props.get("max_speed", 3), self._speed)
ha_speed = math.ceil(self._speed * (len(self.speed_list) - 1) / max_speed)
return self.speed_list[ha_speed]
def _speed_range(self) -> Tuple[int, int]:
"""Return the range of speeds."""
return (1, self._device.props.get("max_speed", 3))
@property
def speed_list(self) -> list:
"""Get the list of available speeds."""
return [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
def percentage(self) -> Optional[str]:
"""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 current_direction(self) -> Optional[str]:
@ -98,33 +92,27 @@ class BondFan(BondEntity, FanEntity):
return direction
async def async_set_speed(self, speed: str) -> None:
async def async_set_percentage(self, percentage: int) -> None:
"""Set the desired speed for the fan."""
_LOGGER.debug("async_set_speed called with speed %s", speed)
_LOGGER.debug("async_set_percentage called with percentage %s", percentage)
if speed == SPEED_OFF:
if percentage == 0:
await self.async_turn_off()
return
max_speed = self._device.props.get("max_speed", 3)
if speed == SPEED_LOW:
bond_speed = 1
elif speed == SPEED_HIGH:
bond_speed = max_speed
else:
bond_speed = math.ceil(max_speed / 2)
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)
)
#
# The fan entity model has changed to use percentages and preset_modes
# instead of speeds.
#
# Please review
# https://developers.home-assistant.io/docs/core/entity/fan/
#
async def async_turn_on(
self,
speed: Optional[str] = None,
@ -133,13 +121,10 @@ class BondFan(BondEntity, FanEntity):
**kwargs,
) -> None:
"""Turn on the fan."""
_LOGGER.debug("Fan async_turn_on called with speed %s", speed)
_LOGGER.debug("Fan async_turn_on called with percentage %s", percentage)
if speed is not None:
if speed == SPEED_OFF:
await self.async_turn_off()
else:
await self.async_set_speed(speed)
if percentage is not None:
await self.async_set_percentage(percentage)
else:
await self._hub.bond.action(self._device.device_id, Action.turn_on())

View file

@ -41,12 +41,17 @@ def ceiling_fan(name: str):
async def turn_fan_on(
hass: core.HomeAssistant, fan_id: str, speed: Optional[str] = None
hass: core.HomeAssistant,
fan_id: str,
speed: Optional[str] = None,
percentage: Optional[int] = None,
) -> None:
"""Turn the fan on at the specified speed."""
service_data = {ATTR_ENTITY_ID: fan_id}
if speed:
service_data[fan.ATTR_SPEED] = speed
if percentage:
service_data[fan.ATTR_PERCENTAGE] = percentage
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_TURN_ON,
@ -93,13 +98,13 @@ async def test_non_standard_speed_list(hass: core.HomeAssistant):
with patch_bond_action() as mock_set_speed_low:
await turn_fan_on(hass, "fan.name_1", fan.SPEED_LOW)
mock_set_speed_low.assert_called_once_with(
"test-device-id", Action.set_speed(1)
"test-device-id", Action.set_speed(2)
)
with patch_bond_action() as mock_set_speed_medium:
await turn_fan_on(hass, "fan.name_1", fan.SPEED_MEDIUM)
mock_set_speed_medium.assert_called_once_with(
"test-device-id", Action.set_speed(3)
"test-device-id", Action.set_speed(4)
)
with patch_bond_action() as mock_set_speed_high:
@ -135,6 +140,58 @@ async def test_turn_on_fan_with_speed(hass: core.HomeAssistant):
mock_set_speed.assert_called_with("test-device-id", Action.set_speed(1))
async def test_turn_on_fan_with_percentage_3_speeds(hass: core.HomeAssistant):
"""Tests that turn on command delegates to set speed API."""
await setup_platform(
hass, FAN_DOMAIN, ceiling_fan("name-1"), bond_device_id="test-device-id"
)
with patch_bond_action() as mock_set_speed, patch_bond_device_state():
await turn_fan_on(hass, "fan.name_1", percentage=10)
mock_set_speed.assert_called_with("test-device-id", Action.set_speed(1))
mock_set_speed.reset_mock()
with patch_bond_action() as mock_set_speed, patch_bond_device_state():
await turn_fan_on(hass, "fan.name_1", percentage=50)
mock_set_speed.assert_called_with("test-device-id", Action.set_speed(2))
mock_set_speed.reset_mock()
with patch_bond_action() as mock_set_speed, patch_bond_device_state():
await turn_fan_on(hass, "fan.name_1", percentage=100)
mock_set_speed.assert_called_with("test-device-id", Action.set_speed(3))
async def test_turn_on_fan_with_percentage_6_speeds(hass: core.HomeAssistant):
"""Tests that turn on command delegates to set speed API."""
await setup_platform(
hass,
FAN_DOMAIN,
ceiling_fan("name-1"),
bond_device_id="test-device-id",
props={"max_speed": 6},
)
with patch_bond_action() as mock_set_speed, patch_bond_device_state():
await turn_fan_on(hass, "fan.name_1", percentage=10)
mock_set_speed.assert_called_with("test-device-id", Action.set_speed(1))
mock_set_speed.reset_mock()
with patch_bond_action() as mock_set_speed, patch_bond_device_state():
await turn_fan_on(hass, "fan.name_1", percentage=50)
mock_set_speed.assert_called_with("test-device-id", Action.set_speed(3))
mock_set_speed.reset_mock()
with patch_bond_action() as mock_set_speed, patch_bond_device_state():
await turn_fan_on(hass, "fan.name_1", percentage=100)
mock_set_speed.assert_called_with("test-device-id", Action.set_speed(6))
async def test_turn_on_fan_without_speed(hass: core.HomeAssistant):
"""Tests that turn on command delegates to turn on API."""
await setup_platform(