mirror of
https://github.com/python-kasa/python-kasa.git
synced 2026-10-18 02:32:55 +00:00
Add strip segment module for configurable light strip length (#1744)
A light strip can be cut shorter than it ships, and the device has to be told how much of it is actually there so effects and colours span the right distance. The Tapo app exposes this as "Light Strip Length". python-kasa has no way to read or change it, so the setting is missing from Home Assistant. This change exposes a new feature backed by `segment` component: - add a `Segment` module: `REQUIRED_COMPONENT = "segment"`, `QUERY_GETTER_NAME = "get_device_segment"` - expose one Number feature, `strip_segments`, range 0-50, `Category.Config` - add a `segments` property and `set_segments()`, which writes `set_device_segment`
This commit is contained in:
@@ -163,6 +163,9 @@ class Module(ABC):
|
||||
PowerProtection: Final[ModuleName[smart.PowerProtection]] = ModuleName(
|
||||
"PowerProtection"
|
||||
)
|
||||
LightStripSegment: Final[ModuleName[smart.LightStripSegment]] = ModuleName(
|
||||
"LightStripSegment"
|
||||
)
|
||||
|
||||
HomeKit: Final[ModuleName[smart.HomeKit]] = ModuleName("HomeKit")
|
||||
Matter: Final[ModuleName[smart.Matter]] = ModuleName("Matter")
|
||||
|
||||
@@ -29,6 +29,7 @@ from .light import Light
|
||||
from .lighteffect import LightEffect
|
||||
from .lightpreset import LightPreset
|
||||
from .lightstripeffect import LightStripEffect
|
||||
from .lightstripsegment import LightStripSegment
|
||||
from .lighttransition import LightTransition
|
||||
from .matter import Matter
|
||||
from .mop import Mop
|
||||
@@ -83,6 +84,7 @@ __all__ = [
|
||||
"SmartLightEffect",
|
||||
"PowerProtection",
|
||||
"OverheatProtection",
|
||||
"LightStripSegment",
|
||||
"Speaker",
|
||||
"HomeKit",
|
||||
"Matter",
|
||||
|
||||
52
kasa/smart/modules/lightstripsegment.py
Normal file
52
kasa/smart/modules/lightstripsegment.py
Normal file
@@ -0,0 +1,52 @@
|
||||
"""Implementation of the light strip segment module."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from ...feature import Feature
|
||||
from ..smartmodule import SmartModule
|
||||
|
||||
# The device reports no maximum, so it cannot be queried: a run is 5m in 10cm
|
||||
# segments. Multi-spool products drive every run from this one value, making
|
||||
# the limit per-run rather than per-model.
|
||||
SEGMENTS_MIN = 0
|
||||
SEGMENTS_MAX = 50
|
||||
|
||||
|
||||
class LightStripSegment(SmartModule):
|
||||
"""Implementation of the configurable light strip length."""
|
||||
|
||||
REQUIRED_COMPONENT = "segment"
|
||||
QUERY_GETTER_NAME = "get_device_segment"
|
||||
|
||||
def _initialize_features(self) -> None:
|
||||
"""Initialize features."""
|
||||
self._add_feature(
|
||||
Feature(
|
||||
self._device,
|
||||
id="strip_segments",
|
||||
name="Strip segments",
|
||||
container=self,
|
||||
attribute_getter="segments",
|
||||
attribute_setter="set_segments",
|
||||
range_getter=lambda: (SEGMENTS_MIN, SEGMENTS_MAX),
|
||||
type=Feature.Type.Number,
|
||||
category=Feature.Category.Config,
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
def segments(self) -> int:
|
||||
"""Return the number of 10cm segments the strip is configured for."""
|
||||
return self.data["segment"]
|
||||
|
||||
async def set_segments(self, segments: int) -> dict:
|
||||
"""Set the number of 10cm segments the strip is cut to."""
|
||||
if not isinstance(segments, int) or not (
|
||||
SEGMENTS_MIN <= segments <= SEGMENTS_MAX
|
||||
):
|
||||
raise ValueError(
|
||||
f"Invalid segment count: {segments} "
|
||||
f"(valid range: {SEGMENTS_MIN}-{SEGMENTS_MAX})"
|
||||
)
|
||||
|
||||
return await self.call("set_device_segment", {"segment": segments})
|
||||
Reference in New Issue
Block a user