mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-08-06 18:54:08 +00:00
Update docs for the new module attributes has/get feature (#1301)
This commit is contained in:
@@ -64,9 +64,9 @@ from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import NamedTuple
|
||||
from typing import Annotated, NamedTuple
|
||||
|
||||
from ..module import Module
|
||||
from ..module import FeatureAttribute, Module
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -129,7 +129,7 @@ class Light(Module, ABC):
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def hsv(self) -> HSV:
|
||||
def hsv(self) -> Annotated[HSV, FeatureAttribute()]:
|
||||
"""Return the current HSV state of the bulb.
|
||||
|
||||
:return: hue, saturation and value (degrees, %, %)
|
||||
@@ -137,12 +137,12 @@ class Light(Module, ABC):
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def color_temp(self) -> int:
|
||||
def color_temp(self) -> Annotated[int, FeatureAttribute()]:
|
||||
"""Whether the bulb supports color temperature changes."""
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def brightness(self) -> int:
|
||||
def brightness(self) -> Annotated[int, FeatureAttribute()]:
|
||||
"""Return the current brightness in percentage."""
|
||||
|
||||
@abstractmethod
|
||||
@@ -153,7 +153,7 @@ class Light(Module, ABC):
|
||||
value: int | None = None,
|
||||
*,
|
||||
transition: int | None = None,
|
||||
) -> dict:
|
||||
) -> Annotated[dict, FeatureAttribute()]:
|
||||
"""Set new HSV.
|
||||
|
||||
Note, transition is not supported and will be ignored.
|
||||
@@ -167,7 +167,7 @@ class Light(Module, ABC):
|
||||
@abstractmethod
|
||||
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.
|
||||
@@ -179,7 +179,7 @@ class Light(Module, ABC):
|
||||
@abstractmethod
|
||||
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.
|
||||
|
@@ -14,9 +14,17 @@ Light, AutoOff, Firmware etc.
|
||||
>>> print(dev.alias)
|
||||
Living Room Bulb
|
||||
|
||||
To see whether a device supports functionality check for the existence of the module:
|
||||
To see whether a device supports a group of functionality
|
||||
check for the existence of the module:
|
||||
|
||||
>>> if light := dev.modules.get("Light"):
|
||||
>>> print(light.brightness)
|
||||
100
|
||||
|
||||
To see whether a device supports specific functionality, you can check whether the
|
||||
module has that feature:
|
||||
|
||||
>>> if light.has_feature("hsv"):
|
||||
>>> print(light.hsv)
|
||||
HSV(hue=0, saturation=100, value=100)
|
||||
|
||||
@@ -70,6 +78,9 @@ ModuleT = TypeVar("ModuleT", bound="Module")
|
||||
class FeatureAttribute:
|
||||
"""Class for annotating attributes bound to feature."""
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "FeatureAttribute"
|
||||
|
||||
|
||||
class Module(ABC):
|
||||
"""Base class implemention for all modules.
|
||||
@@ -147,6 +158,11 @@ class Module(ABC):
|
||||
self._module = module
|
||||
self._module_features: dict[str, Feature] = {}
|
||||
|
||||
@property
|
||||
def _all_features(self) -> dict[str, Feature]:
|
||||
"""Get the features for this module and any sub modules."""
|
||||
return self._module_features
|
||||
|
||||
def has_feature(self, attribute: str | property | Callable) -> bool:
|
||||
"""Return True if the module attribute feature is supported."""
|
||||
return bool(self.get_feature(attribute))
|
||||
@@ -247,7 +263,7 @@ def _get_bound_feature(
|
||||
)
|
||||
|
||||
check = {attribute_name, attribute_callable}
|
||||
for feature in module._module_features.values():
|
||||
for feature in module._all_features.values():
|
||||
if (getter := feature.attribute_getter) and getter in check:
|
||||
return feature
|
||||
|
||||
|
@@ -3,11 +3,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict
|
||||
from typing import Annotated
|
||||
|
||||
from ...exceptions import KasaException
|
||||
from ...feature import Feature
|
||||
from ...interfaces.light import HSV, ColorTempRange, LightState
|
||||
from ...interfaces.light import Light as LightInterface
|
||||
from ...module import Module
|
||||
from ...module import FeatureAttribute, Module
|
||||
from ..smartmodule import SmartModule
|
||||
|
||||
|
||||
@@ -16,6 +18,18 @@ 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 {}
|
||||
@@ -47,7 +61,7 @@ class Light(SmartModule, LightInterface):
|
||||
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, %, %)
|
||||
@@ -58,7 +72,7 @@ class Light(SmartModule, LightInterface):
|
||||
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:
|
||||
raise KasaException("Bulb does not support colortemp.")
|
||||
@@ -66,7 +80,7 @@ class Light(SmartModule, LightInterface):
|
||||
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
|
||||
raise KasaException("Bulb is not dimmable.")
|
||||
@@ -80,7 +94,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.
|
||||
@@ -97,7 +111,7 @@ class Light(SmartModule, LightInterface):
|
||||
|
||||
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.
|
||||
@@ -113,7 +127,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.
|
||||
|
Reference in New Issue
Block a user