Fix loss of ability to control white channel in HomeKit on RGB&W lights (#65864)
* Fix loss of ability to control white channel in HomeKit on RGB&W lights - Fix white channel missing from RGB/W lights - Fix temp missing from RGB/CW lights - Fixes #65529 * cover the missing case * bright fix * force brightness notify on color mode change as wellpull/65956/head
parent
b1dcf7e0d8
commit
41f602c3df
|
@ -1,4 +1,6 @@
|
||||||
"""Class to hold all light accessories."""
|
"""Class to hold all light accessories."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
@ -12,12 +14,13 @@ from homeassistant.components.light import (
|
||||||
ATTR_HS_COLOR,
|
ATTR_HS_COLOR,
|
||||||
ATTR_MAX_MIREDS,
|
ATTR_MAX_MIREDS,
|
||||||
ATTR_MIN_MIREDS,
|
ATTR_MIN_MIREDS,
|
||||||
ATTR_RGB_COLOR,
|
|
||||||
ATTR_RGBW_COLOR,
|
ATTR_RGBW_COLOR,
|
||||||
ATTR_RGBWW_COLOR,
|
ATTR_RGBWW_COLOR,
|
||||||
ATTR_SUPPORTED_COLOR_MODES,
|
ATTR_SUPPORTED_COLOR_MODES,
|
||||||
|
ATTR_WHITE,
|
||||||
COLOR_MODE_RGBW,
|
COLOR_MODE_RGBW,
|
||||||
COLOR_MODE_RGBWW,
|
COLOR_MODE_RGBWW,
|
||||||
|
COLOR_MODE_WHITE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
brightness_supported,
|
brightness_supported,
|
||||||
color_supported,
|
color_supported,
|
||||||
|
@ -32,9 +35,9 @@ from homeassistant.const import (
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.event import async_call_later
|
from homeassistant.helpers.event import async_call_later
|
||||||
from homeassistant.util.color import (
|
from homeassistant.util.color import (
|
||||||
color_hsv_to_RGB,
|
|
||||||
color_temperature_mired_to_kelvin,
|
color_temperature_mired_to_kelvin,
|
||||||
color_temperature_to_hs,
|
color_temperature_to_hs,
|
||||||
|
color_temperature_to_rgbww,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .accessories import TYPES, HomeAccessory
|
from .accessories import TYPES, HomeAccessory
|
||||||
|
@ -51,12 +54,13 @@ from .const import (
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
RGB_COLOR = "rgb_color"
|
|
||||||
|
|
||||||
CHANGE_COALESCE_TIME_WINDOW = 0.01
|
CHANGE_COALESCE_TIME_WINDOW = 0.01
|
||||||
|
|
||||||
|
DEFAULT_MIN_MIREDS = 153
|
||||||
|
DEFAULT_MAX_MIREDS = 500
|
||||||
|
|
||||||
COLOR_MODES_WITH_WHITES = {COLOR_MODE_RGBW, COLOR_MODE_RGBWW}
|
COLOR_MODES_WITH_WHITES = {COLOR_MODE_RGBW, COLOR_MODE_RGBWW, COLOR_MODE_WHITE}
|
||||||
|
|
||||||
|
|
||||||
@TYPES.register("Light")
|
@TYPES.register("Light")
|
||||||
|
@ -79,8 +83,12 @@ class Light(HomeAccessory):
|
||||||
self.color_modes = color_modes = (
|
self.color_modes = color_modes = (
|
||||||
attributes.get(ATTR_SUPPORTED_COLOR_MODES) or []
|
attributes.get(ATTR_SUPPORTED_COLOR_MODES) or []
|
||||||
)
|
)
|
||||||
|
self._previous_color_mode = attributes.get(ATTR_COLOR_MODE)
|
||||||
self.color_supported = color_supported(color_modes)
|
self.color_supported = color_supported(color_modes)
|
||||||
self.color_temp_supported = color_temp_supported(color_modes)
|
self.color_temp_supported = color_temp_supported(color_modes)
|
||||||
|
self.rgbw_supported = COLOR_MODE_RGBW in color_modes
|
||||||
|
self.rgbww_supported = COLOR_MODE_RGBWW in color_modes
|
||||||
|
self.white_supported = COLOR_MODE_WHITE in color_modes
|
||||||
self.brightness_supported = brightness_supported(color_modes)
|
self.brightness_supported = brightness_supported(color_modes)
|
||||||
|
|
||||||
if self.brightness_supported:
|
if self.brightness_supported:
|
||||||
|
@ -89,7 +97,9 @@ class Light(HomeAccessory):
|
||||||
if self.color_supported:
|
if self.color_supported:
|
||||||
self.chars.extend([CHAR_HUE, CHAR_SATURATION])
|
self.chars.extend([CHAR_HUE, CHAR_SATURATION])
|
||||||
|
|
||||||
if self.color_temp_supported:
|
if self.color_temp_supported or COLOR_MODES_WITH_WHITES.intersection(
|
||||||
|
self.color_modes
|
||||||
|
):
|
||||||
self.chars.append(CHAR_COLOR_TEMPERATURE)
|
self.chars.append(CHAR_COLOR_TEMPERATURE)
|
||||||
|
|
||||||
serv_light = self.add_preload_service(SERV_LIGHTBULB, self.chars)
|
serv_light = self.add_preload_service(SERV_LIGHTBULB, self.chars)
|
||||||
|
@ -101,13 +111,22 @@ class Light(HomeAccessory):
|
||||||
# to set to the correct initial value.
|
# to set to the correct initial value.
|
||||||
self.char_brightness = serv_light.configure_char(CHAR_BRIGHTNESS, value=100)
|
self.char_brightness = serv_light.configure_char(CHAR_BRIGHTNESS, value=100)
|
||||||
|
|
||||||
if self.color_temp_supported:
|
if CHAR_COLOR_TEMPERATURE in self.chars:
|
||||||
min_mireds = math.floor(attributes.get(ATTR_MIN_MIREDS, 153))
|
self.min_mireds = math.floor(
|
||||||
max_mireds = math.ceil(attributes.get(ATTR_MAX_MIREDS, 500))
|
attributes.get(ATTR_MIN_MIREDS, DEFAULT_MIN_MIREDS)
|
||||||
|
)
|
||||||
|
self.max_mireds = math.ceil(
|
||||||
|
attributes.get(ATTR_MAX_MIREDS, DEFAULT_MAX_MIREDS)
|
||||||
|
)
|
||||||
|
if not self.color_temp_supported and not self.rgbww_supported:
|
||||||
|
self.max_mireds = self.min_mireds
|
||||||
self.char_color_temp = serv_light.configure_char(
|
self.char_color_temp = serv_light.configure_char(
|
||||||
CHAR_COLOR_TEMPERATURE,
|
CHAR_COLOR_TEMPERATURE,
|
||||||
value=min_mireds,
|
value=self.min_mireds,
|
||||||
properties={PROP_MIN_VALUE: min_mireds, PROP_MAX_VALUE: max_mireds},
|
properties={
|
||||||
|
PROP_MIN_VALUE: self.min_mireds,
|
||||||
|
PROP_MAX_VALUE: self.max_mireds,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.color_supported:
|
if self.color_supported:
|
||||||
|
@ -165,33 +184,32 @@ class Light(HomeAccessory):
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Handle white channels
|
||||||
if CHAR_COLOR_TEMPERATURE in char_values:
|
if CHAR_COLOR_TEMPERATURE in char_values:
|
||||||
params[ATTR_COLOR_TEMP] = char_values[CHAR_COLOR_TEMPERATURE]
|
temp = char_values[CHAR_COLOR_TEMPERATURE]
|
||||||
events.append(f"color temperature at {params[ATTR_COLOR_TEMP]}")
|
events.append(f"color temperature at {temp}")
|
||||||
|
bright_val = round(
|
||||||
|
((brightness_pct or self.char_brightness.value) * 255) / 100
|
||||||
|
)
|
||||||
|
if self.color_temp_supported:
|
||||||
|
params[ATTR_COLOR_TEMP] = temp
|
||||||
|
elif self.rgbww_supported:
|
||||||
|
params[ATTR_RGBWW_COLOR] = color_temperature_to_rgbww(
|
||||||
|
temp, bright_val, self.min_mireds, self.max_mireds
|
||||||
|
)
|
||||||
|
elif self.rgbw_supported:
|
||||||
|
params[ATTR_RGBW_COLOR] = (*(0,) * 3, bright_val)
|
||||||
|
elif self.white_supported:
|
||||||
|
params[ATTR_WHITE] = bright_val
|
||||||
|
|
||||||
elif (
|
elif CHAR_HUE in char_values or CHAR_SATURATION in char_values:
|
||||||
CHAR_HUE in char_values
|
|
||||||
or CHAR_SATURATION in char_values
|
|
||||||
# If we are adjusting brightness we need to send the full RGBW/RGBWW values
|
|
||||||
# since HomeKit does not support RGBW/RGBWW
|
|
||||||
or brightness_pct
|
|
||||||
and COLOR_MODES_WITH_WHITES.intersection(self.color_modes)
|
|
||||||
):
|
|
||||||
hue_sat = (
|
hue_sat = (
|
||||||
char_values.get(CHAR_HUE, self.char_hue.value),
|
char_values.get(CHAR_HUE, self.char_hue.value),
|
||||||
char_values.get(CHAR_SATURATION, self.char_saturation.value),
|
char_values.get(CHAR_SATURATION, self.char_saturation.value),
|
||||||
)
|
)
|
||||||
_LOGGER.debug("%s: Set hs_color to %s", self.entity_id, hue_sat)
|
_LOGGER.debug("%s: Set hs_color to %s", self.entity_id, hue_sat)
|
||||||
events.append(f"set color at {hue_sat}")
|
events.append(f"set color at {hue_sat}")
|
||||||
# HomeKit doesn't support RGBW/RGBWW so we need to remove any white values
|
params[ATTR_HS_COLOR] = hue_sat
|
||||||
if COLOR_MODE_RGBWW in self.color_modes:
|
|
||||||
val = brightness_pct or self.char_brightness.value
|
|
||||||
params[ATTR_RGBWW_COLOR] = (*color_hsv_to_RGB(*hue_sat, val), 0, 0)
|
|
||||||
elif COLOR_MODE_RGBW in self.color_modes:
|
|
||||||
val = brightness_pct or self.char_brightness.value
|
|
||||||
params[ATTR_RGBW_COLOR] = (*color_hsv_to_RGB(*hue_sat, val), 0)
|
|
||||||
else:
|
|
||||||
params[ATTR_HS_COLOR] = hue_sat
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
brightness_pct
|
brightness_pct
|
||||||
|
@ -200,6 +218,9 @@ class Light(HomeAccessory):
|
||||||
):
|
):
|
||||||
params[ATTR_BRIGHTNESS_PCT] = brightness_pct
|
params[ATTR_BRIGHTNESS_PCT] = brightness_pct
|
||||||
|
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Calling light service with params: %s -> %s", char_values, params
|
||||||
|
)
|
||||||
self.async_call_service(DOMAIN, service, params, ", ".join(events))
|
self.async_call_service(DOMAIN, service, params, ", ".join(events))
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@ -210,52 +231,59 @@ class Light(HomeAccessory):
|
||||||
attributes = new_state.attributes
|
attributes = new_state.attributes
|
||||||
color_mode = attributes.get(ATTR_COLOR_MODE)
|
color_mode = attributes.get(ATTR_COLOR_MODE)
|
||||||
self.char_on.set_value(int(state == STATE_ON))
|
self.char_on.set_value(int(state == STATE_ON))
|
||||||
|
color_mode_changed = self._previous_color_mode != color_mode
|
||||||
|
self._previous_color_mode = color_mode
|
||||||
|
|
||||||
# Handle Brightness
|
# Handle Brightness
|
||||||
if self.brightness_supported:
|
if (
|
||||||
if (
|
self.brightness_supported
|
||||||
color_mode
|
and (brightness := attributes.get(ATTR_BRIGHTNESS)) is not None
|
||||||
and COLOR_MODES_WITH_WHITES.intersection({color_mode})
|
and isinstance(brightness, (int, float))
|
||||||
and (rgb_color := attributes.get(ATTR_RGB_COLOR))
|
):
|
||||||
):
|
brightness = round(brightness / 255 * 100, 0)
|
||||||
# HomeKit doesn't support RGBW/RGBWW so we need to
|
# The homeassistant component might report its brightness as 0 but is
|
||||||
# give it the color brightness only
|
# not off. But 0 is a special value in homekit. When you turn on a
|
||||||
brightness = max(rgb_color)
|
# homekit accessory it will try to restore the last brightness state
|
||||||
else:
|
# which will be the last value saved by char_brightness.set_value.
|
||||||
brightness = attributes.get(ATTR_BRIGHTNESS)
|
# But if it is set to 0, HomeKit will update the brightness to 100 as
|
||||||
if isinstance(brightness, (int, float)):
|
# it thinks 0 is off.
|
||||||
brightness = round(brightness / 255 * 100, 0)
|
#
|
||||||
# The homeassistant component might report its brightness as 0 but is
|
# Therefore, if the the brightness is 0 and the device is still on,
|
||||||
# not off. But 0 is a special value in homekit. When you turn on a
|
# the brightness is mapped to 1 otherwise the update is ignored in
|
||||||
# homekit accessory it will try to restore the last brightness state
|
# order to avoid this incorrect behavior.
|
||||||
# which will be the last value saved by char_brightness.set_value.
|
if brightness == 0 and state == STATE_ON:
|
||||||
# But if it is set to 0, HomeKit will update the brightness to 100 as
|
brightness = 1
|
||||||
# it thinks 0 is off.
|
self.char_brightness.set_value(brightness)
|
||||||
#
|
if color_mode_changed:
|
||||||
# Therefore, if the the brightness is 0 and the device is still on,
|
self.char_brightness.notify()
|
||||||
# the brightness is mapped to 1 otherwise the update is ignored in
|
|
||||||
# order to avoid this incorrect behavior.
|
|
||||||
if brightness == 0 and state == STATE_ON:
|
|
||||||
brightness = 1
|
|
||||||
self.char_brightness.set_value(brightness)
|
|
||||||
|
|
||||||
# Handle Color - color must always be set before color temperature
|
# Handle Color - color must always be set before color temperature
|
||||||
# or the iOS UI will not display it correctly.
|
# or the iOS UI will not display it correctly.
|
||||||
if self.color_supported:
|
if self.color_supported:
|
||||||
if ATTR_COLOR_TEMP in attributes:
|
if color_temp := attributes.get(ATTR_COLOR_TEMP):
|
||||||
hue, saturation = color_temperature_to_hs(
|
hue, saturation = color_temperature_to_hs(
|
||||||
color_temperature_mired_to_kelvin(
|
color_temperature_mired_to_kelvin(color_temp)
|
||||||
new_state.attributes[ATTR_COLOR_TEMP]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
elif color_mode == COLOR_MODE_WHITE:
|
||||||
|
hue, saturation = 0, 0
|
||||||
else:
|
else:
|
||||||
hue, saturation = attributes.get(ATTR_HS_COLOR, (None, None))
|
hue, saturation = attributes.get(ATTR_HS_COLOR, (None, None))
|
||||||
if isinstance(hue, (int, float)) and isinstance(saturation, (int, float)):
|
if isinstance(hue, (int, float)) and isinstance(saturation, (int, float)):
|
||||||
self.char_hue.set_value(round(hue, 0))
|
self.char_hue.set_value(round(hue, 0))
|
||||||
self.char_saturation.set_value(round(saturation, 0))
|
self.char_saturation.set_value(round(saturation, 0))
|
||||||
|
if color_mode_changed:
|
||||||
|
# If the color temp changed, be sure to force the color to update
|
||||||
|
self.char_hue.notify()
|
||||||
|
self.char_saturation.notify()
|
||||||
|
|
||||||
# Handle color temperature
|
# Handle white channels
|
||||||
if self.color_temp_supported:
|
if CHAR_COLOR_TEMPERATURE in self.chars:
|
||||||
color_temp = attributes.get(ATTR_COLOR_TEMP)
|
color_temp = None
|
||||||
|
if self.color_temp_supported:
|
||||||
|
color_temp = attributes.get(ATTR_COLOR_TEMP)
|
||||||
|
elif color_mode == COLOR_MODE_WHITE:
|
||||||
|
color_temp = self.min_mireds
|
||||||
if isinstance(color_temp, (int, float)):
|
if isinstance(color_temp, (int, float)):
|
||||||
self.char_color_temp.set_value(round(color_temp, 0))
|
self.char_color_temp.set_value(round(color_temp, 0))
|
||||||
|
if color_mode_changed:
|
||||||
|
self.char_color_temp.notify()
|
||||||
|
|
|
@ -5,7 +5,11 @@ from datetime import timedelta
|
||||||
from pyhap.const import HAP_REPR_AID, HAP_REPR_CHARS, HAP_REPR_IID, HAP_REPR_VALUE
|
from pyhap.const import HAP_REPR_AID, HAP_REPR_CHARS, HAP_REPR_IID, HAP_REPR_VALUE
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.homekit.const import ATTR_VALUE
|
from homeassistant.components.homekit.const import (
|
||||||
|
ATTR_VALUE,
|
||||||
|
PROP_MAX_VALUE,
|
||||||
|
PROP_MIN_VALUE,
|
||||||
|
)
|
||||||
from homeassistant.components.homekit.type_lights import (
|
from homeassistant.components.homekit.type_lights import (
|
||||||
CHANGE_COALESCE_TIME_WINDOW,
|
CHANGE_COALESCE_TIME_WINDOW,
|
||||||
Light,
|
Light,
|
||||||
|
@ -22,9 +26,12 @@ from homeassistant.components.light import (
|
||||||
ATTR_RGBW_COLOR,
|
ATTR_RGBW_COLOR,
|
||||||
ATTR_RGBWW_COLOR,
|
ATTR_RGBWW_COLOR,
|
||||||
ATTR_SUPPORTED_COLOR_MODES,
|
ATTR_SUPPORTED_COLOR_MODES,
|
||||||
|
ATTR_WHITE,
|
||||||
COLOR_MODE_COLOR_TEMP,
|
COLOR_MODE_COLOR_TEMP,
|
||||||
|
COLOR_MODE_RGB,
|
||||||
COLOR_MODE_RGBW,
|
COLOR_MODE_RGBW,
|
||||||
COLOR_MODE_RGBWW,
|
COLOR_MODE_RGBWW,
|
||||||
|
COLOR_MODE_WHITE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
@ -573,7 +580,7 @@ async def test_light_restore(hass, hk_driver, events):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"supported_color_modes, state_props, turn_on_props, turn_on_props_with_brightness",
|
"supported_color_modes, state_props, turn_on_props_with_brightness",
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
[COLOR_MODE_COLOR_TEMP, COLOR_MODE_RGBW],
|
[COLOR_MODE_COLOR_TEMP, COLOR_MODE_RGBW],
|
||||||
|
@ -584,8 +591,7 @@ async def test_light_restore(hass, hk_driver, events):
|
||||||
ATTR_BRIGHTNESS: 255,
|
ATTR_BRIGHTNESS: 255,
|
||||||
ATTR_COLOR_MODE: COLOR_MODE_RGBW,
|
ATTR_COLOR_MODE: COLOR_MODE_RGBW,
|
||||||
},
|
},
|
||||||
{ATTR_RGBW_COLOR: (31, 127, 71, 0)},
|
{ATTR_HS_COLOR: (145, 75), ATTR_BRIGHTNESS_PCT: 25},
|
||||||
{ATTR_RGBW_COLOR: (15, 63, 35, 0)},
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
[COLOR_MODE_COLOR_TEMP, COLOR_MODE_RGBWW],
|
[COLOR_MODE_COLOR_TEMP, COLOR_MODE_RGBWW],
|
||||||
|
@ -596,21 +602,19 @@ async def test_light_restore(hass, hk_driver, events):
|
||||||
ATTR_BRIGHTNESS: 255,
|
ATTR_BRIGHTNESS: 255,
|
||||||
ATTR_COLOR_MODE: COLOR_MODE_RGBWW,
|
ATTR_COLOR_MODE: COLOR_MODE_RGBWW,
|
||||||
},
|
},
|
||||||
{ATTR_RGBWW_COLOR: (31, 127, 71, 0, 0)},
|
{ATTR_HS_COLOR: (145, 75), ATTR_BRIGHTNESS_PCT: 25},
|
||||||
{ATTR_RGBWW_COLOR: (15, 63, 35, 0, 0)},
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_light_rgb_with_white(
|
async def test_light_rgb_with_color_temp(
|
||||||
hass,
|
hass,
|
||||||
hk_driver,
|
hk_driver,
|
||||||
events,
|
events,
|
||||||
supported_color_modes,
|
supported_color_modes,
|
||||||
state_props,
|
state_props,
|
||||||
turn_on_props,
|
|
||||||
turn_on_props_with_brightness,
|
turn_on_props_with_brightness,
|
||||||
):
|
):
|
||||||
"""Test lights with RGBW/RGBWW."""
|
"""Test lights with RGBW/RGBWW with color temp support."""
|
||||||
entity_id = "light.demo"
|
entity_id = "light.demo"
|
||||||
|
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
|
@ -629,7 +633,7 @@ async def test_light_rgb_with_white(
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert acc.char_hue.value == 23
|
assert acc.char_hue.value == 23
|
||||||
assert acc.char_saturation.value == 100
|
assert acc.char_saturation.value == 100
|
||||||
assert acc.char_brightness.value == 50
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
# Set from HomeKit
|
# Set from HomeKit
|
||||||
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
|
@ -658,11 +662,10 @@ async def test_light_rgb_with_white(
|
||||||
await _wait_for_light_coalesce(hass)
|
await _wait_for_light_coalesce(hass)
|
||||||
assert call_turn_on
|
assert call_turn_on
|
||||||
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
for k, v in turn_on_props.items():
|
assert call_turn_on[-1].data[ATTR_HS_COLOR] == (145, 75)
|
||||||
assert call_turn_on[-1].data[k] == v
|
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
|
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
|
||||||
assert acc.char_brightness.value == 50
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
hk_driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
|
@ -697,7 +700,204 @@ async def test_light_rgb_with_white(
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"supported_color_modes, state_props, turn_on_props, turn_on_props_with_brightness",
|
"supported_color_modes, state_props, turn_on_props_with_brightness",
|
||||||
|
[
|
||||||
|
[
|
||||||
|
[COLOR_MODE_RGBW],
|
||||||
|
{
|
||||||
|
ATTR_RGBW_COLOR: (128, 50, 0, 255),
|
||||||
|
ATTR_RGB_COLOR: (128, 50, 0),
|
||||||
|
ATTR_HS_COLOR: (23.438, 100.0),
|
||||||
|
ATTR_BRIGHTNESS: 255,
|
||||||
|
ATTR_COLOR_MODE: COLOR_MODE_RGBW,
|
||||||
|
},
|
||||||
|
{ATTR_RGBW_COLOR: (0, 0, 0, 191)},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[COLOR_MODE_RGBWW],
|
||||||
|
{
|
||||||
|
ATTR_RGBWW_COLOR: (128, 50, 0, 255, 255),
|
||||||
|
ATTR_RGB_COLOR: (128, 50, 0),
|
||||||
|
ATTR_HS_COLOR: (23.438, 100.0),
|
||||||
|
ATTR_BRIGHTNESS: 255,
|
||||||
|
ATTR_COLOR_MODE: COLOR_MODE_RGBWW,
|
||||||
|
},
|
||||||
|
{ATTR_RGBWW_COLOR: (0, 0, 0, 165, 26)},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_light_rgbwx_with_color_temp_and_brightness(
|
||||||
|
hass,
|
||||||
|
hk_driver,
|
||||||
|
events,
|
||||||
|
supported_color_modes,
|
||||||
|
state_props,
|
||||||
|
turn_on_props_with_brightness,
|
||||||
|
):
|
||||||
|
"""Test lights with RGBW/RGBWW with color temp support and setting brightness."""
|
||||||
|
entity_id = "light.demo"
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
STATE_ON,
|
||||||
|
{ATTR_SUPPORTED_COLOR_MODES: supported_color_modes, **state_props},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
acc = Light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||||
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
|
assert acc.char_hue.value == 23
|
||||||
|
assert acc.char_saturation.value == 100
|
||||||
|
|
||||||
|
await acc.run()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_hue.value == 23
|
||||||
|
assert acc.char_saturation.value == 100
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
|
# Set from HomeKit
|
||||||
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
|
|
||||||
|
char_color_temp_iid = acc.char_color_temp.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_brightness_iid = acc.char_brightness.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_color_temp_iid,
|
||||||
|
HAP_REPR_VALUE: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_brightness_iid,
|
||||||
|
HAP_REPR_VALUE: 75,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await _wait_for_light_coalesce(hass)
|
||||||
|
assert call_turn_on
|
||||||
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
for k, v in turn_on_props_with_brightness.items():
|
||||||
|
assert call_turn_on[-1].data[k] == v
|
||||||
|
assert len(events) == 1
|
||||||
|
assert events[-1].data[ATTR_VALUE] == "brightness at 75%, color temperature at 200"
|
||||||
|
assert acc.char_brightness.value == 75
|
||||||
|
|
||||||
|
|
||||||
|
async def test_light_rgb_or_w_lights(
|
||||||
|
hass,
|
||||||
|
hk_driver,
|
||||||
|
events,
|
||||||
|
):
|
||||||
|
"""Test lights with RGB or W lights."""
|
||||||
|
entity_id = "light.demo"
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
STATE_ON,
|
||||||
|
{
|
||||||
|
ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_RGB, COLOR_MODE_WHITE],
|
||||||
|
ATTR_RGBW_COLOR: (128, 50, 0, 255),
|
||||||
|
ATTR_RGB_COLOR: (128, 50, 0),
|
||||||
|
ATTR_HS_COLOR: (23.438, 100.0),
|
||||||
|
ATTR_BRIGHTNESS: 255,
|
||||||
|
ATTR_COLOR_MODE: COLOR_MODE_RGB,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
acc = Light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||||
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
|
assert acc.char_hue.value == 23
|
||||||
|
assert acc.char_saturation.value == 100
|
||||||
|
|
||||||
|
await acc.run()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_hue.value == 23
|
||||||
|
assert acc.char_saturation.value == 100
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
assert acc.char_color_temp.value == 153
|
||||||
|
|
||||||
|
# Set from HomeKit
|
||||||
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
|
|
||||||
|
char_hue_iid = acc.char_hue.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_saturation_iid = acc.char_saturation.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_brightness_iid = acc.char_brightness.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_color_temp_iid = acc.char_color_temp.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_hue_iid,
|
||||||
|
HAP_REPR_VALUE: 145,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_saturation_iid,
|
||||||
|
HAP_REPR_VALUE: 75,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await _wait_for_light_coalesce(hass)
|
||||||
|
assert call_turn_on
|
||||||
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_turn_on[-1].data[ATTR_HS_COLOR] == (145, 75)
|
||||||
|
assert len(events) == 1
|
||||||
|
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_color_temp_iid,
|
||||||
|
HAP_REPR_VALUE: acc.min_mireds,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_brightness_iid,
|
||||||
|
HAP_REPR_VALUE: 25,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await _wait_for_light_coalesce(hass)
|
||||||
|
assert call_turn_on
|
||||||
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_turn_on[-1].data[ATTR_WHITE] == round(25 * 255 / 100)
|
||||||
|
assert len(events) == 2
|
||||||
|
assert events[-1].data[ATTR_VALUE] == "brightness at 25%, color temperature at 153"
|
||||||
|
assert acc.char_brightness.value == 25
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
STATE_ON,
|
||||||
|
{
|
||||||
|
ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_RGB, COLOR_MODE_WHITE],
|
||||||
|
ATTR_BRIGHTNESS: 255,
|
||||||
|
ATTR_COLOR_MODE: COLOR_MODE_WHITE,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_hue.value == 0
|
||||||
|
assert acc.char_saturation.value == 0
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
assert acc.char_color_temp.value == 153
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"supported_color_modes, state_props",
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
[COLOR_MODE_COLOR_TEMP, COLOR_MODE_RGBW],
|
[COLOR_MODE_COLOR_TEMP, COLOR_MODE_RGBW],
|
||||||
|
@ -708,8 +908,6 @@ async def test_light_rgb_with_white(
|
||||||
ATTR_BRIGHTNESS: 255,
|
ATTR_BRIGHTNESS: 255,
|
||||||
ATTR_COLOR_MODE: COLOR_MODE_RGBW,
|
ATTR_COLOR_MODE: COLOR_MODE_RGBW,
|
||||||
},
|
},
|
||||||
{ATTR_RGBW_COLOR: (31, 127, 71, 0)},
|
|
||||||
{ATTR_COLOR_TEMP: 2700},
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
[COLOR_MODE_COLOR_TEMP, COLOR_MODE_RGBWW],
|
[COLOR_MODE_COLOR_TEMP, COLOR_MODE_RGBWW],
|
||||||
|
@ -720,8 +918,6 @@ async def test_light_rgb_with_white(
|
||||||
ATTR_BRIGHTNESS: 255,
|
ATTR_BRIGHTNESS: 255,
|
||||||
ATTR_COLOR_MODE: COLOR_MODE_RGBWW,
|
ATTR_COLOR_MODE: COLOR_MODE_RGBWW,
|
||||||
},
|
},
|
||||||
{ATTR_RGBWW_COLOR: (31, 127, 71, 0, 0)},
|
|
||||||
{ATTR_COLOR_TEMP: 2700},
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -731,8 +927,6 @@ async def test_light_rgb_with_white_switch_to_temp(
|
||||||
events,
|
events,
|
||||||
supported_color_modes,
|
supported_color_modes,
|
||||||
state_props,
|
state_props,
|
||||||
turn_on_props,
|
|
||||||
turn_on_props_with_brightness,
|
|
||||||
):
|
):
|
||||||
"""Test lights with RGBW/RGBWW that preserves brightness when switching to color temp."""
|
"""Test lights with RGBW/RGBWW that preserves brightness when switching to color temp."""
|
||||||
entity_id = "light.demo"
|
entity_id = "light.demo"
|
||||||
|
@ -753,7 +947,7 @@ async def test_light_rgb_with_white_switch_to_temp(
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert acc.char_hue.value == 23
|
assert acc.char_hue.value == 23
|
||||||
assert acc.char_saturation.value == 100
|
assert acc.char_saturation.value == 100
|
||||||
assert acc.char_brightness.value == 50
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
# Set from HomeKit
|
# Set from HomeKit
|
||||||
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
|
@ -782,19 +976,17 @@ async def test_light_rgb_with_white_switch_to_temp(
|
||||||
await _wait_for_light_coalesce(hass)
|
await _wait_for_light_coalesce(hass)
|
||||||
assert call_turn_on
|
assert call_turn_on
|
||||||
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
for k, v in turn_on_props.items():
|
assert call_turn_on[-1].data[ATTR_HS_COLOR] == (145, 75)
|
||||||
assert call_turn_on[-1].data[k] == v
|
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
|
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
|
||||||
assert acc.char_brightness.value == 50
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
hk_driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
HAP_REPR_CHARS: [
|
HAP_REPR_CHARS: [
|
||||||
{
|
{
|
||||||
HAP_REPR_AID: acc.aid,
|
HAP_REPR_AID: acc.aid,
|
||||||
HAP_REPR_IID: char_color_temp_iid,
|
HAP_REPR_IID: char_color_temp_iid,
|
||||||
HAP_REPR_VALUE: 2700,
|
HAP_REPR_VALUE: 500,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -803,11 +995,221 @@ async def test_light_rgb_with_white_switch_to_temp(
|
||||||
await _wait_for_light_coalesce(hass)
|
await _wait_for_light_coalesce(hass)
|
||||||
assert call_turn_on
|
assert call_turn_on
|
||||||
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
for k, v in turn_on_props_with_brightness.items():
|
assert call_turn_on[-1].data[ATTR_COLOR_TEMP] == 500
|
||||||
assert call_turn_on[-1].data[k] == v
|
|
||||||
assert len(events) == 2
|
assert len(events) == 2
|
||||||
assert events[-1].data[ATTR_VALUE] == "color temperature at 2700"
|
assert events[-1].data[ATTR_VALUE] == "color temperature at 500"
|
||||||
assert acc.char_brightness.value == 50
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
|
|
||||||
|
async def test_light_rgbww_with_color_temp_conversion(
|
||||||
|
hass,
|
||||||
|
hk_driver,
|
||||||
|
events,
|
||||||
|
):
|
||||||
|
"""Test lights with RGBWW convert color temp as expected."""
|
||||||
|
entity_id = "light.demo"
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
STATE_ON,
|
||||||
|
{
|
||||||
|
ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_RGBWW],
|
||||||
|
ATTR_RGBWW_COLOR: (128, 50, 0, 255, 255),
|
||||||
|
ATTR_RGB_COLOR: (128, 50, 0),
|
||||||
|
ATTR_HS_COLOR: (23.438, 100.0),
|
||||||
|
ATTR_BRIGHTNESS: 255,
|
||||||
|
ATTR_COLOR_MODE: COLOR_MODE_RGBWW,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
acc = Light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||||
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
|
assert acc.char_hue.value == 23
|
||||||
|
assert acc.char_saturation.value == 100
|
||||||
|
|
||||||
|
await acc.run()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_hue.value == 23
|
||||||
|
assert acc.char_saturation.value == 100
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
|
# Set from HomeKit
|
||||||
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
|
|
||||||
|
char_hue_iid = acc.char_hue.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_saturation_iid = acc.char_saturation.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_color_temp_iid = acc.char_color_temp.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_brightness_iid = acc.char_brightness.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_hue_iid,
|
||||||
|
HAP_REPR_VALUE: 145,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_saturation_iid,
|
||||||
|
HAP_REPR_VALUE: 75,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await _wait_for_light_coalesce(hass)
|
||||||
|
assert call_turn_on
|
||||||
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_turn_on[-1].data[ATTR_HS_COLOR] == (145, 75)
|
||||||
|
assert len(events) == 1
|
||||||
|
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_color_temp_iid,
|
||||||
|
HAP_REPR_VALUE: 200,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await _wait_for_light_coalesce(hass)
|
||||||
|
assert call_turn_on
|
||||||
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_turn_on[-1].data[ATTR_RGBWW_COLOR] == (0, 0, 0, 220, 35)
|
||||||
|
assert len(events) == 2
|
||||||
|
assert events[-1].data[ATTR_VALUE] == "color temperature at 200"
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
STATE_ON,
|
||||||
|
{
|
||||||
|
ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_RGBWW],
|
||||||
|
ATTR_RGBWW_COLOR: (0, 0, 0, 128, 255),
|
||||||
|
ATTR_RGB_COLOR: (255, 163, 79),
|
||||||
|
ATTR_HS_COLOR: (28.636, 69.02),
|
||||||
|
ATTR_BRIGHTNESS: 180,
|
||||||
|
ATTR_COLOR_MODE: COLOR_MODE_RGBWW,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_brightness_iid,
|
||||||
|
HAP_REPR_VALUE: 100,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await _wait_for_light_coalesce(hass)
|
||||||
|
assert call_turn_on
|
||||||
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_turn_on[-1].data[ATTR_BRIGHTNESS_PCT] == 100
|
||||||
|
assert len(events) == 3
|
||||||
|
assert events[-1].data[ATTR_VALUE] == "brightness at 100%"
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
|
|
||||||
|
async def test_light_rgbw_with_color_temp_conversion(
|
||||||
|
hass,
|
||||||
|
hk_driver,
|
||||||
|
events,
|
||||||
|
):
|
||||||
|
"""Test lights with RGBW convert color temp as expected."""
|
||||||
|
entity_id = "light.demo"
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
STATE_ON,
|
||||||
|
{
|
||||||
|
ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_RGBW],
|
||||||
|
ATTR_RGBWW_COLOR: (128, 50, 0, 255, 255),
|
||||||
|
ATTR_RGB_COLOR: (128, 50, 0),
|
||||||
|
ATTR_HS_COLOR: (23.438, 100.0),
|
||||||
|
ATTR_BRIGHTNESS: 255,
|
||||||
|
ATTR_COLOR_MODE: COLOR_MODE_RGBW,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
acc = Light(hass, hk_driver, "Light", entity_id, 1, None)
|
||||||
|
hk_driver.add_accessory(acc)
|
||||||
|
|
||||||
|
assert acc.char_hue.value == 23
|
||||||
|
assert acc.char_saturation.value == 100
|
||||||
|
|
||||||
|
await acc.run()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_hue.value == 23
|
||||||
|
assert acc.char_saturation.value == 100
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
|
# Set from HomeKit
|
||||||
|
call_turn_on = async_mock_service(hass, DOMAIN, "turn_on")
|
||||||
|
|
||||||
|
char_hue_iid = acc.char_hue.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_saturation_iid = acc.char_saturation.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_color_temp_iid = acc.char_color_temp.to_HAP()[HAP_REPR_IID]
|
||||||
|
assert (
|
||||||
|
acc.char_color_temp.properties[PROP_MIN_VALUE]
|
||||||
|
== acc.char_color_temp.properties[PROP_MAX_VALUE]
|
||||||
|
)
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_hue_iid,
|
||||||
|
HAP_REPR_VALUE: 145,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_saturation_iid,
|
||||||
|
HAP_REPR_VALUE: 75,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await _wait_for_light_coalesce(hass)
|
||||||
|
assert call_turn_on
|
||||||
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_turn_on[-1].data[ATTR_HS_COLOR] == (145, 75)
|
||||||
|
assert len(events) == 1
|
||||||
|
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_color_temp_iid,
|
||||||
|
HAP_REPR_VALUE: 153,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await _wait_for_light_coalesce(hass)
|
||||||
|
assert call_turn_on
|
||||||
|
assert call_turn_on[-1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
assert call_turn_on[-1].data[ATTR_RGBW_COLOR] == (0, 0, 0, 255)
|
||||||
|
assert len(events) == 2
|
||||||
|
assert events[-1].data[ATTR_VALUE] == "color temperature at 153"
|
||||||
|
assert acc.char_brightness.value == 100
|
||||||
|
|
||||||
|
|
||||||
async def test_light_set_brightness_and_color(hass, hk_driver, events):
|
async def test_light_set_brightness_and_color(hass, hk_driver, events):
|
||||||
|
|
Loading…
Reference in New Issue