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.""" """Support for Bond fans."""
import logging import logging
import math 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 bond_api import Action, DeviceType, Direction
from homeassistant.components.fan import ( from homeassistant.components.fan import (
DIRECTION_FORWARD, DIRECTION_FORWARD,
DIRECTION_REVERSE, DIRECTION_REVERSE,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_DIRECTION, SUPPORT_DIRECTION,
SUPPORT_SET_SPEED, SUPPORT_SET_SPEED,
FanEntity, FanEntity,
@ -19,6 +15,10 @@ from homeassistant.components.fan import (
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.util.percentage import (
percentage_to_ranged_value,
ranged_value_to_percentage,
)
from .const import DOMAIN from .const import DOMAIN
from .entity import BondEntity from .entity import BondEntity
@ -70,22 +70,16 @@ class BondFan(BondEntity, FanEntity):
return features return features
@property @property
def speed(self) -> Optional[str]: def _speed_range(self) -> Tuple[int, int]:
"""Return the current speed.""" """Return the range of speeds."""
if self._power == 0: return (1, self._device.props.get("max_speed", 3))
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]
@property @property
def speed_list(self) -> list: def percentage(self) -> Optional[str]:
"""Get the list of available speeds.""" """Return the current speed percentage for the fan."""
return [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] if not self._speed or not self._power:
return 0
return ranged_value_to_percentage(self._speed_range, self._speed)
@property @property
def current_direction(self) -> Optional[str]: def current_direction(self) -> Optional[str]:
@ -98,33 +92,27 @@ class BondFan(BondEntity, FanEntity):
return direction 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.""" """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() await self.async_turn_off()
return return
max_speed = self._device.props.get("max_speed", 3) bond_speed = math.ceil(
if speed == SPEED_LOW: percentage_to_ranged_value(self._speed_range, percentage)
bond_speed = 1 )
elif speed == SPEED_HIGH: _LOGGER.debug(
bond_speed = max_speed "async_set_percentage converted percentage %s to bond speed %s",
else: percentage,
bond_speed = math.ceil(max_speed / 2) bond_speed,
)
await self._hub.bond.action( await self._hub.bond.action(
self._device.device_id, Action.set_speed(bond_speed) 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( async def async_turn_on(
self, self,
speed: Optional[str] = None, speed: Optional[str] = None,
@ -133,13 +121,10 @@ class BondFan(BondEntity, FanEntity):
**kwargs, **kwargs,
) -> None: ) -> None:
"""Turn on the fan.""" """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 percentage is not None:
if speed == SPEED_OFF: await self.async_set_percentage(percentage)
await self.async_turn_off()
else:
await self.async_set_speed(speed)
else: else:
await self._hub.bond.action(self._device.device_id, Action.turn_on()) 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( 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: ) -> None:
"""Turn the fan on at the specified speed.""" """Turn the fan on at the specified speed."""
service_data = {ATTR_ENTITY_ID: fan_id} service_data = {ATTR_ENTITY_ID: fan_id}
if speed: if speed:
service_data[fan.ATTR_SPEED] = speed service_data[fan.ATTR_SPEED] = speed
if percentage:
service_data[fan.ATTR_PERCENTAGE] = percentage
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_TURN_ON, 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: with patch_bond_action() as mock_set_speed_low:
await turn_fan_on(hass, "fan.name_1", fan.SPEED_LOW) await turn_fan_on(hass, "fan.name_1", fan.SPEED_LOW)
mock_set_speed_low.assert_called_once_with( 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: with patch_bond_action() as mock_set_speed_medium:
await turn_fan_on(hass, "fan.name_1", fan.SPEED_MEDIUM) await turn_fan_on(hass, "fan.name_1", fan.SPEED_MEDIUM)
mock_set_speed_medium.assert_called_once_with( 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: 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)) 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): async def test_turn_on_fan_without_speed(hass: core.HomeAssistant):
"""Tests that turn on command delegates to turn on API.""" """Tests that turn on command delegates to turn on API."""
await setup_platform( await setup_platform(