Fix level controllable output controls in deCONZ (#77223)

Fix level controllable output controls
This commit is contained in:
Robert Svensson 2022-08-25 04:00:54 +02:00 committed by GitHub
parent 859effee56
commit 2161b6f049
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 125 additions and 6 deletions

View File

@ -4,6 +4,7 @@ from __future__ import annotations
from typing import Any, cast from typing import Any, cast
from pydeconz.interfaces.lights import CoverAction from pydeconz.interfaces.lights import CoverAction
from pydeconz.models import ResourceType
from pydeconz.models.event import EventType from pydeconz.models.event import EventType
from pydeconz.models.light.cover import Cover from pydeconz.models.light.cover import Cover
@ -23,9 +24,9 @@ from .deconz_device import DeconzDevice
from .gateway import DeconzGateway, get_gateway_from_config_entry from .gateway import DeconzGateway, get_gateway_from_config_entry
DECONZ_TYPE_TO_DEVICE_CLASS = { DECONZ_TYPE_TO_DEVICE_CLASS = {
"Level controllable output": CoverDeviceClass.DAMPER, ResourceType.LEVEL_CONTROLLABLE_OUTPUT.value: CoverDeviceClass.DAMPER,
"Window covering controller": CoverDeviceClass.SHADE, ResourceType.WINDOW_COVERING_CONTROLLER.value: CoverDeviceClass.SHADE,
"Window covering device": CoverDeviceClass.SHADE, ResourceType.WINDOW_COVERING_DEVICE.value: CoverDeviceClass.SHADE,
} }
@ -71,6 +72,8 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity):
self._attr_device_class = DECONZ_TYPE_TO_DEVICE_CLASS.get(cover.type) self._attr_device_class = DECONZ_TYPE_TO_DEVICE_CLASS.get(cover.type)
self.legacy_mode = cover.type == ResourceType.LEVEL_CONTROLLABLE_OUTPUT.value
@property @property
def current_cover_position(self) -> int: def current_cover_position(self) -> int:
"""Return the current position of the cover.""" """Return the current position of the cover."""
@ -87,6 +90,7 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity):
await self.gateway.api.lights.covers.set_state( await self.gateway.api.lights.covers.set_state(
id=self._device.resource_id, id=self._device.resource_id,
lift=position, lift=position,
legacy_mode=self.legacy_mode,
) )
async def async_open_cover(self, **kwargs: Any) -> None: async def async_open_cover(self, **kwargs: Any) -> None:
@ -94,6 +98,7 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity):
await self.gateway.api.lights.covers.set_state( await self.gateway.api.lights.covers.set_state(
id=self._device.resource_id, id=self._device.resource_id,
action=CoverAction.OPEN, action=CoverAction.OPEN,
legacy_mode=self.legacy_mode,
) )
async def async_close_cover(self, **kwargs: Any) -> None: async def async_close_cover(self, **kwargs: Any) -> None:
@ -101,6 +106,7 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity):
await self.gateway.api.lights.covers.set_state( await self.gateway.api.lights.covers.set_state(
id=self._device.resource_id, id=self._device.resource_id,
action=CoverAction.CLOSE, action=CoverAction.CLOSE,
legacy_mode=self.legacy_mode,
) )
async def async_stop_cover(self, **kwargs: Any) -> None: async def async_stop_cover(self, **kwargs: Any) -> None:
@ -108,6 +114,7 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity):
await self.gateway.api.lights.covers.set_state( await self.gateway.api.lights.covers.set_state(
id=self._device.resource_id, id=self._device.resource_id,
action=CoverAction.STOP, action=CoverAction.STOP,
legacy_mode=self.legacy_mode,
) )
@property @property
@ -123,6 +130,7 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity):
await self.gateway.api.lights.covers.set_state( await self.gateway.api.lights.covers.set_state(
id=self._device.resource_id, id=self._device.resource_id,
tilt=position, tilt=position,
legacy_mode=self.legacy_mode,
) )
async def async_open_cover_tilt(self, **kwargs: Any) -> None: async def async_open_cover_tilt(self, **kwargs: Any) -> None:
@ -130,6 +138,7 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity):
await self.gateway.api.lights.covers.set_state( await self.gateway.api.lights.covers.set_state(
id=self._device.resource_id, id=self._device.resource_id,
tilt=0, tilt=0,
legacy_mode=self.legacy_mode,
) )
async def async_close_cover_tilt(self, **kwargs: Any) -> None: async def async_close_cover_tilt(self, **kwargs: Any) -> None:
@ -137,6 +146,7 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity):
await self.gateway.api.lights.covers.set_state( await self.gateway.api.lights.covers.set_state(
id=self._device.resource_id, id=self._device.resource_id,
tilt=100, tilt=100,
legacy_mode=self.legacy_mode,
) )
async def async_stop_cover_tilt(self, **kwargs: Any) -> None: async def async_stop_cover_tilt(self, **kwargs: Any) -> None:
@ -144,4 +154,5 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity):
await self.gateway.api.lights.covers.set_state( await self.gateway.api.lights.covers.set_state(
id=self._device.resource_id, id=self._device.resource_id,
action=CoverAction.STOP, action=CoverAction.STOP,
legacy_mode=self.legacy_mode,
) )

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==103"], "requirements": ["pydeconz==104"],
"ssdp": [ "ssdp": [
{ {
"manufacturer": "Royal Philips Electronics", "manufacturer": "Royal Philips Electronics",

View File

@ -1467,7 +1467,7 @@ pydaikin==2.7.0
pydanfossair==0.1.0 pydanfossair==0.1.0
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==103 pydeconz==104
# homeassistant.components.delijn # homeassistant.components.delijn
pydelijn==1.0.0 pydelijn==1.0.0

View File

@ -1022,7 +1022,7 @@ pycoolmasternet-async==0.1.2
pydaikin==2.7.0 pydaikin==2.7.0
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==103 pydeconz==104
# homeassistant.components.dexcom # homeassistant.components.dexcom
pydexcom==0.2.3 pydexcom==0.2.3

View File

@ -213,3 +213,111 @@ async def test_tilt_cover(hass, aioclient_mock):
blocking=True, blocking=True,
) )
assert aioclient_mock.mock_calls[4][2] == {"stop": True} assert aioclient_mock.mock_calls[4][2] == {"stop": True}
async def test_level_controllable_output_cover(hass, aioclient_mock):
"""Test that tilting a cover works."""
data = {
"lights": {
"0": {
"etag": "4cefc909134c8e99086b55273c2bde67",
"hascolor": False,
"lastannounced": "2022-08-08T12:06:18Z",
"lastseen": "2022-08-14T14:22Z",
"manufacturername": "Keen Home Inc",
"modelid": "SV01-410-MP-1.0",
"name": "Vent",
"state": {
"alert": "none",
"bri": 242,
"on": False,
"reachable": True,
"sat": 10,
},
"swversion": "0x00000012",
"type": "Level controllable output",
"uniqueid": "00:22:a3:00:00:00:00:00-01",
}
}
}
with patch.dict(DECONZ_WEB_REQUEST, data):
config_entry = await setup_deconz_integration(hass, aioclient_mock)
assert len(hass.states.async_all()) == 1
covering_device = hass.states.get("cover.vent")
assert covering_device.state == STATE_OPEN
assert covering_device.attributes[ATTR_CURRENT_TILT_POSITION] == 97
# Verify service calls for tilting cover
mock_deconz_put_request(aioclient_mock, config_entry.data, "/lights/0/state")
# Service open cover
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_OPEN_COVER,
{ATTR_ENTITY_ID: "cover.vent"},
blocking=True,
)
assert aioclient_mock.mock_calls[1][2] == {"on": False}
# Service close cover
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_CLOSE_COVER,
{ATTR_ENTITY_ID: "cover.vent"},
blocking=True,
)
assert aioclient_mock.mock_calls[2][2] == {"on": True}
# Service set cover position
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_SET_COVER_POSITION,
{ATTR_ENTITY_ID: "cover.vent", ATTR_POSITION: 40},
blocking=True,
)
assert aioclient_mock.mock_calls[3][2] == {"bri": 152}
# Service set tilt cover
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_SET_COVER_TILT_POSITION,
{ATTR_ENTITY_ID: "cover.vent", ATTR_TILT_POSITION: 40},
blocking=True,
)
assert aioclient_mock.mock_calls[4][2] == {"sat": 152}
# Service open tilt cover
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_OPEN_COVER_TILT,
{ATTR_ENTITY_ID: "cover.vent"},
blocking=True,
)
assert aioclient_mock.mock_calls[5][2] == {"sat": 0}
# Service close tilt cover
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_CLOSE_COVER_TILT,
{ATTR_ENTITY_ID: "cover.vent"},
blocking=True,
)
assert aioclient_mock.mock_calls[6][2] == {"sat": 254}
# Service stop cover movement
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_STOP_COVER_TILT,
{ATTR_ENTITY_ID: "cover.vent"},
blocking=True,
)
assert aioclient_mock.mock_calls[7][2] == {"bri_inc": 0}