mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-10-20 22:38:02 +00:00
Migrate Light module to feature based capability checks
This commit is contained in:
@@ -3,11 +3,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict
|
||||
from typing import Annotated
|
||||
|
||||
from ...exceptions import KasaException
|
||||
from ...interfaces.light import HSV, ColorTempRange, LightState
|
||||
from ...feature import Feature
|
||||
from ...interfaces.light import HSV, LightState
|
||||
from ...interfaces.light import Light as LightInterface
|
||||
from ...module import Module
|
||||
from ...module import FeatureAttribute, Module
|
||||
from ..smartmodule import SmartModule
|
||||
|
||||
|
||||
@@ -16,59 +18,45 @@ class Light(SmartModule, LightInterface):
|
||||
|
||||
_light_state: LightState
|
||||
|
||||
@property
|
||||
def _all_features(self) -> dict[str, Feature]:
|
||||
"""Get the features for this module and any sub modules."""
|
||||
ret: dict[str, Feature] = {}
|
||||
if brightness := self._device.modules.get(Module.Brightness):
|
||||
ret.update(**brightness._module_features)
|
||||
if color := self._device.modules.get(Module.Color):
|
||||
ret.update(**color._module_features)
|
||||
if temp := self._device.modules.get(Module.ColorTemperature):
|
||||
ret.update(**temp._module_features)
|
||||
return ret
|
||||
|
||||
def query(self) -> dict:
|
||||
"""Query to execute during the update cycle."""
|
||||
return {}
|
||||
|
||||
@property
|
||||
def is_color(self) -> bool:
|
||||
"""Whether the bulb supports color changes."""
|
||||
return Module.Color in self._device.modules
|
||||
|
||||
@property
|
||||
def is_dimmable(self) -> bool:
|
||||
"""Whether the bulb supports brightness changes."""
|
||||
return Module.Brightness in self._device.modules
|
||||
|
||||
@property
|
||||
def is_variable_color_temp(self) -> bool:
|
||||
"""Whether the bulb supports color temperature changes."""
|
||||
return Module.ColorTemperature in self._device.modules
|
||||
|
||||
@property
|
||||
def valid_temperature_range(self) -> ColorTempRange:
|
||||
"""Return the device-specific white temperature range (in Kelvin).
|
||||
|
||||
:return: White temperature range in Kelvin (minimum, maximum)
|
||||
"""
|
||||
if not self.is_variable_color_temp:
|
||||
raise KasaException("Color temperature not supported")
|
||||
|
||||
return self._device.modules[Module.ColorTemperature].valid_temperature_range
|
||||
|
||||
@property
|
||||
def hsv(self) -> HSV:
|
||||
def hsv(self) -> Annotated[HSV, FeatureAttribute()]:
|
||||
"""Return the current HSV state of the bulb.
|
||||
|
||||
:return: hue, saturation and value (degrees, %, %)
|
||||
"""
|
||||
if not self.is_color:
|
||||
if Module.Color not in self._device.modules:
|
||||
raise KasaException("Bulb does not support color.")
|
||||
|
||||
return self._device.modules[Module.Color].hsv
|
||||
|
||||
@property
|
||||
def color_temp(self) -> int:
|
||||
def color_temp(self) -> Annotated[int, FeatureAttribute()]:
|
||||
"""Whether the bulb supports color temperature changes."""
|
||||
if not self.is_variable_color_temp:
|
||||
if Module.ColorTemperature not in self._device.modules:
|
||||
raise KasaException("Bulb does not support colortemp.")
|
||||
|
||||
return self._device.modules[Module.ColorTemperature].color_temp
|
||||
|
||||
@property
|
||||
def brightness(self) -> int:
|
||||
def brightness(self) -> Annotated[int, FeatureAttribute()]:
|
||||
"""Return the current brightness in percentage."""
|
||||
if not self.is_dimmable: # pragma: no cover
|
||||
if Module.Brightness not in self._device.modules: # pragma: no cover
|
||||
raise KasaException("Bulb is not dimmable.")
|
||||
|
||||
return self._device.modules[Module.Brightness].brightness
|
||||
@@ -80,7 +68,7 @@ class Light(SmartModule, LightInterface):
|
||||
value: int | None = None,
|
||||
*,
|
||||
transition: int | None = None,
|
||||
) -> dict:
|
||||
) -> Annotated[dict, FeatureAttribute()]:
|
||||
"""Set new HSV.
|
||||
|
||||
Note, transition is not supported and will be ignored.
|
||||
@@ -90,14 +78,14 @@ class Light(SmartModule, LightInterface):
|
||||
:param int value: value between 1 and 100
|
||||
:param int transition: transition in milliseconds.
|
||||
"""
|
||||
if not self.is_color:
|
||||
if Module.Color not in self._device.modules:
|
||||
raise KasaException("Bulb does not support color.")
|
||||
|
||||
return await self._device.modules[Module.Color].set_hsv(hue, saturation, value)
|
||||
|
||||
async def set_color_temp(
|
||||
self, temp: int, *, brightness: int | None = None, transition: int | None = None
|
||||
) -> dict:
|
||||
) -> Annotated[dict, FeatureAttribute()]:
|
||||
"""Set the color temperature of the device in kelvin.
|
||||
|
||||
Note, transition is not supported and will be ignored.
|
||||
@@ -105,7 +93,7 @@ class Light(SmartModule, LightInterface):
|
||||
:param int temp: The new color temperature, in Kelvin
|
||||
:param int transition: transition in milliseconds.
|
||||
"""
|
||||
if not self.is_variable_color_temp:
|
||||
if Module.ColorTemperature not in self._device.modules:
|
||||
raise KasaException("Bulb does not support colortemp.")
|
||||
return await self._device.modules[Module.ColorTemperature].set_color_temp(
|
||||
temp, brightness=brightness
|
||||
@@ -113,7 +101,7 @@ class Light(SmartModule, LightInterface):
|
||||
|
||||
async def set_brightness(
|
||||
self, brightness: int, *, transition: int | None = None
|
||||
) -> dict:
|
||||
) -> Annotated[dict, FeatureAttribute()]:
|
||||
"""Set the brightness in percentage.
|
||||
|
||||
Note, transition is not supported and will be ignored.
|
||||
@@ -121,16 +109,11 @@ class Light(SmartModule, LightInterface):
|
||||
:param int brightness: brightness in percent
|
||||
:param int transition: transition in milliseconds.
|
||||
"""
|
||||
if not self.is_dimmable: # pragma: no cover
|
||||
if Module.Brightness not in self._device.modules: # pragma: no cover
|
||||
raise KasaException("Bulb is not dimmable.")
|
||||
|
||||
return await self._device.modules[Module.Brightness].set_brightness(brightness)
|
||||
|
||||
@property
|
||||
def has_effects(self) -> bool:
|
||||
"""Return True if the device supports effects."""
|
||||
return Module.LightEffect in self._device.modules
|
||||
|
||||
async def set_state(self, state: LightState) -> dict:
|
||||
"""Set the light state."""
|
||||
state_dict = asdict(state)
|
||||
@@ -157,12 +140,12 @@ class Light(SmartModule, LightInterface):
|
||||
state = LightState(light_on=False)
|
||||
else:
|
||||
state = LightState(light_on=True)
|
||||
if self.is_dimmable:
|
||||
if Module.Brightness in self._device.modules:
|
||||
state.brightness = self.brightness
|
||||
if self.is_color:
|
||||
if Module.Color in self._device.modules:
|
||||
hsv = self.hsv
|
||||
state.hue = hsv.hue
|
||||
state.saturation = hsv.saturation
|
||||
if self.is_variable_color_temp:
|
||||
if Module.ColorTemperature in self._device.modules:
|
||||
state.color_temp = self.color_temp
|
||||
self._light_state = state
|
||||
|
@@ -96,13 +96,20 @@ class LightPreset(SmartModule, LightPresetInterface):
|
||||
"""Return current preset name."""
|
||||
light = self._device.modules[SmartModule.Light]
|
||||
brightness = light.brightness
|
||||
color_temp = light.color_temp if light.is_variable_color_temp else None
|
||||
h, s = (light.hsv.hue, light.hsv.saturation) if light.is_color else (None, None)
|
||||
color_temp = (
|
||||
light.color_temp if light.has_feature(light.set_color_temp) else None
|
||||
)
|
||||
h, s = (
|
||||
(light.hsv.hue, light.hsv.saturation)
|
||||
if light.has_feature(light.set_hsv)
|
||||
else (None, None)
|
||||
)
|
||||
for preset_name, preset in self._presets.items():
|
||||
if (
|
||||
preset.brightness == brightness
|
||||
and (
|
||||
preset.color_temp == color_temp or not light.is_variable_color_temp
|
||||
preset.color_temp == color_temp
|
||||
or not light.has_feature(light.set_color_temp)
|
||||
)
|
||||
and preset.hue == h
|
||||
and preset.saturation == s
|
||||
@@ -117,7 +124,7 @@ class LightPreset(SmartModule, LightPresetInterface):
|
||||
"""Set a light preset for the device."""
|
||||
light = self._device.modules[SmartModule.Light]
|
||||
if preset_name == self.PRESET_NOT_SET:
|
||||
if light.is_color:
|
||||
if light.has_feature(light.set_hsv):
|
||||
preset = LightState(hue=0, saturation=0, brightness=100)
|
||||
else:
|
||||
preset = LightState(brightness=100)
|
||||
|
Reference in New Issue
Block a user