Update light turn_on schema to coerce colors to tuple before asserting sequence type (#58670)
* Make color_name_to_rgb return a tuple * Tweak * Tweak * Update test * Tweak testpull/58977/head
parent
78082afa94
commit
e9b67b3590
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||
|
||||
from collections import Counter
|
||||
import itertools
|
||||
import logging
|
||||
from typing import Any, Set, cast
|
||||
|
||||
import voluptuous as vol
|
||||
|
@ -66,6 +67,8 @@ SUPPORT_GROUP_LIGHT = (
|
|||
SUPPORT_EFFECT | SUPPORT_FLASH | SUPPORT_TRANSITION | SUPPORT_WHITE_VALUE
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass: HomeAssistant,
|
||||
|
@ -152,6 +155,8 @@ class LightGroup(GroupEntity, light.LightEntity):
|
|||
}
|
||||
data[ATTR_ENTITY_ID] = self._entity_ids
|
||||
|
||||
_LOGGER.debug("Forwarded turn_on command: %s", data)
|
||||
|
||||
await self.hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
light.SERVICE_TURN_ON,
|
||||
|
|
|
@ -202,25 +202,25 @@ LIGHT_TURN_ON_SCHEMA = {
|
|||
),
|
||||
vol.Exclusive(ATTR_KELVIN, COLOR_GROUP): cv.positive_int,
|
||||
vol.Exclusive(ATTR_HS_COLOR, COLOR_GROUP): vol.All(
|
||||
vol.Coerce(tuple),
|
||||
vol.ExactSequence(
|
||||
(
|
||||
vol.All(vol.Coerce(float), vol.Range(min=0, max=360)),
|
||||
vol.All(vol.Coerce(float), vol.Range(min=0, max=100)),
|
||||
)
|
||||
),
|
||||
vol.Coerce(tuple),
|
||||
),
|
||||
vol.Exclusive(ATTR_RGB_COLOR, COLOR_GROUP): vol.All(
|
||||
vol.ExactSequence((cv.byte,) * 3), vol.Coerce(tuple)
|
||||
vol.Coerce(tuple), vol.ExactSequence((cv.byte,) * 3)
|
||||
),
|
||||
vol.Exclusive(ATTR_RGBW_COLOR, COLOR_GROUP): vol.All(
|
||||
vol.ExactSequence((cv.byte,) * 4), vol.Coerce(tuple)
|
||||
vol.Coerce(tuple), vol.ExactSequence((cv.byte,) * 4)
|
||||
),
|
||||
vol.Exclusive(ATTR_RGBWW_COLOR, COLOR_GROUP): vol.All(
|
||||
vol.ExactSequence((cv.byte,) * 5), vol.Coerce(tuple)
|
||||
vol.Coerce(tuple), vol.ExactSequence((cv.byte,) * 5)
|
||||
),
|
||||
vol.Exclusive(ATTR_XY_COLOR, COLOR_GROUP): vol.All(
|
||||
vol.ExactSequence((cv.small_float, cv.small_float)), vol.Coerce(tuple)
|
||||
vol.Coerce(tuple), vol.ExactSequence((cv.small_float, cv.small_float))
|
||||
),
|
||||
vol.Exclusive(ATTR_WHITE, COLOR_GROUP): VALID_BRIGHTNESS,
|
||||
ATTR_WHITE_VALUE: vol.All(vol.Coerce(int), vol.Range(min=0, max=255)),
|
||||
|
|
|
@ -3,12 +3,15 @@ from os import path
|
|||
import unittest.mock
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant import config as hass_config
|
||||
from homeassistant.components.group import DOMAIN, SERVICE_RELOAD
|
||||
import homeassistant.components.group.light as group
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_MODE,
|
||||
ATTR_COLOR_NAME,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_EFFECT_LIST,
|
||||
|
@ -28,6 +31,7 @@ from homeassistant.components.light import (
|
|||
COLOR_MODE_COLOR_TEMP,
|
||||
COLOR_MODE_HS,
|
||||
COLOR_MODE_ONOFF,
|
||||
COLOR_MODE_RGB,
|
||||
COLOR_MODE_RGBW,
|
||||
COLOR_MODE_RGBWW,
|
||||
COLOR_MODE_WHITE,
|
||||
|
@ -261,6 +265,77 @@ async def test_color_hs(hass, enable_custom_integrations):
|
|||
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||
|
||||
|
||||
async def test_color_rgb(hass, enable_custom_integrations):
|
||||
"""Test rgbw color reporting."""
|
||||
platform = getattr(hass.components, "test.light")
|
||||
platform.init(empty=True)
|
||||
|
||||
platform.ENTITIES.append(platform.MockLight("test1", STATE_ON))
|
||||
platform.ENTITIES.append(platform.MockLight("test2", STATE_OFF))
|
||||
|
||||
entity0 = platform.ENTITIES[0]
|
||||
entity0.supported_color_modes = {COLOR_MODE_RGB}
|
||||
entity0.color_mode = COLOR_MODE_RGB
|
||||
entity0.brightness = 255
|
||||
entity0.rgb_color = (0, 64, 128)
|
||||
|
||||
entity1 = platform.ENTITIES[1]
|
||||
entity1.supported_color_modes = {COLOR_MODE_RGB}
|
||||
entity1.color_mode = COLOR_MODE_RGB
|
||||
entity1.brightness = 255
|
||||
entity1.rgb_color = (255, 128, 64)
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
{
|
||||
LIGHT_DOMAIN: [
|
||||
{"platform": "test"},
|
||||
{
|
||||
"platform": DOMAIN,
|
||||
"entities": ["light.test1", "light.test2"],
|
||||
},
|
||||
]
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.light_group")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_COLOR_MODE] == "rgb"
|
||||
assert state.attributes[ATTR_RGB_COLOR] == (0, 64, 128)
|
||||
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == ["rgb"]
|
||||
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_on",
|
||||
{"entity_id": [entity1.entity_id]},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("light.light_group")
|
||||
assert state.attributes[ATTR_COLOR_MODE] == "rgb"
|
||||
assert state.attributes[ATTR_RGB_COLOR] == (127, 96, 96)
|
||||
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == ["rgb"]
|
||||
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_off",
|
||||
{"entity_id": [entity0.entity_id]},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("light.light_group")
|
||||
assert state.attributes[ATTR_COLOR_MODE] == "rgb"
|
||||
assert state.attributes[ATTR_RGB_COLOR] == (255, 128, 64)
|
||||
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == ["rgb"]
|
||||
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||
|
||||
|
||||
async def test_color_rgbw(hass, enable_custom_integrations):
|
||||
"""Test rgbw color reporting."""
|
||||
platform = getattr(hass.components, "test.light")
|
||||
|
@ -1039,14 +1114,40 @@ async def test_supported_features(hass):
|
|||
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 40
|
||||
|
||||
|
||||
async def test_service_calls(hass):
|
||||
@pytest.mark.parametrize("supported_color_modes", [COLOR_MODE_HS, COLOR_MODE_RGB])
|
||||
async def test_service_calls(hass, enable_custom_integrations, supported_color_modes):
|
||||
"""Test service calls."""
|
||||
platform = getattr(hass.components, "test.light")
|
||||
platform.init(empty=True)
|
||||
|
||||
platform.ENTITIES.append(platform.MockLight("bed_light", STATE_ON))
|
||||
platform.ENTITIES.append(platform.MockLight("ceiling_lights", STATE_OFF))
|
||||
platform.ENTITIES.append(platform.MockLight("kitchen_lights", STATE_OFF))
|
||||
|
||||
entity0 = platform.ENTITIES[0]
|
||||
entity0.supported_color_modes = {supported_color_modes}
|
||||
entity0.color_mode = supported_color_modes
|
||||
entity0.brightness = 255
|
||||
entity0.rgb_color = (0, 64, 128)
|
||||
|
||||
entity1 = platform.ENTITIES[1]
|
||||
entity1.supported_color_modes = {supported_color_modes}
|
||||
entity1.color_mode = supported_color_modes
|
||||
entity1.brightness = 255
|
||||
entity1.rgb_color = (255, 128, 64)
|
||||
|
||||
entity2 = platform.ENTITIES[2]
|
||||
entity2.supported_color_modes = {supported_color_modes}
|
||||
entity2.color_mode = supported_color_modes
|
||||
entity2.brightness = 255
|
||||
entity2.rgb_color = (255, 128, 64)
|
||||
|
||||
await async_setup_component(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
{
|
||||
LIGHT_DOMAIN: [
|
||||
{"platform": "demo"},
|
||||
{"platform": "test"},
|
||||
{
|
||||
"platform": DOMAIN,
|
||||
"entities": [
|
||||
|
@ -1062,14 +1163,16 @@ async def test_service_calls(hass):
|
|||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("light.light_group").state == STATE_ON
|
||||
group_state = hass.states.get("light.light_group")
|
||||
assert group_state.state == STATE_ON
|
||||
assert group_state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [supported_color_modes]
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TOGGLE,
|
||||
{ATTR_ENTITY_ID: "light.light_group"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert hass.states.get("light.bed_light").state == STATE_OFF
|
||||
assert hass.states.get("light.ceiling_lights").state == STATE_OFF
|
||||
assert hass.states.get("light.kitchen_lights").state == STATE_OFF
|
||||
|
@ -1096,6 +1199,84 @@ async def test_service_calls(hass):
|
|||
assert hass.states.get("light.ceiling_lights").state == STATE_OFF
|
||||
assert hass.states.get("light.kitchen_lights").state == STATE_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.light_group",
|
||||
ATTR_BRIGHTNESS: 128,
|
||||
ATTR_RGB_COLOR: (42, 255, 255),
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
state = hass.states.get("light.bed_light")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert state.attributes[ATTR_RGB_COLOR] == (42, 255, 255)
|
||||
|
||||
state = hass.states.get("light.ceiling_lights")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert state.attributes[ATTR_RGB_COLOR] == (42, 255, 255)
|
||||
|
||||
state = hass.states.get("light.kitchen_lights")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert state.attributes[ATTR_RGB_COLOR] == (42, 255, 255)
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.light_group",
|
||||
ATTR_BRIGHTNESS: 128,
|
||||
ATTR_COLOR_NAME: "red",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
state = hass.states.get("light.bed_light")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert state.attributes[ATTR_RGB_COLOR] == (255, 0, 0)
|
||||
|
||||
state = hass.states.get("light.ceiling_lights")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert state.attributes[ATTR_RGB_COLOR] == (255, 0, 0)
|
||||
|
||||
state = hass.states.get("light.kitchen_lights")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert state.attributes[ATTR_RGB_COLOR] == (255, 0, 0)
|
||||
|
||||
|
||||
async def test_service_call_effect(hass):
|
||||
"""Test service calls."""
|
||||
await async_setup_component(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
{
|
||||
LIGHT_DOMAIN: [
|
||||
{"platform": "demo"},
|
||||
{
|
||||
"platform": DOMAIN,
|
||||
"entities": [
|
||||
"light.bed_light",
|
||||
"light.ceiling_lights",
|
||||
"light.kitchen_lights",
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("light.light_group").state == STATE_ON
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
|
|
|
@ -18,6 +18,7 @@ from homeassistant.const import (
|
|||
)
|
||||
from homeassistant.exceptions import Unauthorized
|
||||
from homeassistant.setup import async_setup_component
|
||||
import homeassistant.util.color as color_util
|
||||
|
||||
from tests.common import async_mock_service
|
||||
|
||||
|
@ -1589,6 +1590,83 @@ async def test_light_service_call_color_conversion(hass, enable_custom_integrati
|
|||
assert data == {"brightness": 128, "rgbww_color": (0, 75, 140, 255, 255)}
|
||||
|
||||
|
||||
async def test_light_service_call_color_conversion_named_tuple(
|
||||
hass, enable_custom_integrations
|
||||
):
|
||||
"""Test a named tuple (RGBColor) is handled correctly."""
|
||||
platform = getattr(hass.components, "test.light")
|
||||
platform.init(empty=True)
|
||||
|
||||
platform.ENTITIES.append(platform.MockLight("Test_hs", STATE_ON))
|
||||
platform.ENTITIES.append(platform.MockLight("Test_rgb", STATE_ON))
|
||||
platform.ENTITIES.append(platform.MockLight("Test_xy", STATE_ON))
|
||||
platform.ENTITIES.append(platform.MockLight("Test_all", STATE_ON))
|
||||
platform.ENTITIES.append(platform.MockLight("Test_legacy", STATE_ON))
|
||||
platform.ENTITIES.append(platform.MockLight("Test_rgbw", STATE_ON))
|
||||
platform.ENTITIES.append(platform.MockLight("Test_rgbww", STATE_ON))
|
||||
|
||||
entity0 = platform.ENTITIES[0]
|
||||
entity0.supported_color_modes = {light.COLOR_MODE_HS}
|
||||
|
||||
entity1 = platform.ENTITIES[1]
|
||||
entity1.supported_color_modes = {light.COLOR_MODE_RGB}
|
||||
|
||||
entity2 = platform.ENTITIES[2]
|
||||
entity2.supported_color_modes = {light.COLOR_MODE_XY}
|
||||
|
||||
entity3 = platform.ENTITIES[3]
|
||||
entity3.supported_color_modes = {
|
||||
light.COLOR_MODE_HS,
|
||||
light.COLOR_MODE_RGB,
|
||||
light.COLOR_MODE_XY,
|
||||
}
|
||||
|
||||
entity4 = platform.ENTITIES[4]
|
||||
entity4.supported_features = light.SUPPORT_COLOR
|
||||
|
||||
entity5 = platform.ENTITIES[5]
|
||||
entity5.supported_color_modes = {light.COLOR_MODE_RGBW}
|
||||
|
||||
entity6 = platform.ENTITIES[6]
|
||||
entity6.supported_color_modes = {light.COLOR_MODE_RGBWW}
|
||||
|
||||
assert await async_setup_component(hass, "light", {"light": {"platform": "test"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_on",
|
||||
{
|
||||
"entity_id": [
|
||||
entity0.entity_id,
|
||||
entity1.entity_id,
|
||||
entity2.entity_id,
|
||||
entity3.entity_id,
|
||||
entity4.entity_id,
|
||||
entity5.entity_id,
|
||||
entity6.entity_id,
|
||||
],
|
||||
"brightness_pct": 25,
|
||||
"rgb_color": color_util.RGBColor(128, 0, 0),
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
_, data = entity0.last_call("turn_on")
|
||||
assert data == {"brightness": 64, "hs_color": (0.0, 100.0)}
|
||||
_, data = entity1.last_call("turn_on")
|
||||
assert data == {"brightness": 64, "rgb_color": (128, 0, 0)}
|
||||
_, data = entity2.last_call("turn_on")
|
||||
assert data == {"brightness": 64, "xy_color": (0.701, 0.299)}
|
||||
_, data = entity3.last_call("turn_on")
|
||||
assert data == {"brightness": 64, "rgb_color": (128, 0, 0)}
|
||||
_, data = entity4.last_call("turn_on")
|
||||
assert data == {"brightness": 64, "hs_color": (0.0, 100.0)}
|
||||
_, data = entity5.last_call("turn_on")
|
||||
assert data == {"brightness": 64, "rgbw_color": (128, 0, 0, 0)}
|
||||
_, data = entity6.last_call("turn_on")
|
||||
assert data == {"brightness": 64, "rgbww_color": (128, 0, 0, 0, 0)}
|
||||
|
||||
|
||||
async def test_light_service_call_color_temp_emulation(
|
||||
hass, enable_custom_integrations
|
||||
):
|
||||
|
|
Loading…
Reference in New Issue