Map bond fan speeds to standard HA speeds (#37808)

This commit is contained in:
Eugene Prystupa 2020-07-13 19:00:05 -04:00 committed by GitHub
parent 9e8e5c37f4
commit 95e72b4c4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 20 deletions

View File

@ -1,4 +1,5 @@
"""Support for Bond fans."""
import math
from typing import Any, Callable, List, Optional
from bond import DeviceTypes, Directions
@ -67,12 +68,15 @@ class BondFan(BondEntity, FanEntity):
@property
def speed(self) -> Optional[str]:
"""Return the current speed."""
if self._power is None:
return None
if self._power == 0:
return SPEED_OFF
if not self._power or not self._speed:
return None
return self.speed_list[self._speed] if self._speed is not None else None
# map 1..max_speed Bond speed to 1..3 HA speed
max_speed = self._device.props.get("max_speed", 3)
ha_speed = math.ceil(self._speed * (len(self.speed_list) - 1) / max_speed)
return self.speed_list[ha_speed]
@property
def speed_list(self) -> list:
@ -99,8 +103,14 @@ class BondFan(BondEntity, FanEntity):
def set_speed(self, speed: str) -> None:
"""Set the desired speed for the fan."""
speed_index = self.speed_list.index(speed)
self._hub.bond.setSpeed(self._device.device_id, speed=speed_index)
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)
self._hub.bond.setSpeed(self._device.device_id, speed=bond_speed)
def turn_on(self, speed: Optional[str] = None, **kwargs) -> None:
"""Turn on the fan."""

View File

@ -8,9 +8,10 @@ from bond import Actions, Bond
class BondDevice:
"""Helper device class to hold ID and attributes together."""
def __init__(self, device_id: str, attrs: dict):
def __init__(self, device_id: str, attrs: dict, props: dict):
"""Create a helper device from ID and attributes returned by API."""
self.device_id = device_id
self.props = props
self._attrs = attrs
@property
@ -67,7 +68,11 @@ class BondHub:
"""Fetch all available devices using Bond API."""
device_ids = self.bond.getDeviceIds()
devices = [
BondDevice(device_id, self.bond.getDevice(device_id))
BondDevice(
device_id,
self.bond.getDevice(device_id),
self.bond.getProperties(device_id),
)
for device_id in device_ids
]
return devices

View File

@ -28,9 +28,16 @@ async def setup_bond_entity(
async def setup_platform(
hass: core.HomeAssistant, platform: str, discovered_device: Dict[str, Any]
hass: core.HomeAssistant,
platform: str,
discovered_device: Dict[str, Any],
bond_device_id: str = "bond-device-id",
props: Dict[str, Any] = None,
):
"""Set up the specified Bond platform."""
if not props:
props = {}
mock_entry = MockConfigEntry(
domain=BOND_DOMAIN,
data={CONF_HOST: "1.1.1.1", CONF_ACCESS_TOKEN: "test-token"},
@ -41,11 +48,13 @@ async def setup_platform(
"homeassistant.components.bond.Bond.getVersion", return_value=MOCK_HUB_VERSION
), patch(
"homeassistant.components.bond.Bond.getDeviceIds",
return_value=["bond-device-id"],
return_value=[bond_device_id],
), patch(
"homeassistant.components.bond.Bond.getDevice", return_value=discovered_device
), patch(
"homeassistant.components.bond.Bond.getDeviceState", return_value={}
), patch(
"homeassistant.components.bond.Bond.getProperties", return_value=props
):
assert await async_setup_component(hass, BOND_DOMAIN, {})
await hass.async_block_till_done()

View File

@ -7,6 +7,7 @@ from homeassistant import core
from homeassistant.components import fan
from homeassistant.components.fan import (
ATTR_DIRECTION,
ATTR_SPEED_LIST,
DIRECTION_FORWARD,
DIRECTION_REVERSE,
DOMAIN as FAN_DOMAIN,
@ -16,10 +17,10 @@ from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_O
from homeassistant.helpers.entity_registry import EntityRegistry
from homeassistant.util import utcnow
from ...common import async_fire_time_changed
from .common import setup_platform
from tests.async_mock import patch
from tests.common import async_fire_time_changed
def ceiling_fan(name: str):
@ -31,6 +32,17 @@ def ceiling_fan(name: str):
}
async def turn_fan_on(hass: core.HomeAssistant, fan_id: str, speed: str) -> None:
"""Turn the fan on at the specified speed."""
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: fan_id, fan.ATTR_SPEED: speed},
blocking=True,
)
await hass.async_block_till_done()
async def test_entity_registry(hass: core.HomeAssistant):
"""Tests that the devices are registered in the entity registry."""
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
@ -39,6 +51,43 @@ async def test_entity_registry(hass: core.HomeAssistant):
assert [key for key in registry.entities] == ["fan.name_1"]
async def test_entity_non_standard_speed_list(hass: core.HomeAssistant):
"""Tests that the device is registered with custom speed list if number of supported speeds differs form 3."""
await setup_platform(
hass,
FAN_DOMAIN,
ceiling_fan("name-1"),
bond_device_id="test-device-id",
props={"max_speed": 6},
)
actual_speeds = hass.states.get("fan.name_1").attributes[ATTR_SPEED_LIST]
assert actual_speeds == [
fan.SPEED_OFF,
fan.SPEED_LOW,
fan.SPEED_MEDIUM,
fan.SPEED_HIGH,
]
with patch("homeassistant.components.bond.Bond.turnOn"), patch(
"homeassistant.components.bond.Bond.setSpeed"
) 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", speed=1)
with patch("homeassistant.components.bond.Bond.turnOn"), patch(
"homeassistant.components.bond.Bond.setSpeed"
) 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", speed=3)
with patch("homeassistant.components.bond.Bond.turnOn"), patch(
"homeassistant.components.bond.Bond.setSpeed"
) as mock_set_speed_high:
await turn_fan_on(hass, "fan.name_1", fan.SPEED_HIGH)
mock_set_speed_high.assert_called_once_with("test-device-id", speed=6)
async def test_turn_on_fan(hass: core.HomeAssistant):
"""Tests that turn on command delegates to API."""
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
@ -46,16 +95,10 @@ async def test_turn_on_fan(hass: core.HomeAssistant):
with patch("homeassistant.components.bond.Bond.turnOn") as mock_turn_on, patch(
"homeassistant.components.bond.Bond.setSpeed"
) as mock_set_speed:
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.name_1", fan.ATTR_SPEED: fan.SPEED_LOW},
blocking=True,
)
await hass.async_block_till_done()
await turn_fan_on(hass, "fan.name_1", fan.SPEED_LOW)
mock_set_speed.assert_called_once()
mock_turn_on.assert_called_once()
mock_set_speed.assert_called_once()
mock_turn_on.assert_called_once()
async def test_turn_off_fan(hass: core.HomeAssistant):
@ -67,7 +110,8 @@ async def test_turn_off_fan(hass: core.HomeAssistant):
FAN_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: "fan.name_1"}, blocking=True,
)
await hass.async_block_till_done()
mock_turn_off.assert_called_once()
mock_turn_off.assert_called_once()
async def test_update_reports_fan_on(hass: core.HomeAssistant):