mirror of
https://github.com/python-kasa/python-kasa.git
synced 2024-12-24 12:13:35 +00:00
ef2e21ff69
* Add support for new-style emeter This commit adds a straightforward dict-extending container, which converts between the old and new keys of the get_emeter_realtime() Furthermore the unit tests are converted to base on HS100 instead of HS110. This is the first step to fix #103, other emeter-using functionality has not yet been converted, only getting the current consumption. * fix a couple of linting issues * Convert new-style emeter values also for get_emeter_daily() and get_emeter_monthly() * Adds a new 'kwh' parameter for those calls, which defaults to True * This changes the behavior of bulbs emeter reporting, use False if you prefer the preciser values
524 lines
24 KiB
Python
524 lines
24 KiB
Python
from ..protocol import TPLinkSmartHomeProtocol
|
|
from .. import SmartDeviceException
|
|
import logging
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
def get_realtime(obj, x):
|
|
return {"current":0.268587,"voltage":125.836131,"power":33.495623,"total":0.199000}
|
|
|
|
def get_monthstat(obj, x):
|
|
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):
|
|
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):
|
|
return {"power_mw": 10800}
|
|
|
|
def get_monthstat_units(obj, x):
|
|
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):
|
|
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,}
|
|
|
|
sysinfo_hs100 = {'system': {'get_sysinfo':
|
|
{'active_mode': 'schedule',
|
|
'alias': 'My Smart Plug',
|
|
'dev_name': 'Wi-Fi Smart Plug',
|
|
'deviceId': '80061E93E28EEBA9FA1929D15C4678C7172A8AF2',
|
|
'feature': 'TIM',
|
|
'fwId': 'BFF24826FBC561803E49379DBE74FD71',
|
|
'hwId': '22603EA5E716DEAEA6642A30BE87AFCA',
|
|
'hw_ver': '1.0',
|
|
'icon_hash': '',
|
|
'latitude': 12.2,
|
|
'led_off': 0,
|
|
'longitude': 12.2,
|
|
'mac': '50:C7:BF:11:22:33',
|
|
'model': 'HS100(EU)',
|
|
'oemId': '812A90EB2FCF306A993FAD8748024B07',
|
|
'on_time': 255419,
|
|
'relay_state': 1,
|
|
'sw_ver': '1.0.8 Build 151101 Rel.24452',
|
|
'type': 'smartplug',
|
|
'updating': 0}}}
|
|
|
|
sysinfo_hs105 = {'system': {'get_sysinfo':
|
|
{'sw_ver': '1.0.6 Build 160722 Rel.081616',
|
|
'hw_ver': '1.0', 'type': 'IOT.SMARTPLUGSWITCH',
|
|
'model': 'HS105(US)',
|
|
'mac': '50:C7:BF:11:22:33',
|
|
'dev_name': 'Smart Wi-Fi Plug Mini',
|
|
'alias': 'TP-LINK_Smart Plug_CF0B',
|
|
'relay_state': 0,
|
|
'on_time': 0,
|
|
'active_mode': 'none',
|
|
'feature': 'TIM',
|
|
'updating': 0,
|
|
'icon_hash': '',
|
|
'rssi': 33,
|
|
'led_off': 0,
|
|
'longitude_i': -12.2,
|
|
'latitude_i': 12.2,
|
|
'hwId': '60FF6B258734EA6880E186F8C96DDC61',
|
|
'fwId': '00000000000000000000000000000000',
|
|
'deviceId': '800654F32938FCBA8F7327887A38647617',
|
|
'oemId': 'FFF22CFF774A0B89F7624BFC6F50D5DE'}}}
|
|
|
|
sysinfo_hs110 = {'system': {'get_sysinfo':
|
|
{'active_mode': 'schedule',
|
|
'alias': 'Mobile Plug',
|
|
'dev_name': 'Wi-Fi Smart Plug With Energy Monitoring',
|
|
'deviceId': '800654F32938FCBA8F7327887A386476172B5B53',
|
|
'err_code': 0,
|
|
'feature': 'TIM:ENE',
|
|
'fwId': 'E16EB3E95DB6B47B5B72B3FD86FD1438',
|
|
'hwId': '60FF6B258734EA6880E186F8C96DDC61',
|
|
'hw_ver': '1.0',
|
|
'icon_hash': '',
|
|
'latitude': 12.2,
|
|
'led_off': 0,
|
|
'longitude': -12.2,
|
|
'mac': 'AA:BB:CC:11:22:33',
|
|
'model': 'HS110(US)',
|
|
'oemId': 'FFF22CFF774A0B89F7624BFC6F50D5DE',
|
|
'on_time': 9022,
|
|
'relay_state': 1,
|
|
'rssi': -61,
|
|
'sw_ver': '1.0.8 Build 151113 Rel.24658',
|
|
'type': 'IOT.SMARTPLUGSWITCH',
|
|
'updating': 0}
|
|
},
|
|
'emeter': emeter_support,
|
|
}
|
|
|
|
sysinfo_hs110_au_v2 = {'system': {'get_sysinfo':
|
|
{'active_mode': 'none',
|
|
'alias': 'Tplink Test',
|
|
'dev_name': 'Smart Wi-Fi Plug With Energy Monitoring',
|
|
'deviceId': '80062952E2F3D9461CFB91FF21B7868F194F627A',
|
|
'feature': 'TIM:ENE',
|
|
'fwId': '00000000000000000000000000000000',
|
|
'hwId': 'A28C8BB92AFCB6CAFB83A8C00145F7E2',
|
|
'hw_ver': '2.0',
|
|
'icon_hash': '',
|
|
'latitude_i': -1.1,
|
|
'led_off': 0,
|
|
'longitude_i': 2.2,
|
|
'mac': '70:4F:57:12:12:12',
|
|
'model': 'HS110(AU)',
|
|
'oemId': '6480C2101948463DC65D7009CAECDECC',
|
|
'on_time': 0,
|
|
'relay_state': 0,
|
|
'rssi': -70,
|
|
'sw_ver': '1.5.2 Build 171201 Rel.084625',
|
|
'type': 'IOT.SMARTPLUGSWITCH',
|
|
'updating': 0}
|
|
},
|
|
'emeter': {'voltage_mv': 246520, 'power_mw': 258401, 'current_ma': 3104, 'total_wh': 387}}
|
|
|
|
sysinfo_hs200 = {'system': {'get_sysinfo': {'active_mode': 'schedule',
|
|
'alias': 'Christmas Tree Switch',
|
|
'dev_name': 'Wi-Fi Smart Light Switch',
|
|
'deviceId': '8006E0D62C90698C6A3EF72944F56DDC17D0DB80',
|
|
'err_code': 0,
|
|
'feature': 'TIM',
|
|
'fwId': 'DB4F3246CD85AA59CAE738A63E7B9C34',
|
|
'hwId': 'A0E3CC8F5C1166B27A16D56BE262A6D3',
|
|
'hw_ver': '1.0',
|
|
'icon_hash': '',
|
|
'latitude': 12.2,
|
|
'led_off': 0,
|
|
'longitude': -12.2,
|
|
'mac': 'AA:BB:CC:11:22:33',
|
|
'mic_type': 'IOT.SMARTPLUGSWITCH',
|
|
'model': 'HS200(US)',
|
|
'oemId': '4AFE44A41F868FD2340E6D1308D8551D',
|
|
'on_time': 9586,
|
|
'relay_state': 1,
|
|
'rssi': -53,
|
|
'sw_ver': '1.1.0 Build 160521 Rel.085826',
|
|
'updating': 0}}
|
|
}
|
|
|
|
sysinfo_lb130 = {'system': {'get_sysinfo':
|
|
{'active_mode': 'none',
|
|
'alias': 'Living Room Side Table',
|
|
'ctrl_protocols': {'name': 'Linkie', 'version': '1.0'},
|
|
'description': 'Smart Wi-Fi LED Bulb with Color Changing',
|
|
'dev_state': 'normal',
|
|
'deviceId': '80123C4640E9FC33A9019A0F3FD8BF5C17B7D9A8',
|
|
'disco_ver': '1.0',
|
|
'heapsize': 347000,
|
|
'hwId': '111E35908497A05512E259BB76801E10',
|
|
'hw_ver': '1.0',
|
|
'is_color': 1,
|
|
'is_dimmable': 1,
|
|
'is_factory': False,
|
|
'is_variable_color_temp': 1,
|
|
'light_state': {'brightness': 100,
|
|
'color_temp': 3700,
|
|
'hue': 0,
|
|
'mode': 'normal',
|
|
'on_off': 1,
|
|
'saturation': 0},
|
|
'mic_mac': '50C7BF104865',
|
|
'mic_type': 'IOT.SMARTBULB',
|
|
'model': 'LB130(US)',
|
|
'oemId': '05BF7B3BE1675C5A6867B7A7E4C9F6F7',
|
|
'preferred_state': [{'brightness': 50,
|
|
'color_temp': 2700,
|
|
'hue': 0,
|
|
'index': 0,
|
|
'saturation': 0},
|
|
{'brightness': 100,
|
|
'color_temp': 0,
|
|
'hue': 0,
|
|
'index': 1,
|
|
'saturation': 75},
|
|
{'brightness': 100,
|
|
'color_temp': 0,
|
|
'hue': 120,
|
|
'index': 2,
|
|
'saturation': 75},
|
|
{'brightness': 100,
|
|
'color_temp': 0,
|
|
'hue': 240,
|
|
'index': 3,
|
|
'saturation': 75}],
|
|
'rssi': -55,
|
|
'sw_ver': '1.1.2 Build 160927 Rel.111100'}},
|
|
'smartlife.iot.smartbulb.lightingservice': {'get_light_state':
|
|
{'on_off':1,
|
|
'mode':'normal',
|
|
'hue': 0,
|
|
'saturation': 0,
|
|
'color_temp': 3700,
|
|
'brightness': 100,
|
|
'err_code': 0}},
|
|
'smartlife.iot.common.emeter': emeter_units_support,
|
|
}
|
|
|
|
sysinfo_lb100 = {'system': {
|
|
'sys_info': {
|
|
'emeter': {
|
|
'err_code': -2001,
|
|
'err_msg': 'Module not support'
|
|
},
|
|
'system': {
|
|
'get_sysinfo': {
|
|
'active_mode': 'none',
|
|
'alias': 'New Light',
|
|
'ctrl_protocols': {
|
|
'name': 'Linkie',
|
|
'version': '1.0'
|
|
},
|
|
'description': 'Smart Wi-Fi LED Bulb with Dimmable Light',
|
|
'dev_state': 'normal',
|
|
'deviceId': '8012996ED1F8DA43EFFD58B62BEC5ADE18192F88',
|
|
'disco_ver': '1.0',
|
|
'err_code': 0,
|
|
'heapsize': 340808,
|
|
'hwId': '111E35908497A05512E259BB76801E10',
|
|
'hw_ver': '1.0',
|
|
'is_color': 0,
|
|
'is_dimmable': 1,
|
|
'is_factory': False,
|
|
'is_variable_color_temp': 0,
|
|
'light_state': {
|
|
'dft_on_state': {
|
|
'brightness': 50,
|
|
'color_temp': 2700,
|
|
'hue': 0,
|
|
'mode': 'normal',
|
|
'saturation': 0
|
|
},
|
|
'on_off': 0
|
|
},
|
|
'mic_mac': '50C7BF3393F1',
|
|
'mic_type': 'IOT.SMARTBULB',
|
|
'model': 'LB100(US)',
|
|
'oemId': '264E4E97B2D2B086F289AC1F00B90679',
|
|
'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': -54,
|
|
'sw_ver': '1.2.3 Build 170123 Rel.100146'
|
|
}
|
|
}
|
|
}
|
|
}}
|
|
|
|
sysinfo_lb110 = {'system': {
|
|
'sys_info':
|
|
{'emeter':
|
|
{'err_code': -2001,
|
|
'err_msg': 'Module not support'},
|
|
'system':
|
|
{'get_sysinfo':
|
|
{'active_mode': 'schedule',
|
|
'alias': 'Downstairs Light',
|
|
'ctrl_protocols':
|
|
{'name': 'Linkie',
|
|
'version': '1.0'},
|
|
'description': 'Smart Wi-Fi LED Bulb '
|
|
'with Dimmable Light',
|
|
'dev_state': 'normal',
|
|
'deviceId':
|
|
'80120B3D03E0B639CDF33E3CB1466490187FEF32',
|
|
'disco_ver': '1.0',
|
|
'err_code': 0,
|
|
'heapsize': 309908,
|
|
'hwId': '111E35908497A05512E259BB76801E10',
|
|
'hw_ver': '1.0',
|
|
'is_color': 0,
|
|
'is_dimmable': 1,
|
|
'is_factory': False,
|
|
'is_variable_color_temp': 0,
|
|
'light_state':
|
|
{'dft_on_state':
|
|
{'brightness': 92,
|
|
'color_temp': 2700,
|
|
'hue': 0,
|
|
'mode': 'normal',
|
|
'saturation': 0},
|
|
'on_off': 0},
|
|
'mic_mac': '50C7BF7BE306',
|
|
'mic_type': 'IOT.SMARTBULB',
|
|
'model': 'LB110(EU)',
|
|
'oemId':
|
|
'A68E15472071CB761E5CCFB388A1D8AE',
|
|
'preferred_state': [{'brightness': 100,
|
|
'color_temp': 2700,
|
|
'hue': 0,
|
|
'index': 0,
|
|
'saturation': 0},
|
|
{'brightness': 58,
|
|
'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': -61,
|
|
'sw_ver': '1.5.5 Build 170623 '
|
|
'Rel.090105'
|
|
}
|
|
}
|
|
}
|
|
}}
|
|
|
|
sysinfo_lb120 = {'system':
|
|
{'sys_info':
|
|
{'system':
|
|
{'get_sysinfo':
|
|
{'active_mode': 'none',
|
|
'alias': 'LB1202',
|
|
'ctrl_protocols': {'name': 'Linkie', 'version': '1.0'},
|
|
'description': 'Smart Wi-Fi LED Bulb with Tunable White Light',
|
|
'dev_state': 'normal',
|
|
'deviceId': 'foo',
|
|
'disco_ver': '1.0',
|
|
'heapsize': 329032,
|
|
'hwId': 'foo',
|
|
'hw_ver': '1.0',
|
|
'is_color': 0,
|
|
'is_dimmable': 1,
|
|
'is_factory': False,
|
|
'is_variable_color_temp': 1,
|
|
'light_state': {'dft_on_state': {'brightness': 31,
|
|
'color_temp': 4100,
|
|
'hue': 0,
|
|
'mode': 'normal',
|
|
'saturation': 0},
|
|
'on_off': 0},
|
|
'mic_mac': '50C7BF33937C',
|
|
'mic_type': 'IOT.SMARTBULB',
|
|
'model': 'LB120(US)',
|
|
'oemId': 'foo',
|
|
'preferred_state': [{'brightness': 100,
|
|
'color_temp': 3500,
|
|
'hue': 0,
|
|
'index': 0,
|
|
'saturation': 0},
|
|
{'brightness': 50,
|
|
'color_temp': 6500,
|
|
'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': -47,
|
|
'sw_ver': '1.4.3 Build 170504 Rel.144921'}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
def error(cls, 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, sysinfo, invalid=False):
|
|
""" invalid is set only for testing
|
|
to force query() to throw the exception for non-connected """
|
|
proto = FakeTransportProtocol.baseproto
|
|
for target in sysinfo:
|
|
for cmd in sysinfo[target]:
|
|
proto[target][cmd] = sysinfo[target][cmd]
|
|
self.proto = proto
|
|
self.invalid = invalid
|
|
|
|
def set_alias(self, x):
|
|
_LOGGER.debug("Setting alias to %s", x["alias"])
|
|
self.proto["system"]["get_sysinfo"]["alias"] = x["alias"]
|
|
|
|
def set_relay_state(self, x):
|
|
_LOGGER.debug("Setting relay state to %s", x)
|
|
self.proto["system"]["get_sysinfo"]["relay_state"] = x["state"]
|
|
|
|
def set_led_off(self, x):
|
|
_LOGGER.debug("Setting led off to %s", x)
|
|
self.proto["system"]["get_sysinfo"]["led_off"] = x["off"]
|
|
|
|
def set_mac(self, x):
|
|
_LOGGER.debug("Setting mac to %s", x)
|
|
self.proto["system"]["get_sysinfo"][""]
|
|
|
|
def transition_light_state(self, x):
|
|
_LOGGER.debug("Setting light state to %s", x)
|
|
for key in x:
|
|
self.proto["smartlife.iot.smartbulb.lightingservice"]["get_light_state"][key]=x[key]
|
|
|
|
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": None,
|
|
"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,
|
|
|
|
}
|
|
}
|
|
|
|
def query(self, host, request, port=9999):
|
|
if self.invalid:
|
|
raise SmartDeviceException("Invalid connection, can't query!")
|
|
|
|
proto = self.proto
|
|
|
|
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("Going to execute {}.{} (params: {}).. ".format(target, cmd, params))
|
|
|
|
if callable(proto[target][cmd]):
|
|
res = proto[target][cmd](self, params)
|
|
# 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):
|
|
return success(target, cmd, proto[target][cmd])
|
|
else:
|
|
raise NotImplementedError("target {} cmd {}".format(target, cmd))
|