mirror of
https://github.com/python-kasa/python-kasa.git
synced 2024-12-22 19:23:34 +00:00
Move dimmer support to its own class (#34)
* Move dimmer support to its own class SmartDimmer extends SmartPlug with brightness settings. This will make the API of SmartPlug less confusing and will make it simpler to downstream users to act with dimmers. Fixes #33 * Lint & make tests pass * Fix rebase after cache and emeter cleanups, hopefully everything went smoothly.. * oopsie, has_emeter was mistakenly included in smartplug
This commit is contained in:
parent
b6c3a7c54b
commit
b73c0d222e
@ -15,6 +15,7 @@ from kasa.discover import Discover
|
||||
from kasa.protocol import TPLinkSmartHomeProtocol
|
||||
from kasa.smartbulb import SmartBulb
|
||||
from kasa.smartdevice import DeviceType, EmeterStatus, SmartDevice, SmartDeviceException
|
||||
from kasa.smartdimmer import SmartDimmer
|
||||
from kasa.smartplug import SmartPlug
|
||||
from kasa.smartstrip import SmartStrip
|
||||
|
||||
@ -28,4 +29,5 @@ __all__ = [
|
||||
"SmartDeviceException",
|
||||
"SmartPlug",
|
||||
"SmartStrip",
|
||||
"SmartDimmer",
|
||||
]
|
||||
|
@ -29,6 +29,7 @@ class DeviceType(Enum):
|
||||
Plug = 1
|
||||
Bulb = 2
|
||||
Strip = 3
|
||||
Dimmer = 4
|
||||
Unknown = -1
|
||||
|
||||
|
||||
@ -583,6 +584,11 @@ class SmartDevice:
|
||||
"""Return True if the device is a strip."""
|
||||
return self._device_type == DeviceType.Strip
|
||||
|
||||
@property
|
||||
def is_dimmer(self) -> bool:
|
||||
"""Return True if the device is a dimmer."""
|
||||
return self._device_type == DeviceType.Dimmer
|
||||
|
||||
@property
|
||||
def is_dimmable(self) -> bool:
|
||||
"""Return True if the device is dimmable."""
|
||||
|
94
kasa/smartdimmer.py
Normal file
94
kasa/smartdimmer.py
Normal file
@ -0,0 +1,94 @@
|
||||
"""Module for dimmers (currently only HS220)."""
|
||||
from typing import Any, Dict
|
||||
|
||||
from kasa import DeviceType, SmartDeviceException
|
||||
from kasa.smartdevice import requires_update
|
||||
from kasa.smartplug import SmartPlug
|
||||
|
||||
|
||||
class SmartDimmer(SmartPlug):
|
||||
"""Representation of a TP-Link Smart Dimmer.
|
||||
|
||||
Dimmers work similarly to plugs, but provide also support for
|
||||
adjusting the brightness. This class extends SmartPlug interface.
|
||||
|
||||
Example:
|
||||
```
|
||||
dimmer = SmartDimmer("192.168.1.105")
|
||||
await dimmer.turn_on()
|
||||
print("Current brightness: %s" % dimmer.brightness)
|
||||
|
||||
await dimmer.set_brightness(100)
|
||||
```
|
||||
|
||||
Refer to SmartPlug for the full API.
|
||||
"""
|
||||
|
||||
def __init__(self, host: str) -> None:
|
||||
super().__init__(host)
|
||||
self._device_type = DeviceType.Dimmer
|
||||
|
||||
@property # type: ignore
|
||||
@requires_update
|
||||
def brightness(self) -> int:
|
||||
"""Return current brightness on dimmers.
|
||||
|
||||
Will return a range between 0 - 100.
|
||||
|
||||
:returns: integer
|
||||
:rtype: int
|
||||
"""
|
||||
if not self.is_dimmable:
|
||||
raise SmartDeviceException("Device is not dimmable.")
|
||||
|
||||
sys_info = self.sys_info
|
||||
return int(sys_info["brightness"])
|
||||
|
||||
@requires_update
|
||||
async def set_brightness(self, value: int):
|
||||
"""Set the new dimmer brightness level.
|
||||
|
||||
Note:
|
||||
When setting brightness, if the light is not
|
||||
already on, it will be turned on automatically.
|
||||
|
||||
:param value: integer between 1 and 100
|
||||
|
||||
"""
|
||||
if not self.is_dimmable:
|
||||
raise SmartDeviceException("Device is not dimmable.")
|
||||
|
||||
if not isinstance(value, int):
|
||||
raise ValueError("Brightness must be integer, " "not of %s.", type(value))
|
||||
elif 0 < value <= 100:
|
||||
await self.turn_on()
|
||||
await self._query_helper(
|
||||
"smartlife.iot.dimmer", "set_brightness", {"brightness": value}
|
||||
)
|
||||
await self.update()
|
||||
else:
|
||||
raise ValueError("Brightness value %s is not valid." % value)
|
||||
|
||||
@property # type: ignore
|
||||
@requires_update
|
||||
def is_dimmable(self):
|
||||
"""Whether the switch supports brightness changes.
|
||||
|
||||
:return: True if switch supports brightness changes, False otherwise
|
||||
:rtype: bool
|
||||
"""
|
||||
sys_info = self.sys_info
|
||||
return "brightness" in sys_info
|
||||
|
||||
@property # type: ignore
|
||||
@requires_update
|
||||
def state_information(self) -> Dict[str, Any]:
|
||||
"""Return switch-specific state information.
|
||||
|
||||
:return: Switch information dict, keys in user-presentable form.
|
||||
:rtype: dict
|
||||
"""
|
||||
info = super().state_information
|
||||
info["Brightness"] = self.brightness
|
||||
|
||||
return info
|
@ -3,12 +3,7 @@ import datetime
|
||||
import logging
|
||||
from typing import Any, Dict
|
||||
|
||||
from kasa.smartdevice import (
|
||||
DeviceType,
|
||||
SmartDevice,
|
||||
SmartDeviceException,
|
||||
requires_update,
|
||||
)
|
||||
from kasa.smartdevice import DeviceType, SmartDevice, requires_update
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -40,58 +35,6 @@ class SmartPlug(SmartDevice):
|
||||
self.emeter_type = "emeter"
|
||||
self._device_type = DeviceType.Plug
|
||||
|
||||
@property # type: ignore
|
||||
@requires_update
|
||||
def brightness(self) -> int:
|
||||
"""Return current brightness on dimmers.
|
||||
|
||||
Will return a range between 0 - 100.
|
||||
|
||||
:returns: integer
|
||||
:rtype: int
|
||||
"""
|
||||
if not self.is_dimmable:
|
||||
raise SmartDeviceException("Device is not dimmable.")
|
||||
|
||||
sys_info = self.sys_info
|
||||
return int(sys_info["brightness"])
|
||||
|
||||
@requires_update
|
||||
async def set_brightness(self, value: int):
|
||||
"""Set the new dimmer brightness level.
|
||||
|
||||
Note:
|
||||
When setting brightness, if the light is not
|
||||
already on, it will be turned on automatically.
|
||||
|
||||
:param value: integer between 1 and 100
|
||||
|
||||
"""
|
||||
if not self.is_dimmable:
|
||||
raise SmartDeviceException("Device is not dimmable.")
|
||||
|
||||
if not isinstance(value, int):
|
||||
raise ValueError("Brightness must be integer, " "not of %s.", type(value))
|
||||
elif 0 < value <= 100:
|
||||
await self.turn_on()
|
||||
await self._query_helper(
|
||||
"smartlife.iot.dimmer", "set_brightness", {"brightness": value}
|
||||
)
|
||||
await self.update()
|
||||
else:
|
||||
raise ValueError("Brightness value %s is not valid." % value)
|
||||
|
||||
@property # type: ignore
|
||||
@requires_update
|
||||
def is_dimmable(self):
|
||||
"""Whether the switch supports brightness changes.
|
||||
|
||||
:return: True if switch supports brightness changes, False otherwise
|
||||
:rtype: bool
|
||||
"""
|
||||
sys_info = self.sys_info
|
||||
return "brightness" in sys_info
|
||||
|
||||
@property # type: ignore
|
||||
@requires_update
|
||||
def is_on(self) -> bool:
|
||||
@ -159,6 +102,4 @@ class SmartPlug(SmartDevice):
|
||||
:rtype: dict
|
||||
"""
|
||||
info = {"LED state": self.led, "On since": self.on_since}
|
||||
if self.is_dimmable:
|
||||
info["Brightness"] = self.brightness
|
||||
return info
|
||||
|
@ -45,7 +45,7 @@ class SmartStrip(SmartDevice):
|
||||
and should be handled by the user of the library.
|
||||
"""
|
||||
|
||||
def __init__(self, host: str, *, cache_ttl: int = 3) -> None:
|
||||
def __init__(self, host: str) -> None:
|
||||
super().__init__(host=host)
|
||||
self.emeter_type = "emeter"
|
||||
self._device_type = DeviceType.Strip
|
||||
|
@ -6,7 +6,7 @@ from os.path import basename
|
||||
|
||||
import pytest
|
||||
|
||||
from kasa import Discover, SmartBulb, SmartPlug, SmartStrip
|
||||
from kasa import Discover, SmartBulb, SmartDimmer, SmartPlug, SmartStrip
|
||||
|
||||
from .newfakes import FakeTransportProtocol
|
||||
|
||||
@ -14,15 +14,17 @@ SUPPORTED_DEVICES = glob.glob(
|
||||
os.path.dirname(os.path.abspath(__file__)) + "/fixtures/*.json"
|
||||
)
|
||||
|
||||
|
||||
BULBS = {"LB100", "LB120", "LB130", "KL120", "KL130"}
|
||||
VARIABLE_TEMP = {"LB120", "LB130", "KL120", "KL130"}
|
||||
PLUGS = {"HS100", "HS103", "HS105", "HS110", "HS200", "HS210", "HS220", "HS300"}
|
||||
PLUGS = {"HS100", "HS103", "HS105", "HS110", "HS200", "HS210", "HS300"}
|
||||
STRIPS = {"HS107", "HS300", "KP303", "KP400"}
|
||||
DIMMERS = {"HS220"}
|
||||
COLOR_BULBS = {"LB130", "KL130"}
|
||||
DIMMABLE = {*BULBS, "HS220"}
|
||||
EMETER = {"HS110", "HS300", *BULBS}
|
||||
EMETER = {"HS110", "HS300", *BULBS, *STRIPS}
|
||||
|
||||
ALL_DEVICES = BULBS.union(PLUGS)
|
||||
ALL_DEVICES = BULBS.union(PLUGS).union(STRIPS).union(DIMMERS)
|
||||
|
||||
|
||||
def filter_model(desc, filter):
|
||||
@ -52,7 +54,9 @@ dimmable = pytest.mark.parametrize(
|
||||
"dev", filter_model("dimmable", DIMMABLE), indirect=True
|
||||
)
|
||||
non_dimmable = pytest.mark.parametrize(
|
||||
"dev", filter_model("non-dimmable", ALL_DEVICES - DIMMABLE - STRIPS), indirect=True
|
||||
"dev",
|
||||
filter_model("non-dimmable", ALL_DEVICES - DIMMABLE - STRIPS - PLUGS),
|
||||
indirect=True,
|
||||
)
|
||||
|
||||
variable_temp = pytest.mark.parametrize(
|
||||
@ -110,6 +114,9 @@ def dev(request):
|
||||
for d in BULBS:
|
||||
if d in model:
|
||||
return SmartBulb
|
||||
for d in DIMMERS:
|
||||
if d in model:
|
||||
return SmartDimmer
|
||||
|
||||
raise Exception("Unable to find type for %s", model)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user