Implement motion & ambient light sensor modules for dimmers (#278)

This commit is contained in:
Teemu R 2022-01-29 17:53:18 +01:00
parent e3588047fc
commit 8c7b1b4a68
4 changed files with 116 additions and 0 deletions

View File

@ -1,9 +1,11 @@
# flake8: noqa
from .ambientlight import AmbientLight
from .antitheft import Antitheft
from .cloud import Cloud
from .countdown import Countdown
from .emeter import Emeter
from .module import Module
from .motion import Motion
from .rulemodule import Rule, RuleModule
from .schedule import Schedule
from .time import Time

View File

@ -0,0 +1,47 @@
"""Implementation of the ambient light (LAS) module found in some dimmers."""
from .module import Module
# TODO create tests and use the config reply there
# [{"hw_id":0,"enable":0,"dark_index":1,"min_adc":0,"max_adc":2450,
# "level_array":[{"name":"cloudy","adc":490,"value":20},
# {"name":"overcast","adc":294,"value":12},
# {"name":"dawn","adc":222,"value":9},
# {"name":"twilight","adc":222,"value":9},
# {"name":"total darkness","adc":111,"value":4},
# {"name":"custom","adc":2400,"value":97}]}]
class AmbientLight(Module):
"""Implements ambient light controls for the motion sensor."""
def query(self):
"""Request configuration."""
return self.query_for_command("get_config")
@property
def presets(self) -> dict:
"""Return device-defined presets for brightness setting."""
return self.data["level_array"]
@property
def enabled(self) -> bool:
"""Return True if the module is enabled."""
return bool(self.data["enable"])
async def set_enabled(self, state: bool):
"""Enable/disable LAS."""
return await self.call("set_enable", {"enable": int(state)})
async def current_brightness(self) -> int:
"""Return current brightness.
Return value units.
"""
return await self.call("get_current_brt")
async def set_brightness_limit(self, value: int):
"""Set the limit when the motion sensor is inactive.
See `presets` for preset values. Custom values are also likely allowed.
"""
return await self.call("set_brt_level", {"index": 0, "value": value})

62
kasa/modules/motion.py Normal file
View File

@ -0,0 +1,62 @@
"""Implementation of the motion detection (PIR) module found in some dimmers."""
from enum import Enum
from typing import Optional
from kasa.smartdevice import SmartDeviceException
from .module import Module
class Range(Enum):
"""Range for motion detection."""
Far = 0
Mid = 1
Near = 2
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(Module):
"""Implements the motion detection (PIR) module."""
def query(self):
"""Request PIR configuration."""
return self.query_for_command("get_config")
@property
def range(self) -> Range:
"""Return motion detection range."""
return Range(self.data["trigger_index"])
@property
def enabled(self) -> bool:
"""Return True if module is enabled."""
return bool(self.data["enable"])
async def set_enabled(self, state: bool):
"""Enable/disable PIR."""
return await self.call("set_enable", {"enable": int(state)})
async def set_range(
self, *, range: Optional[Range] = None, custom_range: Optional[int] = None
):
"""Set the range for the sensor.
:param range: for using standard ranges
:param custom_range: range in decimeters, overrides the range parameter
"""
if custom_range is not None:
payload = {"index": Range.Custom.value, "value": custom_range}
elif range is not None:
payload = {"index": range.value}
else:
raise SmartDeviceException(
"Either range or custom_range need to be defined"
)
return await self.call("set_trigger_sens", payload)

View File

@ -1,6 +1,7 @@
"""Module for dimmers (currently only HS220)."""
from typing import Any, Dict
from kasa.modules import AmbientLight, Motion
from kasa.smartdevice import DeviceType, SmartDeviceException, requires_update
from kasa.smartplug import SmartPlug
@ -40,6 +41,10 @@ class SmartDimmer(SmartPlug):
def __init__(self, host: str) -> None:
super().__init__(host)
self._device_type = DeviceType.Dimmer
# TODO: need to be verified if it's okay to call these on HS220 w/o these
# TODO: need to be figured out what's the best approach to detect support for these
self.add_module("motion", Motion(self, "smartlife.iot.PIR"))
self.add_module("ambient", AmbientLight(self, "smartlife.iot.LAS"))
@property # type: ignore
@requires_update