From 191fc8f8d412320688edc5b5be391fbf9ff09450 Mon Sep 17 00:00:00 2001 From: Nolan Gilley Date: Sat, 21 May 2016 13:19:27 -0400 Subject: [PATCH] Change color_RGB_to_xy formula & return brightness (#2095) * Use RGB to XY calculations from Philips Hue developer site * uppercase X,Y,Z * rename cx,cy to x,y * return brightness in color_RGB_to_xy * remove try/catch * update existing platforms using color_RGB_to_xy * improve wemo w/ jaharkes suggestion * allow brightness override of rgb_to_xy --- homeassistant/components/light/hue.py | 10 +++-- homeassistant/components/light/wemo.py | 1 + homeassistant/components/light/wink.py | 4 +- homeassistant/util/color.py | 51 ++++++++++++-------------- tests/util/test_color.py | 11 +++--- 5 files changed, 40 insertions(+), 37 deletions(-) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 60c1e7f6605..614df66b133 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -235,14 +235,16 @@ class HueLight(Light): if ATTR_TRANSITION in kwargs: command['transitiontime'] = kwargs[ATTR_TRANSITION] * 10 - if ATTR_BRIGHTNESS in kwargs: - command['bri'] = kwargs[ATTR_BRIGHTNESS] - if ATTR_XY_COLOR in kwargs: command['xy'] = kwargs[ATTR_XY_COLOR] elif ATTR_RGB_COLOR in kwargs: - command['xy'] = color_util.color_RGB_to_xy( + xyb = color_util.color_RGB_to_xy( *(int(val) for val in kwargs[ATTR_RGB_COLOR])) + command['xy'] = xyb[0], xyb[1] + command['bri'] = xyb[2] + + if ATTR_BRIGHTNESS in kwargs: + command['bri'] = kwargs[ATTR_BRIGHTNESS] if ATTR_COLOR_TEMP in kwargs: command['ct'] = kwargs[ATTR_COLOR_TEMP] diff --git a/homeassistant/components/light/wemo.py b/homeassistant/components/light/wemo.py index d2844826400..a4aa6686a17 100644 --- a/homeassistant/components/light/wemo.py +++ b/homeassistant/components/light/wemo.py @@ -105,6 +105,7 @@ class WemoLight(Light): elif ATTR_RGB_COLOR in kwargs: xycolor = color_util.color_RGB_to_xy( *(int(val) for val in kwargs[ATTR_RGB_COLOR])) + kwargs.setdefault(ATTR_BRIGHTNESS, xycolor[2]) else: xycolor = None diff --git a/homeassistant/components/light/wink.py b/homeassistant/components/light/wink.py index 86d2a29c21f..c7a7637b047 100644 --- a/homeassistant/components/light/wink.py +++ b/homeassistant/components/light/wink.py @@ -97,7 +97,9 @@ class WinkLight(Light): } if rgb_color: - state_kwargs['color_xy'] = color_util.color_RGB_to_xy(*rgb_color) + xyb = color_util.color_RGB_to_xy(*rgb_color) + state_kwargs['color_xy'] = xyb[0], xyb[1] + state_kwargs['brightness'] = xyb[2] if color_temp_mired: state_kwargs['color_kelvin'] = mired_to_kelvin(color_temp_mired) diff --git a/homeassistant/util/color.py b/homeassistant/util/color.py index 940d435ed44..23412344a85 100644 --- a/homeassistant/util/color.py +++ b/homeassistant/util/color.py @@ -7,44 +7,41 @@ HASS_COLOR_MAX = 500 # mireds (inverted) HASS_COLOR_MIN = 154 -# Taken from: http://www.cse.unr.edu/~quiroz/inc/colortransforms.py +# Taken from: +# http://www.developers.meethue.com/documentation/color-conversions-rgb-xy # License: Code is given as is. Use at your own risk and discretion. # pylint: disable=invalid-name def color_RGB_to_xy(R, G, B): """Convert from RGB color to XY color.""" if R + G + B == 0: - return 0, 0 + return 0, 0, 0 - var_R = (R / 255.) - var_G = (G / 255.) - var_B = (B / 255.) + R = R / 255 + B = B / 255 + G = G / 255 - if var_R > 0.04045: - var_R = ((var_R + 0.055) / 1.055) ** 2.4 - else: - var_R /= 12.92 + # Gamma correction + R = pow((R + 0.055) / (1.0 + 0.055), + 2.4) if (R > 0.04045) else (R / 12.92) + G = pow((G + 0.055) / (1.0 + 0.055), + 2.4) if (G > 0.04045) else (G / 12.92) + B = pow((B + 0.055) / (1.0 + 0.055), + 2.4) if (B > 0.04045) else (B / 12.92) - if var_G > 0.04045: - var_G = ((var_G + 0.055) / 1.055) ** 2.4 - else: - var_G /= 12.92 + # Wide RGB D65 conversion formula + X = R * 0.664511 + G * 0.154324 + B * 0.162028 + Y = R * 0.313881 + G * 0.668433 + B * 0.047685 + Z = R * 0.000088 + G * 0.072310 + B * 0.986039 - if var_B > 0.04045: - var_B = ((var_B + 0.055) / 1.055) ** 2.4 - else: - var_B /= 12.92 + # Convert XYZ to xy + x = X / (X + Y + Z) + y = Y / (X + Y + Z) - var_R *= 100 - var_G *= 100 - var_B *= 100 + # Brightness + Y = 1 if Y > 1 else Y + brightness = round(Y * 255) - # Observer. = 2 deg, Illuminant = D65 - X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805 - Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722 - Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505 - - # Convert XYZ to xy, see CIE 1931 color space on wikipedia - return X / (X + Y + Z), Y / (X + Y + Z) + return round(x, 3), round(y, 3), brightness # taken from diff --git a/tests/util/test_color.py b/tests/util/test_color.py index 06d413778cf..82222a0b8a1 100644 --- a/tests/util/test_color.py +++ b/tests/util/test_color.py @@ -9,16 +9,17 @@ class TestColorUtil(unittest.TestCase): # pylint: disable=invalid-name def test_color_RGB_to_xy(self): """Test color_RGB_to_xy.""" - self.assertEqual((0, 0), color_util.color_RGB_to_xy(0, 0, 0)) - self.assertEqual((0.3127159072215825, 0.3290014805066623), + self.assertEqual((0, 0, 0), color_util.color_RGB_to_xy(0, 0, 0)) + self.assertEqual((0.32, 0.336, 255), color_util.color_RGB_to_xy(255, 255, 255)) - self.assertEqual((0.15001662234042554, 0.060006648936170214), + self.assertEqual((0.136, 0.04, 12), color_util.color_RGB_to_xy(0, 0, 255)) - self.assertEqual((0.3, 0.6), color_util.color_RGB_to_xy(0, 255, 0)) + self.assertEqual((0.172, 0.747, 170), + color_util.color_RGB_to_xy(0, 255, 0)) - self.assertEqual((0.6400744994567747, 0.3299705106316933), + self.assertEqual((0.679, 0.321, 80), color_util.color_RGB_to_xy(255, 0, 0)) def test_color_xy_brightness_to_RGB(self):