Homekit: Use util functions for unit conversion (#13253)

* Updated to util/color for conversion
* Updated temperature sensor to use util/temperature conversion
This commit is contained in:
cdce8p 2018-03-16 11:38:44 +01:00 committed by GitHub
parent 99f7e2bd97
commit f6ae2d338d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 17 additions and 106 deletions

View File

@ -5,6 +5,7 @@ from homeassistant.components.light import (
ATTR_RGB_COLOR, ATTR_BRIGHTNESS,
SUPPORT_BRIGHTNESS, SUPPORT_RGB_COLOR)
from homeassistant.const import ATTR_SUPPORTED_FEATURES, STATE_ON, STATE_OFF
from homeassistant.util.color import color_RGB_to_hsv, color_hsv_to_RGB
from . import TYPES
from .accessories import HomeAccessory, add_preload_service
@ -17,69 +18,6 @@ _LOGGER = logging.getLogger(__name__)
RGB_COLOR = 'rgb_color'
class Color:
"""Class to handle color conversions."""
# pylint: disable=invalid-name
def __init__(self, hue=None, saturation=None):
"""Initialize a new Color object."""
self.hue = hue # [0, 360]
self.saturation = saturation # [0, 1]
def calc_hsv_to_rgb(self):
"""Convert hsv_color value to rgb_color."""
if not self.hue or not self.saturation:
return [None] * 3
i = int(self.hue / 60)
f = self.hue / 60 - i
v = 1
p = 1 - self.saturation
q = 1 - self.saturation * f
t = 1 - self.saturation * (1 - f)
rgb = []
if i in [0, 6]:
rgb = [v, t, p]
elif i == 1:
rgb = [q, v, p]
elif i == 2:
rgb = [p, v, t]
elif i == 3:
rgb = [p, q, v]
elif i == 4:
rgb = [t, p, v]
elif i == 5:
rgb = [v, p, q]
return [round(c * 255) for c in rgb]
@classmethod
def calc_rgb_to_hsv(cls, rgb_color):
"""Convert a give rgb_color back to a hsv_color."""
rgb_color = [c / 255 for c in rgb_color]
c_max = max(rgb_color)
c_min = min(rgb_color)
c_diff = c_max - c_min
r, g, b = rgb_color
hue, saturation = 0, 0
if c_max == r:
hue = 60 * (0 + (g - b) / c_diff)
elif c_max == g:
hue = 60 * (2 + (b - r) / c_diff)
elif c_max == b:
hue = 60 * (4 + (r - g) / c_diff)
hue = round(hue + 360) if hue < 0 else round(hue)
if c_max != 0:
saturation = round((c_max - c_min) / c_max * 100)
return (hue, saturation)
@TYPES.register('Light')
class Light(HomeAccessory):
"""Generate a Light accessory for a light entity.
@ -97,8 +35,6 @@ class Light(HomeAccessory):
CHAR_HUE: False, CHAR_SATURATION: False,
RGB_COLOR: False}
self.color = Color()
self.chars = []
self._features = self._hass.states.get(self._entity_id) \
.attributes.get(ATTR_SUPPORTED_FEATURES)
@ -107,6 +43,8 @@ class Light(HomeAccessory):
if self._features & SUPPORT_RGB_COLOR:
self.chars.append(CHAR_HUE)
self.chars.append(CHAR_SATURATION)
self._hue = None
self._saturation = None
serv_light = add_preload_service(self, SERV_LIGHTBULB, self.chars)
self.char_on = serv_light.get_characteristic(CHAR_ON)
@ -152,14 +90,14 @@ class Light(HomeAccessory):
"""Set saturation if call came from HomeKit."""
_LOGGER.debug('%s: Set saturation to %d', self._entity_id, value)
self._flag[CHAR_SATURATION] = True
self.color.saturation = value / 100
self._saturation = value
self.set_color()
def set_hue(self, value):
"""Set hue if call came from HomeKit."""
_LOGGER.debug('%s: Set hue to %d', self._entity_id, value)
self._flag[CHAR_HUE] = True
self.color.hue = value
self._hue = value
self.set_color()
def set_color(self):
@ -167,7 +105,7 @@ class Light(HomeAccessory):
# Handle RGB Color
if self._features & SUPPORT_RGB_COLOR and self._flag[CHAR_HUE] and \
self._flag[CHAR_SATURATION]:
color = self.color.calc_hsv_to_rgb()
color = color_hsv_to_RGB(self._hue, self._saturation, 100)
_LOGGER.debug('%s: Set rgb_color to %s', self._entity_id, color)
self._flag.update({
CHAR_HUE: False, CHAR_SATURATION: False, RGB_COLOR: True})
@ -199,10 +137,12 @@ class Light(HomeAccessory):
# Handle RGB Color
if CHAR_SATURATION in self.chars and CHAR_HUE in self.chars:
rgb_color = new_state.attributes.get(ATTR_RGB_COLOR)
current_color = color_hsv_to_RGB(self._hue, self._saturation, 100)\
if self._hue and self._saturation else [None] * 3
if not self._flag[RGB_COLOR] and \
isinstance(rgb_color, (list, tuple)) and \
list(rgb_color) != self.color.calc_hsv_to_rgb():
hue, saturation = Color.calc_rgb_to_hsv(rgb_color)
tuple(rgb_color) != current_color:
hue, saturation, _ = color_RGB_to_hsv(*rgb_color)
self.char_hue.set_value(hue, should_callback=False)
self.char_saturation.set_value(saturation,
should_callback=False)

View File

@ -3,6 +3,7 @@ import logging
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT, TEMP_FAHRENHEIT, TEMP_CELSIUS)
from homeassistant.util.temperature import fahrenheit_to_celsius
from . import TYPES
from .accessories import (
@ -26,7 +27,7 @@ def calc_temperature(state, unit=TEMP_CELSIUS):
except ValueError:
return None
return round((value - 32) / 1.8, 2) if unit == TEMP_FAHRENHEIT else value
return fahrenheit_to_celsius(value) if unit == TEMP_FAHRENHEIT else value
def calc_humidity(state):

View File

@ -2,7 +2,7 @@
import unittest
from homeassistant.core import callback
from homeassistant.components.homekit.type_lights import Light, Color
from homeassistant.components.homekit.type_lights import Light
from homeassistant.components.light import (
DOMAIN, ATTR_BRIGHTNESS, ATTR_BRIGHTNESS_PCT, ATTR_RGB_COLOR,
SUPPORT_BRIGHTNESS, SUPPORT_RGB_COLOR)
@ -14,34 +14,6 @@ from homeassistant.const import (
from tests.common import get_test_home_assistant
def test_calc_hsv_to_rgb():
"""Test conversion hsv to rgb."""
color = Color(43, 23 / 100)
assert color.calc_hsv_to_rgb() == [255, 238, 196]
color.hue, color.saturation = (79, 12 / 100)
assert color.calc_hsv_to_rgb() == [245, 255, 224]
color.hue, color.saturation = (177, 2 / 100)
assert color.calc_hsv_to_rgb() == [250, 255, 255]
color.hue, color.saturation = (212, 26 / 100)
assert color.calc_hsv_to_rgb() == [189, 220, 255]
color.hue, color.saturation = (271, 93 / 100)
assert color.calc_hsv_to_rgb() == [140, 18, 255]
color.hue, color.saturation = (355, 100 / 100)
assert color.calc_hsv_to_rgb() == [255, 0, 21]
def test_calc_rgb_to_hsv():
"""Test conversion rgb to hsv."""
assert Color.calc_rgb_to_hsv([255, 0, 21]) == (355, 100)
assert Color.calc_rgb_to_hsv([245, 255, 224]) == (79, 12)
assert Color.calc_rgb_to_hsv([189, 220, 255]) == (212, 26)
class TestHomekitLights(unittest.TestCase):
"""Test class for all accessory types regarding lights."""
@ -137,15 +109,15 @@ class TestHomekitLights(unittest.TestCase):
entity_id = 'light.demo'
self.hass.states.set(entity_id, STATE_ON, {
ATTR_SUPPORTED_FEATURES: SUPPORT_RGB_COLOR,
ATTR_RGB_COLOR: (120, 20, 300)})
ATTR_RGB_COLOR: (120, 20, 255)})
acc = Light(self.hass, entity_id, 'Light', aid=2)
self.assertEqual(acc.char_hue.value, 0)
self.assertEqual(acc.char_saturation.value, 75)
acc.run()
self.hass.block_till_done()
self.assertEqual(acc.char_hue.value, 261)
self.assertEqual(acc.char_saturation.value, 93)
self.assertEqual(acc.char_hue.value, 265.532)
self.assertEqual(acc.char_saturation.value, 92.157)
# Set from HomeKit
acc.char_hue.set_value(145)
@ -157,4 +129,4 @@ class TestHomekitLights(unittest.TestCase):
self.events[0].data[ATTR_SERVICE], SERVICE_TURN_ON)
self.assertEqual(
self.events[0].data[ATTR_SERVICE_DATA], {
ATTR_ENTITY_ID: entity_id, ATTR_RGB_COLOR: [64, 255, 143]})
ATTR_ENTITY_ID: entity_id, ATTR_RGB_COLOR: (63, 255, 143)})

View File

@ -17,9 +17,7 @@ def test_calc_temperature():
assert calc_temperature('20') == 20
assert calc_temperature('20.12', TEMP_CELSIUS) == 20.12
assert calc_temperature('75.2', TEMP_FAHRENHEIT) == 24
assert calc_temperature('-20.6', TEMP_FAHRENHEIT) == -29.22
def test_calc_humidity():