mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Map bond fan speeds to standard HA speeds (#37808)
This commit is contained in:
parent
9e8e5c37f4
commit
95e72b4c4b
@ -1,4 +1,5 @@
|
|||||||
"""Support for Bond fans."""
|
"""Support for Bond fans."""
|
||||||
|
import math
|
||||||
from typing import Any, Callable, List, Optional
|
from typing import Any, Callable, List, Optional
|
||||||
|
|
||||||
from bond import DeviceTypes, Directions
|
from bond import DeviceTypes, Directions
|
||||||
@ -67,12 +68,15 @@ class BondFan(BondEntity, FanEntity):
|
|||||||
@property
|
@property
|
||||||
def speed(self) -> Optional[str]:
|
def speed(self) -> Optional[str]:
|
||||||
"""Return the current speed."""
|
"""Return the current speed."""
|
||||||
if self._power is None:
|
|
||||||
return None
|
|
||||||
if self._power == 0:
|
if self._power == 0:
|
||||||
return SPEED_OFF
|
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
|
@property
|
||||||
def speed_list(self) -> list:
|
def speed_list(self) -> list:
|
||||||
@ -99,8 +103,14 @@ class BondFan(BondEntity, FanEntity):
|
|||||||
|
|
||||||
def set_speed(self, speed: str) -> None:
|
def set_speed(self, speed: str) -> None:
|
||||||
"""Set the desired speed for the fan."""
|
"""Set the desired speed for the fan."""
|
||||||
speed_index = self.speed_list.index(speed)
|
max_speed = self._device.props.get("max_speed", 3)
|
||||||
self._hub.bond.setSpeed(self._device.device_id, speed=speed_index)
|
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:
|
def turn_on(self, speed: Optional[str] = None, **kwargs) -> None:
|
||||||
"""Turn on the fan."""
|
"""Turn on the fan."""
|
||||||
|
@ -8,9 +8,10 @@ from bond import Actions, Bond
|
|||||||
class BondDevice:
|
class BondDevice:
|
||||||
"""Helper device class to hold ID and attributes together."""
|
"""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."""
|
"""Create a helper device from ID and attributes returned by API."""
|
||||||
self.device_id = device_id
|
self.device_id = device_id
|
||||||
|
self.props = props
|
||||||
self._attrs = attrs
|
self._attrs = attrs
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -67,7 +68,11 @@ class BondHub:
|
|||||||
"""Fetch all available devices using Bond API."""
|
"""Fetch all available devices using Bond API."""
|
||||||
device_ids = self.bond.getDeviceIds()
|
device_ids = self.bond.getDeviceIds()
|
||||||
devices = [
|
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
|
for device_id in device_ids
|
||||||
]
|
]
|
||||||
return devices
|
return devices
|
||||||
|
@ -28,9 +28,16 @@ async def setup_bond_entity(
|
|||||||
|
|
||||||
|
|
||||||
async def setup_platform(
|
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."""
|
"""Set up the specified Bond platform."""
|
||||||
|
if not props:
|
||||||
|
props = {}
|
||||||
|
|
||||||
mock_entry = MockConfigEntry(
|
mock_entry = MockConfigEntry(
|
||||||
domain=BOND_DOMAIN,
|
domain=BOND_DOMAIN,
|
||||||
data={CONF_HOST: "1.1.1.1", CONF_ACCESS_TOKEN: "test-token"},
|
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
|
"homeassistant.components.bond.Bond.getVersion", return_value=MOCK_HUB_VERSION
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.bond.Bond.getDeviceIds",
|
"homeassistant.components.bond.Bond.getDeviceIds",
|
||||||
return_value=["bond-device-id"],
|
return_value=[bond_device_id],
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.bond.Bond.getDevice", return_value=discovered_device
|
"homeassistant.components.bond.Bond.getDevice", return_value=discovered_device
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.bond.Bond.getDeviceState", return_value={}
|
"homeassistant.components.bond.Bond.getDeviceState", return_value={}
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.bond.Bond.getProperties", return_value=props
|
||||||
):
|
):
|
||||||
assert await async_setup_component(hass, BOND_DOMAIN, {})
|
assert await async_setup_component(hass, BOND_DOMAIN, {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@ -7,6 +7,7 @@ from homeassistant import core
|
|||||||
from homeassistant.components import fan
|
from homeassistant.components import fan
|
||||||
from homeassistant.components.fan import (
|
from homeassistant.components.fan import (
|
||||||
ATTR_DIRECTION,
|
ATTR_DIRECTION,
|
||||||
|
ATTR_SPEED_LIST,
|
||||||
DIRECTION_FORWARD,
|
DIRECTION_FORWARD,
|
||||||
DIRECTION_REVERSE,
|
DIRECTION_REVERSE,
|
||||||
DOMAIN as FAN_DOMAIN,
|
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.helpers.entity_registry import EntityRegistry
|
||||||
from homeassistant.util import utcnow
|
from homeassistant.util import utcnow
|
||||||
|
|
||||||
from ...common import async_fire_time_changed
|
|
||||||
from .common import setup_platform
|
from .common import setup_platform
|
||||||
|
|
||||||
from tests.async_mock import patch
|
from tests.async_mock import patch
|
||||||
|
from tests.common import async_fire_time_changed
|
||||||
|
|
||||||
|
|
||||||
def ceiling_fan(name: str):
|
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):
|
async def test_entity_registry(hass: core.HomeAssistant):
|
||||||
"""Tests that the devices are registered in the entity registry."""
|
"""Tests that the devices are registered in the entity registry."""
|
||||||
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
|
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"]
|
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):
|
async def test_turn_on_fan(hass: core.HomeAssistant):
|
||||||
"""Tests that turn on command delegates to API."""
|
"""Tests that turn on command delegates to API."""
|
||||||
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
|
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(
|
with patch("homeassistant.components.bond.Bond.turnOn") as mock_turn_on, patch(
|
||||||
"homeassistant.components.bond.Bond.setSpeed"
|
"homeassistant.components.bond.Bond.setSpeed"
|
||||||
) as mock_set_speed:
|
) as mock_set_speed:
|
||||||
await hass.services.async_call(
|
await turn_fan_on(hass, "fan.name_1", fan.SPEED_LOW)
|
||||||
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()
|
|
||||||
|
|
||||||
mock_set_speed.assert_called_once()
|
mock_set_speed.assert_called_once()
|
||||||
mock_turn_on.assert_called_once()
|
mock_turn_on.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
async def test_turn_off_fan(hass: core.HomeAssistant):
|
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,
|
FAN_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: "fan.name_1"}, blocking=True,
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
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):
|
async def test_update_reports_fan_on(hass: core.HomeAssistant):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user