8000 Add Dimmer Configuration Support · python-kasa/python-kasa@db7c2f1 · GitHub
[go: up one dir, main page]

Skip to content

Commit db7c2f1

Browse files
committed
Add Dimmer Configuration Support
- Add: Support for configuring minimum dimming level. - Add: Support for configuring dimmer ramp rate. - Add: Support for configuring dimmer gentle fade time. - Add: Support for configuring dimmper fade time.
1 parent 7f2a1be commit db7c2f1

File tree

4 files changed

+250
-1
lines changed

4 files changed

+250
-1
lines changed

kasa/iot/iotdimmer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from ..protocols import BaseProtocol
1212
from .iotdevice import KasaException, requires_update
1313
from .iotplug import IotPlug
14-
from .modules import AmbientLight, Light, Motion
14+
from .modules import AmbientLight, Dimmer, Light, Motion
1515

1616

1717
class ButtonAction(Enum):
@@ -87,6 +87,7 @@ async def _initialize_modules(self) -> None:
8787
# TODO: need to be figured out what's the best approach to detect support
8888
self.add_module(Module.IotMotion, Motion(self, "smartlife.iot.PIR"))
8989
self.add_module(Module.IotAmbientLight, AmbientLight(self, "smartlife.iot.LAS"))
90+
self.add_module(Module.IotDimmer, Dimmer(self, "smartlife.iot.dimmer"))
9091
self.add_module(Module.Light, Light(self, "light"))
9192

9293
@property # type: ignore

kasa/iot/modules/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .antitheft import Antitheft
55
from .cloud import Cloud
66
from .countdown import Countdown
7+
from .dimmer import Dimmer
78
from .emeter import Emeter
89
from .led import Led
910
from .light import Light
@@ -20,6 +21,7 @@
2021
"Antitheft",
2122
"Cloud",
2223
"Countdown",
24+
"Dimmer",
2325
"Emeter",
2426
"Led",
2527
"Light",

kasa/iot/modules/dimmer.py

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
"""Implementation of the dimmer config module found in dimmers."""
2+
3+
from __future__ import annotations
4+
5+
import logging
6+
7+
from ...exceptions import KasaException
8+
from ...feature import Feature
9+
from ..iotmodule import IotModule, merge
10+
11+
_LOGGER = logging.getLogger(__name__)
12+
13+
14+
class Dimmer(IotModule):
15+
"""Implements the dimmer config module."""
16+
17+
def _initialize_features(self) -> None:
18+
"""Initialize features after the initial update."""
19+
# Only add features if the device supports the module
20+
if "get_dimmer_parameters" not in self.data:
21+
return
22+
23+
self._add_feature(
24+
Feature(
25+
device=self._device,
26+
container=self,
27+
id="dimmer_threshold_min",
28+
name="Minimum Dimming Level",
29+
icon="mdi:lightbulb-on-20",
30+
attribute_getter="threshold_min",
31+
attribute_setter="set_threshold_min",
32+
type=Feature.Type.Switch,
33+
category=Feature.Category.Config,
34+
)
35+
)
36+
37+
self._add_feature(
38+
Feature(
39+
device=self._device,
40+
container=self,
41+
id="dimmer_fade_off_time",
42+
name="Dimmer Fade Off Time",
43+
icon="mdi:clock-in",
44+
attribute_getter="fade_off_time",
45+
attribute_setter="set_fade_off_time",
46+
type=Feature.Type.Switch,
47+
category=Feature.Category.Config,
48+
)
49+
)
50+
51+
self._add_feature(
52+
Feature(
53+
device=self._device,
54+
container=self,
55+
id="dimmer_fade_on_time",
56+
name="Dimmer Fade On Time",
57+
icon="mdi:clock-out",
58+
attribute_getter="fade_on_time",
59+
attribute_setter="set_fade_on_time",
60+
type=Feature.Type.Switch,
61+
category=Feature.Category.Config,
62+
)
63+
)
64+
65+
self._add_feature(
66+
Feature(
67+
device=self._device,
68+
container=self,
69+
id="dimmer_gentle_off_time",
70+
name="Dimmer Gentle Off Time",
71+
icon="mdi:clock-in",
72+
attribute_getter="gentle_off_time",
73+
attribute_setter="set_gentle_off_time",
74+
type=Feature.Type.Switch,
75+
category=Feature.Category.Config,
76+
)
77+
)
78+
79+
self._add_feature(
80+
Feature(
81+
device=self._device,
82+
container=self,
83+
id="dimmer_gentle_on_time",
< 10000 /td>
84+
name="Dimmer Gentle On Time",
85+
icon="mdi:clock-out",
86+
attribute_getter="gentle_on_time",
87+
attribute_setter="set_gentle_on_time",
88+
type=Feature.Type.Switch,
89+
category=Feature.Category.Config,
90+
)
91+
)
92+
93+
self._add_feature(
94+
Feature(
95+
device=self._device,
96+
container=self,
97+
id="dimmer_ramp_rate",
98+
name="Dimmer Ramp Rate",
99+
icon="mdi:clock-fast",
100+
attribute_getter="ramp_rate",
101+
attribute_setter="set_ramp_rate",
102+
type=Feature.Type.Switch,
103+
category=Feature.Category.Config,
104+
)
105+
)
106+
107+
def query(self) -> dict:
108+
"""Request Dimming configuration."""
109+
req = merge(
110+
self.query_for_command("get_dimmer_parameters"),
111+
self.query_for_command("get_default_behavior"),
112+
)
113+
114+
return req
115+
116+
@property
117+
def config(self) -> dict:
118+
"""Return current configuration."""
119+
return self.data["get_dimmer_parameters"]
120+
121+
@property
122+
def threshold_min(self) -> int | None:
123+
"""Return the minimum dimming level for this dimmer."""
124+
if (min := self.config.get("minThreshold")) is not None:
125+
return int(min)
126+
return None
127+
128+
async def set_threshold_min(self, min: int) -> dict:
129+
"""
130+
Set the minimum dimming level for this dimmer.
131+
132+
The value will depend on the luminaries connected to the dimmer.
133+
134+
:param min: The minimum dimming level, in the range 0-51.
135+
"""
136+
if (min < 0) or (min > 51):
137+
raise KasaException(
138+
"Minimum dimming threshold is outside the supported range: 0-51."
139+
)
140+
return await self.call("calibrate_brightness", {"minThreshold": min})
141+
142+
@property
143+
def fade_off_time(self) -> int | None:
144+
"""Return the fade off animation duration."""
145+
if (fade_time := self.config.get("fadeOffTime")) is not None:
146+
return int(fade_time)
147+
return None
148+
149+
async def set_fade_off_time(self, time: int) -> dict:
150+
"""
151+
Set the duration of the fade off animation.
152+
153+
:param time: The animation duration, in ms.
154+
"""
155+
if (time < 0) or (time > 10_000):
156+
# FYI: Not sure if there is really a max bound here,
157+
# but anything above 10s seems ridiculous.
158+
raise KasaException(
159+
"Fade time is outside the bounds of the supported range: 0-10,000."
160+
)
161+
return await self.call("set_fade_on_time", {"fadeTime": time})
162+
163+
@property
164+
def fade_on_time(self) -> int | None:
165+
"""Return the fade on animation duration."""
166+
if (fade_time := self.config.get("fadeOnTime")) is not None:
167+
return int(fade_time)
168+
return None
169+
170+
async def set_fade_on_time(self, time: int) -> dict:
171+
"""
172+
Set the duration of the fade on animation.
173+
174+
:param time: The animation duration, in ms.
175+
"""
176+
if (time < 0) or (time > 10_000):
177+
# FYI: Not sure if there is really a max bound here,
178+
# but anything above 10s seems ridiculous.
179+
raise KasaException(
180+
"Fade time is outside the bounds of the supported range: 0-10,000."
181+
)
182+
return await self.call("set_fade_on_time", {"fadeTime": time})
183+
184+
@property
185+
def gentle_off_time(self) -> int | None:
186+
"""Return the gentle fade off animation duration."""
187+
if (duration := self.config.get("gentleOffTime")) is not None:
188+
return int(duration)
189+
return None
190+
191+
async def set_gentle_off_time(self, time: int) -> dict:
192+
"""
193+
Set the duration of the gentle fade off animation.
194+
195+
:param time: The animation duration, in ms.
196+
"""
197+
if (time < 0) or (time > 100_000):
198+
# FYI: Not sure if there is really a max bound here,
199+
# but anything above 100s seems ridiculous.
200+
raise KasaException(
201+
"Gentle off time is outside the bounds of the supported range: "
202+
"0-100,000."
203+
)
204+
return await self.call("set_gentle_off_time", {"duration": time})
205+
206+
@property
207+
def gentle_on_time(self) -> int | None:
208+
"""Return the gentle fade on animation duration."""
209+
if (duration := self.config.get("gentleOnTime")) is not None:
210+
return int(duration)
211+
return None
212+
213+
async def set_gentle_on_time(self, time: int) -> dict:
214+
"""
215+
Set the duration of the gentle fade on animation.
216+
217+
:param time: The animation duration, in ms.
218+
"""
219+
if (time < 0) or (time > 100_000):
220+
# FYI: Not sure if there is really a max bound here,
221+
# but anything above 100s seems ridiculous.
222+
raise KasaException(
223+
"Gentle off time is outside the bounds of the supported range: "
224+
"0-100,000."
225+
)
226+
return await self.call("set_gentle_on_time", {"duration": time})
227+
228+
@property
229+
def ramp_rate(self) -> int | None:
230+
"""Return the rate that the dimmer buttons increment the dimmer level."""
231+
if (rate := self.config.get("rampRate")) is not None:
232+
return int(rate)
233+
return None
234+
235+
async def set_ramp_rate(self, rate: int) -> dict:
236+
"""
237+
Set how quickly to ramp the dimming level when using the dimmer buttons.
238+
239+
:param rate: The rate to increment the dimming level with each press.
240+
"""
241+
if (rate < 10) or (rate > 50):
242+
raise KasaException(
243+
"Gentle off time is outside the bounds of the supported range: 10-50"
244+
)
245+
return await self.call("set_button_ramp_rate", {"rampRate": rate})

kasa/module.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class Module(ABC):
107107
IotAmbientLight: Final[ModuleName[iot.AmbientLight]] = ModuleName("ambient")
108108
IotAntitheft: Final[ModuleName[iot.Antitheft]] = ModuleName("anti_theft")
109109
IotCountdown: Final[ModuleName[iot.Countdown]] = ModuleName("countdown")
110+
IotDimmer: Final[ModuleName[iot.Dimmer]] = ModuleName("dimmer")
110111
IotMotion: Final[ModuleName[iot.Motion]] = ModuleName("motion")
111112
IotSchedule: Final[ModuleName[iot.Schedule]] = ModuleName("schedule")
112113
IotUsage: Final[ModuleName[iot.Usage]] = ModuleName("usage")

0 commit comments

Comments
 (0)
0