mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-04-25 08:06:25 +00:00
Add Dimmer Configuration Support (#1484)
This commit is contained in:
parent
8259d28b12
commit
bff5409d22
@ -11,7 +11,7 @@ from ..module import Module
|
||||
from ..protocols import BaseProtocol
|
||||
from .iotdevice import KasaException, requires_update
|
||||
from .iotplug import IotPlug
|
||||
from .modules import AmbientLight, Light, Motion
|
||||
from .modules import AmbientLight, Dimmer, Light, Motion
|
||||
|
||||
|
||||
class ButtonAction(Enum):
|
||||
@ -87,6 +87,7 @@ class IotDimmer(IotPlug):
|
||||
# TODO: need to be figured out what's the best approach to detect support
|
||||
self.add_module(Module.IotMotion, Motion(self, "smartlife.iot.PIR"))
|
||||
self.add_module(Module.IotAmbientLight, AmbientLight(self, "smartlife.iot.LAS"))
|
||||
self.add_module(Module.IotDimmer, Dimmer(self, "smartlife.iot.dimmer"))
|
||||
self.add_module(Module.Light, Light(self, "light"))
|
||||
|
||||
@property # type: ignore
|
||||
|
@ -4,6 +4,7 @@ from .ambientlight import AmbientLight
|
||||
from .antitheft import Antitheft
|
||||
from .cloud import Cloud
|
||||
from .countdown import Countdown
|
||||
from .dimmer import Dimmer
|
||||
from .emeter import Emeter
|
||||
from .led import Led
|
||||
from .light import Light
|
||||
@ -20,6 +21,7 @@ __all__ = [
|
||||
"Antitheft",
|
||||
"Cloud",
|
||||
"Countdown",
|
||||
"Dimmer",
|
||||
"Emeter",
|
||||
"Led",
|
||||
"Light",
|
||||
|
270
kasa/iot/modules/dimmer.py
Normal file
270
kasa/iot/modules/dimmer.py
Normal file
@ -0,0 +1,270 @@
|
||||
"""Implementation of the dimmer config module found in dimmers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from typing import Any, Final, cast
|
||||
|
||||
from ...exceptions import KasaException
|
||||
from ...feature import Feature
|
||||
from ..iotmodule import IotModule, merge
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _td_to_ms(td: timedelta) -> int:
|
||||
"""
|
||||
Convert timedelta to integer milliseconds.
|
||||
|
||||
Uses default float to integer rounding.
|
||||
"""
|
||||
return int(td / timedelta(milliseconds=1))
|
||||
|
||||
|
||||
class Dimmer(IotModule):
|
||||
"""Implements the dimmer config module."""
|
||||
|
||||
THRESHOLD_ABS_MIN: Final[int] = 0
|
||||
# Strange value, but verified against hardware (KS220).
|
||||
THRESHOLD_ABS_MAX: Final[int] = 51
|
||||
FADE_TIME_ABS_MIN: Final[timedelta] = timedelta(seconds=0)
|
||||
# Arbitrary, but set low intending GENTLE FADE for longer fades.
|
||||
FADE_TIME_ABS_MAX: Final[timedelta] = timedelta(seconds=10)
|
||||
GENTLE_TIME_ABS_MIN: Final[timedelta] = timedelta(seconds=0)
|
||||
# Arbitrary, but reasonable default.
|
||||
GENTLE_TIME_ABS_MAX: Final[timedelta] = timedelta(seconds=120)
|
||||
# Verified against KS220.
|
||||
RAMP_RATE_ABS_MIN: Final[int] = 10
|
||||
# Verified against KS220.
|
||||
RAMP_RATE_ABS_MAX: Final[int] = 50
|
||||
|
||||
def _initialize_features(self) -> None:
|
||||
"""Initialize features after the initial update."""
|
||||
self._add_feature(
|
||||
Feature(
|
||||
device=self._device,
|
||||
container=self,
|
||||
id="dimmer_threshold_min",
|
||||
name="Minimum dimming level",
|
||||
icon="mdi:lightbulb-on-20",
|
||||
attribute_getter="threshold_min",
|
||||
attribute_setter="set_threshold_min",
|
||||
range_getter=lambda: (self.THRESHOLD_ABS_MIN, self.THRESHOLD_ABS_MAX),
|
||||
type=Feature.Type.Number,
|
||||
category=Feature.Category.Config,
|
||||
)
|
||||
)
|
||||
|
||||
self._add_feature(
|
||||
Feature(
|
||||
device=self._device,
|
||||
container=self,
|
||||
id="dimmer_fade_off_time",
|
||||
name="Dimmer fade off time",
|
||||
icon="mdi:clock-in",
|
||||
attribute_getter="fade_off_time",
|
||||
attribute_setter="set_fade_off_time",
|
||||
range_getter=lambda: (
|
||||
_td_to_ms(self.FADE_TIME_ABS_MIN),
|
||||
_td_to_ms(self.FADE_TIME_ABS_MAX),
|
||||
),
|
||||
type=Feature.Type.Number,
|
||||
category=Feature.Category.Config,
|
||||
)
|
||||
)
|
||||
|
||||
self._add_feature(
|
||||
Feature(
|
||||
device=self._device,
|
||||
container=self,
|
||||
id="dimmer_fade_on_time",
|
||||
name="Dimmer fade on time",
|
||||
icon="mdi:clock-out",
|
||||
attribute_getter="fade_on_time",
|
||||
attribute_setter="set_fade_on_time",
|
||||
range_getter=lambda: (
|
||||
_td_to_ms(self.FADE_TIME_ABS_MIN),
|
||||
_td_to_ms(self.FADE_TIME_ABS_MAX),
|
||||
),
|
||||
type=Feature.Type.Number,
|
||||
category=Feature.Category.Config,
|
||||
)
|
||||
)
|
||||
|
||||
self._add_feature(
|
||||
Feature(
|
||||
device=self._device,
|
||||
container=self,
|
||||
id="dimmer_gentle_off_time",
|
||||
name="Dimmer gentle off time",
|
||||
icon="mdi:clock-in",
|
||||
attribute_getter="gentle_off_time",
|
||||
attribute_setter="set_gentle_off_time",
|
||||
range_getter=lambda: (
|
||||
_td_to_ms(self.GENTLE_TIME_ABS_MIN),
|
||||
_td_to_ms(self.GENTLE_TIME_ABS_MAX),
|
||||
),
|
||||
type=Feature.Type.Number,
|
||||
category=Feature.Category.Config,
|
||||
)
|
||||
)
|
||||
|
||||
self._add_feature(
|
||||
Feature(
|
||||
device=self._device,
|
||||
container=self,
|
||||
id="dimmer_gentle_on_time",
|
||||
name="Dimmer gentle on time",
|
||||
icon="mdi:clock-out",
|
||||
attribute_getter="gentle_on_time",
|
||||
attribute_setter="set_gentle_on_time",
|
||||
range_getter=lambda: (
|
||||
_td_to_ms(self.GENTLE_TIME_ABS_MIN),
|
||||
_td_to_ms(self.GENTLE_TIME_ABS_MAX),
|
||||
),
|
||||
type=Feature.Type.Number,
|
||||
category=Feature.Category.Config,
|
||||
)
|
||||
)
|
||||
|
||||
self._add_feature(
|
||||
Feature(
|
||||
device=self._device,
|
||||
container=self,
|
||||
id="dimmer_ramp_rate",
|
||||
name="Dimmer ramp rate",
|
||||
icon="mdi:clock-fast",
|
||||
attribute_getter="ramp_rate",
|
||||
attribute_setter="set_ramp_rate",
|
||||
range_getter=lambda: (self.RAMP_RATE_ABS_MIN, self.RAMP_RATE_ABS_MAX),
|
||||
type=Feature.Type.Number,
|
||||
category=Feature.Category.Config,
|
||||
)
|
||||
)
|
||||
|
||||
def query(self) -> dict:
|
||||
"""Request Dimming configuration."""
|
||||
req = merge(
|
||||
self.query_for_command("get_dimmer_parameters"),
|
||||
self.query_for_command("get_default_behavior"),
|
||||
)
|
||||
|
||||
return req
|
||||
|
||||
@property
|
||||
def config(self) -> dict[str, Any]:
|
||||
"""Return current configuration."""
|
||||
return self.data["get_dimmer_parameters"]
|
||||
|
||||
@property
|
||||
def threshold_min(self) -> int:
|
||||
"""Return the minimum dimming level for this dimmer."""
|
||||
return self.config["minThreshold"]
|
||||
|
||||
async def set_threshold_min(self, min: int) -> dict:
|
||||
"""Set the minimum dimming level for this dimmer.
|
||||
|
||||
The value will depend on the luminaries connected to the dimmer.
|
||||
|
||||
:param min: The minimum dimming level, in the range 0-51.
|
||||
"""
|
||||
if min < self.THRESHOLD_ABS_MIN or min > self.THRESHOLD_ABS_MAX:
|
||||
raise KasaException(
|
||||
"Minimum dimming threshold is outside the supported range: "
|
||||
f"{self.THRESHOLD_ABS_MIN}-{self.THRESHOLD_ABS_MAX}"
|
||||
)
|
||||
return await self.call("calibrate_brightness", {"minThreshold": min})
|
||||
|
||||
@property
|
||||
def fade_off_time(self) -> timedelta:
|
||||
"""Return the fade off animation duration."""
|
||||
return timedelta(milliseconds=cast(int, self.config["fadeOffTime"]))
|
||||
|
||||
async def set_fade_off_time(self, time: int | timedelta) -> dict:
|
||||
"""Set the duration of the fade off animation.
|
||||
|
||||
:param time: The animation duration, in ms.
|
||||
"""
|
||||
if isinstance(time, int):
|
||||
time = timedelta(milliseconds=time)
|
||||
if time < self.FADE_TIME_ABS_MIN or time > self.FADE_TIME_ABS_MAX:
|
||||
raise KasaException(
|
||||
"Fade time is outside the bounds of the supported range:"
|
||||
f"{self.FADE_TIME_ABS_MIN}-{self.FADE_TIME_ABS_MAX}"
|
||||
)
|
||||
return await self.call("set_fade_off_time", {"fadeTime": _td_to_ms(time)})
|
||||
|
||||
@property
|
||||
def fade_on_time(self) -> timedelta:
|
||||
"""Return the fade on animation duration."""
|
||||
return timedelta(milliseconds=cast(int, self.config["fadeOnTime"]))
|
||||
|
||||
async def set_fade_on_time(self, time: int | timedelta) -> dict:
|
||||
"""Set the duration of the fade on animation.
|
||||
|
||||
:param time: The animation duration, in ms.
|
||||
"""
|
||||
if isinstance(time, int):
|
||||
time = timedelta(milliseconds=time)
|
||||
if time < self.FADE_TIME_ABS_MIN or time > self.FADE_TIME_ABS_MAX:
|
||||
raise KasaException(
|
||||
"Fade time is outside the bounds of the supported range:"
|
||||
f"{self.FADE_TIME_ABS_MIN}-{self.FADE_TIME_ABS_MAX}"
|
||||
)
|
||||
return await self.call("set_fade_on_time", {"fadeTime": _td_to_ms(time)})
|
||||
|
||||
@property
|
||||
def gentle_off_time(self) -> timedelta:
|
||||
"""Return the gentle fade off animation duration."""
|
||||
return timedelta(milliseconds=cast(int, self.config["gentleOffTime"]))
|
||||
|
||||
async def set_gentle_off_time(self, time: int | timedelta) -> dict:
|
||||
"""Set the duration of the gentle fade off animation.
|
||||
|
||||
:param time: The animation duration, in ms.
|
||||
"""
|
||||
if isinstance(time, int):
|
||||
time = timedelta(milliseconds=time)
|
||||
if time < self.GENTLE_TIME_ABS_MIN or time > self.GENTLE_TIME_ABS_MAX:
|
||||
raise KasaException(
|
||||
"Gentle off time is outside the bounds of the supported range: "
|
||||
f"{self.GENTLE_TIME_ABS_MIN}-{self.GENTLE_TIME_ABS_MAX}."
|
||||
)
|
||||
return await self.call("set_gentle_off_time", {"duration": _td_to_ms(time)})
|
||||
|
||||
@property
|
||||
def gentle_on_time(self) -> timedelta:
|
||||
"""Return the gentle fade on animation duration."""
|
||||
return timedelta(milliseconds=cast(int, self.config["gentleOnTime"]))
|
||||
|
||||
async def set_gentle_on_time(self, time: int | timedelta) -> dict:
|
||||
"""Set the duration of the gentle fade on animation.
|
||||
|
||||
:param time: The animation duration, in ms.
|
||||
"""
|
||||
if isinstance(time, int):
|
||||
time = timedelta(milliseconds=time)
|
||||
if time < self.GENTLE_TIME_ABS_MIN or time > self.GENTLE_TIME_ABS_MAX:
|
||||
raise KasaException(
|
||||
"Gentle off time is outside the bounds of the supported range: "
|
||||
f"{self.GENTLE_TIME_ABS_MIN}-{self.GENTLE_TIME_ABS_MAX}."
|
||||
)
|
||||
return await self.call("set_gentle_on_time", {"duration": _td_to_ms(time)})
|
||||
|
||||
@property
|
||||
def ramp_rate(self) -> int:
|
||||
"""Return the rate that the dimmer buttons increment the dimmer level."""
|
||||
return self.config["rampRate"]
|
||||
|
||||
async def set_ramp_rate(self, rate: int) -> dict:
|
||||
"""Set how quickly to ramp the dimming level when using the dimmer buttons.
|
||||
|
||||
:param rate: The rate to increment the dimming level with each press.
|
||||
"""
|
||||
if rate < self.RAMP_RATE_ABS_MIN or rate > self.RAMP_RATE_ABS_MAX:
|
||||
raise KasaException(
|
||||
"Gentle off time is outside the bounds of the supported range:"
|
||||
f"{self.RAMP_RATE_ABS_MIN}-{self.RAMP_RATE_ABS_MAX}"
|
||||
)
|
||||
return await self.call("set_button_ramp_rate", {"rampRate": rate})
|
@ -111,6 +111,7 @@ class Module(ABC):
|
||||
IotAmbientLight: Final[ModuleName[iot.AmbientLight]] = ModuleName("ambient")
|
||||
IotAntitheft: Final[ModuleName[iot.Antitheft]] = ModuleName("anti_theft")
|
||||
IotCountdown: Final[ModuleName[iot.Countdown]] = ModuleName("countdown")
|
||||
IotDimmer: Final[ModuleName[iot.Dimmer]] = ModuleName("dimmer")
|
||||
IotMotion: Final[ModuleName[iot.Motion]] = ModuleName("motion")
|
||||
IotSchedule: Final[ModuleName[iot.Schedule]] = ModuleName("schedule")
|
||||
IotUsage: Final[ModuleName[iot.Usage]] = ModuleName("usage")
|
||||
|
204
tests/iot/modules/test_dimmer.py
Normal file
204
tests/iot/modules/test_dimmer.py
Normal file
@ -0,0 +1,204 @@
|
||||
from datetime import timedelta
|
||||
from typing import Final
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from kasa import KasaException, Module
|
||||
from kasa.iot import IotDimmer
|
||||
from kasa.iot.modules.dimmer import Dimmer
|
||||
|
||||
from ...device_fixtures import dimmer_iot
|
||||
|
||||
_TD_ONE_MS: Final[timedelta] = timedelta(milliseconds=1)
|
||||
|
||||
|
||||
@dimmer_iot
|
||||
def test_dimmer_getters(dev: IotDimmer):
|
||||
assert Module.IotDimmer in dev.modules
|
||||
dimmer: Dimmer = dev.modules[Module.IotDimmer]
|
||||
|
||||
assert dimmer.threshold_min == dimmer.config["minThreshold"]
|
||||
assert int(dimmer.fade_off_time / _TD_ONE_MS) == dimmer.config["fadeOffTime"]
|
||||
assert int(dimmer.fade_on_time / _TD_ONE_MS) == dimmer.config["fadeOnTime"]
|
||||
assert int(dimmer.gentle_off_time / _TD_ONE_MS) == dimmer.config["gentleOffTime"]
|
||||
assert int(dimmer.gentle_on_time / _TD_ONE_MS) == dimmer.config["gentleOnTime"]
|
||||
assert dimmer.ramp_rate == dimmer.config["rampRate"]
|
||||
|
||||
|
||||
@dimmer_iot
|
||||
async def test_dimmer_setters(dev: IotDimmer, mocker: MockerFixture):
|
||||
dimmer: Dimmer = dev.modules[Module.IotDimmer]
|
||||
query_helper = mocker.patch("kasa.iot.IotDimmer._query_helper")
|
||||
|
||||
test_threshold = 10
|
||||
await dimmer.set_threshold_min(test_threshold)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "calibrate_brightness", {"minThreshold": test_threshold}
|
||||
)
|
||||
|
||||
test_time = 100
|
||||
await dimmer.set_fade_off_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_fade_off_time", {"fadeTime": test_time}
|
||||
)
|
||||
await dimmer.set_fade_on_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_fade_on_time", {"fadeTime": test_time}
|
||||
)
|
||||
|
||||
test_time = 1000
|
||||
await dimmer.set_gentle_off_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_gentle_off_time", {"duration": test_time}
|
||||
)
|
||||
await dimmer.set_gentle_on_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_gentle_on_time", {"duration": test_time}
|
||||
)
|
||||
|
||||
test_rate = 30
|
||||
await dimmer.set_ramp_rate(test_rate)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_button_ramp_rate", {"rampRate": test_rate}
|
||||
)
|
||||
|
||||
|
||||
@dimmer_iot
|
||||
async def test_dimmer_setter_min(dev: IotDimmer, mocker: MockerFixture):
|
||||
dimmer: Dimmer = dev.modules[Module.IotDimmer]
|
||||
query_helper = mocker.patch("kasa.iot.IotDimmer._query_helper")
|
||||
|
||||
test_threshold = dimmer.THRESHOLD_ABS_MIN
|
||||
await dimmer.set_threshold_min(test_threshold)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "calibrate_brightness", {"minThreshold": test_threshold}
|
||||
)
|
||||
|
||||
test_time = int(dimmer.FADE_TIME_ABS_MIN / _TD_ONE_MS)
|
||||
await dimmer.set_fade_off_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_fade_off_time", {"fadeTime": test_time}
|
||||
)
|
||||
await dimmer.set_fade_on_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_fade_on_time", {"fadeTime": test_time}
|
||||
)
|
||||
|
||||
test_time = int(dimmer.GENTLE_TIME_ABS_MIN / _TD_ONE_MS)
|
||||
await dimmer.set_gentle_off_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_gentle_off_time", {"duration": test_time}
|
||||
)
|
||||
await dimmer.set_gentle_on_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_gentle_on_time", {"duration": test_time}
|
||||
)
|
||||
|
||||
test_rate = dimmer.RAMP_RATE_ABS_MIN
|
||||
await dimmer.set_ramp_rate(test_rate)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_button_ramp_rate", {"rampRate": test_rate}
|
||||
)
|
||||
|
||||
|
||||
@dimmer_iot
|
||||
async def test_dimmer_setter_max(dev: IotDimmer, mocker: MockerFixture):
|
||||
dimmer: Dimmer = dev.modules[Module.IotDimmer]
|
||||
query_helper = mocker.patch("kasa.iot.IotDimmer._query_helper")
|
||||
|
||||
test_threshold = dimmer.THRESHOLD_ABS_MAX
|
||||
await dimmer.set_threshold_min(test_threshold)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "calibrate_brightness", {"minThreshold": test_threshold}
|
||||
)
|
||||
|
||||
test_time = int(dimmer.FADE_TIME_ABS_MAX / _TD_ONE_MS)
|
||||
await dimmer.set_fade_off_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_fade_off_time", {"fadeTime": test_time}
|
||||
)
|
||||
await dimmer.set_fade_on_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_fade_on_time", {"fadeTime": test_time}
|
||||
)
|
||||
|
||||
test_time = int(dimmer.GENTLE_TIME_ABS_MAX / _TD_ONE_MS)
|
||||
await dimmer.set_gentle_off_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_gentle_off_time", {"duration": test_time}
|
||||
)
|
||||
await dimmer.set_gentle_on_time(test_time)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_gentle_on_time", {"duration": test_time}
|
||||
)
|
||||
|
||||
test_rate = dimmer.RAMP_RATE_ABS_MAX
|
||||
await dimmer.set_ramp_rate(test_rate)
|
||||
query_helper.assert_called_with(
|
||||
"smartlife.iot.dimmer", "set_button_ramp_rate", {"rampRate": test_rate}
|
||||
)
|
||||
|
||||
|
||||
@dimmer_iot
|
||||
async def test_dimmer_setters_min_oob(dev: IotDimmer, mocker: MockerFixture):
|
||||
dimmer: Dimmer = dev.modules[Module.IotDimmer]
|
||||
query_helper = mocker.patch("kasa.iot.IotDimmer._query_helper")
|
||||
|
||||
test_threshold = dimmer.THRESHOLD_ABS_MIN - 1
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_threshold_min(test_threshold)
|
||||
query_helper.assert_not_called()
|
||||
|
||||
test_time = dimmer.FADE_TIME_ABS_MIN - _TD_ONE_MS
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_fade_off_time(test_time)
|
||||
query_helper.assert_not_called()
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_fade_on_time(test_time)
|
||||
query_helper.assert_not_called()
|
||||
|
||||
test_time = dimmer.GENTLE_TIME_ABS_MIN - _TD_ONE_MS
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_gentle_off_time(test_time)
|
||||
query_helper.assert_not_called()
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_gentle_on_time(test_time)
|
||||
query_helper.assert_not_called()
|
||||
|
||||
test_rate = dimmer.RAMP_RATE_ABS_MIN - 1
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_ramp_rate(test_rate)
|
||||
query_helper.assert_not_called()
|
||||
|
||||
|
||||
@dimmer_iot
|
||||
async def test_dimmer_setters_max_oob(dev: IotDimmer, mocker: MockerFixture):
|
||||
dimmer: Dimmer = dev.modules[Module.IotDimmer]
|
||||
query_helper = mocker.patch("kasa.iot.IotDimmer._query_helper")
|
||||
|
||||
test_threshold = dimmer.THRESHOLD_ABS_MAX + 1
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_threshold_min(test_threshold)
|
||||
query_helper.assert_not_called()
|
||||
|
||||
test_time = dimmer.FADE_TIME_ABS_MAX + _TD_ONE_MS
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_fade_off_time(test_time)
|
||||
query_helper.assert_not_called()
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_fade_on_time(test_time)
|
||||
query_helper.assert_not_called()
|
||||
|
||||
test_time = dimmer.GENTLE_TIME_ABS_MAX + _TD_ONE_MS
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_gentle_off_time(test_time)
|
||||
query_helper.assert_not_called()
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_gentle_on_time(test_time)
|
||||
query_helper.assert_not_called()
|
||||
|
||||
test_rate = dimmer.RAMP_RATE_ABS_MAX + 1
|
||||
with pytest.raises(KasaException):
|
||||
await dimmer.set_ramp_rate(test_rate)
|
||||
query_helper.assert_not_called()
|
Loading…
x
Reference in New Issue
Block a user