Add colortemp module (#814)

Allow controlling the color temperature via features interface:
```
$ kasa --host 192.168.xx.xx feature color_temperature                                                                                                                             
Color temperature (color_temperature): 0

$ kasa --host 192.168.xx.xx feature color_temperature 2000
Setting color_temperature to 2000
Raised error: Temperature should be between 2500 and 6500, was 2000
Run with --debug enabled to see stacktrace

$ kasa --host 192.168.xx.xx feature color_temperature 3000
Setting color_temperature to 3000

$ kasa --host 192.168.xx.xx feature color_temperature                                                                                                                             
Color temperature (color_temperature): 3000
```
This commit is contained in:
Teemu R 2024-03-15 17:36:07 +01:00 committed by GitHub
parent 270614aa02
commit d63f43a230
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 99 additions and 0 deletions

View File

@ -41,6 +41,17 @@ class Feature:
minimum_value: int = 0
#: Maximum value
maximum_value: int = 2**16 # Arbitrary max
#: Attribute containing the name of the range getter property.
#: If set, this property will be used to set *minimum_value* and *maximum_value*.
range_getter: Optional[str] = None
def __post_init__(self):
"""Handle late-binding of members."""
container = self.container if self.container is not None else self.device
if self.range_getter is not None:
self.minimum_value, self.maximum_value = getattr(
container, self.range_getter
)
@property
def value(self):

View File

@ -5,6 +5,7 @@ from .battery import BatterySensor
from .brightness import Brightness
from .childdevicemodule import ChildDeviceModule
from .cloudmodule import CloudModule
from .colortemp import ColorTemperatureModule
from .devicemodule import DeviceModule
from .energymodule import EnergyModule
from .firmware import Firmware
@ -31,4 +32,5 @@ __all__ = [
"Firmware",
"CloudModule",
"LightTransitionModule",
"ColorTemperatureModule",
]

View File

@ -0,0 +1,55 @@
"""Implementation of color temp module."""
from typing import TYPE_CHECKING, Dict
from ...bulb import ColorTempRange
from ...feature import Feature
from ..smartmodule import SmartModule
if TYPE_CHECKING:
from ..smartdevice import SmartDevice
class ColorTemperatureModule(SmartModule):
"""Implementation of color temp module."""
REQUIRED_COMPONENT = "color_temperature"
def __init__(self, device: "SmartDevice", module: str):
super().__init__(device, module)
self._add_feature(
Feature(
device,
"Color temperature",
container=self,
attribute_getter="color_temp",
attribute_setter="set_color_temp",
range_getter="valid_temperature_range",
)
)
def query(self) -> Dict:
"""Query to execute during the update cycle."""
# Color temp is contained in the main device info response.
return {}
@property
def valid_temperature_range(self) -> ColorTempRange:
"""Return valid color-temp range."""
return ColorTempRange(*self.data.get("color_temp_range"))
@property
def color_temp(self):
"""Return current color temperature."""
return self.data["color_temp"]
async def set_color_temp(self, temp: int):
"""Set the color temperature."""
valid_temperature_range = self.valid_temperature_range
if temp < valid_temperature_range[0] or temp > valid_temperature_range[1]:
raise ValueError(
"Temperature should be between {} and {}, was {}".format(
*valid_temperature_range, temp
)
)
return await self.call("set_device_info", {"color_temp": temp})

View File

View File

@ -0,0 +1,31 @@
import pytest
from kasa.smart import SmartDevice
from kasa.tests.conftest import parametrize
brightness = parametrize("colortemp smart", component_filter="color_temperature")
@brightness
async def test_colortemp_component(dev: SmartDevice):
"""Test brightness feature."""
assert isinstance(dev, SmartDevice)
assert "color_temperature" in dev._components
# Test getting the value
feature = dev.features["color_temperature"]
assert isinstance(feature.value, int)
assert isinstance(feature.minimum_value, int)
assert isinstance(feature.maximum_value, int)
# Test setting the value
# We need to take the min here, as L9xx reports a range [9000, 9000].
new_value = min(feature.minimum_value + 1, feature.maximum_value)
await feature.set_value(new_value)
assert feature.value == new_value
with pytest.raises(ValueError):
await feature.set_value(feature.minimum_value - 10)
with pytest.raises(ValueError):
await feature.set_value(feature.maximum_value + 10)