mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-08-09 20:24:02 +00:00
Add generic interface for accessing device features (#741)
This adds a generic interface for all device classes to introspect available device features, that is necessary to make it easier to support a wide variety of supported devices with different set of features. This will allow constructing generic interfaces (e.g., in homeassistant) that fetch and change these features without hard-coding the API calls. `Device.features()` now returns a mapping of `<identifier, Feature>` where the `Feature` contains all necessary information (like the name, the icon, a way to get and change the setting) to present and change the defined feature through its interface.
This commit is contained in:
50
kasa/feature.py
Normal file
50
kasa/feature.py
Normal file
@@ -0,0 +1,50 @@
|
||||
"""Generic interface for defining device features."""
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum, auto
|
||||
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .device import Device
|
||||
|
||||
|
||||
class FeatureType(Enum):
|
||||
"""Type to help decide how to present the feature."""
|
||||
|
||||
Sensor = auto()
|
||||
BinarySensor = auto()
|
||||
Switch = auto()
|
||||
Button = auto()
|
||||
|
||||
|
||||
@dataclass
|
||||
class Feature:
|
||||
"""Feature defines a generic interface for device features."""
|
||||
|
||||
#: Device instance required for getting and setting values
|
||||
device: "Device"
|
||||
#: User-friendly short description
|
||||
name: str
|
||||
#: Name of the property that allows accessing the value
|
||||
attribute_getter: Union[str, Callable]
|
||||
#: Name of the method that allows changing the value
|
||||
attribute_setter: Optional[str] = None
|
||||
#: Container storing the data, this overrides 'device' for getters
|
||||
container: Any = None
|
||||
#: Icon suggestion
|
||||
icon: Optional[str] = None
|
||||
#: Type of the feature
|
||||
type: FeatureType = FeatureType.Sensor
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
"""Return the current value."""
|
||||
container = self.container if self.container is not None else self.device
|
||||
if isinstance(self.attribute_getter, Callable):
|
||||
return self.attribute_getter(container)
|
||||
return getattr(container, self.attribute_getter)
|
||||
|
||||
async def set_value(self, value):
|
||||
"""Set the value."""
|
||||
if self.attribute_setter is None:
|
||||
raise ValueError("Tried to set read-only feature.")
|
||||
return await getattr(self.device, self.attribute_setter)(value)
|
Reference in New Issue
Block a user