From 6ea74ce74002c1f711c43839d21fab3090086c55 Mon Sep 17 00:00:00 2001 From: groth-its Date: Mon, 27 Feb 2017 06:28:31 +0100 Subject: [PATCH] Fix for OSRAM lights connected to hue bridge (#6122) * Fix for OSRAM lights connected to hue bridge Do not send command "effect = none" to OSRAM lights Osram lights connected to a hue bridge do not seem to handle "effect = none" very well. Most of the times they jump to the selected color and then change to red within a second. Osram lights connected to a hue bridge do not handle xy values outside of their gamut. Since they just stay at their old color value, handling the UI is very unpredictable. Sending HSV values to the lights fixes this. * Add tests for new util methods --- homeassistant/components/light/hue.py | 28 +++++++++++++++++----- homeassistant/util/color.py | 13 ++++++++++ tests/util/test_color.py | 34 +++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 645d4b81c8d..09444ee5765 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -379,12 +379,27 @@ class HueLight(Light): command['transitiontime'] = int(kwargs[ATTR_TRANSITION] * 10) if ATTR_XY_COLOR in kwargs: - command['xy'] = kwargs[ATTR_XY_COLOR] + if self.info['manufacturername'] == "OSRAM": + hsv = color_util.color_xy_brightness_to_hsv( + *kwargs[ATTR_XY_COLOR], + ibrightness=self.info['bri']) + command['hue'] = hsv[0] + command['sat'] = hsv[1] + command['bri'] = hsv[2] + else: + command['xy'] = kwargs[ATTR_XY_COLOR] elif ATTR_RGB_COLOR in kwargs: - 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 self.info['manufacturername'] == "OSRAM": + hsv = color_util.color_RGB_to_hsv( + *(int(val) for val in kwargs[ATTR_RGB_COLOR])) + command['hue'] = hsv[0] + command['sat'] = hsv[1] + command['bri'] = hsv[2] + else: + 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] @@ -411,7 +426,8 @@ class HueLight(Light): command['hue'] = random.randrange(0, 65535) command['sat'] = random.randrange(150, 254) elif self.bridge_type == 'hue': - command['effect'] = 'none' + if self.info['manufacturername'] != "OSRAM": + command['effect'] = 'none' self._command_func(self.light_id, command) diff --git a/homeassistant/util/color.py b/homeassistant/util/color.py index 9502849e1d9..5a7c3b12e04 100644 --- a/homeassistant/util/color.py +++ b/homeassistant/util/color.py @@ -1,6 +1,7 @@ """Color util methods.""" import logging import math +import colorsys from typing import Tuple @@ -259,6 +260,18 @@ def color_xy_brightness_to_RGB(vX: float, vY: float, return (ir, ig, ib) +def color_RGB_to_hsv(iR: int, iG: int, iB: int) -> Tuple[int, int, int]: + """Convert an rgb color to its hsv representation.""" + fHSV = colorsys.rgb_to_hsv(iR/255.0, iG/255.0, iB/255.0) + return (int(fHSV[0]*65536), int(fHSV[1]*255), int(fHSV[2]*255)) + + +def color_xy_brightness_to_hsv(vX: float, vY: float, + ibrightness: int) -> Tuple[int, int, int]: + """Convert an xy brightness color to its hsv representation.""" + return color_RGB_to_hsv(*color_xy_brightness_to_RGB(vX, vY, ibrightness)) + + def _match_max_scale(input_colors: Tuple[int, ...], output_colors: Tuple[int, ...]) -> Tuple[int, ...]: """Match the maximum value of the output to the input.""" diff --git a/tests/util/test_color.py b/tests/util/test_color.py index e4048cd3cde..ada7ccc072e 100644 --- a/tests/util/test_color.py +++ b/tests/util/test_color.py @@ -39,6 +39,40 @@ class TestColorUtil(unittest.TestCase): self.assertEqual((0, 83, 255), color_util.color_xy_brightness_to_RGB(0, 0, 255)) + def test_color_RGB_to_hsv(self): + """Test color_RGB_to_hsv.""" + self.assertEqual((0, 0, 0), + color_util.color_RGB_to_hsv(0, 0, 0)) + + self.assertEqual((0, 0, 255), + color_util.color_RGB_to_hsv(255, 255, 255)) + + self.assertEqual((43690, 255, 255), + color_util.color_RGB_to_hsv(0, 0, 255)) + + self.assertEqual((21845, 255, 255), + color_util.color_RGB_to_hsv(0, 255, 0)) + + self.assertEqual((0, 255, 255), + color_util.color_RGB_to_hsv(255, 0, 0)) + + def test_color_xy_brightness_to_hsv(self): + """Test color_RGB_to_xy.""" + self.assertEqual(color_util.color_RGB_to_hsv(0, 0, 0), + color_util.color_xy_brightness_to_hsv(1, 1, 0)) + + self.assertEqual(color_util.color_RGB_to_hsv(255, 235, 214), + color_util.color_xy_brightness_to_hsv(.35, .35, 255)) + + self.assertEqual(color_util.color_RGB_to_hsv(255, 0, 45), + color_util.color_xy_brightness_to_hsv(1, 0, 255)) + + self.assertEqual(color_util.color_RGB_to_hsv(0, 255, 0), + color_util.color_xy_brightness_to_hsv(0, 1, 255)) + + self.assertEqual(color_util.color_RGB_to_hsv(0, 83, 255), + color_util.color_xy_brightness_to_hsv(0, 0, 255)) + def test_rgb_hex_to_rgb_list(self): """Test rgb_hex_to_rgb_list.""" self.assertEqual([255, 255, 255],