Fix set_state for common light modules (#929)

PR contains a number of fixes from testing with HA devices:

- Fixes a bug with turning the light on and off via `set_state`
- Aligns `set_brightness` behaviour across `smart` and `iot` devices
such that a value of 0 is off.
- Aligns `set_brightness` behaviour for `IotDimmer` such that setting
the brightness turns on the device with a transition of 1ms. ([HA
comment](https://github.com/home-assistant/core/pull/117839#discussion_r1608720006))
- Fixes a typing issue in `LightState`.
- Adds `ColorTempRange` and `HSV` to `__init__.py`
- Adds a `state` property to the interface returning `LightState` for
validating `set_state` changes.
- Adds tests for `set_state`
This commit is contained in:
Steven B
2024-05-22 14:33:55 +01:00
committed by GitHub
parent 5e619af29f
commit db6e335346
9 changed files with 127 additions and 19 deletions

View File

@@ -241,7 +241,7 @@ async def test_dimmable_brightness_transition(dev: IotBulb, mocker):
set_light_state = mocker.patch("kasa.iot.IotBulb._set_light_state")
await dev.set_brightness(10, transition=1000)
set_light_state.assert_called_with({"brightness": 10}, transition=1000)
set_light_state.assert_called_with({"brightness": 10, "on_off": 1}, transition=1000)
@dimmable_iot

View File

@@ -4,6 +4,7 @@ from pytest_mock import MockerFixture
from kasa import Device, LightState, Module
from kasa.tests.device_fixtures import (
bulb_iot,
bulb_smart,
dimmable_iot,
dimmer_iot,
lightstrip_iot,
@@ -40,6 +41,8 @@ light_preset_smart = parametrize(
light_preset = parametrize_combine([light_preset_smart, bulb_iot])
light = parametrize_combine([bulb_smart, bulb_iot, dimmable])
@led
async def test_led_module(dev: Device, mocker: MockerFixture):
@@ -139,6 +142,30 @@ async def test_light_brightness(dev: Device):
await light.set_brightness(feature.maximum_value + 10)
@light
async def test_light_set_state(dev: Device):
"""Test brightness setter and getter."""
assert isinstance(dev, Device)
light = dev.modules.get(Module.Light)
assert light
await light.set_state(LightState(light_on=False))
await dev.update()
assert light.state.light_on is False
await light.set_state(LightState(light_on=True))
await dev.update()
assert light.state.light_on is True
await light.set_state(LightState(brightness=0))
await dev.update()
assert light.state.light_on is False
await light.set_state(LightState(brightness=50))
await dev.update()
assert light.state.light_on is True
@light_preset
async def test_light_preset_module(dev: Device, mocker: MockerFixture):
"""Test light preset module."""
@@ -148,7 +175,6 @@ async def test_light_preset_module(dev: Device, mocker: MockerFixture):
assert light_mod
feat = dev.features["light_preset"]
call = mocker.spy(light_mod, "set_state")
preset_list = preset_mod.preset_list
assert "Not set" in preset_list
assert preset_list.index("Not set") == 0
@@ -157,7 +183,6 @@ async def test_light_preset_module(dev: Device, mocker: MockerFixture):
assert preset_mod.has_save_preset is True
await light_mod.set_brightness(33) # Value that should not be a preset
assert call.call_count == 0
await dev.update()
assert preset_mod.preset == "Not set"
assert feat.value == "Not set"
@@ -165,6 +190,7 @@ async def test_light_preset_module(dev: Device, mocker: MockerFixture):
if len(preset_list) == 1:
return
call = mocker.spy(light_mod, "set_state")
second_preset = preset_list[1]
await preset_mod.set_preset(second_preset)
assert call.call_count == 1

View File

@@ -7,19 +7,19 @@ from .conftest import dimmer_iot, handle_turn_on, turn_on
@dimmer_iot
@turn_on
async def test_set_brightness(dev, turn_on):
await handle_turn_on(dev, turn_on)
async def test_set_brightness(dev):
await handle_turn_on(dev, False)
assert dev.is_on is False
await dev.set_brightness(99)
await dev.update()
assert dev.brightness == 99
assert dev.is_on == turn_on
assert dev.is_on is True
await dev.set_brightness(0)
await dev.update()
assert dev.brightness == 1
assert dev.is_on == turn_on
assert dev.brightness == 99
assert dev.is_on is False
@dimmer_iot
@@ -41,7 +41,7 @@ async def test_set_brightness_transition(dev, turn_on, mocker):
await dev.set_brightness(0, transition=1000)
await dev.update()
assert dev.brightness == 1
assert dev.is_on is False
@dimmer_iot
@@ -50,7 +50,7 @@ async def test_set_brightness_invalid(dev):
with pytest.raises(ValueError):
await dev.set_brightness(invalid_brightness)
for invalid_transition in [-1, 0, 0.5]:
for invalid_transition in [-1, 0.5]:
with pytest.raises(ValueError):
await dev.set_brightness(1, transition=invalid_transition)
@@ -133,7 +133,7 @@ async def test_set_dimmer_transition_invalid(dev):
with pytest.raises(ValueError):
await dev.set_dimmer_transition(invalid_brightness, 1000)
for invalid_transition in [-1, 0, 0.5]:
for invalid_transition in [-1, 0.5]:
with pytest.raises(ValueError):
await dev.set_dimmer_transition(1, invalid_transition)