mirror of
https://github.com/python-kasa/python-kasa.git
synced 2024-12-22 19:23:34 +00:00
Fix warnings in our test suite (#1246)
Co-authored-by: Steven B <51370195+sdb9696@users.noreply.github.com>
This commit is contained in:
parent
157ad8e807
commit
a82ee56a27
@ -484,11 +484,11 @@ class Device(ABC):
|
|||||||
|
|
||||||
_deprecated_device_type_attributes = {
|
_deprecated_device_type_attributes = {
|
||||||
# is_type
|
# is_type
|
||||||
"is_bulb": (Module.Light, DeviceType.Bulb),
|
"is_bulb": (None, DeviceType.Bulb),
|
||||||
"is_dimmer": (Module.Light, DeviceType.Dimmer),
|
"is_dimmer": (None, DeviceType.Dimmer),
|
||||||
"is_light_strip": (Module.LightEffect, DeviceType.LightStrip),
|
"is_light_strip": (None, DeviceType.LightStrip),
|
||||||
"is_plug": (Module.Led, DeviceType.Plug),
|
"is_plug": (None, DeviceType.Plug),
|
||||||
"is_wallswitch": (Module.Led, DeviceType.WallSwitch),
|
"is_wallswitch": (None, DeviceType.WallSwitch),
|
||||||
"is_strip": (None, DeviceType.Strip),
|
"is_strip": (None, DeviceType.Strip),
|
||||||
"is_strip_socket": (None, DeviceType.StripSocket),
|
"is_strip_socket": (None, DeviceType.StripSocket),
|
||||||
}
|
}
|
||||||
@ -503,7 +503,9 @@ class Device(ABC):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
for attr in attrs:
|
for attr in attrs:
|
||||||
if hasattr(check, attr):
|
# Use dir() as opposed to hasattr() to avoid raising exceptions
|
||||||
|
# from properties
|
||||||
|
if attr in dir(check):
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@ -552,10 +554,7 @@ class Device(ABC):
|
|||||||
def __getattr__(self, name: str) -> Any:
|
def __getattr__(self, name: str) -> Any:
|
||||||
# is_device_type
|
# is_device_type
|
||||||
if dep_device_type_attr := self._deprecated_device_type_attributes.get(name):
|
if dep_device_type_attr := self._deprecated_device_type_attributes.get(name):
|
||||||
module = dep_device_type_attr[0]
|
msg = f"{name} is deprecated, use device_type property instead"
|
||||||
msg = f"{name} is deprecated"
|
|
||||||
if module:
|
|
||||||
msg += f", use: {module} in device.modules instead"
|
|
||||||
warn(msg, DeprecationWarning, stacklevel=2)
|
warn(msg, DeprecationWarning, stacklevel=2)
|
||||||
return self.device_type == dep_device_type_attr[1]
|
return self.device_type == dep_device_type_attr[1]
|
||||||
# Other deprecated attributes
|
# Other deprecated attributes
|
||||||
|
@ -33,6 +33,7 @@ class FakeSmartTransport(BaseTransport):
|
|||||||
warn_fixture_missing_methods=True,
|
warn_fixture_missing_methods=True,
|
||||||
fix_incomplete_fixture_lists=True,
|
fix_incomplete_fixture_lists=True,
|
||||||
is_child=False,
|
is_child=False,
|
||||||
|
get_child_fixtures=True,
|
||||||
):
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
config=DeviceConfig(
|
config=DeviceConfig(
|
||||||
@ -48,9 +49,10 @@ class FakeSmartTransport(BaseTransport):
|
|||||||
# child are then still reflected on the parent's lis of child device in
|
# child are then still reflected on the parent's lis of child device in
|
||||||
if not is_child:
|
if not is_child:
|
||||||
self.info = copy.deepcopy(info)
|
self.info = copy.deepcopy(info)
|
||||||
self.child_protocols = self._get_child_protocols(
|
if get_child_fixtures:
|
||||||
self.info, self.fixture_name, "get_child_device_list"
|
self.child_protocols = self._get_child_protocols(
|
||||||
)
|
self.info, self.fixture_name, "get_child_device_list"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.info = info
|
self.info = info
|
||||||
if not component_nego_not_included:
|
if not component_nego_not_included:
|
||||||
@ -220,10 +222,7 @@ class FakeSmartTransport(BaseTransport):
|
|||||||
"""Handle control_child command."""
|
"""Handle control_child command."""
|
||||||
device_id = params.get("device_id")
|
device_id = params.get("device_id")
|
||||||
if device_id not in self.child_protocols:
|
if device_id not in self.child_protocols:
|
||||||
warn(
|
# no need to warn as the warning was raised during protocol init
|
||||||
f"Could not find child fixture {device_id} in {self.fixture_name}",
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self._handle_control_child_missing(params)
|
return self._handle_control_child_missing(params)
|
||||||
|
|
||||||
child_protocol: SmartProtocol = self.child_protocols[device_id]
|
child_protocol: SmartProtocol = self.child_protocols[device_id]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from kasa import Module, SmartDevice
|
from kasa import Device, Module
|
||||||
|
|
||||||
from ...device_fixtures import parametrize
|
from ...device_fixtures import parametrize
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ contact = parametrize(
|
|||||||
("is_open", bool),
|
("is_open", bool),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_contact_features(dev: SmartDevice, feature, type):
|
async def test_contact_features(dev: Device, feature, type):
|
||||||
"""Test that features are registered and work as expected."""
|
"""Test that features are registered and work as expected."""
|
||||||
contact = dev.modules.get(Module.ContactSensor)
|
contact = dev.modules.get(Module.ContactSensor)
|
||||||
assert contact is not None
|
assert contact is not None
|
||||||
|
@ -71,7 +71,7 @@ async def test_light_effect_brightness(
|
|||||||
|
|
||||||
if effect_active:
|
if effect_active:
|
||||||
assert light_effect.is_active
|
assert light_effect.is_active
|
||||||
assert light_effect.brightness == dev.brightness
|
assert light_effect.brightness == light_module.brightness
|
||||||
|
|
||||||
light_effect_set_brightness.assert_called_with(10)
|
light_effect_set_brightness.assert_called_with(10)
|
||||||
mock_light_effect_call.assert_called_with(
|
mock_light_effect_call.assert_called_with(
|
||||||
|
@ -86,7 +86,7 @@ async def test_light_effect_brightness(
|
|||||||
|
|
||||||
if effect_active:
|
if effect_active:
|
||||||
assert light_effect.is_active
|
assert light_effect.is_active
|
||||||
assert light_effect.brightness == dev.brightness
|
assert light_effect.brightness == light_module.brightness
|
||||||
|
|
||||||
light_effect_set_brightness.assert_called_with(10)
|
light_effect_set_brightness.assert_called_with(10)
|
||||||
mock_light_effect_call.assert_called_with(
|
mock_light_effect_call.assert_called_with(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from kasa import Module, SmartDevice
|
from kasa import Device, Module
|
||||||
|
|
||||||
from ...device_fixtures import parametrize
|
from ...device_fixtures import parametrize
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ motion = parametrize(
|
|||||||
("motion_detected", bool),
|
("motion_detected", bool),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_motion_features(dev: SmartDevice, feature, type):
|
async def test_motion_features(dev: Device, feature, type):
|
||||||
"""Test that features are registered and work as expected."""
|
"""Test that features are registered and work as expected."""
|
||||||
motion = dev.modules.get(Module.MotionSensor)
|
motion = dev.modules.get(Module.MotionSensor)
|
||||||
assert motion is not None
|
assert motion is not None
|
||||||
|
@ -13,6 +13,7 @@ from voluptuous import (
|
|||||||
|
|
||||||
from kasa import Device, DeviceType, IotLightPreset, KasaException, LightState, Module
|
from kasa import Device, DeviceType, IotLightPreset, KasaException, LightState, Module
|
||||||
from kasa.iot import IotBulb, IotDimmer
|
from kasa.iot import IotBulb, IotDimmer
|
||||||
|
from kasa.iot.modules import LightPreset as IotLightPresetModule
|
||||||
|
|
||||||
from .conftest import (
|
from .conftest import (
|
||||||
bulb,
|
bulb,
|
||||||
@ -39,11 +40,6 @@ async def test_bulb_sysinfo(dev: Device):
|
|||||||
|
|
||||||
assert dev.model is not None
|
assert dev.model is not None
|
||||||
|
|
||||||
# TODO: remove special handling for lightstrip
|
|
||||||
if not dev.is_light_strip:
|
|
||||||
assert dev.device_type == DeviceType.Bulb
|
|
||||||
assert dev.is_bulb
|
|
||||||
|
|
||||||
|
|
||||||
@bulb
|
@bulb
|
||||||
async def test_state_attributes(dev: Device):
|
async def test_state_attributes(dev: Device):
|
||||||
@ -88,7 +84,9 @@ async def test_hsv(dev: Device, turn_on):
|
|||||||
@color_bulb_iot
|
@color_bulb_iot
|
||||||
async def test_set_hsv_transition(dev: IotBulb, mocker):
|
async def test_set_hsv_transition(dev: IotBulb, mocker):
|
||||||
set_light_state = mocker.patch("kasa.iot.IotBulb._set_light_state")
|
set_light_state = mocker.patch("kasa.iot.IotBulb._set_light_state")
|
||||||
await dev.set_hsv(10, 10, 100, transition=1000)
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
|
await light.set_hsv(10, 10, 100, transition=1000)
|
||||||
|
|
||||||
set_light_state.assert_called_with(
|
set_light_state.assert_called_with(
|
||||||
{"hue": 10, "saturation": 10, "brightness": 100, "color_temp": 0},
|
{"hue": 10, "saturation": 10, "brightness": 100, "color_temp": 0},
|
||||||
@ -226,7 +224,9 @@ async def test_try_set_colortemp(dev: Device, turn_on):
|
|||||||
@variable_temp_iot
|
@variable_temp_iot
|
||||||
async def test_set_color_temp_transition(dev: IotBulb, mocker):
|
async def test_set_color_temp_transition(dev: IotBulb, mocker):
|
||||||
set_light_state = mocker.patch("kasa.iot.IotBulb._set_light_state")
|
set_light_state = mocker.patch("kasa.iot.IotBulb._set_light_state")
|
||||||
await dev.set_color_temp(2700, transition=100)
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
|
await light.set_color_temp(2700, transition=100)
|
||||||
|
|
||||||
set_light_state.assert_called_with({"color_temp": 2700}, transition=100)
|
set_light_state.assert_called_with({"color_temp": 2700}, transition=100)
|
||||||
|
|
||||||
@ -234,8 +234,9 @@ async def test_set_color_temp_transition(dev: IotBulb, mocker):
|
|||||||
@variable_temp_iot
|
@variable_temp_iot
|
||||||
async def test_unknown_temp_range(dev: IotBulb, monkeypatch, caplog):
|
async def test_unknown_temp_range(dev: IotBulb, monkeypatch, caplog):
|
||||||
monkeypatch.setitem(dev._sys_info, "model", "unknown bulb")
|
monkeypatch.setitem(dev._sys_info, "model", "unknown bulb")
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
assert dev.valid_temperature_range == (2700, 5000)
|
assert light
|
||||||
|
assert light.valid_temperature_range == (2700, 5000)
|
||||||
assert "Unknown color temperature range, fallback to 2700-5000" in caplog.text
|
assert "Unknown color temperature range, fallback to 2700-5000" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
@ -278,19 +279,21 @@ async def test_non_variable_temp(dev: Device):
|
|||||||
@turn_on
|
@turn_on
|
||||||
async def test_dimmable_brightness(dev: IotBulb, turn_on):
|
async def test_dimmable_brightness(dev: IotBulb, turn_on):
|
||||||
assert isinstance(dev, (IotBulb, IotDimmer))
|
assert isinstance(dev, (IotBulb, IotDimmer))
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
await handle_turn_on(dev, turn_on)
|
await handle_turn_on(dev, turn_on)
|
||||||
assert dev._is_dimmable
|
assert dev._is_dimmable
|
||||||
|
|
||||||
await dev.set_brightness(50)
|
await light.set_brightness(50)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.brightness == 50
|
assert light.brightness == 50
|
||||||
|
|
||||||
await dev.set_brightness(10)
|
await light.set_brightness(10)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.brightness == 10
|
assert light.brightness == 10
|
||||||
|
|
||||||
with pytest.raises(TypeError, match="Brightness must be an integer"):
|
with pytest.raises(TypeError, match="Brightness must be an integer"):
|
||||||
await dev.set_brightness("foo") # type: ignore[arg-type]
|
await light.set_brightness("foo") # type: ignore[arg-type]
|
||||||
|
|
||||||
|
|
||||||
@bulb_iot
|
@bulb_iot
|
||||||
@ -308,7 +311,9 @@ async def test_turn_on_transition(dev: IotBulb, mocker):
|
|||||||
@bulb_iot
|
@bulb_iot
|
||||||
async def test_dimmable_brightness_transition(dev: IotBulb, mocker):
|
async def test_dimmable_brightness_transition(dev: IotBulb, mocker):
|
||||||
set_light_state = mocker.patch("kasa.iot.IotBulb._set_light_state")
|
set_light_state = mocker.patch("kasa.iot.IotBulb._set_light_state")
|
||||||
await dev.set_brightness(10, transition=1000)
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
|
await light.set_brightness(10, transition=1000)
|
||||||
|
|
||||||
set_light_state.assert_called_with({"brightness": 10, "on_off": 1}, transition=1000)
|
set_light_state.assert_called_with({"brightness": 10, "on_off": 1}, transition=1000)
|
||||||
|
|
||||||
@ -316,28 +321,30 @@ async def test_dimmable_brightness_transition(dev: IotBulb, mocker):
|
|||||||
@dimmable_iot
|
@dimmable_iot
|
||||||
async def test_invalid_brightness(dev: IotBulb):
|
async def test_invalid_brightness(dev: IotBulb):
|
||||||
assert dev._is_dimmable
|
assert dev._is_dimmable
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match=re.escape("Invalid brightness value: 110 (valid range: 0-100%)"),
|
match=re.escape("Invalid brightness value: 110 (valid range: 0-100%)"),
|
||||||
):
|
):
|
||||||
await dev.set_brightness(110)
|
await light.set_brightness(110)
|
||||||
|
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match=re.escape("Invalid brightness value: -100 (valid range: 0-100%)"),
|
match=re.escape("Invalid brightness value: -100 (valid range: 0-100%)"),
|
||||||
):
|
):
|
||||||
await dev.set_brightness(-100)
|
await light.set_brightness(-100)
|
||||||
|
|
||||||
|
|
||||||
@non_dimmable_iot
|
@non_dimmable_iot
|
||||||
async def test_non_dimmable(dev: IotBulb):
|
async def test_non_dimmable(dev: IotBulb):
|
||||||
assert not dev._is_dimmable
|
assert not dev._is_dimmable
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
with pytest.raises(KasaException):
|
with pytest.raises(KasaException):
|
||||||
assert dev.brightness == 0
|
assert light.brightness == 0
|
||||||
with pytest.raises(KasaException):
|
with pytest.raises(KasaException):
|
||||||
await dev.set_brightness(100)
|
await light.set_brightness(100)
|
||||||
|
|
||||||
|
|
||||||
@bulb_iot
|
@bulb_iot
|
||||||
@ -357,7 +364,10 @@ async def test_ignore_default_not_set_without_color_mode_change_turn_on(
|
|||||||
|
|
||||||
@bulb_iot
|
@bulb_iot
|
||||||
async def test_list_presets(dev: IotBulb):
|
async def test_list_presets(dev: IotBulb):
|
||||||
presets = dev.presets
|
light_preset = dev.modules.get(Module.LightPreset)
|
||||||
|
assert light_preset
|
||||||
|
assert isinstance(light_preset, IotLightPresetModule)
|
||||||
|
presets = light_preset._deprecated_presets
|
||||||
# Light strip devices may list some light effects along with normal presets but these
|
# Light strip devices may list some light effects along with normal presets but these
|
||||||
# are handled by the LightEffect module so exclude preferred states with id
|
# are handled by the LightEffect module so exclude preferred states with id
|
||||||
raw_presets = [
|
raw_presets = [
|
||||||
@ -376,9 +386,13 @@ async def test_list_presets(dev: IotBulb):
|
|||||||
@bulb_iot
|
@bulb_iot
|
||||||
async def test_modify_preset(dev: IotBulb, mocker):
|
async def test_modify_preset(dev: IotBulb, mocker):
|
||||||
"""Verify that modifying preset calls the and exceptions are raised properly."""
|
"""Verify that modifying preset calls the and exceptions are raised properly."""
|
||||||
if not dev.presets:
|
if (
|
||||||
|
not (light_preset := dev.modules.get(Module.LightPreset))
|
||||||
|
or not light_preset._deprecated_presets
|
||||||
|
):
|
||||||
pytest.skip("Some strips do not support presets")
|
pytest.skip("Some strips do not support presets")
|
||||||
|
|
||||||
|
assert isinstance(light_preset, IotLightPresetModule)
|
||||||
data: dict[str, int | None] = {
|
data: dict[str, int | None] = {
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"brightness": 10,
|
"brightness": 10,
|
||||||
@ -394,12 +408,12 @@ async def test_modify_preset(dev: IotBulb, mocker):
|
|||||||
assert preset.saturation == 0
|
assert preset.saturation == 0
|
||||||
assert preset.color_temp == 0
|
assert preset.color_temp == 0
|
||||||
|
|
||||||
await dev.save_preset(preset)
|
await light_preset._deprecated_save_preset(preset)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.presets[0].brightness == 10
|
assert light_preset._deprecated_presets[0].brightness == 10
|
||||||
|
|
||||||
with pytest.raises(KasaException):
|
with pytest.raises(KasaException):
|
||||||
await dev.save_preset(
|
await light_preset._deprecated_save_preset(
|
||||||
IotLightPreset(index=5, hue=0, brightness=0, saturation=0, color_temp=0) # type: ignore[call-arg]
|
IotLightPreset(index=5, hue=0, brightness=0, saturation=0, color_temp=0) # type: ignore[call-arg]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -420,11 +434,14 @@ async def test_modify_preset(dev: IotBulb, mocker):
|
|||||||
)
|
)
|
||||||
async def test_modify_preset_payloads(dev: IotBulb, preset, payload, mocker):
|
async def test_modify_preset_payloads(dev: IotBulb, preset, payload, mocker):
|
||||||
"""Test that modify preset payloads ignore none values."""
|
"""Test that modify preset payloads ignore none values."""
|
||||||
if not dev.presets:
|
if (
|
||||||
|
not (light_preset := dev.modules.get(Module.LightPreset))
|
||||||
|
or not light_preset._deprecated_presets
|
||||||
|
):
|
||||||
pytest.skip("Some strips do not support presets")
|
pytest.skip("Some strips do not support presets")
|
||||||
|
|
||||||
query_helper = mocker.patch("kasa.iot.IotBulb._query_helper")
|
query_helper = mocker.patch("kasa.iot.IotBulb._query_helper")
|
||||||
await dev.save_preset(preset)
|
await light_preset._deprecated_save_preset(preset)
|
||||||
query_helper.assert_called_with(dev.LIGHT_SERVICE, "set_preferred_state", payload)
|
query_helper.assert_called_with(dev.LIGHT_SERVICE, "set_preferred_state", payload)
|
||||||
|
|
||||||
|
|
||||||
@ -476,6 +493,4 @@ SYSINFO_SCHEMA_BULB = SYSINFO_SCHEMA.extend(
|
|||||||
|
|
||||||
@bulb
|
@bulb
|
||||||
def test_device_type_bulb(dev: Device):
|
def test_device_type_bulb(dev: Device):
|
||||||
if dev.is_light_strip:
|
assert dev.device_type in {DeviceType.Bulb, DeviceType.LightStrip}
|
||||||
pytest.skip("bulb has also lightstrips to test the api")
|
|
||||||
assert dev.device_type == DeviceType.Bulb
|
|
||||||
|
@ -6,7 +6,7 @@ import importlib
|
|||||||
import inspect
|
import inspect
|
||||||
import pkgutil
|
import pkgutil
|
||||||
import sys
|
import sys
|
||||||
from contextlib import AbstractContextManager
|
from contextlib import AbstractContextManager, nullcontext
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -170,15 +170,22 @@ async def _test_attribute(
|
|||||||
dev: Device, attribute_name, is_expected, module_name, *args, will_raise=False
|
dev: Device, attribute_name, is_expected, module_name, *args, will_raise=False
|
||||||
):
|
):
|
||||||
if is_expected and will_raise:
|
if is_expected and will_raise:
|
||||||
ctx: AbstractContextManager = pytest.raises(will_raise)
|
ctx: AbstractContextManager | nullcontext = pytest.raises(will_raise)
|
||||||
|
dep_context: pytest.WarningsRecorder | nullcontext = pytest.deprecated_call(
|
||||||
|
match=(f"{attribute_name} is deprecated, use:")
|
||||||
|
)
|
||||||
elif is_expected:
|
elif is_expected:
|
||||||
ctx = pytest.deprecated_call(match=(f"{attribute_name} is deprecated, use:"))
|
ctx = nullcontext()
|
||||||
|
dep_context = pytest.deprecated_call(
|
||||||
|
match=(f"{attribute_name} is deprecated, use:")
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
ctx = pytest.raises(
|
ctx = pytest.raises(
|
||||||
AttributeError, match=f"Device has no attribute '{attribute_name}'"
|
AttributeError, match=f"Device has no attribute '{attribute_name}'"
|
||||||
)
|
)
|
||||||
|
dep_context = nullcontext()
|
||||||
|
|
||||||
with ctx:
|
with dep_context, ctx:
|
||||||
if args:
|
if args:
|
||||||
await getattr(dev, attribute_name)(*args)
|
await getattr(dev, attribute_name)(*args)
|
||||||
else:
|
else:
|
||||||
@ -267,16 +274,19 @@ async def test_deprecated_light_preset_attributes(dev: Device):
|
|||||||
await _test_attribute(dev, "presets", bool(preset), "LightPreset", will_raise=exc)
|
await _test_attribute(dev, "presets", bool(preset), "LightPreset", will_raise=exc)
|
||||||
|
|
||||||
exc = None
|
exc = None
|
||||||
|
is_expected = bool(preset)
|
||||||
# deprecated save_preset not implemented for smart devices as it's unlikely anyone
|
# deprecated save_preset not implemented for smart devices as it's unlikely anyone
|
||||||
# has an existing reliance on this for the newer devices.
|
# has an existing reliance on this for the newer devices.
|
||||||
if not preset or isinstance(dev, SmartDevice):
|
if isinstance(dev, SmartDevice):
|
||||||
exc = AttributeError
|
is_expected = False
|
||||||
elif len(preset.preset_states_list) == 0:
|
|
||||||
|
if preset and len(preset.preset_states_list) == 0:
|
||||||
exc = KasaException
|
exc = KasaException
|
||||||
|
|
||||||
await _test_attribute(
|
await _test_attribute(
|
||||||
dev,
|
dev,
|
||||||
"save_preset",
|
"save_preset",
|
||||||
bool(preset),
|
is_expected,
|
||||||
"LightPreset",
|
"LightPreset",
|
||||||
IotLightPreset(index=0, hue=100, brightness=100, saturation=0, color_temp=0), # type: ignore[call-arg]
|
IotLightPreset(index=0, hue=100, brightness=100, saturation=0, color_temp=0), # type: ignore[call-arg]
|
||||||
will_raise=exc,
|
will_raise=exc,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from kasa import DeviceType
|
from kasa import DeviceType, Module
|
||||||
from kasa.iot import IotDimmer
|
from kasa.iot import IotDimmer
|
||||||
|
|
||||||
from .conftest import dimmer_iot, handle_turn_on, turn_on
|
from .conftest import dimmer_iot, handle_turn_on, turn_on
|
||||||
@ -8,28 +8,32 @@ from .conftest import dimmer_iot, handle_turn_on, turn_on
|
|||||||
|
|
||||||
@dimmer_iot
|
@dimmer_iot
|
||||||
async def test_set_brightness(dev):
|
async def test_set_brightness(dev):
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
await handle_turn_on(dev, False)
|
await handle_turn_on(dev, False)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.is_on is False
|
assert dev.is_on is False
|
||||||
|
|
||||||
await dev.set_brightness(99)
|
await light.set_brightness(99)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.brightness == 99
|
assert light.brightness == 99
|
||||||
assert dev.is_on is True
|
assert dev.is_on is True
|
||||||
|
|
||||||
await dev.set_brightness(0)
|
await light.set_brightness(0)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.brightness == 99
|
assert light.brightness == 99
|
||||||
assert dev.is_on is False
|
assert dev.is_on is False
|
||||||
|
|
||||||
|
|
||||||
@dimmer_iot
|
@dimmer_iot
|
||||||
@turn_on
|
@turn_on
|
||||||
async def test_set_brightness_transition(dev, turn_on, mocker):
|
async def test_set_brightness_transition(dev, turn_on, mocker):
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
await handle_turn_on(dev, turn_on)
|
await handle_turn_on(dev, turn_on)
|
||||||
query_helper = mocker.spy(IotDimmer, "_query_helper")
|
query_helper = mocker.spy(IotDimmer, "_query_helper")
|
||||||
|
|
||||||
await dev.set_brightness(99, transition=1000)
|
await light.set_brightness(99, transition=1000)
|
||||||
query_helper.assert_called_with(
|
query_helper.assert_called_with(
|
||||||
mocker.ANY,
|
mocker.ANY,
|
||||||
"smartlife.iot.dimmer",
|
"smartlife.iot.dimmer",
|
||||||
@ -37,39 +41,45 @@ async def test_set_brightness_transition(dev, turn_on, mocker):
|
|||||||
{"brightness": 99, "duration": 1000},
|
{"brightness": 99, "duration": 1000},
|
||||||
)
|
)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.brightness == 99
|
assert light.brightness == 99
|
||||||
assert dev.is_on
|
assert dev.is_on
|
||||||
|
|
||||||
await dev.set_brightness(0, transition=1000)
|
await light.set_brightness(0, transition=1000)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.is_on is False
|
assert dev.is_on is False
|
||||||
|
|
||||||
|
|
||||||
@dimmer_iot
|
@dimmer_iot
|
||||||
async def test_set_brightness_invalid(dev):
|
async def test_set_brightness_invalid(dev):
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
for invalid_brightness in [-1, 101]:
|
for invalid_brightness in [-1, 101]:
|
||||||
with pytest.raises(ValueError, match="Invalid brightness"):
|
with pytest.raises(ValueError, match="Invalid brightness"):
|
||||||
await dev.set_brightness(invalid_brightness)
|
await light.set_brightness(invalid_brightness)
|
||||||
|
|
||||||
for invalid_type in [0.5, "foo"]:
|
for invalid_type in [0.5, "foo"]:
|
||||||
with pytest.raises(TypeError, match="Brightness must be an integer"):
|
with pytest.raises(TypeError, match="Brightness must be an integer"):
|
||||||
await dev.set_brightness(invalid_type)
|
await light.set_brightness(invalid_type)
|
||||||
|
|
||||||
|
|
||||||
@dimmer_iot
|
@dimmer_iot
|
||||||
async def test_set_brightness_invalid_transition(dev):
|
async def test_set_brightness_invalid_transition(dev):
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
for invalid_transition in [-1]:
|
for invalid_transition in [-1]:
|
||||||
with pytest.raises(ValueError, match="Transition value .+? is not valid."):
|
with pytest.raises(ValueError, match="Transition value .+? is not valid."):
|
||||||
await dev.set_brightness(1, transition=invalid_transition)
|
await light.set_brightness(1, transition=invalid_transition)
|
||||||
for invalid_type in [0.5, "foo"]:
|
for invalid_type in [0.5, "foo"]:
|
||||||
with pytest.raises(TypeError, match="Transition must be integer"):
|
with pytest.raises(TypeError, match="Transition must be integer"):
|
||||||
await dev.set_brightness(1, transition=invalid_type)
|
await light.set_brightness(1, transition=invalid_type)
|
||||||
|
|
||||||
|
|
||||||
@dimmer_iot
|
@dimmer_iot
|
||||||
async def test_turn_on_transition(dev, mocker):
|
async def test_turn_on_transition(dev, mocker):
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
query_helper = mocker.spy(IotDimmer, "_query_helper")
|
query_helper = mocker.spy(IotDimmer, "_query_helper")
|
||||||
original_brightness = dev.brightness
|
original_brightness = light.brightness
|
||||||
|
|
||||||
await dev.turn_on(transition=1000)
|
await dev.turn_on(transition=1000)
|
||||||
query_helper.assert_called_with(
|
query_helper.assert_called_with(
|
||||||
@ -80,20 +90,22 @@ async def test_turn_on_transition(dev, mocker):
|
|||||||
)
|
)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.is_on
|
assert dev.is_on
|
||||||
assert dev.brightness == original_brightness
|
assert light.brightness == original_brightness
|
||||||
|
|
||||||
|
|
||||||
@dimmer_iot
|
@dimmer_iot
|
||||||
async def test_turn_off_transition(dev, mocker):
|
async def test_turn_off_transition(dev, mocker):
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
await handle_turn_on(dev, True)
|
await handle_turn_on(dev, True)
|
||||||
query_helper = mocker.spy(IotDimmer, "_query_helper")
|
query_helper = mocker.spy(IotDimmer, "_query_helper")
|
||||||
original_brightness = dev.brightness
|
original_brightness = light.brightness
|
||||||
|
|
||||||
await dev.turn_off(transition=1000)
|
await dev.turn_off(transition=1000)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
|
|
||||||
assert dev.is_off
|
assert dev.is_off
|
||||||
assert dev.brightness == original_brightness
|
assert light.brightness == original_brightness
|
||||||
query_helper.assert_called_with(
|
query_helper.assert_called_with(
|
||||||
mocker.ANY,
|
mocker.ANY,
|
||||||
"smartlife.iot.dimmer",
|
"smartlife.iot.dimmer",
|
||||||
@ -105,6 +117,8 @@ async def test_turn_off_transition(dev, mocker):
|
|||||||
@dimmer_iot
|
@dimmer_iot
|
||||||
@turn_on
|
@turn_on
|
||||||
async def test_set_dimmer_transition(dev, turn_on, mocker):
|
async def test_set_dimmer_transition(dev, turn_on, mocker):
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
await handle_turn_on(dev, turn_on)
|
await handle_turn_on(dev, turn_on)
|
||||||
query_helper = mocker.spy(IotDimmer, "_query_helper")
|
query_helper = mocker.spy(IotDimmer, "_query_helper")
|
||||||
|
|
||||||
@ -117,21 +131,23 @@ async def test_set_dimmer_transition(dev, turn_on, mocker):
|
|||||||
)
|
)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.is_on
|
assert dev.is_on
|
||||||
assert dev.brightness == 99
|
assert light.brightness == 99
|
||||||
|
|
||||||
|
|
||||||
@dimmer_iot
|
@dimmer_iot
|
||||||
@turn_on
|
@turn_on
|
||||||
async def test_set_dimmer_transition_to_off(dev, turn_on, mocker):
|
async def test_set_dimmer_transition_to_off(dev, turn_on, mocker):
|
||||||
|
light = dev.modules.get(Module.Light)
|
||||||
|
assert light
|
||||||
await handle_turn_on(dev, turn_on)
|
await handle_turn_on(dev, turn_on)
|
||||||
original_brightness = dev.brightness
|
original_brightness = light.brightness
|
||||||
query_helper = mocker.spy(IotDimmer, "_query_helper")
|
query_helper = mocker.spy(IotDimmer, "_query_helper")
|
||||||
|
|
||||||
await dev.set_dimmer_transition(0, 1000)
|
await dev.set_dimmer_transition(0, 1000)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
|
|
||||||
assert dev.is_off
|
assert dev.is_off
|
||||||
assert dev.brightness == original_brightness
|
assert light.brightness == original_brightness
|
||||||
query_helper.assert_called_with(
|
query_helper.assert_called_with(
|
||||||
mocker.ANY,
|
mocker.ANY,
|
||||||
"smartlife.iot.dimmer",
|
"smartlife.iot.dimmer",
|
||||||
|
@ -81,14 +81,14 @@ UNSUPPORTED = {
|
|||||||
@wallswitch_iot
|
@wallswitch_iot
|
||||||
async def test_type_detection_switch(dev: Device):
|
async def test_type_detection_switch(dev: Device):
|
||||||
d = Discover._get_device_class(dev._last_update)("localhost")
|
d = Discover._get_device_class(dev._last_update)("localhost")
|
||||||
assert d.is_wallswitch
|
with pytest.deprecated_call(match="use device_type property instead"):
|
||||||
assert d.device_type == DeviceType.WallSwitch
|
assert d.is_wallswitch
|
||||||
|
assert d.device_type is DeviceType.WallSwitch
|
||||||
|
|
||||||
|
|
||||||
@plug_iot
|
@plug_iot
|
||||||
async def test_type_detection_plug(dev: Device):
|
async def test_type_detection_plug(dev: Device):
|
||||||
d = Discover._get_device_class(dev._last_update)("localhost")
|
d = Discover._get_device_class(dev._last_update)("localhost")
|
||||||
assert d.is_plug
|
|
||||||
assert d.device_type == DeviceType.Plug
|
assert d.device_type == DeviceType.Plug
|
||||||
|
|
||||||
|
|
||||||
@ -96,29 +96,26 @@ async def test_type_detection_plug(dev: Device):
|
|||||||
async def test_type_detection_bulb(dev: Device):
|
async def test_type_detection_bulb(dev: Device):
|
||||||
d = Discover._get_device_class(dev._last_update)("localhost")
|
d = Discover._get_device_class(dev._last_update)("localhost")
|
||||||
# TODO: light_strip is a special case for now to force bulb tests on it
|
# TODO: light_strip is a special case for now to force bulb tests on it
|
||||||
if not d.is_light_strip:
|
|
||||||
assert d.is_bulb
|
if d.device_type is not DeviceType.LightStrip:
|
||||||
assert d.device_type == DeviceType.Bulb
|
assert d.device_type == DeviceType.Bulb
|
||||||
|
|
||||||
|
|
||||||
@strip_iot
|
@strip_iot
|
||||||
async def test_type_detection_strip(dev: Device):
|
async def test_type_detection_strip(dev: Device):
|
||||||
d = Discover._get_device_class(dev._last_update)("localhost")
|
d = Discover._get_device_class(dev._last_update)("localhost")
|
||||||
assert d.is_strip
|
|
||||||
assert d.device_type == DeviceType.Strip
|
assert d.device_type == DeviceType.Strip
|
||||||
|
|
||||||
|
|
||||||
@dimmer_iot
|
@dimmer_iot
|
||||||
async def test_type_detection_dimmer(dev: Device):
|
async def test_type_detection_dimmer(dev: Device):
|
||||||
d = Discover._get_device_class(dev._last_update)("localhost")
|
d = Discover._get_device_class(dev._last_update)("localhost")
|
||||||
assert d.is_dimmer
|
|
||||||
assert d.device_type == DeviceType.Dimmer
|
assert d.device_type == DeviceType.Dimmer
|
||||||
|
|
||||||
|
|
||||||
@lightstrip_iot
|
@lightstrip_iot
|
||||||
async def test_type_detection_lightstrip(dev: Device):
|
async def test_type_detection_lightstrip(dev: Device):
|
||||||
d = Discover._get_device_class(dev._last_update)("localhost")
|
d = Discover._get_device_class(dev._last_update)("localhost")
|
||||||
assert d.is_light_strip
|
|
||||||
assert d.device_type == DeviceType.LightStrip
|
assert d.device_type == DeviceType.LightStrip
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ from voluptuous import (
|
|||||||
Schema,
|
Schema,
|
||||||
)
|
)
|
||||||
|
|
||||||
from kasa import Device, EmeterStatus, Module
|
from kasa import Device, DeviceType, EmeterStatus, Module
|
||||||
from kasa.interfaces.energy import Energy
|
from kasa.interfaces.energy import Energy
|
||||||
from kasa.iot import IotDevice, IotStrip
|
from kasa.iot import IotDevice, IotStrip
|
||||||
from kasa.iot.modules.emeter import Emeter
|
from kasa.iot.modules.emeter import Emeter
|
||||||
@ -61,20 +61,20 @@ async def test_get_emeter_realtime(dev):
|
|||||||
if not await mod._check_supported():
|
if not await mod._check_supported():
|
||||||
pytest.skip(f"Energy module not supported for {dev}.")
|
pytest.skip(f"Energy module not supported for {dev}.")
|
||||||
|
|
||||||
assert dev.has_emeter
|
emeter = dev.modules[Module.Energy]
|
||||||
|
|
||||||
current_emeter = await dev.get_emeter_realtime()
|
current_emeter = await emeter.get_status()
|
||||||
CURRENT_CONSUMPTION_SCHEMA(current_emeter)
|
CURRENT_CONSUMPTION_SCHEMA(current_emeter)
|
||||||
|
|
||||||
|
|
||||||
@has_emeter_iot
|
@has_emeter_iot
|
||||||
@pytest.mark.requires_dummy()
|
@pytest.mark.requires_dummy()
|
||||||
async def test_get_emeter_daily(dev):
|
async def test_get_emeter_daily(dev):
|
||||||
assert dev.has_emeter
|
emeter = dev.modules[Module.Energy]
|
||||||
|
|
||||||
assert await dev.get_emeter_daily(year=1900, month=1) == {}
|
assert await emeter.get_daily_stats(year=1900, month=1) == {}
|
||||||
|
|
||||||
d = await dev.get_emeter_daily()
|
d = await emeter.get_daily_stats()
|
||||||
assert len(d) > 0
|
assert len(d) > 0
|
||||||
|
|
||||||
k, v = d.popitem()
|
k, v = d.popitem()
|
||||||
@ -82,7 +82,7 @@ async def test_get_emeter_daily(dev):
|
|||||||
assert isinstance(v, float)
|
assert isinstance(v, float)
|
||||||
|
|
||||||
# Test kwh (energy, energy_wh)
|
# Test kwh (energy, energy_wh)
|
||||||
d = await dev.get_emeter_daily(kwh=False)
|
d = await emeter.get_daily_stats(kwh=False)
|
||||||
k2, v2 = d.popitem()
|
k2, v2 = d.popitem()
|
||||||
assert v * 1000 == v2
|
assert v * 1000 == v2
|
||||||
|
|
||||||
@ -90,11 +90,11 @@ async def test_get_emeter_daily(dev):
|
|||||||
@has_emeter_iot
|
@has_emeter_iot
|
||||||
@pytest.mark.requires_dummy()
|
@pytest.mark.requires_dummy()
|
||||||
async def test_get_emeter_monthly(dev):
|
async def test_get_emeter_monthly(dev):
|
||||||
assert dev.has_emeter
|
emeter = dev.modules[Module.Energy]
|
||||||
|
|
||||||
assert await dev.get_emeter_monthly(year=1900) == {}
|
assert await emeter.get_monthly_stats(year=1900) == {}
|
||||||
|
|
||||||
d = await dev.get_emeter_monthly()
|
d = await emeter.get_monthly_stats()
|
||||||
assert len(d) > 0
|
assert len(d) > 0
|
||||||
|
|
||||||
k, v = d.popitem()
|
k, v = d.popitem()
|
||||||
@ -102,23 +102,26 @@ async def test_get_emeter_monthly(dev):
|
|||||||
assert isinstance(v, float)
|
assert isinstance(v, float)
|
||||||
|
|
||||||
# Test kwh (energy, energy_wh)
|
# Test kwh (energy, energy_wh)
|
||||||
d = await dev.get_emeter_monthly(kwh=False)
|
d = await emeter.get_monthly_stats(kwh=False)
|
||||||
k2, v2 = d.popitem()
|
k2, v2 = d.popitem()
|
||||||
assert v * 1000 == v2
|
assert v * 1000 == v2
|
||||||
|
|
||||||
|
|
||||||
@has_emeter_iot
|
@has_emeter_iot
|
||||||
async def test_emeter_status(dev):
|
async def test_emeter_status(dev):
|
||||||
assert dev.has_emeter
|
emeter = dev.modules[Module.Energy]
|
||||||
|
|
||||||
d = await dev.get_emeter_realtime()
|
d = await emeter.get_status()
|
||||||
|
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
assert d["foo"]
|
assert d["foo"]
|
||||||
|
|
||||||
assert d["power_mw"] == d["power"] * 1000
|
assert d["power_mw"] == d["power"] * 1000
|
||||||
# bulbs have only power according to tplink simulator.
|
# bulbs have only power according to tplink simulator.
|
||||||
if not dev.is_bulb and not dev.is_light_strip:
|
if (
|
||||||
|
dev.device_type is not DeviceType.Bulb
|
||||||
|
and dev.device_type is not DeviceType.LightStrip
|
||||||
|
):
|
||||||
assert d["voltage_mv"] == d["voltage"] * 1000
|
assert d["voltage_mv"] == d["voltage"] * 1000
|
||||||
|
|
||||||
assert d["current_ma"] == d["current"] * 1000
|
assert d["current_ma"] == d["current"] * 1000
|
||||||
@ -128,19 +131,17 @@ async def test_emeter_status(dev):
|
|||||||
@pytest.mark.skip("not clearing your stats..")
|
@pytest.mark.skip("not clearing your stats..")
|
||||||
@has_emeter
|
@has_emeter
|
||||||
async def test_erase_emeter_stats(dev):
|
async def test_erase_emeter_stats(dev):
|
||||||
assert dev.has_emeter
|
emeter = dev.modules[Module.Energy]
|
||||||
|
|
||||||
await dev.erase_emeter()
|
await emeter.erase_emeter()
|
||||||
|
|
||||||
|
|
||||||
@has_emeter_iot
|
@has_emeter_iot
|
||||||
async def test_current_consumption(dev):
|
async def test_current_consumption(dev):
|
||||||
if dev.has_emeter:
|
emeter = dev.modules[Module.Energy]
|
||||||
x = dev.current_consumption
|
x = emeter.current_consumption
|
||||||
assert isinstance(x, float)
|
assert isinstance(x, float)
|
||||||
assert x >= 0.0
|
assert x >= 0.0
|
||||||
else:
|
|
||||||
assert dev.current_consumption is None
|
|
||||||
|
|
||||||
|
|
||||||
async def test_emeterstatus_missing_current():
|
async def test_emeterstatus_missing_current():
|
||||||
@ -180,7 +181,7 @@ async def test_emeter_daily():
|
|||||||
emeter_data["get_daystat"]["day_list"].append(
|
emeter_data["get_daystat"]["day_list"].append(
|
||||||
{"day": now.day, "energy_wh": 500, "month": now.month, "year": now.year}
|
{"day": now.day, "energy_wh": 500, "month": now.month, "year": now.year}
|
||||||
)
|
)
|
||||||
assert emeter.emeter_today == 0.500
|
assert emeter.consumption_today == 0.500
|
||||||
|
|
||||||
|
|
||||||
@has_emeter
|
@has_emeter
|
||||||
|
@ -16,7 +16,7 @@ from voluptuous import (
|
|||||||
Schema,
|
Schema,
|
||||||
)
|
)
|
||||||
|
|
||||||
from kasa import KasaException, Module
|
from kasa import DeviceType, KasaException, Module
|
||||||
from kasa.iot import IotDevice
|
from kasa.iot import IotDevice
|
||||||
from kasa.iot.iotmodule import _merge_dict
|
from kasa.iot.iotmodule import _merge_dict
|
||||||
|
|
||||||
@ -92,10 +92,8 @@ async def test_state_info(dev):
|
|||||||
@pytest.mark.requires_dummy()
|
@pytest.mark.requires_dummy()
|
||||||
@device_iot
|
@device_iot
|
||||||
async def test_invalid_connection(mocker, dev):
|
async def test_invalid_connection(mocker, dev):
|
||||||
with (
|
mocker.patch.object(FakeIotProtocol, "query", side_effect=KasaException)
|
||||||
mocker.patch.object(FakeIotProtocol, "query", side_effect=KasaException),
|
with pytest.raises(KasaException):
|
||||||
pytest.raises(KasaException),
|
|
||||||
):
|
|
||||||
await dev.update()
|
await dev.update()
|
||||||
|
|
||||||
|
|
||||||
@ -169,7 +167,7 @@ async def test_state(dev, turn_on):
|
|||||||
async def test_on_since(dev, turn_on):
|
async def test_on_since(dev, turn_on):
|
||||||
await handle_turn_on(dev, turn_on)
|
await handle_turn_on(dev, turn_on)
|
||||||
orig_state = dev.is_on
|
orig_state = dev.is_on
|
||||||
if "on_time" not in dev.sys_info and not dev.is_strip:
|
if "on_time" not in dev.sys_info and dev.device_type is not DeviceType.Strip:
|
||||||
assert dev.on_since is None
|
assert dev.on_since is None
|
||||||
elif orig_state:
|
elif orig_state:
|
||||||
assert isinstance(dev.on_since, datetime)
|
assert isinstance(dev.on_since, datetime)
|
||||||
@ -179,7 +177,7 @@ async def test_on_since(dev, turn_on):
|
|||||||
|
|
||||||
@device_iot
|
@device_iot
|
||||||
async def test_time(dev):
|
async def test_time(dev):
|
||||||
assert isinstance(await dev.get_time(), datetime)
|
assert isinstance(dev.modules[Module.Time].time, datetime)
|
||||||
|
|
||||||
|
|
||||||
@device_iot
|
@device_iot
|
||||||
@ -216,7 +214,7 @@ async def test_representation(dev):
|
|||||||
@device_iot
|
@device_iot
|
||||||
async def test_children(dev):
|
async def test_children(dev):
|
||||||
"""Make sure that children property is exposed by every device."""
|
"""Make sure that children property is exposed by every device."""
|
||||||
if dev.is_strip:
|
if dev.device_type is DeviceType.Strip:
|
||||||
assert len(dev.children) > 0
|
assert len(dev.children) > 0
|
||||||
else:
|
else:
|
||||||
assert len(dev.children) == 0
|
assert len(dev.children) == 0
|
||||||
|
@ -1,35 +1,37 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from kasa import DeviceType
|
from kasa import DeviceType, Module
|
||||||
from kasa.iot import IotLightStrip
|
from kasa.iot import IotLightStrip
|
||||||
|
from kasa.iot.modules import LightEffect
|
||||||
|
|
||||||
from .conftest import lightstrip_iot
|
from .conftest import lightstrip_iot
|
||||||
|
|
||||||
|
|
||||||
@lightstrip_iot
|
@lightstrip_iot
|
||||||
async def test_lightstrip_length(dev: IotLightStrip):
|
async def test_lightstrip_length(dev: IotLightStrip):
|
||||||
assert dev.is_light_strip
|
|
||||||
assert dev.device_type == DeviceType.LightStrip
|
assert dev.device_type == DeviceType.LightStrip
|
||||||
assert dev.length == dev.sys_info["length"]
|
assert dev.length == dev.sys_info["length"]
|
||||||
|
|
||||||
|
|
||||||
@lightstrip_iot
|
@lightstrip_iot
|
||||||
async def test_lightstrip_effect(dev: IotLightStrip):
|
async def test_lightstrip_effect(dev: IotLightStrip):
|
||||||
assert isinstance(dev.effect, dict)
|
le: LightEffect = dev.modules[Module.LightEffect]
|
||||||
|
assert isinstance(le._deprecated_effect, dict)
|
||||||
for k in ["brightness", "custom", "enable", "id", "name"]:
|
for k in ["brightness", "custom", "enable", "id", "name"]:
|
||||||
assert k in dev.effect
|
assert k in le._deprecated_effect
|
||||||
|
|
||||||
|
|
||||||
@lightstrip_iot
|
@lightstrip_iot
|
||||||
async def test_effects_lightstrip_set_effect(dev: IotLightStrip):
|
async def test_effects_lightstrip_set_effect(dev: IotLightStrip):
|
||||||
|
le: LightEffect = dev.modules[Module.LightEffect]
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError, match="The effect Not real is not a built in effect"
|
ValueError, match="The effect Not real is not a built in effect"
|
||||||
):
|
):
|
||||||
await dev.set_effect("Not real")
|
await le.set_effect("Not real")
|
||||||
|
|
||||||
await dev.set_effect("Candy Cane")
|
await le.set_effect("Candy Cane")
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.effect["name"] == "Candy Cane"
|
assert le.effect == "Candy Cane"
|
||||||
|
|
||||||
|
|
||||||
@lightstrip_iot
|
@lightstrip_iot
|
||||||
@ -38,12 +40,13 @@ async def test_effects_lightstrip_set_effect_brightness(
|
|||||||
dev: IotLightStrip, brightness, mocker
|
dev: IotLightStrip, brightness, mocker
|
||||||
):
|
):
|
||||||
query_helper = mocker.patch("kasa.iot.IotLightStrip._query_helper")
|
query_helper = mocker.patch("kasa.iot.IotLightStrip._query_helper")
|
||||||
|
le: LightEffect = dev.modules[Module.LightEffect]
|
||||||
|
|
||||||
# test that default brightness works (100 for candy cane)
|
# test that default brightness works (100 for candy cane)
|
||||||
if brightness == 100:
|
if brightness == 100:
|
||||||
await dev.set_effect("Candy Cane")
|
await le.set_effect("Candy Cane")
|
||||||
else:
|
else:
|
||||||
await dev.set_effect("Candy Cane", brightness=brightness)
|
await le.set_effect("Candy Cane", brightness=brightness)
|
||||||
|
|
||||||
args, kwargs = query_helper.call_args_list[0]
|
args, kwargs = query_helper.call_args_list[0]
|
||||||
payload = args[2]
|
payload = args[2]
|
||||||
@ -56,12 +59,13 @@ async def test_effects_lightstrip_set_effect_transition(
|
|||||||
dev: IotLightStrip, transition, mocker
|
dev: IotLightStrip, transition, mocker
|
||||||
):
|
):
|
||||||
query_helper = mocker.patch("kasa.iot.IotLightStrip._query_helper")
|
query_helper = mocker.patch("kasa.iot.IotLightStrip._query_helper")
|
||||||
|
le: LightEffect = dev.modules[Module.LightEffect]
|
||||||
|
|
||||||
# test that default (500 for candy cane) transition works
|
# test that default (500 for candy cane) transition works
|
||||||
if transition == 500:
|
if transition == 500:
|
||||||
await dev.set_effect("Candy Cane")
|
await le.set_effect("Candy Cane")
|
||||||
else:
|
else:
|
||||||
await dev.set_effect("Candy Cane", transition=transition)
|
await le.set_effect("Candy Cane", transition=transition)
|
||||||
|
|
||||||
args, kwargs = query_helper.call_args_list[0]
|
args, kwargs = query_helper.call_args_list[0]
|
||||||
payload = args[2]
|
payload = args[2]
|
||||||
@ -70,8 +74,9 @@ async def test_effects_lightstrip_set_effect_transition(
|
|||||||
|
|
||||||
@lightstrip_iot
|
@lightstrip_iot
|
||||||
async def test_effects_lightstrip_has_effects(dev: IotLightStrip):
|
async def test_effects_lightstrip_has_effects(dev: IotLightStrip):
|
||||||
assert dev.has_effects is True
|
le: LightEffect = dev.modules[Module.LightEffect]
|
||||||
assert dev.effect_list
|
assert le is not None
|
||||||
|
assert le.effect_list
|
||||||
|
|
||||||
|
|
||||||
@lightstrip_iot
|
@lightstrip_iot
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
from kasa import DeviceType
|
from kasa import DeviceType
|
||||||
|
|
||||||
from .conftest import plug, plug_iot, plug_smart, switch_smart, wallswitch_iot
|
from .conftest import plug, plug_iot, plug_smart, switch_smart, wallswitch_iot
|
||||||
@ -16,7 +18,6 @@ async def test_plug_sysinfo(dev):
|
|||||||
assert dev.model is not None
|
assert dev.model is not None
|
||||||
|
|
||||||
assert dev.device_type == DeviceType.Plug or dev.device_type == DeviceType.Strip
|
assert dev.device_type == DeviceType.Plug or dev.device_type == DeviceType.Strip
|
||||||
assert dev.is_plug or dev.is_strip
|
|
||||||
|
|
||||||
|
|
||||||
@wallswitch_iot
|
@wallswitch_iot
|
||||||
@ -27,37 +28,38 @@ async def test_switch_sysinfo(dev):
|
|||||||
assert dev.model is not None
|
assert dev.model is not None
|
||||||
|
|
||||||
assert dev.device_type == DeviceType.WallSwitch
|
assert dev.device_type == DeviceType.WallSwitch
|
||||||
assert dev.is_wallswitch
|
|
||||||
|
|
||||||
|
|
||||||
@plug_iot
|
@plug_iot
|
||||||
async def test_plug_led(dev):
|
async def test_plug_led(dev):
|
||||||
original = dev.led
|
with pytest.deprecated_call(match="use: Module.Led in device.modules instead"):
|
||||||
|
original = dev.led
|
||||||
|
|
||||||
await dev.set_led(False)
|
await dev.set_led(False)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert not dev.led
|
assert not dev.led
|
||||||
|
|
||||||
await dev.set_led(True)
|
await dev.set_led(True)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.led
|
assert dev.led
|
||||||
|
|
||||||
await dev.set_led(original)
|
await dev.set_led(original)
|
||||||
|
|
||||||
|
|
||||||
@wallswitch_iot
|
@wallswitch_iot
|
||||||
async def test_switch_led(dev):
|
async def test_switch_led(dev):
|
||||||
original = dev.led
|
with pytest.deprecated_call(match="use: Module.Led in device.modules instead"):
|
||||||
|
original = dev.led
|
||||||
|
|
||||||
await dev.set_led(False)
|
await dev.set_led(False)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert not dev.led
|
assert not dev.led
|
||||||
|
|
||||||
await dev.set_led(True)
|
await dev.set_led(True)
|
||||||
await dev.update()
|
await dev.update()
|
||||||
assert dev.led
|
assert dev.led
|
||||||
|
|
||||||
await dev.set_led(original)
|
await dev.set_led(original)
|
||||||
|
|
||||||
|
|
||||||
@plug_smart
|
@plug_smart
|
||||||
|
@ -45,10 +45,8 @@ async def test_update_no_device_info(dev: SmartDevice, mocker: MockerFixture):
|
|||||||
"get_device_time": {},
|
"get_device_time": {},
|
||||||
}
|
}
|
||||||
msg = f"get_device_info not found in {mock_response} for device 127.0.0.123"
|
msg = f"get_device_info not found in {mock_response} for device 127.0.0.123"
|
||||||
with (
|
mocker.patch.object(dev.protocol, "query", return_value=mock_response)
|
||||||
mocker.patch.object(dev.protocol, "query", return_value=mock_response),
|
with pytest.raises(KasaException, match=msg):
|
||||||
pytest.raises(KasaException, match=msg),
|
|
||||||
):
|
|
||||||
await dev.update()
|
await dev.update()
|
||||||
|
|
||||||
|
|
||||||
|
@ -325,6 +325,7 @@ async def test_smart_protocol_lists_single_request(mocker, list_sum, batch_size)
|
|||||||
"foobar",
|
"foobar",
|
||||||
list_return_size=batch_size,
|
list_return_size=batch_size,
|
||||||
component_nego_not_included=True,
|
component_nego_not_included=True,
|
||||||
|
get_child_fixtures=False,
|
||||||
)
|
)
|
||||||
protocol = SmartProtocol(transport=ft)
|
protocol = SmartProtocol(transport=ft)
|
||||||
query_spy = mocker.spy(protocol, "_execute_query")
|
query_spy = mocker.spy(protocol, "_execute_query")
|
||||||
@ -357,6 +358,7 @@ async def test_smart_protocol_lists_multiple_request(mocker, list_sum, batch_siz
|
|||||||
"foobar",
|
"foobar",
|
||||||
list_return_size=batch_size,
|
list_return_size=batch_size,
|
||||||
component_nego_not_included=True,
|
component_nego_not_included=True,
|
||||||
|
get_child_fixtures=False,
|
||||||
)
|
)
|
||||||
protocol = SmartProtocol(transport=ft)
|
protocol = SmartProtocol(transport=ft)
|
||||||
query_spy = mocker.spy(protocol, "_execute_query")
|
query_spy = mocker.spy(protocol, "_execute_query")
|
||||||
|
Loading…
Reference in New Issue
Block a user