From db5065c43a29453850e8e99c983da54ad35d006c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Soko=C5=82owski?= Date: Sat, 14 Oct 2017 12:06:18 +0200 Subject: [PATCH 1/8] Test data for different lights added --- tests/test_device.py | 84 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/tests/test_device.py b/tests/test_device.py index fc800136..475ec3e8 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -31,6 +31,90 @@ '9054': 0 } +LIGHT_W = { + '9054': 0, + '9001': 'Light W name', + '9002': 1494695583, + '9020': 1507969307, + '9003': 65545, + '5750': 2, + '9019': 1, + '3': { + '6': 1, + '0': 'IKEA of Sweden', + '1': 'TRADFRI bulb E27 opal 1000lm', + '2': '', + '3': '1.2.214' + }, + '3311': [ + { + '5850': 1, + '5851': 96, + '9003': 0 + } + ] +} + +LIGHT_WS = { + '9054': 0, + '9001': 'Light WS name', + '9002': 1491149680, + '9020': 1507970265, + '9003': 65537, + '5750': 2, + '9019': 1, + '3': { + '6': 1, + '0': 'IKEA of Sweden', + '1': 'TRADFRI bulb E27 WS opal 980lm', + '2': '', + '3': '1.2.217' + }, + '3311': [ + { + '5850': 1, + '5709': 30138, + '5851': 157, + '5707': 0, + '5708': 0, + '5710': 26909, + '5711': 0, + '5706': 'f1e0b5', + '9003': 0 + } + ] +} + +LIGHT_CWS = { + '9054': 0, + '9001': 'Light CWS name', + '9002': 1506114735, + '9020': 1507970551, + '9003': 65544, + '5750': 2, + '9019': 1, + '3': { + '6': 1, + '0': 'IKEA of Sweden', + '1': 'TRADFRI bulb E27 CWS opal 600lm', + '2': '', + '3': '1.3.002' + }, + '3311': [ + { + '5850': 1, + '5709': 32768, + '5851': 254, + '5707': 0, + '5708': 0, + '5710': 15729, + '5711': 0, + '5706': 'd9337c', + '9003': 0 + } + ] +} + def test_device_properties(): dev = Device(LIGHT) From ab535cf306ab71b6ae4742686126ef3c89361045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Soko=C5=82owski?= Date: Sat, 14 Oct 2017 15:51:48 +0200 Subject: [PATCH 2/8] Test data for different lights added --- tests/test_device.py | 121 ++++++++++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 30 deletions(-) diff --git a/tests/test_device.py b/tests/test_device.py index 475ec3e8..ca5d6245 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -32,19 +32,12 @@ } LIGHT_W = { - '9054': 0, - '9001': 'Light W name', - '9002': 1494695583, - '9020': 1507969307, - '9003': 65545, - '5750': 2, - '9019': 1, '3': { - '6': 1, '0': 'IKEA of Sweden', '1': 'TRADFRI bulb E27 opal 1000lm', '2': '', - '3': '1.2.214' + '3': '1.2.214', + '6': 1 }, '3311': [ { @@ -52,17 +45,47 @@ '5851': 96, '9003': 0 } - ] + ], + '5750': 2, + '9001': 'Light W name', + '9002': 1494695583, + '9003': 65545, + '9019': 1, + '9020': 1507969307, + '9054': 0 } LIGHT_WS = { - '9054': 0, + '3': { + '0': 'IKEA of Sweden', + '1': 'TRADFRI bulb E27 WS opal 980lm', + '2': '', + '3': '1.2.217', + '6': 1 + }, + '3311': [ + { + '5706': 'f1e0b5', + '5707': 0, + '5708': 0, + '5709': 30138, + '5710': 26909, + '5711': 0, + '5850': 1, + '5851': 157, + '9003': 0 + } + ], + '5750': 2, '9001': 'Light WS name', '9002': 1491149680, - '9020': 1507970265, '9003': 65537, - '5750': 2, '9019': 1, + '9020': 1507970265, + '9054': 0 +} + +LIGHT_WS_CUSTOM_COLOR = { '3': { '6': 1, '0': 'IKEA of Sweden', @@ -72,27 +95,28 @@ }, '3311': [ { - '5850': 1, - '5709': 30138, - '5851': 157, + '5706': '0', '5707': 0, '5708': 0, - '5710': 26909, + '5709': 32228, + '5710': 27203, '5711': 0, - '5706': 'f1e0b5', + '5850': 1, + '5851': 157, '9003': 0 } - ] + ], + '5750': 2, + '9001': 'Light WS name', + '9002': 1491149680, + '9003': 65537, + '9019': 1, + '9020': 1507986461, + '9054': 0 } + LIGHT_CWS = { - '9054': 0, - '9001': 'Light CWS name', - '9002': 1506114735, - '9020': 1507970551, - '9003': 65544, - '5750': 2, - '9019': 1, '3': { '6': 1, '0': 'IKEA of Sweden', @@ -102,17 +126,54 @@ }, '3311': [ { - '5850': 1, + '5706': 'd9337c', + '5707': 0, + '5708': 0, '5709': 32768, + '5710': 15729, + '5711': 0, + '5850': 1, '5851': 254, + '9003': 0 + } + ], + '5750': 2, + '9001': 'Light CWS name', + '9002': 1506114735, + '9003': 65544, + '9019': 1, + '9020': 1507970551, + '9054': 0 +} + +LIGHT_CWS_CUSTOM_COLOR = { + '3': { + '0': 'IKEA of Sweden', + '1': 'TRADFRI bulb E27 CWS opal 600lm', + '2': '', + '3': '1.3.002', + '6': 1 + }, + '3311': [ + { + '5706': '0', '5707': 0, '5708': 0, - '5710': 15729, + '5709': 23327, + '5710': 33940, '5711': 0, - '5706': 'd9337c', + '5850': 1, + '5851': 254, '9003': 0 } - ] + ], + '5750': 2, + '9001': 'Light CWS name', + '9002': 1506114735, + '9003': 65544, + '9019': 1, + '9020': 1507970551, + '9054': 0, } From 2a3ee98b243ede54825fbfdb3744c97014e9b389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Soko=C5=82owski?= Date: Sat, 14 Oct 2017 21:29:57 +0200 Subject: [PATCH 3/8] Calculating missing hex values --- pytradfri/color.py | 31 +++++++ pytradfri/device.py | 27 ++++-- tests/test_device.py | 145 -------------------------------- tests/test_light.py | 192 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 244 insertions(+), 151 deletions(-) create mode 100644 tests/test_light.py diff --git a/pytradfri/color.py b/pytradfri/color.py index d9a0bb39..42694708 100644 --- a/pytradfri/color.py +++ b/pytradfri/color.py @@ -132,3 +132,34 @@ def prepare(val): x, y = xyz2xyY(*rgb2xyzA(r, g, b)) return {X: x, Y: y} + +# Converted to Python from Obj-C, original source from: http://www.developers.meethue.com/documentation/color-conversions-rgb-xy pylint: +# disable=invalid-sequence-index +def xy_brightness_to_rgb(vX: float, vY: float, ibrightness: int): + """Convert from XYZ to RGB.""" + brightness = ibrightness / 255. + if brightness == 0: + return (0, 0, 0) + Y = brightness + if vY == 0: + vY += 0.00000000001 + X = (Y / vY) * vX + Z = (Y / vY) * (1 - vX - vY) + # Convert to RGB using Wide RGB D65 conversion. + r = X * 1.656492 - Y * 0.354851 - Z * 0.255038 + g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152 + b = X * 0.051713 - Y * 0.121364 + Z * 1.011530 + # Apply reverse gamma correction. + r, g, b = map( + lambda x: (12.92 * x) if (x <= 0.0031308) else + ((1.0 + 0.055) * pow(x, (1.0 / 2.4)) - 0.055), + [r, g, b] + ) + # Bring all negative components to zero. + r, g, b = map(lambda x: max(0, x), [r, g, b]) + # If one component is greater than 1, weight components by that value. + max_component = max(r, g, b) + if max_component > 1: + r, g, b = map(lambda x: x / max_component, [r, g, b]) + ir, ig, ib = map(lambda x: int(x * 255), [r, g, b]) + return (ir, ig, ib) diff --git a/pytradfri/device.py b/pytradfri/device.py index c388a60f..31db52d8 100644 --- a/pytradfri/device.py +++ b/pytradfri/device.py @@ -17,7 +17,7 @@ ATTR_TRANSITION_TIME ) from .color import can_kelvin_to_xy, kelvin_to_xyY, xyY_to_kelvin, rgb_to_xyY,\ - COLORS + xy_brightness_to_rgb, COLORS from .resource import ApiResource @@ -230,12 +230,24 @@ def dimmer(self): @property def hex_color(self): - return self.raw.get(ATTR_LIGHT_COLOR) + raw_color = self.raw.get(ATTR_LIGHT_COLOR) + if raw_color is not None and len(raw_color) == 6: + return raw_color + (x, y) = self.xy_color + def scale(val): + return float(val)/65535 + return '{0:02x}{1:02x}{2:02x}'.format(*xy_brightness_to_rgb(scale(x), scale(y), self.dimmer)) @property def xy_color(self): - return (self.raw.get(ATTR_LIGHT_COLOR_X), - self.raw.get(ATTR_LIGHT_COLOR_Y)) + current_x = self.raw.get(ATTR_LIGHT_COLOR_X) + current_y = self.raw.get(ATTR_LIGHT_COLOR_Y) + if current_x is not None and current_y is not None: + return (self.raw.get(ATTR_LIGHT_COLOR_X), + self.raw.get(ATTR_LIGHT_COLOR_Y)) + # White Tradfri has no x and y, but spec provide 2700K value + xy = kelvin_to_xyY(2700) + return (xy[ATTR_LIGHT_COLOR_X], xy[ATTR_LIGHT_COLOR_Y]) @property def kelvin_color(self): @@ -246,6 +258,8 @@ def kelvin_color(self): # Only return a kelvin value if it is inside the range that the # kelvin->xyY function supports return kelvin if can_kelvin_to_xy(kelvin) else None + # White Tradfri has no x and y, but spec provide 2700K value + return 2700 @property def raw(self): @@ -259,6 +273,7 @@ def __repr__(self): "state: {}, " \ "dimmer: {}, "\ "hex_color: {}, " \ - "xy_color: {}" \ + "xy_color: {}, " \ + "kelvin_color: {}" \ ">".format(self.index, self.device.name, state, self.dimmer, - self.hex_color, self.xy_color) + self.hex_color, self.xy_color, self.kelvin_color) diff --git a/tests/test_device.py b/tests/test_device.py index ca5d6245..fc800136 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -31,151 +31,6 @@ '9054': 0 } -LIGHT_W = { - '3': { - '0': 'IKEA of Sweden', - '1': 'TRADFRI bulb E27 opal 1000lm', - '2': '', - '3': '1.2.214', - '6': 1 - }, - '3311': [ - { - '5850': 1, - '5851': 96, - '9003': 0 - } - ], - '5750': 2, - '9001': 'Light W name', - '9002': 1494695583, - '9003': 65545, - '9019': 1, - '9020': 1507969307, - '9054': 0 -} - -LIGHT_WS = { - '3': { - '0': 'IKEA of Sweden', - '1': 'TRADFRI bulb E27 WS opal 980lm', - '2': '', - '3': '1.2.217', - '6': 1 - }, - '3311': [ - { - '5706': 'f1e0b5', - '5707': 0, - '5708': 0, - '5709': 30138, - '5710': 26909, - '5711': 0, - '5850': 1, - '5851': 157, - '9003': 0 - } - ], - '5750': 2, - '9001': 'Light WS name', - '9002': 1491149680, - '9003': 65537, - '9019': 1, - '9020': 1507970265, - '9054': 0 -} - -LIGHT_WS_CUSTOM_COLOR = { - '3': { - '6': 1, - '0': 'IKEA of Sweden', - '1': 'TRADFRI bulb E27 WS opal 980lm', - '2': '', - '3': '1.2.217' - }, - '3311': [ - { - '5706': '0', - '5707': 0, - '5708': 0, - '5709': 32228, - '5710': 27203, - '5711': 0, - '5850': 1, - '5851': 157, - '9003': 0 - } - ], - '5750': 2, - '9001': 'Light WS name', - '9002': 1491149680, - '9003': 65537, - '9019': 1, - '9020': 1507986461, - '9054': 0 -} - - -LIGHT_CWS = { - '3': { - '6': 1, - '0': 'IKEA of Sweden', - '1': 'TRADFRI bulb E27 CWS opal 600lm', - '2': '', - '3': '1.3.002' - }, - '3311': [ - { - '5706': 'd9337c', - '5707': 0, - '5708': 0, - '5709': 32768, - '5710': 15729, - '5711': 0, - '5850': 1, - '5851': 254, - '9003': 0 - } - ], - '5750': 2, - '9001': 'Light CWS name', - '9002': 1506114735, - '9003': 65544, - '9019': 1, - '9020': 1507970551, - '9054': 0 -} - -LIGHT_CWS_CUSTOM_COLOR = { - '3': { - '0': 'IKEA of Sweden', - '1': 'TRADFRI bulb E27 CWS opal 600lm', - '2': '', - '3': '1.3.002', - '6': 1 - }, - '3311': [ - { - '5706': '0', - '5707': 0, - '5708': 0, - '5709': 23327, - '5710': 33940, - '5711': 0, - '5850': 1, - '5851': 254, - '9003': 0 - } - ], - '5750': 2, - '9001': 'Light CWS name', - '9002': 1506114735, - '9003': 65544, - '9019': 1, - '9020': 1507970551, - '9054': 0, -} - def test_device_properties(): dev = Device(LIGHT) diff --git a/tests/test_light.py b/tests/test_light.py new file mode 100644 index 00000000..a01327a9 --- /dev/null +++ b/tests/test_light.py @@ -0,0 +1,192 @@ +from pytradfri.const import ROOT_DEVICES, ATTR_NAME +from pytradfri.device import Device + +LIGHT_W = { + '3': { + '0': 'IKEA of Sweden', + '1': 'TRADFRI bulb E27 opal 1000lm', + '2': '', + '3': '1.2.214', + '6': 1 + }, + '3311': [ + { + '5850': 1, + '5851': 96, + '9003': 0 + } + ], + '5750': 2, + '9001': 'Light W name', + '9002': 1494695583, + '9003': 65545, + '9019': 1, + '9020': 1507969307, + '9054': 0 +} + +LIGHT_WS = { + '3': { + '0': 'IKEA of Sweden', + '1': 'TRADFRI bulb E27 WS opal 980lm', + '2': '', + '3': '1.2.217', + '6': 1 + }, + '3311': [ + { + '5706': 'f1e0b5', + '5707': 0, + '5708': 0, + '5709': 30138, + '5710': 26909, + '5711': 0, + '5850': 1, + '5851': 157, + '9003': 0 + } + ], + '5750': 2, + '9001': 'Light WS name', + '9002': 1491149680, + '9003': 65537, + '9019': 1, + '9020': 1507970265, + '9054': 0 +} + +LIGHT_WS_CUSTOM_COLOR = { + '3': { + '6': 1, + '0': 'IKEA of Sweden', + '1': 'TRADFRI bulb E27 WS opal 980lm', + '2': '', + '3': '1.2.217' + }, + '3311': [ + { + '5706': '0', + '5707': 0, + '5708': 0, + '5709': 32228, + '5710': 27203, + '5711': 0, + '5850': 1, + '5851': 157, + '9003': 0 + } + ], + '5750': 2, + '9001': 'Light WS name', + '9002': 1491149680, + '9003': 65537, + '9019': 1, + '9020': 1507986461, + '9054': 0 +} + + +LIGHT_CWS = { + '3': { + '6': 1, + '0': 'IKEA of Sweden', + '1': 'TRADFRI bulb E27 CWS opal 600lm', + '2': '', + '3': '1.3.002' + }, + '3311': [ + { + '5706': 'd9337c', + '5707': 0, + '5708': 0, + '5709': 32768, + '5710': 15729, + '5711': 0, + '5850': 1, + '5851': 254, + '9003': 0 + } + ], + '5750': 2, + '9001': 'Light CWS name', + '9002': 1506114735, + '9003': 65544, + '9019': 1, + '9020': 1507970551, + '9054': 0 +} + +LIGHT_CWS_CUSTOM_COLOR = { + '3': { + '0': 'IKEA of Sweden', + '1': 'TRADFRI bulb E27 CWS opal 600lm', + '2': '', + '3': '1.3.002', + '6': 1 + }, + '3311': [ + { + '5706': '0', + '5707': 0, + '5708': 0, + '5709': 23327, + '5710': 33940, + '5711': 0, + '5850': 1, + '5851': 254, + '9003': 0 + } + ], + '5750': 2, + '9001': 'Light CWS name', + '9002': 1506114735, + '9003': 65544, + '9019': 1, + '9020': 1507970551, + '9054': 0, +} + + +def light(raw): + return Device(raw).light_control.lights[0] + + +def test_white_bulb(): + bulb = light(LIGHT_W) + + assert bulb.hex_color == 'c19b57' + assert bulb.xy_color == (30101, 26913) + assert bulb.kelvin_color == 2700 + + +def test_spectrum_bulb(): + bulb = light(LIGHT_WS) + + assert bulb.hex_color == 'f1e0b5' + assert bulb.xy_color == (30138, 26909) + assert bulb.kelvin_color == 2697 + + +def test_spectrum_bulb_custom_color(): + bulb = light(LIGHT_WS_CUSTOM_COLOR) + + assert bulb.hex_color == 'f9bc5a' + assert bulb.xy_color == (32228, 27203) + assert bulb.kelvin_color == 2325 + + +def test_color_bulb(): + bulb = light(LIGHT_CWS) + + assert bulb.hex_color == 'd9337c' + assert bulb.xy_color == (32768, 15729) + assert bulb.kelvin_color == 4866 + + +def test_color_bulb_custom_color(): + bulb = light(LIGHT_CWS_CUSTOM_COLOR) + + assert bulb.hex_color == 'cdff67' + assert bulb.xy_color == (23327, 33940) + assert bulb.kelvin_color == 5046 + From 28f990fdfd89b57db195d77254b557d8ebb613ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Soko=C5=82owski?= Date: Sat, 14 Oct 2017 22:39:36 +0200 Subject: [PATCH 4/8] Lets comply to flake --- pytradfri/color.py | 6 ++++-- pytradfri/device.py | 5 ++++- tests/test_light.py | 2 -- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pytradfri/color.py b/pytradfri/color.py index 42694708..dc4b3d29 100644 --- a/pytradfri/color.py +++ b/pytradfri/color.py @@ -133,8 +133,10 @@ def prepare(val): x, y = xyz2xyY(*rgb2xyzA(r, g, b)) return {X: x, Y: y} -# Converted to Python from Obj-C, original source from: http://www.developers.meethue.com/documentation/color-conversions-rgb-xy pylint: -# disable=invalid-sequence-index + +# Converted to Python from Obj-C, original source from: +# http://www.developers.meethue.com/documentation/color-conversions-rgb-xy +# pylint: disable=invalid-sequence-index def xy_brightness_to_rgb(vX: float, vY: float, ibrightness: int): """Convert from XYZ to RGB.""" brightness = ibrightness / 255. diff --git a/pytradfri/device.py b/pytradfri/device.py index 31db52d8..ceb87e31 100644 --- a/pytradfri/device.py +++ b/pytradfri/device.py @@ -234,9 +234,12 @@ def hex_color(self): if raw_color is not None and len(raw_color) == 6: return raw_color (x, y) = self.xy_color + def scale(val): return float(val)/65535 - return '{0:02x}{1:02x}{2:02x}'.format(*xy_brightness_to_rgb(scale(x), scale(y), self.dimmer)) + return '{0:02x}{1:02x}{2:02x}'.format( + *xy_brightness_to_rgb(scale(x), scale(y), self.dimmer) + ) @property def xy_color(self): diff --git a/tests/test_light.py b/tests/test_light.py index a01327a9..c3754a0a 100644 --- a/tests/test_light.py +++ b/tests/test_light.py @@ -1,4 +1,3 @@ -from pytradfri.const import ROOT_DEVICES, ATTR_NAME from pytradfri.device import Device LIGHT_W = { @@ -189,4 +188,3 @@ def test_color_bulb_custom_color(): assert bulb.hex_color == 'cdff67' assert bulb.xy_color == (23327, 33940) assert bulb.kelvin_color == 5046 - From 2ffa1f236c69e4492e12d88bbe84f64ba594ef35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Soko=C5=82owski?= Date: Sun, 15 Oct 2017 11:40:06 +0200 Subject: [PATCH 5/8] Add _raw properties --- pytradfri/device.py | 14 +++++++++++--- tests/test_light.py | 10 ++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/pytradfri/device.py b/pytradfri/device.py index ceb87e31..c277af32 100644 --- a/pytradfri/device.py +++ b/pytradfri/device.py @@ -228,9 +228,13 @@ def state(self): def dimmer(self): return self.raw.get(ATTR_LIGHT_DIMMER) + @property + def hex_color_raw(self): + return self.raw.get(ATTR_LIGHT_COLOR) + @property def hex_color(self): - raw_color = self.raw.get(ATTR_LIGHT_COLOR) + raw_color = self.hex_color_raw if raw_color is not None and len(raw_color) == 6: return raw_color (x, y) = self.xy_color @@ -241,10 +245,14 @@ def scale(val): *xy_brightness_to_rgb(scale(x), scale(y), self.dimmer) ) + @property + def xy_color_raw(self): + return (self.raw.get(ATTR_LIGHT_COLOR_X), + self.raw.get(ATTR_LIGHT_COLOR_Y)) + @property def xy_color(self): - current_x = self.raw.get(ATTR_LIGHT_COLOR_X) - current_y = self.raw.get(ATTR_LIGHT_COLOR_Y) + (current_x, current_y) = self.xy_color_raw if current_x is not None and current_y is not None: return (self.raw.get(ATTR_LIGHT_COLOR_X), self.raw.get(ATTR_LIGHT_COLOR_Y)) diff --git a/tests/test_light.py b/tests/test_light.py index c3754a0a..5efae5bd 100644 --- a/tests/test_light.py +++ b/tests/test_light.py @@ -153,7 +153,9 @@ def light(raw): def test_white_bulb(): bulb = light(LIGHT_W) + assert bulb.hex_color_raw == None assert bulb.hex_color == 'c19b57' + assert bulb.xy_color_raw == (None, None) assert bulb.xy_color == (30101, 26913) assert bulb.kelvin_color == 2700 @@ -161,7 +163,9 @@ def test_white_bulb(): def test_spectrum_bulb(): bulb = light(LIGHT_WS) + assert bulb.hex_color_raw == 'f1e0b5' assert bulb.hex_color == 'f1e0b5' + assert bulb.xy_color_raw == (30138, 26909) assert bulb.xy_color == (30138, 26909) assert bulb.kelvin_color == 2697 @@ -169,7 +173,9 @@ def test_spectrum_bulb(): def test_spectrum_bulb_custom_color(): bulb = light(LIGHT_WS_CUSTOM_COLOR) + assert bulb.hex_color_raw == '0' assert bulb.hex_color == 'f9bc5a' + assert bulb.xy_color_raw == (32228, 27203) assert bulb.xy_color == (32228, 27203) assert bulb.kelvin_color == 2325 @@ -177,7 +183,9 @@ def test_spectrum_bulb_custom_color(): def test_color_bulb(): bulb = light(LIGHT_CWS) + assert bulb.hex_color_raw == 'd9337c' assert bulb.hex_color == 'd9337c' + assert bulb.xy_color_raw == (32768, 15729) assert bulb.xy_color == (32768, 15729) assert bulb.kelvin_color == 4866 @@ -185,6 +193,8 @@ def test_color_bulb(): def test_color_bulb_custom_color(): bulb = light(LIGHT_CWS_CUSTOM_COLOR) + assert bulb.hex_color_raw == '0' assert bulb.hex_color == 'cdff67' + assert bulb.xy_color_raw == (23327, 33940) assert bulb.xy_color == (23327, 33940) assert bulb.kelvin_color == 5046 From df25c06dcc1650b24e32a36e33863544322bbd44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Soko=C5=82owski?= Date: Sun, 15 Oct 2017 11:48:01 +0200 Subject: [PATCH 6/8] Let's flake again --- tests/test_light.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_light.py b/tests/test_light.py index 5efae5bd..751aa5c0 100644 --- a/tests/test_light.py +++ b/tests/test_light.py @@ -153,7 +153,7 @@ def light(raw): def test_white_bulb(): bulb = light(LIGHT_W) - assert bulb.hex_color_raw == None + assert bulb.hex_color_raw is None assert bulb.hex_color == 'c19b57' assert bulb.xy_color_raw == (None, None) assert bulb.xy_color == (30101, 26913) From 902e0dd317e2bc1cdb1c43374134822fbb7d3ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Soko=C5=82owski?= Date: Sun, 15 Oct 2017 21:49:16 +0200 Subject: [PATCH 7/8] LightControl can_set_* properties --- pytradfri/device.py | 36 +++++++++++++++++++++++++++++++++++- tests/test_light.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/pytradfri/device.py b/pytradfri/device.py index c277af32..c171ad82 100644 --- a/pytradfri/device.py +++ b/pytradfri/device.py @@ -17,7 +17,8 @@ ATTR_TRANSITION_TIME ) from .color import can_kelvin_to_xy, kelvin_to_xyY, xyY_to_kelvin, rgb_to_xyY,\ - xy_brightness_to_rgb, COLORS + xy_brightness_to_rgb, COLORS, MIN_KELVIN, MAX_KELVIN,\ + MIN_KELVIN_WS, MAX_KELVIN_WS from .resource import ApiResource @@ -143,6 +144,39 @@ def raw(self): """Return raw data that it represents.""" return self._device.raw[ATTR_LIGHT_CONTROL] + @property + def can_set_kelvin(self): + """Return whether controlled light supports color temperature. + The range of supported tempertures is defined by properties + min_kelvin and max_kelvin.""" + return 'WS' in self._device.device_info.model_number + + @property + def can_set_color(self): + """Return whether controlled light supports arbitrary color.""" + return 'CWS' in self._device.device_info.model_number + + @property + def _kelvin_range(self): + if not self.can_set_kelvin: + # White bulb + return (None, None) + if not self.can_set_color: + # White spectrum bulb + return (MIN_KELVIN_WS, MAX_KELVIN_WS) + # Color bulb + return (MIN_KELVIN, MAX_KELVIN) + + @property + def min_kelvin(self): + """Return minimum supported color temperature.""" + return self._kelvin_range[0] + + @property + def max_kelvin(self): + """Return maximum supported color temperature.""" + return self._kelvin_range[1] + def set_state(self, state, *, index=0): """Set state of a light.""" return self.set_values({ diff --git a/tests/test_light.py b/tests/test_light.py index 751aa5c0..1dbd0a99 100644 --- a/tests/test_light.py +++ b/tests/test_light.py @@ -150,6 +150,10 @@ def light(raw): return Device(raw).light_control.lights[0] +def light_device_control(raw): + return Device(raw).light_control + + def test_white_bulb(): bulb = light(LIGHT_W) @@ -198,3 +202,28 @@ def test_color_bulb_custom_color(): assert bulb.xy_color_raw == (23327, 33940) assert bulb.xy_color == (23327, 33940) assert bulb.kelvin_color == 5046 + + +def test_white_device_control(): + light_control = light_device_control(LIGHT_W) + + assert not light_control.can_set_color + assert not light_control.can_set_kelvin + + +def test_spectrum_device_control(): + light_control = light_device_control(LIGHT_WS) + + assert not light_control.can_set_color + assert light_control.can_set_kelvin + assert light_control.min_kelvin == 2200 + assert light_control.max_kelvin == 4000 + + +def test_color_device_control(): + light_control = light_device_control(LIGHT_CWS) + + assert light_control.can_set_color + assert light_control.can_set_kelvin + assert light_control.min_kelvin == 1667 + assert light_control.max_kelvin == 25000 From 483b54c141339c18e8cd4a9f2e2433cafa18e7aa Mon Sep 17 00:00:00 2001 From: Maciej Sokolowski Date: Mon, 16 Oct 2017 10:02:47 +0200 Subject: [PATCH 8/8] Rename properties according to review --- pytradfri/device.py | 19 +++++++++---------- tests/test_light.py | 38 +++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/pytradfri/device.py b/pytradfri/device.py index c171ad82..2dc59a27 100644 --- a/pytradfri/device.py +++ b/pytradfri/device.py @@ -263,15 +263,15 @@ def dimmer(self): return self.raw.get(ATTR_LIGHT_DIMMER) @property - def hex_color_raw(self): + def hex_color(self): return self.raw.get(ATTR_LIGHT_COLOR) @property - def hex_color(self): - raw_color = self.hex_color_raw + def hex_color_inferred(self): + raw_color = self.hex_color if raw_color is not None and len(raw_color) == 6: return raw_color - (x, y) = self.xy_color + (x, y) = self.xy_color_inferred def scale(val): return float(val)/65535 @@ -280,13 +280,13 @@ def scale(val): ) @property - def xy_color_raw(self): + def xy_color(self): return (self.raw.get(ATTR_LIGHT_COLOR_X), self.raw.get(ATTR_LIGHT_COLOR_Y)) @property - def xy_color(self): - (current_x, current_y) = self.xy_color_raw + def xy_color_inferred(self): + (current_x, current_y) = self.xy_color if current_x is not None and current_y is not None: return (self.raw.get(ATTR_LIGHT_COLOR_X), self.raw.get(ATTR_LIGHT_COLOR_Y)) @@ -295,7 +295,7 @@ def xy_color(self): return (xy[ATTR_LIGHT_COLOR_X], xy[ATTR_LIGHT_COLOR_Y]) @property - def kelvin_color(self): + def kelvin_color_inferred(self): current_x = self.raw.get(ATTR_LIGHT_COLOR_X) current_y = self.raw.get(ATTR_LIGHT_COLOR_Y) if current_x is not None and current_y is not None: @@ -319,6 +319,5 @@ def __repr__(self): "dimmer: {}, "\ "hex_color: {}, " \ "xy_color: {}, " \ - "kelvin_color: {}" \ ">".format(self.index, self.device.name, state, self.dimmer, - self.hex_color, self.xy_color, self.kelvin_color) + self.hex_color, self.xy_color) diff --git a/tests/test_light.py b/tests/test_light.py index 1dbd0a99..c4e15762 100644 --- a/tests/test_light.py +++ b/tests/test_light.py @@ -157,51 +157,51 @@ def light_device_control(raw): def test_white_bulb(): bulb = light(LIGHT_W) - assert bulb.hex_color_raw is None - assert bulb.hex_color == 'c19b57' - assert bulb.xy_color_raw == (None, None) - assert bulb.xy_color == (30101, 26913) - assert bulb.kelvin_color == 2700 + assert bulb.hex_color is None + assert bulb.hex_color_inferred == 'c19b57' + assert bulb.xy_color == (None, None) + assert bulb.xy_color_inferred == (30101, 26913) + assert bulb.kelvin_color_inferred == 2700 def test_spectrum_bulb(): bulb = light(LIGHT_WS) - assert bulb.hex_color_raw == 'f1e0b5' assert bulb.hex_color == 'f1e0b5' - assert bulb.xy_color_raw == (30138, 26909) + assert bulb.hex_color_inferred == 'f1e0b5' assert bulb.xy_color == (30138, 26909) - assert bulb.kelvin_color == 2697 + assert bulb.xy_color_inferred == (30138, 26909) + assert bulb.kelvin_color_inferred == 2697 def test_spectrum_bulb_custom_color(): bulb = light(LIGHT_WS_CUSTOM_COLOR) - assert bulb.hex_color_raw == '0' - assert bulb.hex_color == 'f9bc5a' - assert bulb.xy_color_raw == (32228, 27203) + assert bulb.hex_color == '0' + assert bulb.hex_color_inferred == 'f9bc5a' assert bulb.xy_color == (32228, 27203) - assert bulb.kelvin_color == 2325 + assert bulb.xy_color_inferred == (32228, 27203) + assert bulb.kelvin_color_inferred == 2325 def test_color_bulb(): bulb = light(LIGHT_CWS) - assert bulb.hex_color_raw == 'd9337c' assert bulb.hex_color == 'd9337c' - assert bulb.xy_color_raw == (32768, 15729) + assert bulb.hex_color_inferred == 'd9337c' assert bulb.xy_color == (32768, 15729) - assert bulb.kelvin_color == 4866 + assert bulb.xy_color_inferred == (32768, 15729) + assert bulb.kelvin_color_inferred == 4866 def test_color_bulb_custom_color(): bulb = light(LIGHT_CWS_CUSTOM_COLOR) - assert bulb.hex_color_raw == '0' - assert bulb.hex_color == 'cdff67' - assert bulb.xy_color_raw == (23327, 33940) + assert bulb.hex_color == '0' + assert bulb.hex_color_inferred == 'cdff67' assert bulb.xy_color == (23327, 33940) - assert bulb.kelvin_color == 5046 + assert bulb.xy_color_inferred == (23327, 33940) + assert bulb.kelvin_color_inferred == 5046 def test_white_device_control():