Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove legacy controls from Cover #329

Merged
merged 1 commit into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 10 additions & 56 deletions pydeconz/models/light/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

import enum
from typing import Any, TypedDict
from typing import TypedDict

from . import LightBase

Expand Down Expand Up @@ -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

Expand All @@ -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)
Expand All @@ -62,59 +59,16 @@ 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"]
elif "sat" in self.raw["state"]: # Legacy support
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"]
79 changes: 9 additions & 70 deletions tests/lights/test_cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,15 @@ 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)

assert cover.state is False
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

Expand All @@ -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)

Expand Down Expand Up @@ -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