Add tilt support to bond covers (#59505)

This commit is contained in:
J. Nick Koston 2021-11-11 22:31:58 -05:00 committed by GitHub
parent beb0650a81
commit 5d2eb8d3ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 172 additions and 6 deletions

View file

@ -5,7 +5,16 @@ from typing import Any
from bond_api import Action, BPUPSubscriptions, DeviceType
from homeassistant.components.cover import DEVICE_CLASS_SHADE, CoverEntity
from homeassistant.components.cover import (
DEVICE_CLASS_SHADE,
SUPPORT_CLOSE,
SUPPORT_CLOSE_TILT,
SUPPORT_OPEN,
SUPPORT_OPEN_TILT,
SUPPORT_STOP,
SUPPORT_STOP_TILT,
CoverEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
@ -45,6 +54,21 @@ class BondCover(BondEntity, CoverEntity):
) -> None:
"""Create HA entity representing Bond cover."""
super().__init__(hub, device, bpup_subs)
supported_features = 0
if self._device.supports_open():
supported_features |= SUPPORT_OPEN
if self._device.supports_close():
supported_features |= SUPPORT_CLOSE
if self._device.supports_tilt_open():
supported_features |= SUPPORT_OPEN_TILT
if self._device.supports_tilt_close():
supported_features |= SUPPORT_CLOSE_TILT
if self._device.supports_hold():
if self._device.supports_open() or self._device.supports_close():
supported_features |= SUPPORT_STOP
if self._device.supports_tilt_open() or self._device.supports_tilt_close():
supported_features |= SUPPORT_STOP_TILT
self._attr_supported_features = supported_features
def _apply_state(self, state: dict) -> None:
cover_open = state.get("open")
@ -63,3 +87,15 @@ class BondCover(BondEntity, CoverEntity):
async def async_stop_cover(self, **kwargs: Any) -> None:
"""Hold cover."""
await self._hub.bond.action(self._device.device_id, Action.hold())
async def async_open_cover_tilt(self, **kwargs: Any) -> None:
"""Open the cover tilt."""
await self._hub.bond.action(self._device.device_id, Action.tilt_open())
async def async_close_cover_tilt(self, **kwargs: Any) -> None:
"""Close the cover tilt."""
await self._hub.bond.action(self._device.device_id, Action.tilt_close())
async def async_stop_cover_tilt(self, **kwargs: Any) -> None:
"""Stop the cover."""
await self._hub.bond.action(self._device.device_id, Action.hold())

View file

@ -3,7 +3,7 @@
"name": "Bond",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/bond",
"requirements": ["bond-api==0.1.14"],
"requirements": ["bond-api==0.1.15"],
"zeroconf": ["_bond._tcp.local."],
"codeowners": ["@bdraco", "@prystupa", "@joshs85"],
"quality_scale": "platinum",

View file

@ -82,6 +82,26 @@ class BondDevice:
"""Return True if this device supports any of the direction related commands."""
return self._has_any_action({Action.SET_DIRECTION})
def supports_open(self) -> bool:
"""Return True if this device supports opening."""
return self._has_any_action({Action.OPEN})
def supports_close(self) -> bool:
"""Return True if this device supports closing."""
return self._has_any_action({Action.CLOSE})
def supports_tilt_open(self) -> bool:
"""Return True if this device supports tilt opening."""
return self._has_any_action({Action.TILT_OPEN})
def supports_tilt_close(self) -> bool:
"""Return True if this device supports tilt closing."""
return self._has_any_action({Action.TILT_CLOSE})
def supports_hold(self) -> bool:
"""Return True if this device supports hold aka stop."""
return self._has_any_action({Action.HOLD})
def supports_light(self) -> bool:
"""Return True if this device supports any of the light related commands."""
return self._has_any_action({Action.TURN_LIGHT_ON, Action.TURN_LIGHT_OFF})

View file

@ -418,7 +418,7 @@ blockchain==1.4.4
# bme680==1.0.5
# homeassistant.components.bond
bond-api==0.1.14
bond-api==0.1.15
# homeassistant.components.bosch_shc
boschshcpy==0.2.19

View file

@ -263,7 +263,7 @@ blebox_uniapi==1.3.3
blinkpy==0.17.0
# homeassistant.components.bond
bond-api==0.1.14
bond-api==0.1.15
# homeassistant.components.bosch_shc
boschshcpy==0.2.19

View file

@ -4,12 +4,16 @@ from datetime import timedelta
from bond_api import Action, DeviceType
from homeassistant import core
from homeassistant.components.cover import DOMAIN as COVER_DOMAIN
from homeassistant.components.cover import DOMAIN as COVER_DOMAIN, STATE_CLOSED
from homeassistant.const import (
ATTR_ENTITY_ID,
SERVICE_CLOSE_COVER,
SERVICE_CLOSE_COVER_TILT,
SERVICE_OPEN_COVER,
SERVICE_OPEN_COVER_TILT,
SERVICE_STOP_COVER,
SERVICE_STOP_COVER_TILT,
STATE_UNKNOWN,
)
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_registry import EntityRegistry
@ -27,7 +31,29 @@ from tests.common import async_fire_time_changed
def shades(name: str):
"""Create motorized shades with given name."""
return {"name": name, "type": DeviceType.MOTORIZED_SHADES}
return {
"name": name,
"type": DeviceType.MOTORIZED_SHADES,
"actions": ["Open", "Close", "Hold"],
}
def tilt_only_shades(name: str):
"""Create motorized shades that only tilt."""
return {
"name": name,
"type": DeviceType.MOTORIZED_SHADES,
"actions": ["TiltOpen", "TiltClose", "Hold"],
}
def tilt_shades(name: str):
"""Create motorized shades with given name that can also tilt."""
return {
"name": name,
"type": DeviceType.MOTORIZED_SHADES,
"actions": ["Open", "Close", "Hold", "TiltOpen", "TiltClose", "Hold"],
}
async def test_entity_registry(hass: core.HomeAssistant):
@ -99,6 +125,90 @@ async def test_stop_cover(hass: core.HomeAssistant):
mock_hold.assert_called_once_with("test-device-id", Action.hold())
async def test_tilt_open_cover(hass: core.HomeAssistant):
"""Tests that tilt open cover command delegates to API."""
await setup_platform(
hass, COVER_DOMAIN, tilt_only_shades("name-1"), bond_device_id="test-device-id"
)
with patch_bond_action() as mock_open, patch_bond_device_state():
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_OPEN_COVER_TILT,
{ATTR_ENTITY_ID: "cover.name_1"},
blocking=True,
)
await hass.async_block_till_done()
mock_open.assert_called_once_with("test-device-id", Action.tilt_open())
assert hass.states.get("cover.name_1").state == STATE_UNKNOWN
async def test_tilt_close_cover(hass: core.HomeAssistant):
"""Tests that tilt close cover command delegates to API."""
await setup_platform(
hass, COVER_DOMAIN, tilt_only_shades("name-1"), bond_device_id="test-device-id"
)
with patch_bond_action() as mock_close, patch_bond_device_state():
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_CLOSE_COVER_TILT,
{ATTR_ENTITY_ID: "cover.name_1"},
blocking=True,
)
await hass.async_block_till_done()
mock_close.assert_called_once_with("test-device-id", Action.tilt_close())
assert hass.states.get("cover.name_1").state == STATE_UNKNOWN
async def test_tilt_stop_cover(hass: core.HomeAssistant):
"""Tests that tilt stop cover command delegates to API."""
await setup_platform(
hass,
COVER_DOMAIN,
tilt_only_shades("name-1"),
bond_device_id="test-device-id",
state={"counter1": 123},
)
with patch_bond_action() as mock_hold, patch_bond_device_state():
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_STOP_COVER_TILT,
{ATTR_ENTITY_ID: "cover.name_1"},
blocking=True,
)
await hass.async_block_till_done()
mock_hold.assert_called_once_with("test-device-id", Action.hold())
assert hass.states.get("cover.name_1").state == STATE_UNKNOWN
async def test_tilt_and_open(hass: core.HomeAssistant):
"""Tests that supports both tilt and open."""
await setup_platform(
hass,
COVER_DOMAIN,
tilt_shades("name-1"),
bond_device_id="test-device-id",
state={"open": False},
)
with patch_bond_action() as mock_open, patch_bond_device_state():
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_OPEN_COVER_TILT,
{ATTR_ENTITY_ID: "cover.name_1"},
blocking=True,
)
await hass.async_block_till_done()
mock_open.assert_called_once_with("test-device-id", Action.tilt_open())
assert hass.states.get("cover.name_1").state == STATE_CLOSED
async def test_update_reports_open_cover(hass: core.HomeAssistant):
"""Tests that update command sets correct state when Bond API reports cover is open."""
await setup_platform(hass, COVER_DOMAIN, shades("name-1"))