mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-12-02 06:08:17 +00:00
mass rename to (python-)kasa (#1)
This commit is contained in:
0
kasa/tests/__init__.py
Normal file
0
kasa/tests/__init__.py
Normal file
124
kasa/tests/conftest.py
Normal file
124
kasa/tests/conftest.py
Normal file
@@ -0,0 +1,124 @@
|
||||
import asyncio
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
from os.path import basename
|
||||
|
||||
import pytest
|
||||
|
||||
from kasa import Discover, SmartBulb, SmartPlug, SmartStrip
|
||||
|
||||
from .newfakes import FakeTransportProtocol
|
||||
|
||||
SUPPORTED_DEVICES = glob.glob(
|
||||
os.path.dirname(os.path.abspath(__file__)) + "/fixtures/*.json"
|
||||
)
|
||||
|
||||
BULBS = {"LB100", "LB120", "LB130", "KL120"}
|
||||
VARIABLE_TEMP = {"LB120", "LB130", "KL120"}
|
||||
PLUGS = {"HS100", "HS105", "HS110", "HS200", "HS220", "HS300"}
|
||||
STRIPS = {"HS300"}
|
||||
COLOR_BULBS = {"LB130"}
|
||||
DIMMABLE = {*BULBS, "HS220"}
|
||||
EMETER = {"HS110", "HS300", *BULBS}
|
||||
|
||||
ALL_DEVICES = BULBS.union(PLUGS)
|
||||
|
||||
|
||||
def filter_model(filter):
|
||||
print(filter)
|
||||
filtered = list()
|
||||
for dev in SUPPORTED_DEVICES:
|
||||
for filt in filter:
|
||||
if filt in basename(dev):
|
||||
filtered.append(dev)
|
||||
|
||||
return filtered
|
||||
|
||||
|
||||
def get_ioloop():
|
||||
ioloop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(ioloop)
|
||||
return ioloop
|
||||
|
||||
|
||||
has_emeter = pytest.mark.parametrize("dev", filter_model(EMETER), indirect=True)
|
||||
no_emeter = pytest.mark.parametrize(
|
||||
"dev", filter_model(ALL_DEVICES - EMETER), indirect=True
|
||||
)
|
||||
|
||||
bulb = pytest.mark.parametrize("dev", filter_model(BULBS), indirect=True)
|
||||
plug = pytest.mark.parametrize("dev", filter_model(PLUGS), indirect=True)
|
||||
strip = pytest.mark.parametrize("dev", filter_model(STRIPS), indirect=True)
|
||||
|
||||
dimmable = pytest.mark.parametrize("dev", filter_model(DIMMABLE), indirect=True)
|
||||
non_dimmable = pytest.mark.parametrize(
|
||||
"dev", filter_model(ALL_DEVICES - DIMMABLE), indirect=True
|
||||
)
|
||||
|
||||
variable_temp = pytest.mark.parametrize(
|
||||
"dev", filter_model(VARIABLE_TEMP), indirect=True
|
||||
)
|
||||
non_variable_temp = pytest.mark.parametrize(
|
||||
"dev", filter_model(BULBS - VARIABLE_TEMP), indirect=True
|
||||
)
|
||||
|
||||
color_bulb = pytest.mark.parametrize("dev", filter_model(COLOR_BULBS), indirect=True)
|
||||
non_color_bulb = pytest.mark.parametrize(
|
||||
"dev", filter_model(BULBS - COLOR_BULBS), indirect=True
|
||||
)
|
||||
|
||||
|
||||
# Parametrize tests to run with device both on and off
|
||||
turn_on = pytest.mark.parametrize("turn_on", [True, False])
|
||||
|
||||
|
||||
def handle_turn_on(dev, turn_on):
|
||||
if turn_on:
|
||||
dev.sync.turn_on()
|
||||
else:
|
||||
dev.sync.turn_off()
|
||||
|
||||
|
||||
@pytest.fixture(params=SUPPORTED_DEVICES)
|
||||
def dev(request):
|
||||
ioloop = get_ioloop()
|
||||
file = request.param
|
||||
|
||||
ip = request.config.getoption("--ip")
|
||||
if ip:
|
||||
d = ioloop.run_until_complete(Discover.discover_single(ip))
|
||||
print(d.model)
|
||||
if d.model in file:
|
||||
return d
|
||||
return
|
||||
|
||||
with open(file) as f:
|
||||
sysinfo = json.load(f)
|
||||
model = basename(file)
|
||||
params = {
|
||||
"host": "123.123.123.123",
|
||||
"protocol": FakeTransportProtocol(sysinfo),
|
||||
"cache_ttl": 0,
|
||||
}
|
||||
if "LB" in model or "KL" in model:
|
||||
p = SmartBulb(**params, ioloop=ioloop)
|
||||
elif "HS300" in model:
|
||||
p = SmartStrip(**params, ioloop=ioloop)
|
||||
elif "HS" in model:
|
||||
p = SmartPlug(**params, ioloop=ioloop)
|
||||
else:
|
||||
raise Exception("No tests for %s" % model)
|
||||
yield p
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--ip", action="store", default=None, help="run against device")
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(config, items):
|
||||
if not config.getoption("--ip"):
|
||||
print("Testing against fixtures.")
|
||||
return
|
||||
else:
|
||||
print("Running against ip %s" % config.getoption("--ip"))
|
||||
47
kasa/tests/fixtures/HS100(US)_1.0.json
vendored
Normal file
47
kasa/tests/fixtures/HS100(US)_1.0.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"emeter": {
|
||||
"get_realtime": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"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": "schedule",
|
||||
"alias": "Mock hs100",
|
||||
"dev_name": "Wi-Fi Smart Plug",
|
||||
"deviceId": "048F069965D3230FD1382F0B78EAE68D42CAA2DE",
|
||||
"err_code": 0,
|
||||
"feature": "TIM",
|
||||
"hwId": "92688D028799C60F926049D1C9EFD9E8",
|
||||
"hw_ver": "1.0",
|
||||
"icon_hash": "",
|
||||
"latitude": 63.5442,
|
||||
"latitude_i": 63.5442,
|
||||
"led_off": 0,
|
||||
"longitude": -148.2817,
|
||||
"longitude_i": -148.2817,
|
||||
"mac": "50:c7:bf:a3:71:c0",
|
||||
"model": "HS100(US)",
|
||||
"oemId": "149C8A24AA3A1445DE84F00DFB210D60",
|
||||
"on_time": 0,
|
||||
"relay_state": 0,
|
||||
"rssi": -65,
|
||||
"sw_ver": "1.2.5 Build 171129 Rel.174814",
|
||||
"type": "IOT.SMARTPLUGSWITCH",
|
||||
"updating": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
47
kasa/tests/fixtures/HS105(US)_1.0.json
vendored
Normal file
47
kasa/tests/fixtures/HS105(US)_1.0.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"emeter": {
|
||||
"get_realtime": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"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": "schedule",
|
||||
"alias": "Mock hs105",
|
||||
"dev_name": "Smart Wi-Fi Plug Mini",
|
||||
"deviceId": "F0723FAFC1FA27FC755B9F228A2297D921FEBCD1",
|
||||
"err_code": 0,
|
||||
"feature": "TIM",
|
||||
"hwId": "51E17031929D5FEF9147091AD67B954A",
|
||||
"hw_ver": "1.0",
|
||||
"icon_hash": "",
|
||||
"INVALIDlatitude": 79.7779,
|
||||
"latitude_i": 79.7779,
|
||||
"led_off": 0,
|
||||
"INVALIDlongitude": 90.8844,
|
||||
"longitude_i": 90.8844,
|
||||
"mac": "50:c7:bf:ac:c0:6a",
|
||||
"model": "HS105(US)",
|
||||
"oemId": "990ADB7AEDE871C41D1B7613D1FE7A76",
|
||||
"on_time": 0,
|
||||
"relay_state": 0,
|
||||
"rssi": -65,
|
||||
"sw_ver": "1.2.9 Build 170808 Rel.145916",
|
||||
"type": "IOT.SMARTPLUGSWITCH",
|
||||
"updating": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
49
kasa/tests/fixtures/HS110(EU)_1.0_real.json
vendored
Normal file
49
kasa/tests/fixtures/HS110(EU)_1.0_real.json
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"emeter": {
|
||||
"get_realtime": {
|
||||
"current": 0.015342,
|
||||
"err_code": 0,
|
||||
"power": 0.983971,
|
||||
"total": 32.448,
|
||||
"voltage": 235.595234
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"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": "schedule",
|
||||
"alias": "Kitchen",
|
||||
"dev_name": "Wi-Fi Smart Plug With Energy Monitoring",
|
||||
"deviceId": "8006588E50AD389303FF31AB6302907A17442F16",
|
||||
"err_code": 0,
|
||||
"feature": "TIM:ENE",
|
||||
"fwId": "00000000000000000000000000000000",
|
||||
"hwId": "45E29DA8382494D2E82688B52A0B2EB5",
|
||||
"hw_ver": "1.0",
|
||||
"icon_hash": "",
|
||||
"latitude": 51.476938,
|
||||
"led_off": 1,
|
||||
"longitude": 7.216849,
|
||||
"mac": "50:C7:BF:01:F8:CD",
|
||||
"model": "HS110(EU)",
|
||||
"oemId": "3D341ECE302C0642C99E31CE2430544B",
|
||||
"on_time": 512874,
|
||||
"relay_state": 1,
|
||||
"rssi": -71,
|
||||
"sw_ver": "1.2.5 Build 171213 Rel.101523",
|
||||
"type": "IOT.SMARTPLUGSWITCH",
|
||||
"updating": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
50
kasa/tests/fixtures/HS110(EU)_2.0.json
vendored
Normal file
50
kasa/tests/fixtures/HS110(EU)_2.0.json
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"emeter": {
|
||||
"get_realtime": {
|
||||
"current_ma": 125,
|
||||
"err_code": 0,
|
||||
"power_mw": 3140,
|
||||
"total_wh": 51493,
|
||||
"voltage_mv": 122049
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"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": "schedule",
|
||||
"alias": "Mock hs110v2",
|
||||
"dev_name": "Smart Wi-Fi Plug With Energy Monitoring",
|
||||
"deviceId": "A466BCDB5026318939145B7CC7EF18D8C1D3A954",
|
||||
"err_code": 0,
|
||||
"feature": "TIM:ENE",
|
||||
"hwId": "1F7FABB46373CA51E3AFDE5930ECBB36",
|
||||
"hw_ver": "2.0",
|
||||
"icon_hash": "",
|
||||
"INVALIDlatitude": -60.4599,
|
||||
"latitude_i": -60.4599,
|
||||
"led_off": 0,
|
||||
"INVALIDlongitude": 76.1249,
|
||||
"longitude_i": 76.1249,
|
||||
"mac": "50:c7:bf:b9:40:08",
|
||||
"model": "HS110(EU)",
|
||||
"oemId": "BB668B949FA4559655F1187DD56622BD",
|
||||
"on_time": 0,
|
||||
"relay_state": 0,
|
||||
"rssi": -65,
|
||||
"sw_ver": "1.5.2 Build 180130 Rel.085820",
|
||||
"type": "IOT.SMARTPLUGSWITCH",
|
||||
"updating": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
50
kasa/tests/fixtures/HS110(US)_1.0.json
vendored
Normal file
50
kasa/tests/fixtures/HS110(US)_1.0.json
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"emeter": {
|
||||
"get_realtime": {
|
||||
"current": 0.1256,
|
||||
"err_code": 0,
|
||||
"power": 3.14,
|
||||
"total": 51.493,
|
||||
"voltage": 122.049119
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"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": "schedule",
|
||||
"alias": "Mock hs110",
|
||||
"dev_name": "Wi-Fi Smart Plug With Energy Monitoring",
|
||||
"deviceId": "11A5FD4A0FA1FCE5468F55D23CE77D1753A93E11",
|
||||
"err_code": 0,
|
||||
"feature": "TIM:ENE",
|
||||
"hwId": "6C56A17315351DD0EDE0BDB1D9EBBD66",
|
||||
"hw_ver": "1.0",
|
||||
"icon_hash": "",
|
||||
"latitude": 82.2866,
|
||||
"latitude_i": 82.2866,
|
||||
"led_off": 0,
|
||||
"longitude": 10.0036,
|
||||
"longitude_i": 10.0036,
|
||||
"mac": "50:c7:bf:66:29:29",
|
||||
"model": "HS110(US)",
|
||||
"oemId": "F7DFC14D43DA806B55DB66D21F212B60",
|
||||
"on_time": 0,
|
||||
"relay_state": 0,
|
||||
"rssi": -65,
|
||||
"sw_ver": "1.0.8 Build 151113 Rel.24658",
|
||||
"type": "IOT.SMARTPLUGSWITCH",
|
||||
"updating": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
47
kasa/tests/fixtures/HS200(US)_1.0.json
vendored
Normal file
47
kasa/tests/fixtures/HS200(US)_1.0.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"emeter": {
|
||||
"get_realtime": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"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": "schedule",
|
||||
"alias": "Mock hs200",
|
||||
"dev_name": "Wi-Fi Smart Light Switch",
|
||||
"deviceId": "EC565185337CF59A4C9A73442AAD5F11C6E91716",
|
||||
"err_code": 0,
|
||||
"feature": "TIM",
|
||||
"hwId": "4B5DB5E42F13728107D075EF5C3ECFA1",
|
||||
"hw_ver": "1.0",
|
||||
"icon_hash": "",
|
||||
"latitude": 58.7882,
|
||||
"latitude_i": 58.7882,
|
||||
"led_off": 0,
|
||||
"longitude": 107.7225,
|
||||
"longitude_i": 107.7225,
|
||||
"mac": "50:c7:bf:95:4b:45",
|
||||
"model": "HS200(US)",
|
||||
"oemId": "D2A5D690B25980755216FD684AF8CD88",
|
||||
"on_time": 0,
|
||||
"relay_state": 0,
|
||||
"rssi": -65,
|
||||
"sw_ver": "1.1.0 Build 160521 Rel.085826",
|
||||
"type": "IOT.SMARTPLUGSWITCH",
|
||||
"updating": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
75
kasa/tests/fixtures/HS220(US)_1.0.json
vendored
Normal file
75
kasa/tests/fixtures/HS220(US)_1.0.json
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"emeter": {
|
||||
"get_realtime": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"smartlife.iot.dimmer": {
|
||||
"get_dimmer_parameters": {
|
||||
"bulb_type": 1,
|
||||
"err_code": 0,
|
||||
"fadeOffTime": 3000,
|
||||
"fadeOnTime": 3000,
|
||||
"gentleOffTime": 510000,
|
||||
"gentleOnTime": 3000,
|
||||
"minThreshold": 0,
|
||||
"rampRate": 30
|
||||
}
|
||||
},
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"active_mode": "count_down",
|
||||
"alias": "Mock hs220",
|
||||
"brightness": 50,
|
||||
"dev_name": "Smart Wi-Fi Dimmer",
|
||||
"deviceId": "98E16F2D5ED204F3094CF472260237133DC0D547",
|
||||
"err_code": 0,
|
||||
"feature": "TIM",
|
||||
"hwId": "231004CCCDB6C0B8FC7A3260C3470257",
|
||||
"hw_ver": "1.0",
|
||||
"icon_hash": "",
|
||||
"INVALIDlatitude": 11.6210,
|
||||
"latitude_i": 11.6210,
|
||||
"led_off": 0,
|
||||
"INVALIDlongitude": 42.2074,
|
||||
"longitude_i": 42.2074,
|
||||
"mac": "50:c7:bf:af:75:5d",
|
||||
"mic_type": "IOT.SMARTPLUGSWITCH",
|
||||
"model": "HS220(US)",
|
||||
"oemId": "8FBD0F3CCF7E82836DC7996C524EF772",
|
||||
"on_time": 0,
|
||||
"preferred_state": [
|
||||
{
|
||||
"brightness": 100,
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"brightness": 75,
|
||||
"index": 1
|
||||
},
|
||||
{
|
||||
"brightness": 50,
|
||||
"index": 2
|
||||
},
|
||||
{
|
||||
"brightness": 25,
|
||||
"index": 3
|
||||
}
|
||||
],
|
||||
"relay_state": 0,
|
||||
"rssi": -65,
|
||||
"sw_ver": "1.5.7 Build 180912 Rel.104837",
|
||||
"type": "IOT.SMARTPLUGSWITCH",
|
||||
"updating": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
76
kasa/tests/fixtures/HS220(US)_1.0_real.json
vendored
Normal file
76
kasa/tests/fixtures/HS220(US)_1.0_real.json
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"emeter": {
|
||||
"get_realtime": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"smartlife.iot.dimmer": {
|
||||
"get_dimmer_parameters": {
|
||||
"bulb_type": 1,
|
||||
"err_code": 0,
|
||||
"fadeOffTime": 1000,
|
||||
"fadeOnTime": 1000,
|
||||
"gentleOffTime": 10000,
|
||||
"gentleOnTime": 3000,
|
||||
"minThreshold": 0,
|
||||
"rampRate": 30
|
||||
}
|
||||
},
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"active_mode": "none",
|
||||
"alias": "Living room left dimmer",
|
||||
"brightness": 25,
|
||||
"dev_name": "Smart Wi-Fi Dimmer",
|
||||
"deviceId": "000000000000000000000000000000000000000",
|
||||
"err_code": 0,
|
||||
"feature": "TIM",
|
||||
"fwId": "00000000000000000000000000000000",
|
||||
"hwId": "00000000000000000000000000000000",
|
||||
"hw_ver": "1.0",
|
||||
"icon_hash": "",
|
||||
"latitude_i": 11.6210,
|
||||
"led_off": 0,
|
||||
"longitude_i": 42.2074,
|
||||
"mac": "00:00:00:00:00:00",
|
||||
"mic_type": "IOT.SMARTPLUGSWITCH",
|
||||
"model": "HS220(US)",
|
||||
"next_action": {
|
||||
"type": -1
|
||||
},
|
||||
"oemId": "00000000000000000000000000000000",
|
||||
"on_time": 0,
|
||||
"preferred_state": [
|
||||
{
|
||||
"brightness": 100,
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"brightness": 75,
|
||||
"index": 1
|
||||
},
|
||||
{
|
||||
"brightness": 50,
|
||||
"index": 2
|
||||
},
|
||||
{
|
||||
"brightness": 25,
|
||||
"index": 3
|
||||
}
|
||||
],
|
||||
"relay_state": 0,
|
||||
"rssi": -35,
|
||||
"sw_ver": "1.5.7 Build 180912 Rel.104837",
|
||||
"updating": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
102
kasa/tests/fixtures/HS300(US)_1.0.json
vendored
Normal file
102
kasa/tests/fixtures/HS300(US)_1.0.json
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"emeter": {
|
||||
"get_realtime": {
|
||||
"current_ma": 125,
|
||||
"err_code": 0,
|
||||
"power_mw": 3140,
|
||||
"total_wh": 51493,
|
||||
"voltage_mv": 122049
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"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": {
|
||||
"alias": "Mock hs300",
|
||||
"child_num": 6,
|
||||
"children": [
|
||||
{
|
||||
"alias": "Mock One",
|
||||
"id": "00",
|
||||
"next_action": {
|
||||
"type": -1
|
||||
},
|
||||
"on_time": 123,
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"alias": "Mock Two",
|
||||
"id": "01",
|
||||
"next_action": {
|
||||
"type": -1
|
||||
},
|
||||
"on_time": 333,
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"alias": "Mock Three",
|
||||
"id": "02",
|
||||
"next_action": {
|
||||
"type": -1
|
||||
},
|
||||
"on_time": 0,
|
||||
"state": 0
|
||||
},
|
||||
{
|
||||
"alias": "Mock Four",
|
||||
"id": "03",
|
||||
"next_action": {
|
||||
"type": -1
|
||||
},
|
||||
"on_time": 0,
|
||||
"state": 0
|
||||
},
|
||||
{
|
||||
"alias": "Mock Five",
|
||||
"id": "04",
|
||||
"next_action": {
|
||||
"type": -1
|
||||
},
|
||||
"on_time": 0,
|
||||
"state": 0
|
||||
},
|
||||
{
|
||||
"alias": "Mock Six",
|
||||
"id": "05",
|
||||
"next_action": {
|
||||
"type": -1
|
||||
},
|
||||
"on_time": 0,
|
||||
"state": 0
|
||||
}
|
||||
],
|
||||
"deviceId": "4BFC2F2C8678FE623700FD3737EC4E245196F3CF",
|
||||
"err_code": 0,
|
||||
"feature": "TIM:ENE",
|
||||
"hwId": "1B63E5DF21B5AFB52F364DE66BFAAF8A",
|
||||
"hw_ver": "1.0",
|
||||
"latitude": -68.9980,
|
||||
"latitude_i": -68.9980,
|
||||
"led_off": 0,
|
||||
"longitude": -109.4400,
|
||||
"longitude_i": -109.4400,
|
||||
"mac": "50:c7:bf:c2:75:88",
|
||||
"mic_type": "IOT.SMARTPLUGSWITCH",
|
||||
"model": "HS300(US)",
|
||||
"oemId": "FC71DAAB004326F9369EDEF4353E4FE1",
|
||||
"rssi": -68,
|
||||
"sw_ver": "1.0.6 Build 180627 Rel.081000",
|
||||
"updating": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
93
kasa/tests/fixtures/KL120(US)_1.0_real.json
vendored
Normal file
93
kasa/tests/fixtures/KL120(US)_1.0_real.json
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"emeter": {
|
||||
"err_code": -2001,
|
||||
"err_msg": "Module not support"
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"get_realtime": {
|
||||
"err_code": 0,
|
||||
"power_mw": 1800
|
||||
}
|
||||
},
|
||||
"smartlife.iot.dimmer": {
|
||||
"err_code": -2001,
|
||||
"err_msg": "Module not support"
|
||||
},
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"get_light_state": {
|
||||
"brightness": 10,
|
||||
"color_temp": 2700,
|
||||
"err_code": 0,
|
||||
"hue": 0,
|
||||
"mode": "normal",
|
||||
"on_off": 1,
|
||||
"saturation": 0
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"active_mode": "none",
|
||||
"alias": "",
|
||||
"ctrl_protocols": {
|
||||
"name": "Linkie",
|
||||
"version": "1.0"
|
||||
},
|
||||
"description": "Smart Wi-Fi LED Bulb with Tunable White Light",
|
||||
"dev_state": "normal",
|
||||
"deviceId": "801200814AD69370AC59DE5501319C051AF409C3",
|
||||
"disco_ver": "1.0",
|
||||
"err_code": 0,
|
||||
"heapsize": 290784,
|
||||
"hwId": "111E35908497A05512E259BB76801E10",
|
||||
"hw_ver": "1.0",
|
||||
"is_color": 0,
|
||||
"is_dimmable": 1,
|
||||
"is_factory": false,
|
||||
"is_variable_color_temp": 1,
|
||||
"light_state": {
|
||||
"brightness": 10,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"mode": "normal",
|
||||
"on_off": 1,
|
||||
"saturation": 0
|
||||
},
|
||||
"mic_mac": "D80D17150474",
|
||||
"mic_type": "IOT.SMARTBULB",
|
||||
"model": "KL120(US)",
|
||||
"oemId": "1210657CD7FBDC72895644388EEFAE8B",
|
||||
"preferred_state": [
|
||||
{
|
||||
"brightness": 100,
|
||||
"color_temp": 3500,
|
||||
"hue": 0,
|
||||
"index": 0,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 50,
|
||||
"color_temp": 5000,
|
||||
"hue": 0,
|
||||
"index": 1,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 50,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 2,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 1,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 3,
|
||||
"saturation": 0
|
||||
}
|
||||
],
|
||||
"rssi": -52,
|
||||
"sw_ver": "1.8.6 Build 180809 Rel.091659"
|
||||
}
|
||||
}
|
||||
}
|
||||
103
kasa/tests/fixtures/LB100(US)_1.0.json
vendored
Normal file
103
kasa/tests/fixtures/LB100(US)_1.0.json
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"get_realtime": {
|
||||
"err_code": 0,
|
||||
"power_mw": 10800
|
||||
}
|
||||
},
|
||||
"smartlife.iot.dimmer": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"get_light_state": {
|
||||
"dft_on_state": {
|
||||
"brightness": 100,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"mode": "normal",
|
||||
"saturation": 0
|
||||
},
|
||||
"err_code": 0,
|
||||
"on_off": 0
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"active_mode": "none",
|
||||
"alias": "Mock lb100",
|
||||
"ctrl_protocols": {
|
||||
"name": "Linkie",
|
||||
"version": "1.0"
|
||||
},
|
||||
"description": "Smart Wi-Fi LED Bulb with Dimmable Light",
|
||||
"dev_state": "normal",
|
||||
"deviceId": "15BD5A6C4B729A7C0D4D46ADDFA7E2600793C56A",
|
||||
"disco_ver": "1.0",
|
||||
"err_code": 0,
|
||||
"heapsize": 302452,
|
||||
"hwId": "1B0DF0A2EFE6251DBE726D1D2167C78F",
|
||||
"hw_ver": "1.0",
|
||||
"is_color": 0,
|
||||
"is_dimmable": 1,
|
||||
"is_factory": false,
|
||||
"is_variable_color_temp": 0,
|
||||
"latitude": -51.8361,
|
||||
"latitude_i": -51.8361,
|
||||
"light_state": {
|
||||
"dft_on_state": {
|
||||
"brightness": 100,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"mode": "normal",
|
||||
"saturation": 0
|
||||
},
|
||||
"err_code": 0,
|
||||
"on_off": 0
|
||||
},
|
||||
"longitude": -34.0697,
|
||||
"longitude_i": -34.0697,
|
||||
"mac": "50:c7:bf:51:10:65",
|
||||
"mic_type": "IOT.SMARTBULB",
|
||||
"model": "LB100(US)",
|
||||
"oemId": "C9CF655C9A5AA101E66EBA5B382E40CC",
|
||||
"on_time": 0,
|
||||
"preferred_state": [
|
||||
{
|
||||
"brightness": 100,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 0,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 75,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 1,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 25,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 2,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 1,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 3,
|
||||
"saturation": 0
|
||||
}
|
||||
],
|
||||
"rssi": -65,
|
||||
"sw_ver": "1.4.3 Build 170504 Rel.144921"
|
||||
}
|
||||
}
|
||||
}
|
||||
103
kasa/tests/fixtures/LB120(US)_1.0.json
vendored
Normal file
103
kasa/tests/fixtures/LB120(US)_1.0.json
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"get_realtime": {
|
||||
"err_code": 0,
|
||||
"power_mw": 10800
|
||||
}
|
||||
},
|
||||
"smartlife.iot.dimmer": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"get_light_state": {
|
||||
"dft_on_state": {
|
||||
"brightness": 100,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"mode": "normal",
|
||||
"saturation": 0
|
||||
},
|
||||
"err_code": 0,
|
||||
"on_off": 0
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"active_mode": "none",
|
||||
"alias": "Mock lb120",
|
||||
"ctrl_protocols": {
|
||||
"name": "Linkie",
|
||||
"version": "1.0"
|
||||
},
|
||||
"description": "Smart Wi-Fi LED Bulb with Tunable White Light",
|
||||
"dev_state": "normal",
|
||||
"deviceId": "62FD818E5B66A509D571D07D0F00FA4DD6468494",
|
||||
"disco_ver": "1.0",
|
||||
"err_code": 0,
|
||||
"heapsize": 302452,
|
||||
"hwId": "CC0588817E251DF996F1848ED331F543",
|
||||
"hw_ver": "1.0",
|
||||
"is_color": 0,
|
||||
"is_dimmable": 1,
|
||||
"is_factory": false,
|
||||
"is_variable_color_temp": 1,
|
||||
"latitude": -76.9197,
|
||||
"latitude_i": -76.9197,
|
||||
"light_state": {
|
||||
"dft_on_state": {
|
||||
"brightness": 100,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"mode": "normal",
|
||||
"saturation": 0
|
||||
},
|
||||
"err_code": 0,
|
||||
"on_off": 0
|
||||
},
|
||||
"longitude": 164.7293,
|
||||
"longitude_i": 164.7293,
|
||||
"mac": "50:c7:bf:dc:62:13",
|
||||
"mic_type": "IOT.SMARTBULB",
|
||||
"model": "LB120(US)",
|
||||
"oemId": "05D0D97951F565579A7F5A70A57AED0B",
|
||||
"on_time": 0,
|
||||
"preferred_state": [
|
||||
{
|
||||
"brightness": 100,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 0,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 75,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 1,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 25,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 2,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 1,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 3,
|
||||
"saturation": 0
|
||||
}
|
||||
],
|
||||
"rssi": -65,
|
||||
"sw_ver": "1.1.0 Build 160630 Rel.085319"
|
||||
}
|
||||
}
|
||||
}
|
||||
104
kasa/tests/fixtures/LB130(US)_1.0.json
vendored
Normal file
104
kasa/tests/fixtures/LB130(US)_1.0.json
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"emeter": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"get_realtime": {
|
||||
"err_code": 0,
|
||||
"power_mw": 10800
|
||||
}
|
||||
},
|
||||
"smartlife.iot.dimmer": {
|
||||
"err_code": -1,
|
||||
"err_msg": "module not support"
|
||||
},
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"get_light_state": {
|
||||
"dft_on_state": {
|
||||
"brightness": 100,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"mode": "normal",
|
||||
"saturation": 0
|
||||
},
|
||||
"err_code": 0,
|
||||
"on_off": 0
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"active_mode": "none",
|
||||
"alias": "Mock lb130",
|
||||
"ctrl_protocols": {
|
||||
"name": "Linkie",
|
||||
"version": "1.0"
|
||||
},
|
||||
"description": "Smart Wi-Fi LED Bulb with Color Changing",
|
||||
"dev_state": "normal",
|
||||
"deviceId": "50BE9E7B6F26CA75D495C13EAA459C491768F143",
|
||||
"disco_ver": "1.0",
|
||||
"err_code": 0,
|
||||
"heapsize": 302452,
|
||||
"hwId": "C8AD962B53417C2845CC10CE25C00BB1",
|
||||
"hw_ver": "1.0",
|
||||
"is_color": 1,
|
||||
"is_dimmable": 1,
|
||||
"is_factory": false,
|
||||
"is_variable_color_temp": 1,
|
||||
"latitude": 76.8649,
|
||||
"latitude_i": 76.8649,
|
||||
"light_state": {
|
||||
"dft_on_state": {
|
||||
"brightness": 100,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"mode": "normal",
|
||||
"saturation": 0
|
||||
},
|
||||
"err_code": 0,
|
||||
"on_off": 0
|
||||
},
|
||||
"longitude": -40.7284,
|
||||
"longitude_i": -40.7284,
|
||||
"INVALIDmac": "50:c7:bf:ac:f6:19",
|
||||
"mic_mac": "50C7BFACF619",
|
||||
"mic_type": "IOT.SMARTBULB",
|
||||
"model": "LB130(US)",
|
||||
"oemId": "CF78964560AAB75A43F15D2E468B63EF",
|
||||
"on_time": 0,
|
||||
"preferred_state": [
|
||||
{
|
||||
"brightness": 100,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 0,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 75,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 1,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 25,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 2,
|
||||
"saturation": 0
|
||||
},
|
||||
{
|
||||
"brightness": 1,
|
||||
"color_temp": 2700,
|
||||
"hue": 0,
|
||||
"index": 3,
|
||||
"saturation": 0
|
||||
}
|
||||
],
|
||||
"rssi": -65,
|
||||
"sw_ver": "1.6.0 Build 170703 Rel.141938"
|
||||
}
|
||||
}
|
||||
}
|
||||
425
kasa/tests/newfakes.py
Normal file
425
kasa/tests/newfakes.py
Normal file
@@ -0,0 +1,425 @@
|
||||
import logging
|
||||
import re
|
||||
|
||||
from voluptuous import REMOVE_EXTRA, All, Any, Coerce, Invalid, Optional, Range, Schema
|
||||
|
||||
from ..protocol import TPLinkSmartHomeProtocol
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def check_int_bool(x):
|
||||
if x != 0 and x != 1:
|
||||
raise Invalid(x)
|
||||
return x
|
||||
|
||||
|
||||
def check_mac(x):
|
||||
if re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", x.lower()):
|
||||
return x
|
||||
raise Invalid(x)
|
||||
|
||||
|
||||
def check_mode(x):
|
||||
if x in ["schedule", "none", "count_down"]:
|
||||
return x
|
||||
|
||||
raise Invalid(f"invalid mode {x}")
|
||||
|
||||
|
||||
def lb_dev_state(x):
|
||||
if x in ["normal"]:
|
||||
return x
|
||||
|
||||
raise Invalid(f"Invalid dev_state {x}")
|
||||
|
||||
|
||||
TZ_SCHEMA = Schema(
|
||||
{"zone_str": str, "dst_offset": int, "index": All(int, Range(min=0)), "tz_str": str}
|
||||
)
|
||||
|
||||
CURRENT_CONSUMPTION_SCHEMA = Schema(
|
||||
Any(
|
||||
{
|
||||
"voltage": Any(All(float, Range(min=0, max=300)), None),
|
||||
"power": Any(Coerce(float, Range(min=0)), None),
|
||||
"total": Any(Coerce(float, Range(min=0)), None),
|
||||
"current": Any(All(float, Range(min=0)), None),
|
||||
"voltage_mv": Any(
|
||||
All(float, Range(min=0, max=300000)), int, None
|
||||
), # TODO can this be int?
|
||||
"power_mw": Any(Coerce(float, Range(min=0)), None),
|
||||
"total_wh": Any(Coerce(float, Range(min=0)), None),
|
||||
"current_ma": Any(
|
||||
All(float, Range(min=0)), int, None
|
||||
), # TODO can this be int?
|
||||
},
|
||||
None,
|
||||
)
|
||||
)
|
||||
|
||||
# these schemas should go to the mainlib as
|
||||
# they can be useful when adding support for new features/devices
|
||||
# as well as to check that faked devices are operating properly.
|
||||
PLUG_SCHEMA = Schema(
|
||||
{
|
||||
"active_mode": check_mode,
|
||||
"alias": str,
|
||||
"dev_name": str,
|
||||
"deviceId": str,
|
||||
"feature": str,
|
||||
"fwId": str,
|
||||
"hwId": str,
|
||||
"hw_ver": str,
|
||||
"icon_hash": str,
|
||||
"led_off": check_int_bool,
|
||||
"latitude": Any(All(float, Range(min=-90, max=90)), None),
|
||||
"latitude_i": Any(All(float, Range(min=-90, max=90)), None),
|
||||
"longitude": Any(All(float, Range(min=-180, max=180)), None),
|
||||
"longitude_i": Any(All(float, Range(min=-180, max=180)), None),
|
||||
"mac": check_mac,
|
||||
"model": str,
|
||||
"oemId": str,
|
||||
"on_time": int,
|
||||
"relay_state": int,
|
||||
"rssi": Any(int, None), # rssi can also be positive, see #54
|
||||
"sw_ver": str,
|
||||
"type": str,
|
||||
"mic_type": str,
|
||||
"updating": check_int_bool,
|
||||
# these are available on hs220
|
||||
"brightness": int,
|
||||
"preferred_state": [
|
||||
{"brightness": All(int, Range(min=0, max=100)), "index": int}
|
||||
],
|
||||
"next_action": {"type": int},
|
||||
"child_num": Optional(Any(None, int)), # TODO fix hs300 checks
|
||||
"children": Optional(list), # TODO fix hs300
|
||||
# TODO some tplink simulator entries contain invalid (mic_mac, _i variants for lat/lon)
|
||||
# Therefore we add REMOVE_EXTRA..
|
||||
# "INVALIDmac": Optional,
|
||||
# "INVALIDlatitude": Optional,
|
||||
# "INVALIDlongitude": Optional,
|
||||
},
|
||||
extra=REMOVE_EXTRA,
|
||||
)
|
||||
|
||||
BULB_SCHEMA = PLUG_SCHEMA.extend(
|
||||
{
|
||||
"ctrl_protocols": Optional(dict),
|
||||
"description": Optional(str), # TODO: LBxxx similar to dev_name
|
||||
"dev_state": lb_dev_state,
|
||||
"disco_ver": str,
|
||||
"heapsize": int,
|
||||
"is_color": check_int_bool,
|
||||
"is_dimmable": check_int_bool,
|
||||
"is_factory": bool,
|
||||
"is_variable_color_temp": check_int_bool,
|
||||
"light_state": {
|
||||
"brightness": All(int, Range(min=0, max=100)),
|
||||
"color_temp": int,
|
||||
"hue": All(int, Range(min=0, max=255)),
|
||||
"mode": str,
|
||||
"on_off": check_int_bool,
|
||||
"saturation": All(int, Range(min=0, max=255)),
|
||||
"dft_on_state": Optional(
|
||||
{
|
||||
"brightness": All(int, Range(min=0, max=100)),
|
||||
"color_temp": All(int, Range(min=2700, max=9000)),
|
||||
"hue": All(int, Range(min=0, max=255)),
|
||||
"mode": str,
|
||||
"saturation": All(int, Range(min=0, max=255)),
|
||||
}
|
||||
),
|
||||
"err_code": int,
|
||||
},
|
||||
"preferred_state": [
|
||||
{
|
||||
"brightness": All(int, Range(min=0, max=100)),
|
||||
"color_temp": int,
|
||||
"hue": All(int, Range(min=0, max=255)),
|
||||
"index": int,
|
||||
"saturation": All(int, Range(min=0, max=255)),
|
||||
}
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def get_realtime(obj, x, *args):
|
||||
return {
|
||||
"current": 0.268587,
|
||||
"voltage": 125.836131,
|
||||
"power": 33.495623,
|
||||
"total": 0.199000,
|
||||
}
|
||||
|
||||
|
||||
def get_monthstat(obj, x, *args):
|
||||
if x["year"] < 2016:
|
||||
return {"month_list": []}
|
||||
|
||||
return {
|
||||
"month_list": [
|
||||
{"year": 2016, "month": 11, "energy": 1.089000},
|
||||
{"year": 2016, "month": 12, "energy": 1.582000},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def get_daystat(obj, x, *args):
|
||||
if x["year"] < 2016:
|
||||
return {"day_list": []}
|
||||
|
||||
return {
|
||||
"day_list": [
|
||||
{"year": 2016, "month": 11, "day": 24, "energy": 0.026000},
|
||||
{"year": 2016, "month": 11, "day": 25, "energy": 0.109000},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
emeter_support = {
|
||||
"get_realtime": get_realtime,
|
||||
"get_monthstat": get_monthstat,
|
||||
"get_daystat": get_daystat,
|
||||
}
|
||||
|
||||
|
||||
def get_realtime_units(obj, x, *args):
|
||||
return {"power_mw": 10800}
|
||||
|
||||
|
||||
def get_monthstat_units(obj, x, *args):
|
||||
if x["year"] < 2016:
|
||||
return {"month_list": []}
|
||||
|
||||
return {
|
||||
"month_list": [
|
||||
{"year": 2016, "month": 11, "energy_wh": 32},
|
||||
{"year": 2016, "month": 12, "energy_wh": 16},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def get_daystat_units(obj, x, *args):
|
||||
if x["year"] < 2016:
|
||||
return {"day_list": []}
|
||||
|
||||
return {
|
||||
"day_list": [
|
||||
{"year": 2016, "month": 11, "day": 24, "energy_wh": 20},
|
||||
{"year": 2016, "month": 11, "day": 25, "energy_wh": 32},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
emeter_units_support = {
|
||||
"get_realtime": get_realtime_units,
|
||||
"get_monthstat": get_monthstat_units,
|
||||
"get_daystat": get_daystat_units,
|
||||
}
|
||||
|
||||
|
||||
emeter_commands = {
|
||||
"emeter": emeter_support,
|
||||
"smartlife.iot.common.emeter": emeter_units_support,
|
||||
}
|
||||
|
||||
|
||||
def error(target, cmd="no-command", msg="default msg"):
|
||||
return {target: {cmd: {"err_code": -1323, "msg": msg}}}
|
||||
|
||||
|
||||
def success(target, cmd, res):
|
||||
if res:
|
||||
res.update({"err_code": 0})
|
||||
else:
|
||||
res = {"err_code": 0}
|
||||
return {target: {cmd: res}}
|
||||
|
||||
|
||||
class FakeTransportProtocol(TPLinkSmartHomeProtocol):
|
||||
def __init__(self, info, invalid=False):
|
||||
# TODO remove invalid when removing the old tests.
|
||||
proto = FakeTransportProtocol.baseproto
|
||||
for target in info:
|
||||
# print("target %s" % target)
|
||||
for cmd in info[target]:
|
||||
# print("initializing tgt %s cmd %s" % (target, cmd))
|
||||
proto[target][cmd] = info[target][cmd]
|
||||
# if we have emeter support, check for it
|
||||
for module in ["emeter", "smartlife.iot.common.emeter"]:
|
||||
if module not in info:
|
||||
# TODO required for old tests
|
||||
continue
|
||||
if "get_realtime" in info[module]:
|
||||
get_realtime_res = info[module]["get_realtime"]
|
||||
# TODO remove when removing old tests
|
||||
if callable(get_realtime_res):
|
||||
get_realtime_res = get_realtime_res()
|
||||
if (
|
||||
"err_code" not in get_realtime_res
|
||||
or not get_realtime_res["err_code"]
|
||||
):
|
||||
proto[module] = emeter_commands[module]
|
||||
self.proto = proto
|
||||
|
||||
def set_alias(self, x, child_ids=[]):
|
||||
_LOGGER.debug("Setting alias to %s, child_ids: %s", x["alias"], child_ids)
|
||||
if child_ids:
|
||||
for child in self.proto["system"]["get_sysinfo"]["children"]:
|
||||
if child["id"] in child_ids:
|
||||
child["alias"] = x["alias"]
|
||||
else:
|
||||
self.proto["system"]["get_sysinfo"]["alias"] = x["alias"]
|
||||
|
||||
def set_relay_state(self, x, child_ids=[]):
|
||||
_LOGGER.debug("Setting relay state to %s", x["state"])
|
||||
|
||||
if not child_ids and "children" in self.proto["system"]["get_sysinfo"]:
|
||||
for child in self.proto["system"]["get_sysinfo"]["children"]:
|
||||
child_ids.append(child["id"])
|
||||
|
||||
_LOGGER.info("child_ids: %s", child_ids)
|
||||
if child_ids:
|
||||
for child in self.proto["system"]["get_sysinfo"]["children"]:
|
||||
if child["id"] in child_ids:
|
||||
_LOGGER.info("Found %s, turning to %s", child, x["state"])
|
||||
child["state"] = x["state"]
|
||||
else:
|
||||
self.proto["system"]["get_sysinfo"]["relay_state"] = x["state"]
|
||||
|
||||
def set_led_off(self, x, *args):
|
||||
_LOGGER.debug("Setting led off to %s", x)
|
||||
self.proto["system"]["get_sysinfo"]["led_off"] = x["off"]
|
||||
|
||||
def set_mac(self, x, *args):
|
||||
_LOGGER.debug("Setting mac to %s", x)
|
||||
self.proto["system"]["get_sysinfo"]["mac"] = x
|
||||
|
||||
def set_hs220_brightness(self, x, *args):
|
||||
_LOGGER.debug("Setting brightness to %s", x)
|
||||
self.proto["system"]["get_sysinfo"]["brightness"] = x["brightness"]
|
||||
|
||||
def transition_light_state(self, x, *args):
|
||||
_LOGGER.debug("Setting light state to %s", x)
|
||||
light_state = self.proto["smartlife.iot.smartbulb.lightingservice"][
|
||||
"get_light_state"
|
||||
]
|
||||
# The required change depends on the light state,
|
||||
# exception being turning the bulb on and off
|
||||
|
||||
if "on_off" in x:
|
||||
if x["on_off"] and not light_state["on_off"]: # turning on
|
||||
new_state = light_state["dft_on_state"]
|
||||
new_state["on_off"] = 1
|
||||
self.proto["smartlife.iot.smartbulb.lightingservice"][
|
||||
"get_light_state"
|
||||
] = new_state
|
||||
elif not x["on_off"] and light_state["on_off"]:
|
||||
new_state = {"dft_on_state": light_state, "on_off": 0}
|
||||
|
||||
self.proto["smartlife.iot.smartbulb.lightingservice"][
|
||||
"get_light_state"
|
||||
] = new_state
|
||||
|
||||
return
|
||||
|
||||
if not light_state["on_off"] and "on_off" not in x:
|
||||
light_state = light_state["dft_on_state"]
|
||||
|
||||
_LOGGER.debug("Current state: %s", light_state)
|
||||
for key in x:
|
||||
light_state[key] = x[key]
|
||||
|
||||
def light_state(self, x, *args):
|
||||
light_state = self.proto["smartlife.iot.smartbulb.lightingservice"][
|
||||
"get_light_state"
|
||||
]
|
||||
# Our tests have light state off, so we simply return the dft_on_state when device is on.
|
||||
_LOGGER.info("reporting light state: %s", light_state)
|
||||
if light_state["on_off"]:
|
||||
return light_state["dft_on_state"]
|
||||
else:
|
||||
return light_state
|
||||
|
||||
baseproto = {
|
||||
"system": {
|
||||
"set_relay_state": set_relay_state,
|
||||
"set_dev_alias": set_alias,
|
||||
"set_led_off": set_led_off,
|
||||
"get_dev_icon": {"icon": None, "hash": None},
|
||||
"set_mac_addr": set_mac,
|
||||
"get_sysinfo": None,
|
||||
},
|
||||
"emeter": {
|
||||
"get_realtime": None,
|
||||
"get_daystat": None,
|
||||
"get_monthstat": None,
|
||||
"erase_emeter_state": None,
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"get_realtime": None,
|
||||
"get_daystat": None,
|
||||
"get_monthstat": None,
|
||||
"erase_emeter_state": None,
|
||||
},
|
||||
"smartlife.iot.smartbulb.lightingservice": {
|
||||
"get_light_state": light_state,
|
||||
"transition_light_state": transition_light_state,
|
||||
},
|
||||
"time": {
|
||||
"get_time": {
|
||||
"year": 2017,
|
||||
"month": 1,
|
||||
"mday": 2,
|
||||
"hour": 3,
|
||||
"min": 4,
|
||||
"sec": 5,
|
||||
},
|
||||
"get_timezone": {
|
||||
"zone_str": "test",
|
||||
"dst_offset": -1,
|
||||
"index": 12,
|
||||
"tz_str": "test2",
|
||||
},
|
||||
"set_timezone": None,
|
||||
},
|
||||
# HS220 brightness, different setter and getter
|
||||
"smartlife.iot.dimmer": {"set_brightness": set_hs220_brightness},
|
||||
}
|
||||
|
||||
async def query(self, host, request, port=9999):
|
||||
proto = self.proto
|
||||
|
||||
# collect child ids from context
|
||||
try:
|
||||
child_ids = request["context"]["child_ids"]
|
||||
request.pop("context", None)
|
||||
except KeyError:
|
||||
child_ids = []
|
||||
|
||||
target = next(iter(request))
|
||||
if target not in proto.keys():
|
||||
return error(target, msg="target not found")
|
||||
|
||||
cmd = next(iter(request[target]))
|
||||
if cmd not in proto[target].keys():
|
||||
return error(target, cmd, msg="command not found")
|
||||
|
||||
params = request[target][cmd]
|
||||
_LOGGER.debug(f"Going to execute {target}.{cmd} (params: {params}).. ")
|
||||
|
||||
if callable(proto[target][cmd]):
|
||||
res = proto[target][cmd](self, params, child_ids)
|
||||
_LOGGER.debug("[callable] %s.%s: %s", target, cmd, res)
|
||||
# verify that change didn't break schema, requires refactoring..
|
||||
# TestSmartPlug.sysinfo_schema(self.proto["system"]["get_sysinfo"])
|
||||
return success(target, cmd, res)
|
||||
elif isinstance(proto[target][cmd], dict):
|
||||
res = proto[target][cmd]
|
||||
_LOGGER.debug("[static] %s.%s: %s", target, cmd, res)
|
||||
return success(target, cmd, res)
|
||||
else:
|
||||
raise NotImplementedError(f"target {target} cmd {cmd}")
|
||||
609
kasa/tests/test_fixtures.py
Normal file
609
kasa/tests/test_fixtures.py
Normal file
@@ -0,0 +1,609 @@
|
||||
import asyncio
|
||||
import datetime
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from kasa import DeviceType, SmartDeviceException, SmartStrip
|
||||
|
||||
from .conftest import (
|
||||
bulb,
|
||||
color_bulb,
|
||||
dimmable,
|
||||
handle_turn_on,
|
||||
has_emeter,
|
||||
no_emeter,
|
||||
non_color_bulb,
|
||||
non_dimmable,
|
||||
non_variable_temp,
|
||||
plug,
|
||||
strip,
|
||||
turn_on,
|
||||
variable_temp,
|
||||
)
|
||||
from .newfakes import (
|
||||
BULB_SCHEMA,
|
||||
CURRENT_CONSUMPTION_SCHEMA,
|
||||
PLUG_SCHEMA,
|
||||
TZ_SCHEMA,
|
||||
FakeTransportProtocol,
|
||||
)
|
||||
|
||||
|
||||
@plug
|
||||
def test_plug_sysinfo(dev):
|
||||
dev.sync.update()
|
||||
assert dev.sys_info is not None
|
||||
PLUG_SCHEMA(dev.sys_info)
|
||||
|
||||
assert dev.model is not None
|
||||
|
||||
assert dev.device_type == DeviceType.Plug or dev.device_type == DeviceType.Strip
|
||||
assert dev.is_plug or dev.is_strip
|
||||
|
||||
|
||||
@bulb
|
||||
def test_bulb_sysinfo(dev):
|
||||
dev.sync.update()
|
||||
assert dev.sys_info is not None
|
||||
BULB_SCHEMA(dev.sys_info)
|
||||
|
||||
assert dev.model is not None
|
||||
|
||||
assert dev.device_type == DeviceType.Bulb
|
||||
assert dev.is_bulb
|
||||
|
||||
|
||||
def test_state_info(dev):
|
||||
dev.sync.update()
|
||||
assert isinstance(dev.sync.state_information, dict)
|
||||
|
||||
|
||||
def test_invalid_connection(dev):
|
||||
with patch.object(FakeTransportProtocol, "query", side_effect=SmartDeviceException):
|
||||
with pytest.raises(SmartDeviceException):
|
||||
dev.sync.update()
|
||||
dev.is_on
|
||||
|
||||
|
||||
def test_query_helper(dev):
|
||||
with pytest.raises(SmartDeviceException):
|
||||
dev.sync._query_helper("test", "testcmd", {})
|
||||
# TODO check for unwrapping?
|
||||
|
||||
|
||||
@turn_on
|
||||
def test_state(dev, turn_on):
|
||||
handle_turn_on(dev, turn_on)
|
||||
dev.sync.update()
|
||||
orig_state = dev.is_on
|
||||
if orig_state:
|
||||
dev.sync.turn_off()
|
||||
assert not dev.is_on
|
||||
assert dev.is_off
|
||||
dev.sync.turn_on()
|
||||
assert dev.is_on
|
||||
assert not dev.is_off
|
||||
else:
|
||||
dev.sync.turn_on()
|
||||
assert dev.is_on
|
||||
assert not dev.is_off
|
||||
dev.sync.turn_off()
|
||||
assert not dev.is_on
|
||||
assert dev.is_off
|
||||
|
||||
|
||||
@no_emeter
|
||||
def test_no_emeter(dev):
|
||||
dev.sync.update()
|
||||
assert not dev.has_emeter
|
||||
|
||||
with pytest.raises(SmartDeviceException):
|
||||
dev.sync.get_emeter_realtime()
|
||||
with pytest.raises(SmartDeviceException):
|
||||
dev.sync.get_emeter_daily()
|
||||
with pytest.raises(SmartDeviceException):
|
||||
dev.sync.get_emeter_monthly()
|
||||
with pytest.raises(SmartDeviceException):
|
||||
dev.sync.erase_emeter_stats()
|
||||
|
||||
|
||||
@has_emeter
|
||||
def test_get_emeter_realtime(dev):
|
||||
dev.sync.update()
|
||||
if dev.is_strip:
|
||||
pytest.skip("Disabled for HS300 temporarily")
|
||||
|
||||
assert dev.has_emeter
|
||||
|
||||
current_emeter = dev.sync.get_emeter_realtime()
|
||||
CURRENT_CONSUMPTION_SCHEMA(current_emeter)
|
||||
|
||||
|
||||
@has_emeter
|
||||
def test_get_emeter_daily(dev):
|
||||
dev.sync.update()
|
||||
if dev.is_strip:
|
||||
pytest.skip("Disabled for HS300 temporarily")
|
||||
|
||||
assert dev.has_emeter
|
||||
|
||||
assert dev.sync.get_emeter_daily(year=1900, month=1) == {}
|
||||
|
||||
d = dev.sync.get_emeter_daily()
|
||||
assert len(d) > 0
|
||||
|
||||
k, v = d.popitem()
|
||||
assert isinstance(k, int)
|
||||
assert isinstance(v, float)
|
||||
|
||||
# Test kwh (energy, energy_wh)
|
||||
d = dev.sync.get_emeter_daily(kwh=False)
|
||||
k2, v2 = d.popitem()
|
||||
assert v * 1000 == v2
|
||||
|
||||
|
||||
@has_emeter
|
||||
def test_get_emeter_monthly(dev):
|
||||
dev.sync.update()
|
||||
if dev.is_strip:
|
||||
pytest.skip("Disabled for HS300 temporarily")
|
||||
|
||||
assert dev.has_emeter
|
||||
|
||||
assert dev.sync.get_emeter_monthly(year=1900) == {}
|
||||
|
||||
d = dev.sync.get_emeter_monthly()
|
||||
assert len(d) > 0
|
||||
|
||||
k, v = d.popitem()
|
||||
assert isinstance(k, int)
|
||||
assert isinstance(v, float)
|
||||
|
||||
# Test kwh (energy, energy_wh)
|
||||
d = dev.sync.get_emeter_monthly(kwh=False)
|
||||
k2, v2 = d.popitem()
|
||||
assert v * 1000 == v2
|
||||
|
||||
|
||||
@has_emeter
|
||||
def test_emeter_status(dev):
|
||||
dev.sync.update()
|
||||
if dev.is_strip:
|
||||
pytest.skip("Disabled for HS300 temporarily")
|
||||
|
||||
assert dev.has_emeter
|
||||
|
||||
d = dev.sync.get_emeter_realtime()
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
assert d["foo"]
|
||||
|
||||
assert d["power_mw"] == d["power"] * 1000
|
||||
# bulbs have only power according to tplink simulator.
|
||||
if not dev.is_bulb:
|
||||
assert d["voltage_mv"] == d["voltage"] * 1000
|
||||
|
||||
assert d["current_ma"] == d["current"] * 1000
|
||||
assert d["total_wh"] == d["total"] * 1000
|
||||
|
||||
|
||||
@pytest.mark.skip("not clearing your stats..")
|
||||
@has_emeter
|
||||
def test_erase_emeter_stats(dev):
|
||||
dev.sync.update()
|
||||
assert dev.has_emeter
|
||||
|
||||
dev.sync.erase_emeter()
|
||||
|
||||
|
||||
@has_emeter
|
||||
def test_current_consumption(dev):
|
||||
dev.sync.update()
|
||||
if dev.is_strip:
|
||||
pytest.skip("Disabled for HS300 temporarily")
|
||||
|
||||
if dev.has_emeter:
|
||||
x = dev.sync.current_consumption()
|
||||
assert isinstance(x, float)
|
||||
assert x >= 0.0
|
||||
else:
|
||||
assert dev.sync.current_consumption() is None
|
||||
|
||||
|
||||
def test_alias(dev):
|
||||
dev.sync.update()
|
||||
test_alias = "TEST1234"
|
||||
original = dev.sync.alias
|
||||
|
||||
assert isinstance(original, str)
|
||||
dev.sync.set_alias(test_alias)
|
||||
assert dev.sync.alias == test_alias
|
||||
|
||||
dev.sync.set_alias(original)
|
||||
assert dev.sync.alias == original
|
||||
|
||||
|
||||
@plug
|
||||
def test_led(dev):
|
||||
dev.sync.update()
|
||||
original = dev.led
|
||||
|
||||
dev.sync.set_led(False)
|
||||
assert not dev.led
|
||||
|
||||
dev.sync.set_led(True)
|
||||
assert dev.led
|
||||
|
||||
dev.sync.set_led(original)
|
||||
|
||||
|
||||
@plug
|
||||
def test_on_since(dev):
|
||||
dev.sync.update()
|
||||
assert isinstance(dev.on_since, datetime.datetime)
|
||||
|
||||
|
||||
def test_icon(dev):
|
||||
assert set(dev.sync.get_icon().keys()), {"icon", "hash"}
|
||||
|
||||
|
||||
def test_time(dev):
|
||||
assert isinstance(dev.sync.get_time(), datetime.datetime)
|
||||
# TODO check setting?
|
||||
|
||||
|
||||
def test_timezone(dev):
|
||||
TZ_SCHEMA(dev.sync.get_timezone())
|
||||
|
||||
|
||||
def test_hw_info(dev):
|
||||
dev.sync.update()
|
||||
PLUG_SCHEMA(dev.hw_info)
|
||||
|
||||
|
||||
def test_location(dev):
|
||||
dev.sync.update()
|
||||
PLUG_SCHEMA(dev.location)
|
||||
|
||||
|
||||
def test_rssi(dev):
|
||||
dev.sync.update()
|
||||
PLUG_SCHEMA({"rssi": dev.rssi}) # wrapping for vol
|
||||
|
||||
|
||||
def test_mac(dev):
|
||||
dev.sync.update()
|
||||
PLUG_SCHEMA({"mac": dev.mac}) # wrapping for val
|
||||
# TODO check setting?
|
||||
|
||||
|
||||
@non_variable_temp
|
||||
def test_temperature_on_nonsupporting(dev):
|
||||
dev.sync.update()
|
||||
assert dev.valid_temperature_range == (0, 0)
|
||||
|
||||
# TODO test when device does not support temperature range
|
||||
with pytest.raises(SmartDeviceException):
|
||||
dev.sync.set_color_temp(2700)
|
||||
with pytest.raises(SmartDeviceException):
|
||||
print(dev.sync.color_temp)
|
||||
|
||||
|
||||
@variable_temp
|
||||
def test_out_of_range_temperature(dev):
|
||||
dev.sync.update()
|
||||
with pytest.raises(ValueError):
|
||||
dev.sync.set_color_temp(1000)
|
||||
with pytest.raises(ValueError):
|
||||
dev.sync.set_color_temp(10000)
|
||||
|
||||
|
||||
@non_dimmable
|
||||
def test_non_dimmable(dev):
|
||||
dev.sync.update()
|
||||
assert not dev.is_dimmable
|
||||
|
||||
with pytest.raises(SmartDeviceException):
|
||||
assert dev.brightness == 0
|
||||
with pytest.raises(SmartDeviceException):
|
||||
dev.sync.set_brightness(100)
|
||||
|
||||
|
||||
@dimmable
|
||||
@turn_on
|
||||
def test_dimmable_brightness(dev, turn_on):
|
||||
handle_turn_on(dev, turn_on)
|
||||
dev.sync.update()
|
||||
assert dev.is_dimmable
|
||||
|
||||
dev.sync.set_brightness(50)
|
||||
assert dev.brightness == 50
|
||||
|
||||
dev.sync.set_brightness(10)
|
||||
assert dev.brightness == 10
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
dev.sync.set_brightness("foo")
|
||||
|
||||
|
||||
@dimmable
|
||||
def test_invalid_brightness(dev):
|
||||
dev.sync.update()
|
||||
assert dev.is_dimmable
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
dev.sync.set_brightness(110)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
dev.sync.set_brightness(-100)
|
||||
|
||||
|
||||
@color_bulb
|
||||
@turn_on
|
||||
def test_hsv(dev, turn_on):
|
||||
handle_turn_on(dev, turn_on)
|
||||
dev.sync.update()
|
||||
assert dev.is_color
|
||||
|
||||
hue, saturation, brightness = dev.hsv
|
||||
assert 0 <= hue <= 255
|
||||
assert 0 <= saturation <= 100
|
||||
assert 0 <= brightness <= 100
|
||||
|
||||
dev.sync.set_hsv(hue=1, saturation=1, value=1)
|
||||
|
||||
hue, saturation, brightness = dev.hsv
|
||||
assert hue == 1
|
||||
assert saturation == 1
|
||||
assert brightness == 1
|
||||
|
||||
|
||||
@color_bulb
|
||||
@turn_on
|
||||
def test_invalid_hsv(dev, turn_on):
|
||||
handle_turn_on(dev, turn_on)
|
||||
dev.sync.update()
|
||||
assert dev.is_color
|
||||
|
||||
for invalid_hue in [-1, 361, 0.5]:
|
||||
with pytest.raises(ValueError):
|
||||
dev.sync.set_hsv(invalid_hue, 0, 0)
|
||||
|
||||
for invalid_saturation in [-1, 101, 0.5]:
|
||||
with pytest.raises(ValueError):
|
||||
dev.sync.set_hsv(0, invalid_saturation, 0)
|
||||
|
||||
for invalid_brightness in [-1, 101, 0.5]:
|
||||
with pytest.raises(ValueError):
|
||||
dev.sync.set_hsv(0, 0, invalid_brightness)
|
||||
|
||||
|
||||
@non_color_bulb
|
||||
def test_hsv_on_non_color(dev):
|
||||
dev.sync.update()
|
||||
assert not dev.is_color
|
||||
|
||||
with pytest.raises(SmartDeviceException):
|
||||
dev.sync.set_hsv(0, 0, 0)
|
||||
with pytest.raises(SmartDeviceException):
|
||||
print(dev.hsv)
|
||||
|
||||
|
||||
@variable_temp
|
||||
@turn_on
|
||||
def test_try_set_colortemp(dev, turn_on):
|
||||
dev.sync.update()
|
||||
handle_turn_on(dev, turn_on)
|
||||
dev.sync.set_color_temp(2700)
|
||||
assert dev.sync.color_temp == 2700
|
||||
|
||||
|
||||
@non_variable_temp
|
||||
def test_non_variable_temp(dev):
|
||||
with pytest.raises(SmartDeviceException):
|
||||
dev.sync.update()
|
||||
dev.sync.set_color_temp(2700)
|
||||
|
||||
|
||||
@strip
|
||||
@turn_on
|
||||
def test_children_change_state(dev, turn_on):
|
||||
dev.sync.update()
|
||||
handle_turn_on(dev, turn_on)
|
||||
for plug in dev.plugs:
|
||||
plug.sync.update()
|
||||
orig_state = plug.is_on
|
||||
if orig_state:
|
||||
plug.turn_off()
|
||||
plug.sync.update()
|
||||
assert not plug.is_on
|
||||
assert plug.is_off
|
||||
|
||||
plug.sync.turn_on()
|
||||
plug.sync.update()
|
||||
assert plug.is_on
|
||||
assert not plug.is_off
|
||||
else:
|
||||
plug.sync.turn_on()
|
||||
plug.sync.update()
|
||||
assert plug.is_on
|
||||
assert not plug.is_off
|
||||
plug.sync.turn_off()
|
||||
plug.sync.update()
|
||||
assert not plug.is_on
|
||||
assert plug.is_off
|
||||
|
||||
|
||||
@strip
|
||||
def test_children_alias(dev):
|
||||
test_alias = "TEST1234"
|
||||
for plug in dev.plugs:
|
||||
plug.sync.update()
|
||||
original = plug.alias
|
||||
plug.sync.set_alias(alias=test_alias)
|
||||
plug.sync.update()
|
||||
assert plug.alias == test_alias
|
||||
plug.sync.set_alias(alias=original)
|
||||
plug.sync.update()
|
||||
assert plug.alias == original
|
||||
|
||||
|
||||
@strip
|
||||
def test_children_on_since(dev):
|
||||
for plug in dev.plugs:
|
||||
plug.sync.update()
|
||||
assert plug.on_since
|
||||
|
||||
|
||||
@pytest.mark.skip("this test will wear out your relays")
|
||||
def test_all_binary_states(dev):
|
||||
# test every binary state
|
||||
for state in range(2 ** dev.num_children):
|
||||
# create binary state map
|
||||
state_map = {}
|
||||
for plug_index in range(dev.num_children):
|
||||
state_map[plug_index] = bool((state >> plug_index) & 1)
|
||||
|
||||
if state_map[plug_index]:
|
||||
dev.sync.turn_on(index=plug_index)
|
||||
else:
|
||||
dev.sync.turn_off(index=plug_index)
|
||||
|
||||
# check state map applied
|
||||
for index, state in dev.is_on.items():
|
||||
assert state_map[index] == state
|
||||
|
||||
# toggle each outlet with state map applied
|
||||
for plug_index in range(dev.num_children):
|
||||
|
||||
# toggle state
|
||||
if state_map[plug_index]:
|
||||
dev.sync.turn_off(index=plug_index)
|
||||
else:
|
||||
dev.sync.turn_on(index=plug_index)
|
||||
|
||||
# only target outlet should have state changed
|
||||
for index, state in dev.is_on.items():
|
||||
if index == plug_index:
|
||||
assert state != state_map[index]
|
||||
else:
|
||||
assert state == state_map[index]
|
||||
|
||||
# reset state
|
||||
if state_map[plug_index]:
|
||||
dev.sync.turn_on(index=plug_index)
|
||||
else:
|
||||
dev.sync.turn_off(index=plug_index)
|
||||
|
||||
# original state map should be restored
|
||||
for index, state in dev.is_on.items():
|
||||
assert state == state_map[index]
|
||||
|
||||
|
||||
@strip
|
||||
def test_children_get_emeter_realtime(dev):
|
||||
dev.sync.update()
|
||||
assert dev.has_emeter
|
||||
# test with index
|
||||
for plug in dev.plugs:
|
||||
plug.sync.update()
|
||||
emeter = plug.sync.get_emeter_realtime()
|
||||
CURRENT_CONSUMPTION_SCHEMA(emeter)
|
||||
|
||||
# test without index
|
||||
# TODO test that sum matches the sum of individiaul plugs.
|
||||
|
||||
# for index, emeter in dev.sync.get_emeter_realtime().items():
|
||||
# CURRENT_CONSUMPTION_SCHEMA(emeter)
|
||||
|
||||
|
||||
@strip
|
||||
def test_children_get_emeter_daily(dev):
|
||||
dev.sync.update()
|
||||
assert dev.has_emeter
|
||||
# test individual emeters
|
||||
for plug in dev.plugs:
|
||||
plug.sync.update()
|
||||
emeter = plug.sync.get_emeter_daily(year=1900, month=1)
|
||||
assert emeter == {}
|
||||
|
||||
emeter = plug.sync.get_emeter_daily()
|
||||
assert len(emeter) > 0
|
||||
|
||||
k, v = emeter.popitem()
|
||||
assert isinstance(k, int)
|
||||
assert isinstance(v, float)
|
||||
|
||||
# test sum of emeters
|
||||
all_emeter = dev.sync.get_emeter_daily(year=1900, month=1)
|
||||
|
||||
k, v = all_emeter.popitem()
|
||||
assert isinstance(k, int)
|
||||
assert isinstance(v, float)
|
||||
|
||||
|
||||
@strip
|
||||
def test_children_get_emeter_monthly(dev):
|
||||
dev.sync.update()
|
||||
assert dev.has_emeter
|
||||
# test individual emeters
|
||||
for plug in dev.plugs:
|
||||
plug.sync.update()
|
||||
emeter = plug.sync.get_emeter_monthly(year=1900)
|
||||
assert emeter == {}
|
||||
|
||||
emeter = plug.sync.get_emeter_monthly()
|
||||
assert len(emeter) > 0
|
||||
|
||||
k, v = emeter.popitem()
|
||||
assert isinstance(k, int)
|
||||
assert isinstance(v, float)
|
||||
|
||||
# test sum of emeters
|
||||
all_emeter = dev.sync.get_emeter_monthly(year=1900)
|
||||
|
||||
k, v = all_emeter.popitem()
|
||||
assert isinstance(k, int)
|
||||
assert isinstance(v, float)
|
||||
|
||||
|
||||
# def test_cache(dev):
|
||||
# from datetime import timedelta
|
||||
|
||||
# dev.sync.cache_ttl = timedelta(seconds=3)
|
||||
# with patch.object(
|
||||
# FakeTransportProtocol, "query", wraps=dev.protocol.query
|
||||
# ) as query_mock:
|
||||
# CHECK_COUNT = 1
|
||||
# # Smartstrip calls sysinfo in its __init__ to request children, so
|
||||
# # the even first get call here will get its results from the cache.
|
||||
# if dev.is_strip:
|
||||
# CHECK_COUNT = 0
|
||||
|
||||
# dev.sys_info
|
||||
# assert query_mock.call_count == CHECK_COUNT
|
||||
# dev.sys_info
|
||||
# assert query_mock.call_count == CHECK_COUNT
|
||||
|
||||
|
||||
# def test_cache_invalidates(dev):
|
||||
# from datetime import timedelta
|
||||
|
||||
# dev.sync.cache_ttl = timedelta(seconds=0)
|
||||
|
||||
# with patch.object(
|
||||
# FakeTransportProtocol, "query", wraps=dev.protocol.query
|
||||
# ) as query_mock:
|
||||
# dev.sys_info
|
||||
# assert query_mock.call_count == 1
|
||||
# dev.sys_info
|
||||
# assert query_mock.call_count == 2
|
||||
# # assert query_mock.called_once()
|
||||
|
||||
|
||||
def test_representation(dev):
|
||||
import re
|
||||
|
||||
pattern = re.compile("<.* model .* at .* (.*), is_on: .* - dev specific: .*>")
|
||||
assert pattern.match(str(dev))
|
||||
73
kasa/tests/test_protocol.py
Normal file
73
kasa/tests/test_protocol.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import json
|
||||
from unittest import TestCase
|
||||
|
||||
from ..protocol import TPLinkSmartHomeProtocol
|
||||
|
||||
|
||||
class TestTPLinkSmartHomeProtocol(TestCase):
|
||||
def test_encrypt(self):
|
||||
d = json.dumps({"foo": 1, "bar": 2})
|
||||
encrypted = TPLinkSmartHomeProtocol.encrypt(d)
|
||||
# encrypt adds a 4 byte header
|
||||
encrypted = encrypted[4:]
|
||||
self.assertEqual(d, TPLinkSmartHomeProtocol.decrypt(encrypted))
|
||||
|
||||
def test_encrypt_unicode(self):
|
||||
d = "{'snowman': '\u2603'}"
|
||||
|
||||
e = bytes(
|
||||
[
|
||||
208,
|
||||
247,
|
||||
132,
|
||||
234,
|
||||
133,
|
||||
242,
|
||||
159,
|
||||
254,
|
||||
144,
|
||||
183,
|
||||
141,
|
||||
173,
|
||||
138,
|
||||
104,
|
||||
240,
|
||||
115,
|
||||
84,
|
||||
41,
|
||||
]
|
||||
)
|
||||
|
||||
encrypted = TPLinkSmartHomeProtocol.encrypt(d)
|
||||
# encrypt adds a 4 byte header
|
||||
encrypted = encrypted[4:]
|
||||
|
||||
self.assertEqual(e, encrypted)
|
||||
|
||||
def test_decrypt_unicode(self):
|
||||
e = bytes(
|
||||
[
|
||||
208,
|
||||
247,
|
||||
132,
|
||||
234,
|
||||
133,
|
||||
242,
|
||||
159,
|
||||
254,
|
||||
144,
|
||||
183,
|
||||
141,
|
||||
173,
|
||||
138,
|
||||
104,
|
||||
240,
|
||||
115,
|
||||
84,
|
||||
41,
|
||||
]
|
||||
)
|
||||
|
||||
d = "{'snowman': '\u2603'}"
|
||||
|
||||
self.assertEqual(d, TPLinkSmartHomeProtocol.decrypt(e))
|
||||
Reference in New Issue
Block a user