Merge pull request #135 from rytilahti/add_hs220_tests

Add tests and pretty output for HS220, fix minor issues in tests
This commit is contained in:
Georgi Kirichkov 2018-10-19 11:52:42 +03:00 committed by GitHub
commit ce318bf824
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 103 additions and 13 deletions

View File

@ -15,6 +15,7 @@ Python Library to control TPLink smart plugs/switches and smart bulbs.
* Wall switches * Wall switches
* HS200 * HS200
* HS210 * HS210
* HS220
* Bulbs * Bulbs
* LB100 * LB100
* LB110 * LB110

View File

@ -26,7 +26,6 @@ pass_dev = click.make_pass_decorator(SmartDevice)
help='The host name or IP address of the device to connect to.') help='The host name or IP address of the device to connect to.')
@click.option('--alias', envvar="PYHS100_NAME", required=False, @click.option('--alias', envvar="PYHS100_NAME", required=False,
help='The device name, or alias, of the device to connect to.') help='The device name, or alias, of the device to connect to.')
@click.option('--debug/--normal', default=False) @click.option('--debug/--normal', default=False)
@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)
@ -183,7 +182,10 @@ def emeter(dev, year, month, erase):
required=False) required=False)
@pass_dev @pass_dev
def brightness(dev, brightness): def brightness(dev, brightness):
"""Get or set brightness. (Bulb Only)""" """Get or set brightness."""
if not dev.is_dimmable:
click.echo("This device does not support brightness.")
return
if brightness is None: if brightness is None:
click.echo("Brightness: %s" % dev.brightness) click.echo("Brightness: %s" % dev.brightness)
else: else:
@ -263,5 +265,6 @@ def reboot(plug, delay):
click.echo("Rebooting the device..") click.echo("Rebooting the device..")
plug.reboot(delay) plug.reboot(delay)
if __name__ == "__main__": if __name__ == "__main__":
cli() cli()

View File

@ -119,6 +119,9 @@ class SmartDevice(object):
raise SmartDeviceException("Error on {}.{}: {}" raise SmartDeviceException("Error on {}.{}: {}"
.format(target, cmd, result)) .format(target, cmd, result))
if cmd not in result:
raise SmartDeviceException("No command in response: {}"
.format(response))
result = result[cmd] result = result[cmd]
del result["err_code"] del result["err_code"]

View File

@ -107,7 +107,7 @@ class SmartPlug(SmartDevice):
""" """
if not self.is_dimmable: if not self.is_dimmable:
return None return
if not isinstance(value, int): if not isinstance(value, int):
raise ValueError("Brightness must be integer, " raise ValueError("Brightness must be integer, "
@ -128,10 +128,7 @@ class SmartPlug(SmartDevice):
:rtype: bool :rtype: bool
""" """
dimmable = False return "brightness" in self.sys_info
if "brightness" in self.sys_info:
dimmable = True
return dimmable
@property @property
def has_emeter(self): def has_emeter(self):
@ -201,7 +198,16 @@ class SmartPlug(SmartDevice):
@property @property
def state_information(self) -> Dict[str, Any]: def state_information(self) -> Dict[str, Any]:
return { """
Return switch-specific state information.
:return: Switch information dict, keys in user-presentable form.
:rtype: dict
"""
info = {
'LED state': self.led, 'LED state': self.led,
'On since': self.on_since 'On since': self.on_since
} }
if self.is_dimmable:
info["Brightness"] = self.brightness
return info

View File

@ -165,6 +165,44 @@ sysinfo_hs200 = {'system': {'get_sysinfo': {'active_mode': 'schedule',
'updating': 0}} 'updating': 0}}
} }
sysinfo_hs220 = {
"system": {
"get_sysinfo": {
"sw_ver": "1.4.8 Build 180109 Rel.171240",
"hw_ver": "1.0",
"mic_type": "IOT.SMARTPLUGSWITCH",
"model": "HS220(US)",
"mac": "B0:4E:26:11:22:33",
"dev_name": "Smart Wi-Fi Dimmer",
"alias": "Chandelier",
"relay_state": 0,
"brightness": 25,
"on_time": 0,
"active_mode": "none",
"feature": "TIM",
"updating": 0,
"icon_hash": "",
"rssi": -53,
"led_off": 0,
"longitude_i": -12.2,
"latitude_i": 12.2,
"hwId": "84DCCF37225C9E55319617F7D5C095BD",
"fwId": "00000000000000000000000000000000",
"deviceId": "800695154E6B882428E30F850473F34019A9E999",
"oemId": "3B13224B2807E0D48A9DD06EBD344CD6",
"preferred_state":
[
{"index": 0, "brightness": 100},
{"index": 1, "brightness": 75},
{"index": 2, "brightness": 50},
{"index": 3, "brightness": 25}
],
"next_action": {"type": -1},
"err_code": 0
}
}
}
sysinfo_lb130 = {'system': {'get_sysinfo': sysinfo_lb130 = {'system': {'get_sysinfo':
{'active_mode': 'none', {'active_mode': 'none',
'alias': 'Living Room Side Table', 'alias': 'Living Room Side Table',
@ -423,7 +461,7 @@ sysinfo_lb120 = {'system':
} }
def error(cls, target, cmd="no-command", msg="default msg"): def error(target, cmd="no-command", msg="default msg"):
return {target: {cmd: {"err_code": -1323, "msg": msg}}} return {target: {cmd: {"err_code": -1323, "msg": msg}}}
@ -460,7 +498,11 @@ class FakeTransportProtocol(TPLinkSmartHomeProtocol):
def set_mac(self, x): def set_mac(self, x):
_LOGGER.debug("Setting mac to %s", x) _LOGGER.debug("Setting mac to %s", x)
self.proto["system"]["get_sysinfo"][""] self.proto["system"]["get_sysinfo"]["mac"] = x
def set_hs220_brightness(self, x):
_LOGGER.debug("Setting brightness to %s", x)
self.proto["system"]["get_sysinfo"]["brightness"] = x["brightness"]
def transition_light_state(self, x): def transition_light_state(self, x):
_LOGGER.debug("Setting light state to %s", x) _LOGGER.debug("Setting light state to %s", x)
@ -491,8 +533,10 @@ class FakeTransportProtocol(TPLinkSmartHomeProtocol):
"time": { "get_time": { "year": 2017, "month": 1, "mday": 2, "hour": 3, "min": 4, "sec": 5 }, "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" }, "get_timezone": {'zone_str': "test", 'dst_offset': -1, 'index': 12, 'tz_str': "test2" },
"set_timezone": None, "set_timezone": None,
},
} # HS220 brightness, different setter and getter
"smartlife.iot.dimmer": { "set_brightness": set_hs220_brightness,
},
} }
def query(self, host, request, port=9999): def query(self, host, request, port=9999):

View File

@ -11,7 +11,9 @@ from .fakes import (FakeTransportProtocol,
sysinfo_hs105, sysinfo_hs105,
sysinfo_hs110, sysinfo_hs110,
sysinfo_hs110_au_v2, sysinfo_hs110_au_v2,
sysinfo_hs200) sysinfo_hs200,
sysinfo_hs220,
)
# Set IP instead of None if you want to run tests on a device. # Set IP instead of None if you want to run tests on a device.
PLUG_IP = None PLUG_IP = None
@ -66,6 +68,14 @@ class TestSmartPlugHS100(TestCase):
'type': str, 'type': str,
'mic_type': str, 'mic_type': str,
'updating': check_int_bool, '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},
}) })
current_consumption_schema = Schema(Any({ current_consumption_schema = Schema(Any({
@ -335,3 +345,26 @@ class TestSmartPlugHS105(TestSmartPlugHS100):
protocol=FakeTransportProtocol(self.SYSINFO)) protocol=FakeTransportProtocol(self.SYSINFO))
self.sysinfo_schema(plug_i.location) self.sysinfo_schema(plug_i.location)
class TestSmartPlugHS220(TestSmartPlugHS105):
"""HS220 with dimming functionality. Sysinfo looks similar to HS105."""
SYSINFO = sysinfo_hs220
def test_dimmable(self):
assert self.plug.is_dimmable
assert self.plug.brightness == 25
self.plug.brightness = 100
assert self.plug.brightness == 100
with self.assertRaises(ValueError):
self.plug.brightness = 110
with self.assertRaises(ValueError):
self.plug.brightness = -1
with self.assertRaises(ValueError):
self.plug.brightness = "foo"
with self.assertRaises(ValueError):
self.plug.brightness = 11.1