mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
LIFX: clean up internal color conversions (#7964)
* Add color_util.color_hsv_to_RGB * Use helper functions for LIFX conversions The LIFX API uses 16 bits for saturation/brightness while HA uses 8 bits. Using helper functions makes the conversion a bit nicer and less prone to off-by-one issues. The colorsys library uses 0.0-1.0 but we can avoid that by using the HA color_util converters instead.
This commit is contained in:
parent
1b1619fbf1
commit
9e16be3173
@ -4,7 +4,6 @@ Support for the LIFX platform that implements lights.
|
|||||||
For more details about this platform, please refer to the documentation at
|
For more details about this platform, please refer to the documentation at
|
||||||
https://home-assistant.io/components/light.lifx/
|
https://home-assistant.io/components/light.lifx/
|
||||||
"""
|
"""
|
||||||
import colorsys
|
|
||||||
import logging
|
import logging
|
||||||
import asyncio
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
@ -24,8 +23,6 @@ from homeassistant.components.light import (
|
|||||||
SUPPORT_XY_COLOR, SUPPORT_TRANSITION, SUPPORT_EFFECT,
|
SUPPORT_XY_COLOR, SUPPORT_TRANSITION, SUPPORT_EFFECT,
|
||||||
preprocess_turn_on_alternatives)
|
preprocess_turn_on_alternatives)
|
||||||
from homeassistant.config import load_yaml_config_file
|
from homeassistant.config import load_yaml_config_file
|
||||||
from homeassistant.util.color import (
|
|
||||||
color_temperature_mired_to_kelvin, color_temperature_kelvin_to_mired)
|
|
||||||
from homeassistant import util
|
from homeassistant import util
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.event import async_track_point_in_utc_time
|
from homeassistant.helpers.event import async_track_point_in_utc_time
|
||||||
@ -51,9 +48,6 @@ SERVICE_LIFX_SET_STATE = 'lifx_set_state'
|
|||||||
ATTR_HSBK = 'hsbk'
|
ATTR_HSBK = 'hsbk'
|
||||||
ATTR_POWER = 'power'
|
ATTR_POWER = 'power'
|
||||||
|
|
||||||
BYTE_MAX = 255
|
|
||||||
SHORT_MAX = 65535
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
vol.Optional(CONF_SERVER, default='0.0.0.0'): cv.string,
|
vol.Optional(CONF_SERVER, default='0.0.0.0'): cv.string,
|
||||||
})
|
})
|
||||||
@ -200,15 +194,14 @@ class AwaitAioLIFX:
|
|||||||
return self.message
|
return self.message
|
||||||
|
|
||||||
|
|
||||||
def convert_rgb_to_hsv(rgb):
|
def convert_8_to_16(value):
|
||||||
"""Convert Home Assistant RGB values to HSV values."""
|
"""Scale an 8 bit level into 16 bits."""
|
||||||
red, green, blue = [_ / BYTE_MAX for _ in rgb]
|
return (value << 8) | value
|
||||||
|
|
||||||
hue, saturation, brightness = colorsys.rgb_to_hsv(red, green, blue)
|
|
||||||
|
|
||||||
return [int(hue * SHORT_MAX),
|
def convert_16_to_8(value):
|
||||||
int(saturation * SHORT_MAX),
|
"""Scale a 16 bit level into 8 bits."""
|
||||||
int(brightness * SHORT_MAX)]
|
return value >> 8
|
||||||
|
|
||||||
|
|
||||||
class LIFXLight(Light):
|
class LIFXLight(Light):
|
||||||
@ -260,14 +253,14 @@ class LIFXLight(Light):
|
|||||||
@property
|
@property
|
||||||
def brightness(self):
|
def brightness(self):
|
||||||
"""Return the brightness of this light between 0..255."""
|
"""Return the brightness of this light between 0..255."""
|
||||||
brightness = int(self._bri / (BYTE_MAX + 1))
|
brightness = convert_16_to_8(self._bri)
|
||||||
_LOGGER.debug("brightness: %d", brightness)
|
_LOGGER.debug("brightness: %d", brightness)
|
||||||
return brightness
|
return brightness
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def color_temp(self):
|
def color_temp(self):
|
||||||
"""Return the color temperature."""
|
"""Return the color temperature."""
|
||||||
temperature = color_temperature_kelvin_to_mired(self._kel)
|
temperature = color_util.color_temperature_kelvin_to_mired(self._kel)
|
||||||
|
|
||||||
_LOGGER.debug("color_temp: %d", temperature)
|
_LOGGER.debug("color_temp: %d", temperature)
|
||||||
return temperature
|
return temperature
|
||||||
@ -280,7 +273,7 @@ class LIFXLight(Light):
|
|||||||
kelvin = 6500
|
kelvin = 6500
|
||||||
else:
|
else:
|
||||||
kelvin = 9000
|
kelvin = 9000
|
||||||
return math.floor(color_temperature_kelvin_to_mired(kelvin))
|
return math.floor(color_util.color_temperature_kelvin_to_mired(kelvin))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_mireds(self):
|
def max_mireds(self):
|
||||||
@ -290,7 +283,7 @@ class LIFXLight(Light):
|
|||||||
kelvin = 2700
|
kelvin = 2700
|
||||||
else:
|
else:
|
||||||
kelvin = 2500
|
kelvin = 2500
|
||||||
return math.ceil(color_temperature_kelvin_to_mired(kelvin))
|
return math.ceil(color_util.color_temperature_kelvin_to_mired(kelvin))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
@ -446,7 +439,9 @@ class LIFXLight(Light):
|
|||||||
|
|
||||||
if ATTR_RGB_COLOR in kwargs:
|
if ATTR_RGB_COLOR in kwargs:
|
||||||
hue, saturation, brightness = \
|
hue, saturation, brightness = \
|
||||||
convert_rgb_to_hsv(kwargs[ATTR_RGB_COLOR])
|
color_util.color_RGB_to_hsv(*kwargs[ATTR_RGB_COLOR])
|
||||||
|
saturation = convert_8_to_16(saturation)
|
||||||
|
brightness = convert_8_to_16(brightness)
|
||||||
changed_color = True
|
changed_color = True
|
||||||
else:
|
else:
|
||||||
hue = self._hue
|
hue = self._hue
|
||||||
@ -455,12 +450,12 @@ class LIFXLight(Light):
|
|||||||
|
|
||||||
if ATTR_XY_COLOR in kwargs:
|
if ATTR_XY_COLOR in kwargs:
|
||||||
hue, saturation = color_util.color_xy_to_hs(*kwargs[ATTR_XY_COLOR])
|
hue, saturation = color_util.color_xy_to_hs(*kwargs[ATTR_XY_COLOR])
|
||||||
saturation = saturation * (BYTE_MAX + 1)
|
saturation = convert_8_to_16(saturation)
|
||||||
changed_color = True
|
changed_color = True
|
||||||
|
|
||||||
# When color or temperature is set, use a default value for the other
|
# When color or temperature is set, use a default value for the other
|
||||||
if ATTR_COLOR_TEMP in kwargs:
|
if ATTR_COLOR_TEMP in kwargs:
|
||||||
kelvin = int(color_temperature_mired_to_kelvin(
|
kelvin = int(color_util.color_temperature_mired_to_kelvin(
|
||||||
kwargs[ATTR_COLOR_TEMP]))
|
kwargs[ATTR_COLOR_TEMP]))
|
||||||
if not changed_color:
|
if not changed_color:
|
||||||
saturation = 0
|
saturation = 0
|
||||||
@ -472,7 +467,7 @@ class LIFXLight(Light):
|
|||||||
kelvin = self._kel
|
kelvin = self._kel
|
||||||
|
|
||||||
if ATTR_BRIGHTNESS in kwargs:
|
if ATTR_BRIGHTNESS in kwargs:
|
||||||
brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1)
|
brightness = convert_8_to_16(kwargs[ATTR_BRIGHTNESS])
|
||||||
changed_color = True
|
changed_color = True
|
||||||
else:
|
else:
|
||||||
brightness = self._bri
|
brightness = self._bri
|
||||||
@ -491,12 +486,8 @@ class LIFXLight(Light):
|
|||||||
self._bri = bri
|
self._bri = bri
|
||||||
self._kel = kel
|
self._kel = kel
|
||||||
|
|
||||||
red, green, blue = colorsys.hsv_to_rgb(
|
red, green, blue = color_util.color_hsv_to_RGB(
|
||||||
hue / SHORT_MAX, sat / SHORT_MAX, bri / SHORT_MAX)
|
hue, convert_16_to_8(sat), convert_16_to_8(bri))
|
||||||
|
|
||||||
red = int(red * BYTE_MAX)
|
|
||||||
green = int(green * BYTE_MAX)
|
|
||||||
blue = int(blue * BYTE_MAX)
|
|
||||||
|
|
||||||
_LOGGER.debug("set_color: %d %d %d %d [%d %d %d]",
|
_LOGGER.debug("set_color: %d %d %d %d [%d %d %d]",
|
||||||
hue, sat, bri, kel, red, green, blue)
|
hue, sat, bri, kel, red, green, blue)
|
||||||
|
@ -264,6 +264,13 @@ def color_RGB_to_hsv(iR: int, iG: int, iB: int) -> Tuple[int, int, int]:
|
|||||||
return (int(fHSV[0]*65536), int(fHSV[1]*255), int(fHSV[2]*255))
|
return (int(fHSV[0]*65536), int(fHSV[1]*255), int(fHSV[2]*255))
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=invalid-sequence-index
|
||||||
|
def color_hsv_to_RGB(iH: int, iS: int, iV: int) -> Tuple[int, int, int]:
|
||||||
|
"""Convert an hsv color into its rgb representation."""
|
||||||
|
fRGB = colorsys.hsv_to_rgb(iH/65536, iS/255, iV/255)
|
||||||
|
return (int(fRGB[0]*255), int(fRGB[1]*255), int(fRGB[2]*255))
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=invalid-sequence-index
|
# pylint: disable=invalid-sequence-index
|
||||||
def color_xy_to_hs(vX: float, vY: float) -> Tuple[int, int]:
|
def color_xy_to_hs(vX: float, vY: float) -> Tuple[int, int]:
|
||||||
"""Convert an xy color to its hs representation."""
|
"""Convert an xy color to its hs representation."""
|
||||||
|
@ -56,6 +56,23 @@ class TestColorUtil(unittest.TestCase):
|
|||||||
self.assertEqual((0, 255, 255),
|
self.assertEqual((0, 255, 255),
|
||||||
color_util.color_RGB_to_hsv(255, 0, 0))
|
color_util.color_RGB_to_hsv(255, 0, 0))
|
||||||
|
|
||||||
|
def test_color_hsv_to_RGB(self):
|
||||||
|
"""Test color_RGB_to_hsv."""
|
||||||
|
self.assertEqual((0, 0, 0),
|
||||||
|
color_util.color_hsv_to_RGB(0, 0, 0))
|
||||||
|
|
||||||
|
self.assertEqual((255, 255, 255),
|
||||||
|
color_util.color_hsv_to_RGB(0, 0, 255))
|
||||||
|
|
||||||
|
self.assertEqual((0, 0, 255),
|
||||||
|
color_util.color_hsv_to_RGB(43690, 255, 255))
|
||||||
|
|
||||||
|
self.assertEqual((0, 255, 0),
|
||||||
|
color_util.color_hsv_to_RGB(21845, 255, 255))
|
||||||
|
|
||||||
|
self.assertEqual((255, 0, 0),
|
||||||
|
color_util.color_hsv_to_RGB(0, 255, 255))
|
||||||
|
|
||||||
def test_color_xy_to_hs(self):
|
def test_color_xy_to_hs(self):
|
||||||
"""Test color_xy_to_hs."""
|
"""Test color_xy_to_hs."""
|
||||||
self.assertEqual((8609, 255),
|
self.assertEqual((8609, 255),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user