diff --git a/homeassistant/components/deconz/cover.py b/homeassistant/components/deconz/cover.py index 8df974cf146..3eac9cafd52 100644 --- a/homeassistant/components/deconz/cover.py +++ b/homeassistant/components/deconz/cover.py @@ -4,6 +4,7 @@ from __future__ import annotations from typing import Any, cast from pydeconz.interfaces.lights import CoverAction +from pydeconz.models import ResourceType from pydeconz.models.event import EventType 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 DECONZ_TYPE_TO_DEVICE_CLASS = { - "Level controllable output": CoverDeviceClass.DAMPER, - "Window covering controller": CoverDeviceClass.SHADE, - "Window covering device": CoverDeviceClass.SHADE, + ResourceType.LEVEL_CONTROLLABLE_OUTPUT.value: CoverDeviceClass.DAMPER, + ResourceType.WINDOW_COVERING_CONTROLLER.value: 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.legacy_mode = cover.type == ResourceType.LEVEL_CONTROLLABLE_OUTPUT.value + @property def current_cover_position(self) -> int: """Return the current position of the cover.""" @@ -87,6 +90,7 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity): await self.gateway.api.lights.covers.set_state( id=self._device.resource_id, lift=position, + legacy_mode=self.legacy_mode, ) 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( id=self._device.resource_id, action=CoverAction.OPEN, + legacy_mode=self.legacy_mode, ) 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( id=self._device.resource_id, action=CoverAction.CLOSE, + legacy_mode=self.legacy_mode, ) 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( id=self._device.resource_id, action=CoverAction.STOP, + legacy_mode=self.legacy_mode, ) @property @@ -123,6 +130,7 @@ class DeconzCover(DeconzDevice[Cover], CoverEntity): await self.gateway.api.lights.covers.set_state( id=self._device.resource_id, tilt=position, + legacy_mode=self.legacy_mode, ) 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( id=self._device.resource_id, tilt=0, + legacy_mode=self.legacy_mode, ) 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( id=self._device.resource_id, tilt=100, + legacy_mode=self.legacy_mode, ) 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( id=self._device.resource_id, action=CoverAction.STOP, + legacy_mode=self.legacy_mode, ) diff --git a/homeassistant/components/deconz/manifest.json b/homeassistant/components/deconz/manifest.json index 51de538324f..38c78d849da 100644 --- a/homeassistant/components/deconz/manifest.json +++ b/homeassistant/components/deconz/manifest.json @@ -3,7 +3,7 @@ "name": "deCONZ", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/deconz", - "requirements": ["pydeconz==103"], + "requirements": ["pydeconz==104"], "ssdp": [ { "manufacturer": "Royal Philips Electronics", diff --git a/requirements_all.txt b/requirements_all.txt index ff3a248be34..81e1cf594c4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1467,7 +1467,7 @@ pydaikin==2.7.0 pydanfossair==0.1.0 # homeassistant.components.deconz -pydeconz==103 +pydeconz==104 # homeassistant.components.delijn pydelijn==1.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index bad3671b282..c2cebb49b1d 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1022,7 +1022,7 @@ pycoolmasternet-async==0.1.2 pydaikin==2.7.0 # homeassistant.components.deconz -pydeconz==103 +pydeconz==104 # homeassistant.components.dexcom pydexcom==0.2.3 diff --git a/tests/components/deconz/test_cover.py b/tests/components/deconz/test_cover.py index 0c37edc221d..f2f4c7d7a2d 100644 --- a/tests/components/deconz/test_cover.py +++ b/tests/components/deconz/test_cover.py @@ -213,3 +213,111 @@ async def test_tilt_cover(hass, aioclient_mock): blocking=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}