8000 Apply Suggested Changes · python-kasa/python-kasa@77299dd · GitHub
[go: up one dir, main page]

Skip to content

Commit 77299dd

Browse files
committed
Apply Suggested Changes
- Fix: Return time values as `timedelta` instead of `int`. - Fix: Move constants to top of file. - Fix: Correct feature types. - Fix: Expose range of bounded features.
1 parent db7c2f1 commit 77299dd

File tree

1 file changed

+99
-65
lines changed

1 file changed

+99
-65
lines changed

kasa/iot/modules/dimmer.py

Lines changed: 99 additions & 65 deletions
< 10000 /thead>
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from __future__ import annotations
44

55
import logging
6+
from datetime import timedelta
7+
from typing import Any, Final, cast
68

79
from ...exceptions import KasaException
810
from ...feature import Feature
@@ -11,9 +13,31 @@
1113
_LOGGER = logging.getLogger(__name__)
1214

1315

16+
def _td_to_ms(td: timedelta) -> int:
17+
"""
18+
Convert timedelta to integer milliseconds.
19+
20+
Uses default float to integer rounding.
21+
"""
22+
return int(td / timedelta(milliseconds=1))
23+
24+
1425
class Dimmer(IotModule):
1526
"""Implements the dimmer config module."""
1627

28+
THRESHOLD_ABS_MIN: Final[int] = 0
29+
THRESHOLD_ABS_MAX: Final[int] = (
30+
51 # Strange value, but verified against hardware (KS220).
31+
)
32+
FADE_TIME_ABS_MIN: Final[timedelta] = timedelta(seconds=0)
33+
FADE_TIME_ABS_MAX: Final[timedelta] = timedelta(seconds=10) # Completely arbitrary.
34+
GENTLE_TIME_ABS_MIN: Final[timedelta] = timedelta(seconds=0)
35+
GENTLE_TIME_ABS_MAX: Final[timedelta] = timedelta(
36+
seconds=120
37+
) # Completely arbitrary.
38+
RAMP_RATE_ABS_MIN: Final[int] = 10 # Verified against KS220.
39+
RAMP_RATE_ABS_MAX: Final[int] = 50 # Verified against KS220.
40+
1741
def _initialize_features(self) -> None:
1842
"""Initialize features after the initial update."""
1943
# Only add features if the device supports the module
@@ -25,11 +49,12 @@ def _initialize_features(self) -> None:
2549
device=self._device,
2650
container=self,
2751
id="dimmer_threshold_min",
28-
name="Minimum Dimming Level",
52+
name="Minimum dimming level",
2953
icon="mdi:lightbulb-on-20",
3054
attribute_getter="threshold_min",
3155
attribute_setter="set_threshold_min",
32-
type=Feature.Type.Switch,
56+
range_getter=lambda: (self.THRESHOLD_ABS_MIN, self.THRESHOLD_ABS_MAX),
57+
type=Feature.Type.Number,
3358
category=Feature.Category.Config,
3459
)
3560
)
@@ -39,11 +64,15 @@ def _initialize_features(self) -> None:
3964
device=self._device,
4065
container=self,
4166
id="dimmer_fade_off_time",
42-
name="Dimmer Fade Off Time",
67+
name="Dimmer fade off time",
4368
icon="mdi:clock-in",
4469
attribute_getter="fade_off_time",
4570
attribute_setter="set_fade_off_time",
46-
type=Feature.Type.Switch,
71+
range_getter=lambda: (
72+
_td_to_ms(self.FADE_TIME_ABS_MIN),
73+
_td_to_ms(self.FADE_TIME_ABS_MAX),
74+
),
75+
type=Feature.Type.Number,
4776
category=Feature.Category.Config,
4877
)
4978
)
@@ -53,11 +82,15 @@ def _initialize_features(self) -> None:
5382
device=self._device,
5483
container=self,
5584
id="dimmer_fade_on_time",
56-
name="Dimmer Fade On Time",
85+
name="Dimmer fade on time",
5786
icon="mdi:clock-out",
5887
attribute_getter="fade_on_time",
5988
attribute_setter="set_fade_on_time",
60-
type=Feature.Type.Switch,
89+
range_getter=lambda: (
90+
_td_to_ms(self.FADE_TIME_ABS_MIN),
91+
_td_to_ms(self.FADE_TIME_ABS_MAX),
92+
),
93+
type=Feature.Type.Number,
6194
category=Feature.Category.Config,
6295
)
< 17AE code>6396
)
@@ -67,11 +100,15 @@ def _initialize_features(self) -> None:
67100
device=self._device,
68101
container=self,
69102
id="dimmer_gentle_off_time",
70-
name="Dimmer Gentle Off Time",
103+
name="Dimmer gentle off time",
71104
icon="mdi:clock-in",
72105
attribute_getter="gentle_off_time",
73106
attribute_setter="set_gentle_off_time",
74-
type=Feature.Type.Switch,
107+
range_getter=lambda: (
108+
_td_to_ms(self.GENTLE_TIME_ABS_MIN),
109+
_td_to_ms(self.GENTLE_TIME_ABS_MAX),
110+
),
111+
type=Feature.Type.Number,
75112
category=Feature.Category.Config,
76113
)
77114
)
@@ -81,11 +118,15 @@ def _initialize_features(self) -> None:
81118
device=self._device,
82119
container=self,
83120
id="dimmer_gentle_on_time",
84-
name="Dimmer Gentle On Time",
121+
name="Dimmer gentle on time",
85122
icon="mdi:clock-out",
86123
attribute_getter="gentle_on_time",
87124
attribute_setter="set_gentle_on_time",
88-
type=Feature.Type.Switch,
125+
range_getter=lambda: (
126+
_td_to_ms(self.GENTLE_TIME_ABS_MIN),
127+
_td_to_ms(self.GENTLE_TIME_ABS_MAX),
128+
),
129+
type=Feature.Type.Number,
89130
category=Feature.Category.Config,
90131
)
91132
)
@@ -95,11 +136,12 @@ def _initialize_features(self) -> None:
95136
device=self._device,
96137
container=self,
97138
id="dimmer_ramp_rate",
98-
name="Dimmer Ramp Rate",
139+
name="Dimmer ramp rate",
99140
icon="mdi:clock-fast",
100141
attribute_getter="ramp_rate",
101142
attribute_setter="set_ramp_rate",
102-
type=Feature.Type.Switch,
143+
range_getter=lambda: (self.RAMP_RATE_ABS_MIN, self.RAMP_RATE_ABS_MAX),
144+
type=Feature.Type.Number,
103145
category=Feature.Category.Config,
104146
)
105147
)
@@ -114,16 +156,14 @@ def query(self) -> dict:
114156
return req
115157

116158
@property
117-
def config(self) -> dict:
159+
def config(self) -> dict[str, Any]:
118160
"""Return current configuration."""
119161
return self.data["get_dimmer_parameters"]
120162

121163
@property
122-
def threshold_min(self) -> int | None:
164+
def threshold_min(self) -> int:
123165
"""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
166+
return self.config["minThreshold"]
127167

128168
async def set_threshold_min(self, min: int) -> dict:
129169
"""
@@ -133,113 +173,107 @@ async def set_threshold_min(self, min: int) -> dict:
133173
134174
:param min: The minimum dimming level, in the range 0-51.
135175
"""
136-
if (min < 0) or (min > 51):
176+
if (min < self.THRESHOLD_ABS_MIN) or (min > self.THRESHOLD_ABS_MAX):
137177
raise KasaException(
138-
"Minimum dimming threshold is outside the supported range: 0-51."
178+
"Minimum dimming threshold is outside the supported range: "
179+
f"{self.THRESHOLD_ABS_MIN}-{self.THRESHOLD_ABS_MAX}"
139180
)
140181
return await self.call("calibrate_brightness", {"minThreshold": min})
141182

142183
@property
143-
def fade_off_time(self) -> int | None:
184+
def fade_off_time(self) -> timedelta:
144185
"""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
186+
return timedelta(milliseconds=cast(int, self.config["fadeOffTime"]))
148187

149-
async def set_fade_off_time(self, time: int) -> dict:
188+
async def set_fade_off_time(self, time: int | timedelta) -> dict:
150189
"""
151190
Set the duration of the fade off animation.
152191
153192
:param time: The animation duration, in ms.
154193
"""
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.
194+
if isinstance(time, int):
195+
time = timedelta(milliseconds=time)
196+
if (time < self.FADE_TIME_ABS_MIN) or (time > self.FADE_TIME_ABS_MAX):
158197
raise KasaException(
159-
"Fade time is outside the bounds of the supported range: 0-10,000."
198+
"Fade time is outside the bounds of the supported range:"
199+
f"{self.FADE_TIME_ABS_MIN}-{self.FADE_TIME_ABS_MAX}"
160200
)
161-
return await self.call("set_fade_on_time", {"fadeTime": time})
201+
return await self.call("set_fade_on_time", {"fadeTime": _td_to_ms(time)})
162202

163203
@property
164-
def fade_on_time(self) -> int | None:
204+
def fade_on_time(self) -> timedelta:
165205
"""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
206+
return timedelta(milliseconds=cast(int, self.config["fadeOnTime"]))
169207

170-
async def set_fade_on_time(self, time: int) -> dict:
208+
async def set_fade_on_time(self, time: int | timedelta) -> dict:
171209
"""
172210
Set the duration of the fade on animation.
173211
174212
:param time: The animation duration, in ms.
175213
"""
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.
214+
if isinstance(time, int):
215+
time = timedelta(milliseconds=time)
216+
if (time < self.FADE_TIME_ABS_MIN) or (time > self.FADE_TIME_ABS_MAX):
179217
raise KasaException(
180-
"Fade time is outside the bounds of the supported range: 0-10,000."
218+
"Fade time is outside the bounds of the supported range:"
219+
f"{self.FADE_TIME_ABS_MIN}-{self.FADE_TIME_ABS_MAX}"
181220
)
182-
return await self.call("set_fade_on_time", {"fadeTime": time})
221+
return await self.call("set_fade_on_time", {"fadeTime": _td_to_ms(time)})
183222

184223
@property
185-
def gentle_off_time(self) -> int | None:
224+
def gentle_off_time(self) -> timedelta:
186225
"""Return the gentle fade off animation duration."""
187-
if (duration := self.config.get("gentleOffTime")) is not None:
188-
return int(duration)
189-
return None
226+
return timedelta(milliseconds=cast(int, self.config["gentleOffTime"]))
190227

191-
async def set_gentle_off_time(self, time: int) -> dict:
228+
async def set_gentle_off_time(self, time: int | timedelta) -> dict:
192229
"""
193230
Set the duration of the gentle fade off animation.
194231
195232
:param time: The animation duration, in ms.
196233
"""
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.
234+
if isinstance(time, int):
235+
time = timedelta(milliseconds=time)
236+
if (time < self.GENTLE_TIME_ABS_MIN) or (time > self.GENTLE_TIME_ABS_MAX):
200237
raise KasaException(
201238
"Gentle off time is outside the bounds of the supported range: "
202-
"0-100,000."
239+
f"{self.GENTLE_TIME_ABS_MIN}-{self.GENTLE_TIME_ABS_MAX}."
203240
)
204-
return await self.call("set_gentle_off_time", {"duration": time})
241+
return await self.call("set_gentle_off_time", {"duration": _td_to_ms(time)})
205242

206243
@property
207-
def gentle_on_time(self) -> int | None:
244+
def gentle_on_time(self) -> timedelta:
208245
"""Return the gentle fade on animation duration."""
209-
if (duration := self.config.get("gentleOnTime")) is not None:
210-
return int(duration)
211-
return None
246+
return timedelta(milliseconds=cast(int, self.config["gentleOnTime"]))
212247

213-
async def set_gentle_on_time(self, time: int) -> dict:
248+
async def set_gentle_on_time(self, time: int | timedelta) -> dict:
214249
"""
215250
Set the duration of the gentle fade on animation.
216251
217252
:param time: The animation duration, in ms.
218253
"""
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.
254+
if isinstance(time, int):
255+
time = timedelta(milliseconds=time)
256+
if (time < self.GENTLE_TIME_ABS_MIN) or (time > self.GENTLE_TIME_ABS_MAX):
222257
raise KasaException(
223258
"Gentle off time is outside the bounds of the supported range: "
224-
"0-100,000."
259+
f"{self.GENTLE_TIME_ABS_MIN}-{self.GENTLE_TIME_ABS_MAX}."
225260
)
226-
return await self.call("set_gentle_on_time", {"duration": time})
261+
return await self.call("set_gentle_on_time", {"duration": _td_to_ms(time)})
227262

228263
@property
229-
def ramp_rate(self) -> int | None:
264+
def ramp_rate(self) -> int:
230265
"""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
266+
return self.config["rampRate"]
234267

235268
async def set_ramp_rate(self, rate: int) -> dict:
236269
"""
237270
Set how quickly to ramp the dimming level when using the dimmer buttons.
238271
239272
:param rate: The rate to increment the dimming level with each press.
240273
"""
241-
if (rate < 10) or (rate > 50):
274+
if (rate < self.RAMP_RATE_ABS_MIN) or (rate > self.RAMP_RATE_ABS_MAX):
242275
raise KasaException(
243-
"Gentle off time is outside the bounds of the supported range: 10-50"
276+
"Gentle off time is outside the bounds of the supported range:"
277+
f"{self.RAMP_RATE_ABS_MIN}-{self.RAMP_RATE_ABS_MAX}"
244278
)
245279
return await self.call("set_button_ramp_rate", {"rampRate": rate})

0 commit comments

Comments
 (0)
0