diff --git a/pydeconz/models/light/cover.py b/pydeconz/models/light/cover.py index 77452ad4..13281d7f 100644 --- a/pydeconz/models/light/cover.py +++ b/pydeconz/models/light/cover.py @@ -3,7 +3,7 @@ from __future__ import annotations import enum -from typing import Any, TypedDict +from typing import TypedDict from . import LightBase @@ -33,10 +33,7 @@ class CoverAction(enum.Enum): class Cover(LightBase): - """Cover and Damper class. - - Position 0 means open and 100 means closed. - """ + """Cover and Damper class.""" raw: TypedCover @@ -51,8 +48,8 @@ def is_open(self) -> bool: def lift(self) -> int: """Amount of closed position. - 0 is fully open. - 100 is fully closed. + Supported values: + 0-100 - 0 is open / 100 is closed """ if "lift" not in self.raw["state"]: # Legacy support return int(self.raw["state"]["bri"] / 2.54) @@ -62,8 +59,8 @@ def lift(self) -> int: def tilt(self) -> int | None: """Amount of tilt. - 0 is fully open. - 100 is fully closed. + Supported values: + 0-100 - 0 is open / 100 is closed """ if "tilt" in self.raw["state"]: return self.raw["state"]["tilt"] @@ -71,50 +68,7 @@ def tilt(self) -> int | None: return int(self.raw["state"]["sat"] / 2.54) return None - async def set_position( - self, *, lift: int | None = None, tilt: int | None = None - ) -> dict[str, Any]: - """Set amount of closed position and/or tilt of cover. - - Lift [int] between 0-100. - Scale to brightness 0-254. - Tilt [int] between 0-100. - Scale to saturation 0-254. - """ - data = {} - - if lift is not None: - if "lift" in self.raw["state"]: - data["lift"] = lift - elif "bri" in self.raw["state"]: # Legacy support - data["bri"] = int(lift * 2.54) - - if tilt is not None: - if "tilt" in self.raw["state"]: - data["tilt"] = tilt - elif "sat" in self.raw["state"]: # Legacy support - data["sat"] = int(tilt * 2.54) - - return await self.request(field=f"{self.deconz_id}/state", data=data) - - async def open(self) -> dict[str, Any]: - """Fully open cover.""" - data = {"open": True} - if "open" not in self.raw["state"]: # Legacy support - data = {"on": False} - return await self.request(field=f"{self.deconz_id}/state", data=data) - - async def close(self) -> dict[str, Any]: - """Fully close cover.""" - data = {"open": False} - if "open" not in self.raw["state"]: # Legacy support - data = {"on": True} - return await self.request(field=f"{self.deconz_id}/state", data=data) - - async def stop(self) -> dict[str, Any]: - """Stop cover motion.""" - data: dict[str, bool | int] - data = {"stop": True} - if "lift" not in self.raw["state"]: # Legacy support - data = {"bri_inc": 0} - return await self.request(field=f"{self.deconz_id}/state", data=data) + @property + def supports_tilt(self) -> bool: + """Supports tilt.""" + return "tilt" in self.raw["state"] diff --git a/tests/lights/test_cover.py b/tests/lights/test_cover.py index d5037432..5015b197 100644 --- a/tests/lights/test_cover.py +++ b/tests/lights/test_cover.py @@ -73,7 +73,7 @@ async def test_handler_cover(mock_aioresponse, deconz_session, deconz_called_wit assert deconz_called_with("put", path="/lights/0/state", json={"stop": True}) -async def test_light_cover(mock_aioresponse, deconz_light, deconz_called_with): +async def test_light_cover(deconz_light): """Verify that covers work.""" cover = await deconz_light(DATA) @@ -81,6 +81,7 @@ async def test_light_cover(mock_aioresponse, deconz_light, deconz_called_with): assert cover.is_open is True assert cover.lift == 0 assert cover.tilt is None + assert cover.supports_tilt is False assert cover.reachable is True @@ -96,51 +97,25 @@ async def test_light_cover(mock_aioresponse, deconz_light, deconz_called_with): cover.register_callback(mock_callback := Mock()) assert cover._callbacks - event = {"state": {"lift": 50, "open": True}} - cover.update(event) + cover.update({"state": {"lift": 50, "open": True}}) assert cover.is_open is True assert cover.lift == 50 mock_callback.assert_called_once() assert cover.changed_keys == {"state", "lift", "open"} - event = {"state": {"bri": 30, "on": False}} - cover.update(event) + cover.update({"state": {"tilt": 25, "open": True}}) + assert cover.tilt == 25 + assert cover.supports_tilt is True + + cover.update({"state": {"bri": 30, "on": False}}) assert cover.is_open is True assert cover.lift == 50 - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.open() - assert deconz_called_with("put", path="/lights/0/state", json={"open": True}) - - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.close() - assert deconz_called_with("put", path="/lights/0/state", json={"open": False}) - - # Tilt not supported - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.set_position(lift=30, tilt=60) - assert deconz_called_with("put", path="/lights/0/state", json={"lift": 30}) - - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.stop() - assert deconz_called_with("put", path="/lights/0/state", json={"stop": True}) - - # Verify tilt works as well - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - cover.raw["state"]["tilt"] = 40 - assert cover.tilt == 40 - - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.set_position(lift=20, tilt=60) - assert deconz_called_with( - "put", path="/lights/0/state", json={"lift": 20, "tilt": 60} - ) - cover.remove_callback(mock_callback) assert not cover._callbacks -async def test_light_cover_legacy(mock_aioresponse, deconz_light, deconz_called_with): +async def test_light_cover_legacy(deconz_light): """Verify that covers work with older deconz versions.""" cover = await deconz_light(DATA_LEGACY) @@ -175,51 +150,15 @@ async def test_light_cover_legacy(mock_aioresponse, deconz_light, deconz_called_ assert cover.is_open is True assert cover.lift == 11 - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.open() - assert deconz_called_with("put", path="/lights/0/state", json={"on": False}) - - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.close() - assert deconz_called_with("put", path="/lights/0/state", json={"on": True}) - - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.set_position(lift=30) - assert deconz_called_with("put", path="/lights/0/state", json={"bri": 76}) - - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.stop() - assert deconz_called_with("put", path="/lights/0/state", json={"bri_inc": 0}) - # Verify sat (for tilt) works as well cover.raw["state"]["sat"] = 40 assert cover.tilt == 15 - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.set_position(lift=20, tilt=60) - assert deconz_called_with( - "put", path="/lights/0/state", json={"bri": 50, "sat": 152} - ) - cover.raw["state"]["lift"] = 0 cover.raw["state"]["tilt"] = 0 cover.raw["state"]["open"] = True assert cover.tilt == 0 - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.open() - assert deconz_called_with("put", path="/lights/0/state", json={"open": True}) - - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.close() - assert deconz_called_with("put", path="/lights/0/state", json={"open": False}) - - mock_aioresponse.put("http://host:80/api/apikey/lights/0/state") - await cover.set_position(lift=20, tilt=60) - assert deconz_called_with( - "put", path="/lights/0/state", json={"lift": 20, "tilt": 60} - ) - cover.remove_callback(mock_callback) assert not cover._callbacks