Expose PIR enabled setting for iot dimmers (#1174)

This adds PIR enabled feature to iot dimmers, making it possible to
enable and disable the motion detection.
This commit is contained in:
Teemu R. 2024-10-31 11:41:11 +01:00 committed by GitHub
parent 530cf4b523
commit 9975bbf26a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 93 additions and 8 deletions

View File

@ -2,11 +2,15 @@
from __future__ import annotations
import logging
from enum import Enum
from ...exceptions import KasaException
from ...feature import Feature
from ..iotmodule import IotModule
_LOGGER = logging.getLogger(__name__)
class Range(Enum):
"""Range for motion detection."""
@ -17,27 +21,51 @@ class Range(Enum):
Custom = 3
# TODO: use the config reply in tests
# {"enable":0,"version":"1.0","trigger_index":2,"cold_time":60000,
# "min_adc":0,"max_adc":4095,"array":[80,50,20,0],"err_code":0}}}
class Motion(IotModule):
"""Implements the motion detection (PIR) module."""
def _initialize_features(self):
"""Initialize features after the initial update."""
# Only add features if the device supports the module
if "get_config" not in self.data:
return
if "enable" not in self.config:
_LOGGER.warning("%r initialized, but no enable in response")
return
self._add_feature(
Feature(
device=self._device,
container=self,
id="pir_enabled",
name="PIR enabled",
icon="mdi:motion-sensor",
attribute_getter="enabled",
attribute_setter="set_enabled",
type=Feature.Type.Switch,
category=Feature.Category.Config,
)
)
def query(self):
"""Request PIR configuration."""
return self.query_for_command("get_config")
@property
def config(self) -> dict:
"""Return current configuration."""
return self.data["get_config"]
@property
def range(self) -> Range:
"""Return motion detection range."""
return Range(self.data["trigger_index"])
return Range(self.config["trigger_index"])
@property
def enabled(self) -> bool:
"""Return True if module is enabled."""
return bool(self.data["enable"])
return bool(self.config["enable"])
async def set_enabled(self, state: bool):
"""Enable/disable PIR."""
@ -63,7 +91,7 @@ class Motion(IotModule):
@property
def inactivity_timeout(self) -> int:
"""Return inactivity timeout in milliseconds."""
return self.data["cold_time"]
return self.config["cold_time"]
async def set_inactivity_timeout(self, timeout: int):
"""Set inactivity timeout in milliseconds.

View File

View File

@ -0,0 +1,57 @@
from pytest_mock import MockerFixture
from kasa import Module
from kasa.iot import IotDimmer
from kasa.iot.modules.motion import Motion, Range
from kasa.tests.device_fixtures import dimmer_iot
@dimmer_iot
def test_motion_getters(dev: IotDimmer):
assert Module.IotMotion in dev.modules
motion: Motion = dev.modules[Module.IotMotion]
assert motion.enabled == motion.config["enable"]
assert motion.inactivity_timeout == motion.config["cold_time"]
assert motion.range.value == motion.config["trigger_index"]
@dimmer_iot
async def test_motion_setters(dev: IotDimmer, mocker: MockerFixture):
motion: Motion = dev.modules[Module.IotMotion]
query_helper = mocker.patch("kasa.iot.IotDimmer._query_helper")
await motion.set_enabled(True)
query_helper.assert_called_with("smartlife.iot.PIR", "set_enable", {"enable": True})
await motion.set_inactivity_timeout(10)
query_helper.assert_called_with(
"smartlife.iot.PIR", "set_cold_time", {"cold_time": 10}
)
@dimmer_iot
async def test_motion_range(dev: IotDimmer, mocker: MockerFixture):
motion: Motion = dev.modules[Module.IotMotion]
query_helper = mocker.patch("kasa.iot.IotDimmer._query_helper")
await motion.set_range(custom_range=123)
query_helper.assert_called_with(
"smartlife.iot.PIR",
"set_trigger_sens",
{"index": Range.Custom.value, "value": 123},
)
await motion.set_range(range=Range.Far)
query_helper.assert_called_with(
"smartlife.iot.PIR", "set_trigger_sens", {"index": Range.Far.value}
)
@dimmer_iot
def test_motion_feature(dev: IotDimmer):
assert Module.IotMotion in dev.modules
motion: Motion = dev.modules[Module.IotMotion]
pir_enabled = dev.features["pir_enabled"]
assert motion.enabled == pir_enabled.value