Add tilt support to deCONZ covers (#43607)

This commit is contained in:
Robert Svensson 2020-11-24 21:42:11 +01:00 committed by GitHub
parent dae286aed5
commit acb94b0b59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 133 additions and 16 deletions

View File

@ -1,12 +1,17 @@
"""Support for deCONZ covers.""" """Support for deCONZ covers."""
from homeassistant.components.cover import ( from homeassistant.components.cover import (
ATTR_POSITION, ATTR_POSITION,
ATTR_TILT_POSITION,
DEVICE_CLASS_WINDOW, DEVICE_CLASS_WINDOW,
DOMAIN, DOMAIN,
SUPPORT_CLOSE, SUPPORT_CLOSE,
SUPPORT_CLOSE_TILT,
SUPPORT_OPEN, SUPPORT_OPEN,
SUPPORT_OPEN_TILT,
SUPPORT_SET_POSITION, SUPPORT_SET_POSITION,
SUPPORT_SET_TILT_POSITION,
SUPPORT_STOP, SUPPORT_STOP,
SUPPORT_STOP_TILT,
CoverEntity, CoverEntity,
) )
from homeassistant.core import callback from homeassistant.core import callback
@ -60,15 +65,16 @@ class DeconzCover(DeconzDevice, CoverEntity):
self._features |= SUPPORT_STOP self._features |= SUPPORT_STOP
self._features |= SUPPORT_SET_POSITION self._features |= SUPPORT_SET_POSITION
@property if self._device.tilt is not None:
def current_cover_position(self): self._features |= SUPPORT_OPEN_TILT
"""Return the current position of the cover.""" self._features |= SUPPORT_CLOSE_TILT
return 100 - self._device.position self._features |= SUPPORT_STOP_TILT
self._features |= SUPPORT_SET_TILT_POSITION
@property @property
def is_closed(self): def supported_features(self):
"""Return if the cover is closed.""" """Flag supported features."""
return not self._device.is_open return self._features
@property @property
def device_class(self): def device_class(self):
@ -79,14 +85,19 @@ class DeconzCover(DeconzDevice, CoverEntity):
return DEVICE_CLASS_WINDOW return DEVICE_CLASS_WINDOW
@property @property
def supported_features(self): def current_cover_position(self):
"""Flag supported features.""" """Return the current position of the cover."""
return self._features return 100 - self._device.lift
@property
def is_closed(self):
"""Return if the cover is closed."""
return not self._device.is_open
async def async_set_cover_position(self, **kwargs): async def async_set_cover_position(self, **kwargs):
"""Move the cover to a specific position.""" """Move the cover to a specific position."""
position = 100 - kwargs[ATTR_POSITION] position = 100 - kwargs[ATTR_POSITION]
await self._device.set_position(position) await self._device.set_position(lift=position)
async def async_open_cover(self, **kwargs): async def async_open_cover(self, **kwargs):
"""Open cover.""" """Open cover."""
@ -99,3 +110,26 @@ class DeconzCover(DeconzDevice, CoverEntity):
async def async_stop_cover(self, **kwargs): async def async_stop_cover(self, **kwargs):
"""Stop cover.""" """Stop cover."""
await self._device.stop() await self._device.stop()
@property
def current_cover_tilt_position(self):
"""Return the current tilt position of the cover."""
if self._device.tilt is not None:
return 100 - self._device.tilt
async def async_set_cover_tilt_position(self, **kwargs):
"""Tilt the cover to a specific position."""
position = 100 - kwargs[ATTR_TILT_POSITION]
await self._device.set_position(tilt=position)
async def async_open_cover_tilt(self, **kwargs):
"""Open cover tilt."""
await self._device.set_position(tilt=0)
async def async_close_cover_tilt(self, **kwargs):
"""Close cover tilt."""
await self._device.set_position(tilt=100)
async def async_stop_cover_tilt(self, **kwargs):
"""Stop cover tilt."""
await self._device.stop()

View File

@ -3,7 +3,7 @@
"name": "deCONZ", "name": "deCONZ",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/deconz", "documentation": "https://www.home-assistant.io/integrations/deconz",
"requirements": ["pydeconz==74"], "requirements": ["pydeconz==75"],
"ssdp": [ "ssdp": [
{ {
"manufacturer": "Royal Philips Electronics" "manufacturer": "Royal Philips Electronics"

View File

@ -1337,7 +1337,7 @@ pydaikin==2.3.1
pydanfossair==0.1.0 pydanfossair==0.1.0
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==74 pydeconz==75
# homeassistant.components.delijn # homeassistant.components.delijn
pydelijn==0.6.1 pydelijn==0.6.1

View File

@ -670,7 +670,7 @@ pycountry==19.8.18
pydaikin==2.3.1 pydaikin==2.3.1
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==74 pydeconz==75
# homeassistant.components.dexcom # homeassistant.components.dexcom
pydexcom==0.2.0 pydexcom==0.2.0

View File

@ -3,12 +3,18 @@
from copy import deepcopy from copy import deepcopy
from homeassistant.components.cover import ( from homeassistant.components.cover import (
ATTR_CURRENT_TILT_POSITION,
ATTR_POSITION, ATTR_POSITION,
ATTR_TILT_POSITION,
DOMAIN as COVER_DOMAIN, DOMAIN as COVER_DOMAIN,
SERVICE_CLOSE_COVER, SERVICE_CLOSE_COVER,
SERVICE_CLOSE_COVER_TILT,
SERVICE_OPEN_COVER, SERVICE_OPEN_COVER,
SERVICE_OPEN_COVER_TILT,
SERVICE_SET_COVER_POSITION, SERVICE_SET_COVER_POSITION,
SERVICE_SET_COVER_TILT_POSITION,
SERVICE_STOP_COVER, SERVICE_STOP_COVER,
SERVICE_STOP_COVER_TILT,
) )
from homeassistant.components.deconz.const import DOMAIN as DECONZ_DOMAIN from homeassistant.components.deconz.const import DOMAIN as DECONZ_DOMAIN
from homeassistant.components.deconz.gateway import get_gateway_from_config_entry from homeassistant.components.deconz.gateway import get_gateway_from_config_entry
@ -47,7 +53,7 @@ COVERS = {
"id": "deconz old brightness cover id", "id": "deconz old brightness cover id",
"name": "deconz old brightness cover", "name": "deconz old brightness cover",
"type": "Level controllable output", "type": "Level controllable output",
"state": {"bri": 254, "on": False, "reachable": True}, "state": {"bri": 255, "on": False, "reachable": True},
"modelid": "Not zigbee spec", "modelid": "Not zigbee spec",
"uniqueid": "00:00:00:00:00:00:00:03-00", "uniqueid": "00:00:00:00:00:00:00:03-00",
}, },
@ -165,7 +171,7 @@ async def test_cover(hass):
blocking=True, blocking=True,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
set_callback.assert_called_with("put", "/lights/2/state", json={"bri_inc": 0}) set_callback.assert_called_with("put", "/lights/2/state", json={"stop": True})
# Verify service calls for legacy cover # Verify service calls for legacy cover
@ -247,3 +253,80 @@ async def test_cover(hass):
await hass.config_entries.async_unload(config_entry.entry_id) await hass.config_entries.async_unload(config_entry.entry_id)
assert len(hass.states.async_all()) == 0 assert len(hass.states.async_all()) == 0
async def test_tilt_cover(hass):
"""Test that tilting a cover works."""
data = deepcopy(DECONZ_WEB_REQUEST)
data["lights"] = {
"0": {
"etag": "87269755b9b3a046485fdae8d96b252c",
"lastannounced": None,
"lastseen": "2020-08-01T16:22:05Z",
"manufacturername": "AXIS",
"modelid": "Gear",
"name": "Covering device",
"state": {
"bri": 0,
"lift": 0,
"on": False,
"open": True,
"reachable": True,
"tilt": 0,
},
"swversion": "100-5.3.5.1122",
"type": "Window covering device",
"uniqueid": "00:24:46:00:00:12:34:56-01",
}
}
config_entry = await setup_deconz_integration(hass, get_state_response=data)
gateway = get_gateway_from_config_entry(hass, config_entry)
assert len(hass.states.async_all()) == 1
entity = hass.states.get("cover.covering_device")
assert entity.state == STATE_OPEN
assert entity.attributes[ATTR_CURRENT_TILT_POSITION] == 100
covering_device = gateway.api.lights["0"]
with patch.object(covering_device, "_request", return_value=True) as set_callback:
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_SET_COVER_TILT_POSITION,
{ATTR_ENTITY_ID: "cover.covering_device", ATTR_TILT_POSITION: 40},
blocking=True,
)
await hass.async_block_till_done()
set_callback.assert_called_with("put", "/lights/0/state", json={"tilt": 60})
with patch.object(covering_device, "_request", return_value=True) as set_callback:
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_OPEN_COVER_TILT,
{ATTR_ENTITY_ID: "cover.covering_device"},
blocking=True,
)
await hass.async_block_till_done()
set_callback.assert_called_with("put", "/lights/0/state", json={"tilt": 0})
with patch.object(covering_device, "_request", return_value=True) as set_callback:
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_CLOSE_COVER_TILT,
{ATTR_ENTITY_ID: "cover.covering_device"},
blocking=True,
)
await hass.async_block_till_done()
set_callback.assert_called_with("put", "/lights/0/state", json={"tilt": 100})
# Service stop cover movement
with patch.object(covering_device, "_request", return_value=True) as set_callback:
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_STOP_COVER_TILT,
{ATTR_ENTITY_ID: "cover.covering_device"},
blocking=True,
)
await hass.async_block_till_done()
set_callback.assert_called_with("put", "/lights/0/state", json={"stop": True})