Add support for fan direction in bond integration (#37789)
* Add support for fan direction in bond integration * Add support for fan direction (PR feedback)pull/37795/head
parent
53844488d8
commit
e9440c49d5
|
@ -1,13 +1,16 @@
|
|||
"""Support for Bond fans."""
|
||||
from typing import Any, Callable, List, Optional
|
||||
|
||||
from bond import DeviceTypes
|
||||
from bond import DeviceTypes, Directions
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
DIRECTION_FORWARD,
|
||||
DIRECTION_REVERSE,
|
||||
SPEED_HIGH,
|
||||
SPEED_LOW,
|
||||
SPEED_MEDIUM,
|
||||
SPEED_OFF,
|
||||
SUPPORT_DIRECTION,
|
||||
SUPPORT_SET_SPEED,
|
||||
FanEntity,
|
||||
)
|
||||
|
@ -48,13 +51,17 @@ class BondFan(BondEntity, FanEntity):
|
|||
|
||||
self._power: Optional[bool] = None
|
||||
self._speed: Optional[int] = None
|
||||
self._direction: Optional[int] = None
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
"""Flag supported features."""
|
||||
features = 0
|
||||
if self._device.supports_command("SetSpeed"):
|
||||
if self._device.supports_speed():
|
||||
features |= SUPPORT_SET_SPEED
|
||||
if self._device.supports_direction():
|
||||
features |= SUPPORT_DIRECTION
|
||||
|
||||
return features
|
||||
|
||||
@property
|
||||
|
@ -72,11 +79,23 @@ class BondFan(BondEntity, FanEntity):
|
|||
"""Get the list of available speeds."""
|
||||
return [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
|
||||
|
||||
@property
|
||||
def current_direction(self) -> Optional[str]:
|
||||
"""Return fan rotation direction."""
|
||||
direction = None
|
||||
if self._direction == Directions.FORWARD:
|
||||
direction = DIRECTION_FORWARD
|
||||
elif self._direction == Directions.REVERSE:
|
||||
direction = DIRECTION_REVERSE
|
||||
|
||||
return direction
|
||||
|
||||
def update(self):
|
||||
"""Fetch assumed state of the fan from the hub using API."""
|
||||
state: dict = self._hub.bond.getDeviceState(self._device.device_id)
|
||||
self._power = state.get("power")
|
||||
self._speed = state.get("speed")
|
||||
self._direction = state.get("direction")
|
||||
|
||||
def set_speed(self, speed: str) -> None:
|
||||
"""Set the desired speed for the fan."""
|
||||
|
@ -92,3 +111,10 @@ class BondFan(BondEntity, FanEntity):
|
|||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the fan off."""
|
||||
self._hub.bond.turnOff(self._device.device_id)
|
||||
|
||||
def set_direction(self, direction: str) -> None:
|
||||
"""Set fan rotation direction."""
|
||||
bond_direction = (
|
||||
Directions.REVERSE if direction == DIRECTION_REVERSE else Directions.FORWARD
|
||||
)
|
||||
self._hub.bond.setDirection(self._device.device_id, bond_direction)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from typing import List, Optional
|
||||
|
||||
from bond import Bond
|
||||
from bond import Actions, Bond
|
||||
|
||||
|
||||
class BondDevice:
|
||||
|
@ -23,10 +23,24 @@ class BondDevice:
|
|||
"""Get the type of this device."""
|
||||
return self._attrs["type"]
|
||||
|
||||
def supports_command(self, command: str) -> bool:
|
||||
"""Return True if this device supports specified command."""
|
||||
def supports_speed(self) -> bool:
|
||||
"""Return True if this device supports any of the speed related commands."""
|
||||
actions: List[str] = self._attrs["actions"]
|
||||
return command in actions
|
||||
return len([action for action in actions if action in [Actions.SET_SPEED]]) > 0
|
||||
|
||||
def supports_direction(self) -> bool:
|
||||
"""Return True if this device supports any of the direction related commands."""
|
||||
actions: List[str] = self._attrs["actions"]
|
||||
return (
|
||||
len(
|
||||
[
|
||||
action
|
||||
for action in actions
|
||||
if action in [Actions.SET_DIRECTION, Actions.TOGGLE_DIRECTION]
|
||||
]
|
||||
)
|
||||
> 0
|
||||
)
|
||||
|
||||
|
||||
class BondHub:
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
"""Tests for the Bond fan device."""
|
||||
from datetime import timedelta
|
||||
|
||||
from bond import DeviceTypes
|
||||
from bond import DeviceTypes, Directions
|
||||
|
||||
from homeassistant import core
|
||||
from homeassistant.components import fan
|
||||
from homeassistant.components.fan import DOMAIN as FAN_DOMAIN
|
||||
from homeassistant.components.fan import (
|
||||
ATTR_DIRECTION,
|
||||
DIRECTION_FORWARD,
|
||||
DIRECTION_REVERSE,
|
||||
DOMAIN as FAN_DOMAIN,
|
||||
SERVICE_SET_DIRECTION,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON
|
||||
from homeassistant.helpers.entity_registry import EntityRegistry
|
||||
from homeassistant.util import utcnow
|
||||
|
@ -21,7 +27,7 @@ def ceiling_fan(name: str):
|
|||
return {
|
||||
"name": name,
|
||||
"type": DeviceTypes.CEILING_FAN,
|
||||
"actions": ["SetSpeed"],
|
||||
"actions": ["SetSpeed", "SetDirection"],
|
||||
}
|
||||
|
||||
|
||||
|
@ -90,3 +96,46 @@ async def test_update_reports_fan_off(hass: core.HomeAssistant):
|
|||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("fan.name_1").state == "off"
|
||||
|
||||
|
||||
async def test_update_reports_direction_forward(hass: core.HomeAssistant):
|
||||
"""Tests that update command sets correct direction when Bond API reports fan direction is forward."""
|
||||
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bond.Bond.getDeviceState",
|
||||
return_value={"direction": Directions.FORWARD},
|
||||
):
|
||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=30))
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("fan.name_1").attributes[ATTR_DIRECTION] == DIRECTION_FORWARD
|
||||
|
||||
|
||||
async def test_update_reports_direction_reverse(hass: core.HomeAssistant):
|
||||
"""Tests that update command sets correct direction when Bond API reports fan direction is reverse."""
|
||||
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.bond.Bond.getDeviceState",
|
||||
return_value={"direction": Directions.REVERSE},
|
||||
):
|
||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=30))
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("fan.name_1").attributes[ATTR_DIRECTION] == DIRECTION_REVERSE
|
||||
|
||||
|
||||
async def test_set_fan_direction(hass: core.HomeAssistant):
|
||||
"""Tests that set direction command delegates to API."""
|
||||
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
|
||||
|
||||
with patch("homeassistant.components.bond.Bond.setDirection") as mock_set_direction:
|
||||
await hass.services.async_call(
|
||||
FAN_DOMAIN,
|
||||
SERVICE_SET_DIRECTION,
|
||||
{ATTR_ENTITY_ID: "fan.name_1", ATTR_DIRECTION: DIRECTION_FORWARD},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
mock_set_direction.assert_called_once()
|
||||
|
|
Loading…
Reference in New Issue