mirror of
https://github.com/python-kasa/python-kasa.git
synced 2024-12-23 03:33:35 +00:00
Add support for lightstrips (KL430) (#74)
* Preliminary support for light strips * Add color temperature range and cleanup, thanks to @darkoppressor * Use lightstrip instead of {led,light}strip consistently everywhere * The cli flag is now --lightstrip * add apidocs * Add fixture file for KL430 Signed-off-by: Kevin Wells <darkoppressor@gmail.com> * Add discovery support, expose effect and length of the strip * use set_light_state instead of transition_light_state * Add tests for lightstrip * add doctests * Add KL430 to supported devices in README Co-authored-by: Kevin Wells <darkoppressor@gmail.com>
This commit is contained in:
parent
0edbb4301f
commit
d30d00a3ff
@ -112,15 +112,18 @@ or the `parse_pcap.py` script contained inside the `devtools` directory.
|
|||||||
* HS110
|
* HS110
|
||||||
|
|
||||||
### Power Strips
|
### Power Strips
|
||||||
|
|
||||||
* HS300
|
* HS300
|
||||||
* KP303
|
* KP303
|
||||||
|
|
||||||
### Wall switches
|
### Wall switches
|
||||||
|
|
||||||
* HS200
|
* HS200
|
||||||
* HS210
|
* HS210
|
||||||
* HS220
|
* HS220
|
||||||
|
|
||||||
### Bulbs
|
### Bulbs
|
||||||
|
|
||||||
* LB100
|
* LB100
|
||||||
* LB110
|
* LB110
|
||||||
* LB120
|
* LB120
|
||||||
@ -131,6 +134,10 @@ or the `parse_pcap.py` script contained inside the `devtools` directory.
|
|||||||
* KL120
|
* KL120
|
||||||
* KL130
|
* KL130
|
||||||
|
|
||||||
|
### Light strips
|
||||||
|
|
||||||
|
* KL430
|
||||||
|
|
||||||
**Contributions (be it adding missing features, fixing bugs or improving documentation) are more than welcome, feel free to submit pull requests!**
|
**Contributions (be it adding missing features, fixing bugs or improving documentation) are more than welcome, feel free to submit pull requests!**
|
||||||
|
|
||||||
### Resources
|
### Resources
|
||||||
|
@ -15,3 +15,4 @@ python-kasa documentation
|
|||||||
smartplug
|
smartplug
|
||||||
smartdimmer
|
smartdimmer
|
||||||
smartstrip
|
smartstrip
|
||||||
|
smartlightstrip
|
||||||
|
6
docs/source/smartlightstrip.rst
Normal file
6
docs/source/smartlightstrip.rst
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Light strips
|
||||||
|
============
|
||||||
|
|
||||||
|
.. autoclass:: kasa.SmartLightStrip
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
@ -18,6 +18,7 @@ from kasa.protocol import TPLinkSmartHomeProtocol
|
|||||||
from kasa.smartbulb import SmartBulb
|
from kasa.smartbulb import SmartBulb
|
||||||
from kasa.smartdevice import DeviceType, EmeterStatus, SmartDevice
|
from kasa.smartdevice import DeviceType, EmeterStatus, SmartDevice
|
||||||
from kasa.smartdimmer import SmartDimmer
|
from kasa.smartdimmer import SmartDimmer
|
||||||
|
from kasa.smartlightstrip import SmartLightStrip
|
||||||
from kasa.smartplug import SmartPlug
|
from kasa.smartplug import SmartPlug
|
||||||
from kasa.smartstrip import SmartStrip
|
from kasa.smartstrip import SmartStrip
|
||||||
|
|
||||||
@ -35,4 +36,5 @@ __all__ = [
|
|||||||
"SmartPlug",
|
"SmartPlug",
|
||||||
"SmartStrip",
|
"SmartStrip",
|
||||||
"SmartDimmer",
|
"SmartDimmer",
|
||||||
|
"SmartLightStrip",
|
||||||
]
|
]
|
||||||
|
16
kasa/cli.py
16
kasa/cli.py
@ -7,7 +7,14 @@ from typing import cast
|
|||||||
|
|
||||||
import asyncclick as click
|
import asyncclick as click
|
||||||
|
|
||||||
from kasa import Discover, SmartBulb, SmartDevice, SmartPlug, SmartStrip
|
from kasa import (
|
||||||
|
Discover,
|
||||||
|
SmartBulb,
|
||||||
|
SmartDevice,
|
||||||
|
SmartLightStrip,
|
||||||
|
SmartPlug,
|
||||||
|
SmartStrip,
|
||||||
|
)
|
||||||
|
|
||||||
click.anyio_backend = "asyncio"
|
click.anyio_backend = "asyncio"
|
||||||
|
|
||||||
@ -37,10 +44,11 @@ pass_dev = click.make_pass_decorator(SmartDevice)
|
|||||||
@click.option("-d", "--debug", default=False, is_flag=True)
|
@click.option("-d", "--debug", default=False, is_flag=True)
|
||||||
@click.option("--bulb", default=False, is_flag=True)
|
@click.option("--bulb", default=False, is_flag=True)
|
||||||
@click.option("--plug", default=False, is_flag=True)
|
@click.option("--plug", default=False, is_flag=True)
|
||||||
|
@click.option("--lightstrip", default=False, is_flag=True)
|
||||||
@click.option("--strip", default=False, is_flag=True)
|
@click.option("--strip", default=False, is_flag=True)
|
||||||
@click.version_option()
|
@click.version_option()
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
async def cli(ctx, host, alias, target, debug, bulb, plug, strip):
|
async def cli(ctx, host, alias, target, debug, bulb, plug, lightstrip, strip):
|
||||||
"""A tool for controlling TP-Link smart home devices.""" # noqa
|
"""A tool for controlling TP-Link smart home devices.""" # noqa
|
||||||
if debug:
|
if debug:
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
@ -64,7 +72,7 @@ async def cli(ctx, host, alias, target, debug, bulb, plug, strip):
|
|||||||
await ctx.invoke(discover)
|
await ctx.invoke(discover)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
if not bulb and not plug and not strip:
|
if not bulb and not plug and not strip and not lightstrip:
|
||||||
click.echo("No --strip nor --bulb nor --plug given, discovering..")
|
click.echo("No --strip nor --bulb nor --plug given, discovering..")
|
||||||
dev = await Discover.discover_single(host)
|
dev = await Discover.discover_single(host)
|
||||||
elif bulb:
|
elif bulb:
|
||||||
@ -73,6 +81,8 @@ async def cli(ctx, host, alias, target, debug, bulb, plug, strip):
|
|||||||
dev = SmartPlug(host)
|
dev = SmartPlug(host)
|
||||||
elif strip:
|
elif strip:
|
||||||
dev = SmartStrip(host)
|
dev = SmartStrip(host)
|
||||||
|
elif lightstrip:
|
||||||
|
dev = SmartLightStrip(host)
|
||||||
else:
|
else:
|
||||||
click.echo("Unable to detect type, use --strip or --bulb or --plug!")
|
click.echo("Unable to detect type, use --strip or --bulb or --plug!")
|
||||||
return
|
return
|
||||||
|
@ -9,6 +9,7 @@ from kasa.protocol import TPLinkSmartHomeProtocol
|
|||||||
from kasa.smartbulb import SmartBulb
|
from kasa.smartbulb import SmartBulb
|
||||||
from kasa.smartdevice import SmartDevice, SmartDeviceException
|
from kasa.smartdevice import SmartDevice, SmartDeviceException
|
||||||
from kasa.smartdimmer import SmartDimmer
|
from kasa.smartdimmer import SmartDimmer
|
||||||
|
from kasa.smartlightstrip import SmartLightStrip
|
||||||
from kasa.smartplug import SmartPlug
|
from kasa.smartplug import SmartPlug
|
||||||
from kasa.smartstrip import SmartStrip
|
from kasa.smartstrip import SmartStrip
|
||||||
|
|
||||||
@ -227,11 +228,19 @@ class Discover:
|
|||||||
and "get_dimmer_parameters" in info["smartlife.iot.dimmer"]
|
and "get_dimmer_parameters" in info["smartlife.iot.dimmer"]
|
||||||
):
|
):
|
||||||
return SmartDimmer
|
return SmartDimmer
|
||||||
|
|
||||||
elif "smartplug" in type_.lower() and "children" in sysinfo:
|
elif "smartplug" in type_.lower() and "children" in sysinfo:
|
||||||
return SmartStrip
|
return SmartStrip
|
||||||
|
|
||||||
elif "smartplug" in type_.lower():
|
elif "smartplug" in type_.lower():
|
||||||
|
if "children" in sysinfo:
|
||||||
|
return SmartStrip
|
||||||
|
|
||||||
return SmartPlug
|
return SmartPlug
|
||||||
elif "smartbulb" in type_.lower():
|
elif "smartbulb" in type_.lower():
|
||||||
|
if "length" in sysinfo: # strips have length
|
||||||
|
return SmartLightStrip
|
||||||
|
|
||||||
return SmartBulb
|
return SmartBulb
|
||||||
|
|
||||||
raise SmartDeviceException("Unknown device type: %s", type_)
|
raise SmartDeviceException("Unknown device type: %s", type_)
|
||||||
|
@ -17,6 +17,7 @@ TPLINK_KELVIN = {
|
|||||||
"KL130": (2500, 9000),
|
"KL130": (2500, 9000),
|
||||||
r"KL120\(EU\)": (2700, 6500),
|
r"KL120\(EU\)": (2700, 6500),
|
||||||
r"KL120\(US\)": (2700, 5000),
|
r"KL120\(US\)": (2700, 5000),
|
||||||
|
r"KL430\(US\)": (2500, 9000),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -89,6 +90,7 @@ class SmartBulb(SmartDevice):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
LIGHT_SERVICE = "smartlife.iot.smartbulb.lightingservice"
|
LIGHT_SERVICE = "smartlife.iot.smartbulb.lightingservice"
|
||||||
|
SET_LIGHT_METHOD = "transition_light_state"
|
||||||
|
|
||||||
def __init__(self, host: str) -> None:
|
def __init__(self, host: str) -> None:
|
||||||
super().__init__(host=host)
|
super().__init__(host=host)
|
||||||
@ -190,7 +192,7 @@ class SmartBulb(SmartDevice):
|
|||||||
state["ignore_default"] = 1
|
state["ignore_default"] = 1
|
||||||
|
|
||||||
light_state = await self._query_helper(
|
light_state = await self._query_helper(
|
||||||
self.LIGHT_SERVICE, "transition_light_state", state
|
self.LIGHT_SERVICE, self.SET_LIGHT_METHOD, state
|
||||||
)
|
)
|
||||||
return light_state
|
return light_state
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ class DeviceType(Enum):
|
|||||||
Bulb = 2
|
Bulb = 2
|
||||||
Strip = 3
|
Strip = 3
|
||||||
Dimmer = 4
|
Dimmer = 4
|
||||||
|
LightStrip = 5
|
||||||
Unknown = -1
|
Unknown = -1
|
||||||
|
|
||||||
|
|
||||||
@ -702,6 +703,11 @@ class SmartDevice:
|
|||||||
"""Return True if the device is a bulb."""
|
"""Return True if the device is a bulb."""
|
||||||
return self._device_type == DeviceType.Bulb
|
return self._device_type == DeviceType.Bulb
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_light_strip(self) -> bool:
|
||||||
|
"""Return True if the device is a led strip."""
|
||||||
|
return self._device_type == DeviceType.LightStrip
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_plug(self) -> bool:
|
def is_plug(self) -> bool:
|
||||||
"""Return True if the device is a plug."""
|
"""Return True if the device is a plug."""
|
||||||
|
75
kasa/smartlightstrip.py
Normal file
75
kasa/smartlightstrip.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
"""Module for light strips (KL430)."""
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from .smartbulb import SmartBulb
|
||||||
|
from .smartdevice import DeviceType, requires_update
|
||||||
|
|
||||||
|
|
||||||
|
class SmartLightStrip(SmartBulb):
|
||||||
|
"""Representation of a TP-Link Smart light strip.
|
||||||
|
|
||||||
|
Light strips work similarly to bulbs, but use a different service for controlling,
|
||||||
|
and expose some extra information (such as length and active effect).
|
||||||
|
This class extends :class:`SmartBulb` interface.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> import asyncio
|
||||||
|
>>> strip = SmartLightStrip("127.0.0.1")
|
||||||
|
>>> asyncio.run(strip.update())
|
||||||
|
>>> print(strip.alias)
|
||||||
|
KL430 pantry lightstrip
|
||||||
|
|
||||||
|
Getting the length of the strip:
|
||||||
|
|
||||||
|
>>> strip.length
|
||||||
|
16
|
||||||
|
|
||||||
|
Currently active effect:
|
||||||
|
|
||||||
|
>>> strip.effect
|
||||||
|
{'brightness': 50, 'custom': 0, 'enable': 0, 'id': '', 'name': ''}
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
The device supports some features that are not currently implemented,
|
||||||
|
feel free to find out how to control them and create a PR!
|
||||||
|
|
||||||
|
|
||||||
|
See :class:`SmartBulb` for more examples.
|
||||||
|
"""
|
||||||
|
|
||||||
|
LIGHT_SERVICE = "smartlife.iot.lightStrip"
|
||||||
|
SET_LIGHT_METHOD = "set_light_state"
|
||||||
|
|
||||||
|
def __init__(self, host: str) -> None:
|
||||||
|
super().__init__(host)
|
||||||
|
self._device_type = DeviceType.LightStrip
|
||||||
|
|
||||||
|
@property # type: ignore
|
||||||
|
@requires_update
|
||||||
|
def length(self) -> int:
|
||||||
|
"""Return length of the strip."""
|
||||||
|
return self.sys_info["length"]
|
||||||
|
|
||||||
|
@property # type: ignore
|
||||||
|
@requires_update
|
||||||
|
def effect(self) -> Dict:
|
||||||
|
"""Return effect state.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
{'brightness': 50,
|
||||||
|
'custom': 0,
|
||||||
|
'enable': 0,
|
||||||
|
'id': '',
|
||||||
|
'name': ''}
|
||||||
|
"""
|
||||||
|
return self.sys_info["lighting_effect_state"]
|
||||||
|
|
||||||
|
@property # type: ignore
|
||||||
|
@requires_update
|
||||||
|
def state_information(self) -> Dict[str, Any]:
|
||||||
|
"""Return strip specific state information."""
|
||||||
|
info = super().state_information
|
||||||
|
|
||||||
|
info["Length"] = self.length
|
||||||
|
|
||||||
|
return info
|
@ -8,7 +8,14 @@ from unittest.mock import MagicMock
|
|||||||
|
|
||||||
import pytest # type: ignore # see https://github.com/pytest-dev/pytest/issues/3342
|
import pytest # type: ignore # see https://github.com/pytest-dev/pytest/issues/3342
|
||||||
|
|
||||||
from kasa import Discover, SmartBulb, SmartDimmer, SmartPlug, SmartStrip
|
from kasa import (
|
||||||
|
Discover,
|
||||||
|
SmartBulb,
|
||||||
|
SmartDimmer,
|
||||||
|
SmartLightStrip,
|
||||||
|
SmartPlug,
|
||||||
|
SmartStrip,
|
||||||
|
)
|
||||||
|
|
||||||
from .newfakes import FakeTransportProtocol
|
from .newfakes import FakeTransportProtocol
|
||||||
|
|
||||||
@ -17,9 +24,11 @@ SUPPORTED_DEVICES = glob.glob(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
BULBS = {"KL60", "LB100", "LB120", "LB130", "KL120", "KL130"}
|
LIGHT_STRIPS = {"KL430"}
|
||||||
VARIABLE_TEMP = {"LB120", "LB130", "KL120", "KL130"}
|
BULBS = {"KL60", "LB100", "LB120", "LB130", "KL120", "KL130", *LIGHT_STRIPS}
|
||||||
COLOR_BULBS = {"LB130", "KL130"}
|
VARIABLE_TEMP = {"LB120", "LB130", "KL120", "KL130", "KL430", *LIGHT_STRIPS}
|
||||||
|
COLOR_BULBS = {"LB130", "KL130", *LIGHT_STRIPS}
|
||||||
|
|
||||||
|
|
||||||
PLUGS = {"HS100", "HS103", "HS105", "HS110", "HS200", "HS210"}
|
PLUGS = {"HS100", "HS103", "HS105", "HS110", "HS200", "HS210"}
|
||||||
STRIPS = {"HS107", "HS300", "KP303", "KP400"}
|
STRIPS = {"HS107", "HS300", "KP303", "KP400"}
|
||||||
@ -65,9 +74,12 @@ bulb = parametrize("bulbs", BULBS, ids=name_for_filename)
|
|||||||
plug = parametrize("plugs", PLUGS, ids=name_for_filename)
|
plug = parametrize("plugs", PLUGS, ids=name_for_filename)
|
||||||
strip = parametrize("strips", STRIPS, ids=name_for_filename)
|
strip = parametrize("strips", STRIPS, ids=name_for_filename)
|
||||||
dimmer = parametrize("dimmers", DIMMERS, ids=name_for_filename)
|
dimmer = parametrize("dimmers", DIMMERS, ids=name_for_filename)
|
||||||
|
lightstrip = parametrize("lightstrips", LIGHT_STRIPS, ids=name_for_filename)
|
||||||
|
|
||||||
# This ensures that every single file inside fixtures/ is being placed in some category
|
# This ensures that every single file inside fixtures/ is being placed in some category
|
||||||
categorized_fixtures = set(dimmer.args[1] + strip.args[1] + plug.args[1] + bulb.args[1])
|
categorized_fixtures = set(
|
||||||
|
dimmer.args[1] + strip.args[1] + plug.args[1] + bulb.args[1] + lightstrip.args[1]
|
||||||
|
)
|
||||||
diff = set(SUPPORTED_DEVICES) - set(categorized_fixtures)
|
diff = set(SUPPORTED_DEVICES) - set(categorized_fixtures)
|
||||||
if diff:
|
if diff:
|
||||||
for file in diff:
|
for file in diff:
|
||||||
@ -105,12 +117,20 @@ def device_for_file(model):
|
|||||||
for d in STRIPS:
|
for d in STRIPS:
|
||||||
if d in model:
|
if d in model:
|
||||||
return SmartStrip
|
return SmartStrip
|
||||||
|
|
||||||
for d in PLUGS:
|
for d in PLUGS:
|
||||||
if d in model:
|
if d in model:
|
||||||
return SmartPlug
|
return SmartPlug
|
||||||
|
|
||||||
|
# Light strips are recognized also as bulbs, so this has to go first
|
||||||
|
for d in LIGHT_STRIPS:
|
||||||
|
if d in model:
|
||||||
|
return SmartLightStrip
|
||||||
|
|
||||||
for d in BULBS:
|
for d in BULBS:
|
||||||
if d in model:
|
if d in model:
|
||||||
return SmartBulb
|
return SmartBulb
|
||||||
|
|
||||||
for d in DIMMERS:
|
for d in DIMMERS:
|
||||||
if d in model:
|
if d in model:
|
||||||
return SmartDimmer
|
return SmartDimmer
|
||||||
|
70
kasa/tests/fixtures/KL430(US)_1.0.json
vendored
Normal file
70
kasa/tests/fixtures/KL430(US)_1.0.json
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"emeter": {
|
||||||
|
"err_code": -1,
|
||||||
|
"err_msg": "module not support"
|
||||||
|
},
|
||||||
|
"smartlife.iot.common.emeter": {
|
||||||
|
"get_realtime": {
|
||||||
|
"current_ma": 0,
|
||||||
|
"err_code": 0,
|
||||||
|
"power_mw": 8729,
|
||||||
|
"total_wh": 21,
|
||||||
|
"voltage_mv": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"smartlife.iot.dimmer": {
|
||||||
|
"err_code": -1,
|
||||||
|
"err_msg": "module not support"
|
||||||
|
},
|
||||||
|
"smartlife.iot.smartbulb.lightingservice": {
|
||||||
|
"err_code": -1,
|
||||||
|
"err_msg": "module not support"
|
||||||
|
},
|
||||||
|
"system": {
|
||||||
|
"get_sysinfo": {
|
||||||
|
"active_mode": "none",
|
||||||
|
"alias": "KL430 pantry lightstrip",
|
||||||
|
"ctrl_protocols": {
|
||||||
|
"name": "Linkie",
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"description": "Kasa Smart Light Strip, Multicolor",
|
||||||
|
"dev_state": "normal",
|
||||||
|
"deviceId": "0000000000000000000000000000000000000000",
|
||||||
|
"disco_ver": "1.0",
|
||||||
|
"err_code": 0,
|
||||||
|
"hwId": "00000000000000000000000000000000",
|
||||||
|
"hw_ver": "1.0",
|
||||||
|
"is_color": 1,
|
||||||
|
"is_dimmable": 1,
|
||||||
|
"is_factory": false,
|
||||||
|
"is_variable_color_temp": 1,
|
||||||
|
"latitude_i": 0,
|
||||||
|
"length": 16,
|
||||||
|
"light_state": {
|
||||||
|
"brightness": 50,
|
||||||
|
"color_temp": 3630,
|
||||||
|
"hue": 0,
|
||||||
|
"mode": "normal",
|
||||||
|
"on_off": 1,
|
||||||
|
"saturation": 0
|
||||||
|
},
|
||||||
|
"lighting_effect_state": {
|
||||||
|
"brightness": 50,
|
||||||
|
"custom": 0,
|
||||||
|
"enable": 0,
|
||||||
|
"id": "",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"longitude_i": 0,
|
||||||
|
"mic_mac": "CC32E5230F55",
|
||||||
|
"mic_type": "IOT.SMARTBULB",
|
||||||
|
"model": "KL430(US)",
|
||||||
|
"oemId": "00000000000000000000000000000000",
|
||||||
|
"preferred_state": [],
|
||||||
|
"rssi": -56,
|
||||||
|
"status": "new",
|
||||||
|
"sw_ver": "1.0.10 Build 200522 Rel.104340"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -355,7 +355,8 @@ class FakeTransportProtocol(TPLinkSmartHomeProtocol):
|
|||||||
light_state = self.proto["system"]["get_sysinfo"]["light_state"]
|
light_state = self.proto["system"]["get_sysinfo"]["light_state"]
|
||||||
# Our tests have light state off, so we simply return the dft_on_state when device is on.
|
# Our tests have light state off, so we simply return the dft_on_state when device is on.
|
||||||
_LOGGER.debug("reporting light state: %s", light_state)
|
_LOGGER.debug("reporting light state: %s", light_state)
|
||||||
if light_state["on_off"]:
|
# TODO: hack to go around KL430 fixture differences
|
||||||
|
if light_state["on_off"] and "dft_on_state" in light_state:
|
||||||
return light_state["dft_on_state"]
|
return light_state["dft_on_state"]
|
||||||
else:
|
else:
|
||||||
return light_state
|
return light_state
|
||||||
@ -385,6 +386,11 @@ class FakeTransportProtocol(TPLinkSmartHomeProtocol):
|
|||||||
"get_light_state": light_state,
|
"get_light_state": light_state,
|
||||||
"transition_light_state": transition_light_state,
|
"transition_light_state": transition_light_state,
|
||||||
},
|
},
|
||||||
|
# lightstrip follows the same payloads but uses different module & method
|
||||||
|
"smartlife.iot.lightStrip": {
|
||||||
|
"set_light_state": transition_light_state,
|
||||||
|
"get_light_state": light_state,
|
||||||
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"get_time": {
|
"get_time": {
|
||||||
"year": 2017,
|
"year": 2017,
|
||||||
|
@ -24,6 +24,8 @@ async def test_bulb_sysinfo(dev):
|
|||||||
|
|
||||||
assert dev.model is not None
|
assert dev.model is not None
|
||||||
|
|
||||||
|
# TODO: remove special handling for lightstrip
|
||||||
|
if not dev.is_light_strip:
|
||||||
assert dev.device_type == DeviceType.Bulb
|
assert dev.device_type == DeviceType.Bulb
|
||||||
assert dev.is_bulb
|
assert dev.is_bulb
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import pytest # type: ignore # https://github.com/pytest-dev/pytest/issues/3342
|
|||||||
|
|
||||||
from kasa import DeviceType, Discover, SmartDevice, SmartDeviceException
|
from kasa import DeviceType, Discover, SmartDevice, SmartDeviceException
|
||||||
|
|
||||||
from .conftest import bulb, dimmer, plug, pytestmark, strip
|
from .conftest import bulb, dimmer, lightstrip, plug, pytestmark, strip
|
||||||
|
|
||||||
|
|
||||||
@plug
|
@plug
|
||||||
@ -16,6 +16,8 @@ async def test_type_detection_plug(dev: SmartDevice):
|
|||||||
@bulb
|
@bulb
|
||||||
async def test_type_detection_bulb(dev: SmartDevice):
|
async def test_type_detection_bulb(dev: SmartDevice):
|
||||||
d = Discover._get_device_class(dev.protocol.discovery_data)("localhost")
|
d = Discover._get_device_class(dev.protocol.discovery_data)("localhost")
|
||||||
|
# TODO: light_strip is a special case for now to force bulb tests on it
|
||||||
|
if not d.is_light_strip:
|
||||||
assert d.is_bulb
|
assert d.is_bulb
|
||||||
assert d.device_type == DeviceType.Bulb
|
assert d.device_type == DeviceType.Bulb
|
||||||
|
|
||||||
@ -34,6 +36,13 @@ async def test_type_detection_dimmer(dev: SmartDevice):
|
|||||||
assert d.device_type == DeviceType.Dimmer
|
assert d.device_type == DeviceType.Dimmer
|
||||||
|
|
||||||
|
|
||||||
|
@lightstrip
|
||||||
|
async def test_type_detection_lightstrip(dev: SmartDevice):
|
||||||
|
d = Discover._get_device_class(dev.protocol.discovery_data)("localhost")
|
||||||
|
assert d.is_light_strip
|
||||||
|
assert d.device_type == DeviceType.LightStrip
|
||||||
|
|
||||||
|
|
||||||
async def test_type_unknown():
|
async def test_type_unknown():
|
||||||
invalid_info = {"system": {"get_sysinfo": {"type": "nosuchtype"}}}
|
invalid_info = {"system": {"get_sysinfo": {"type": "nosuchtype"}}}
|
||||||
with pytest.raises(SmartDeviceException):
|
with pytest.raises(SmartDeviceException):
|
||||||
|
@ -51,6 +51,15 @@ def test_dimmer_examples(mocker):
|
|||||||
assert not res["failed"]
|
assert not res["failed"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_lightstrip_examples(mocker):
|
||||||
|
"""Test lightstrip examples."""
|
||||||
|
p = get_device_for_file("KL430(US)_1.0.json")
|
||||||
|
mocker.patch("kasa.smartlightstrip.SmartLightStrip", return_value=p)
|
||||||
|
mocker.patch("kasa.smartlightstrip.SmartLightStrip.update")
|
||||||
|
res = xdoctest.doctest_module("kasa.smartlightstrip", "all")
|
||||||
|
assert not res["failed"]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
sys.version_info < (3, 8), reason="3.7 handles asyncio.run differently"
|
sys.version_info < (3, 8), reason="3.7 handles asyncio.run differently"
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user