Improve color mode handling in light groups (#109390)

* Improve color mode handling in light groups

* Update config flow test
This commit is contained in:
Erik Montnemery 2024-02-03 09:00:00 +01:00 committed by GitHub
parent 6f9876d5e0
commit fe4dd2cb93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 44 additions and 40 deletions

View file

@ -30,6 +30,7 @@ from homeassistant.components.light import (
ColorMode, ColorMode,
LightEntity, LightEntity,
LightEntityFeature, LightEntityFeature,
filter_supported_color_modes,
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
@ -162,6 +163,9 @@ class LightGroup(GroupEntity, LightEntity):
if mode: if mode:
self.mode = all self.mode = all
self._attr_color_mode = ColorMode.UNKNOWN
self._attr_supported_color_modes = {ColorMode.ONOFF}
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Forward the turn_on command to all lights in the light group.""" """Forward the turn_on command to all lights in the light group."""
data = { data = {
@ -261,26 +265,36 @@ class LightGroup(GroupEntity, LightEntity):
effects_count = Counter(itertools.chain(all_effects)) effects_count = Counter(itertools.chain(all_effects))
self._attr_effect = effects_count.most_common(1)[0][0] self._attr_effect = effects_count.most_common(1)[0][0]
self._attr_color_mode = None supported_color_modes = {ColorMode.ONOFF}
all_color_modes = list(find_state_attributes(on_states, ATTR_COLOR_MODE))
if all_color_modes:
# Report the most common color mode, select brightness and onoff last
color_mode_count = Counter(itertools.chain(all_color_modes))
if ColorMode.ONOFF in color_mode_count:
color_mode_count[ColorMode.ONOFF] = -1
if ColorMode.BRIGHTNESS in color_mode_count:
color_mode_count[ColorMode.BRIGHTNESS] = 0
self._attr_color_mode = color_mode_count.most_common(1)[0][0]
self._attr_supported_color_modes = None
all_supported_color_modes = list( all_supported_color_modes = list(
find_state_attributes(states, ATTR_SUPPORTED_COLOR_MODES) find_state_attributes(states, ATTR_SUPPORTED_COLOR_MODES)
) )
if all_supported_color_modes: if all_supported_color_modes:
# Merge all color modes. # Merge all color modes.
self._attr_supported_color_modes = cast( supported_color_modes = filter_supported_color_modes(
set[str], set().union(*all_supported_color_modes) cast(set[ColorMode], set().union(*all_supported_color_modes))
) )
self._attr_supported_color_modes = supported_color_modes
self._attr_color_mode = ColorMode.UNKNOWN
all_color_modes = list(find_state_attributes(on_states, ATTR_COLOR_MODE))
if all_color_modes:
# Report the most common color mode, select brightness and onoff last
color_mode_count = Counter(itertools.chain(all_color_modes))
if ColorMode.ONOFF in color_mode_count:
if ColorMode.ONOFF in supported_color_modes:
color_mode_count[ColorMode.ONOFF] = -1
else:
color_mode_count.pop(ColorMode.ONOFF)
if ColorMode.BRIGHTNESS in color_mode_count:
if ColorMode.BRIGHTNESS in supported_color_modes:
color_mode_count[ColorMode.BRIGHTNESS] = 0
else:
color_mode_count.pop(ColorMode.BRIGHTNESS)
if color_mode_count:
self._attr_color_mode = color_mode_count.most_common(1)[0][0]
else:
self._attr_color_mode = next(iter(supported_color_modes))
self._attr_supported_features = LightEntityFeature(0) self._attr_supported_features = LightEntityFeature(0)
for support in find_state_attributes(states, ATTR_SUPPORTED_FEATURES): for support in find_state_attributes(states, ATTR_SUPPORTED_FEATURES):

View file

@ -479,7 +479,7 @@ LIGHT_ATTRS = [
"supported_color_modes": ["onoff"], "supported_color_modes": ["onoff"],
"supported_features": 0, "supported_features": 0,
}, },
{"color_mode": "onoff"}, {"color_mode": "unknown"},
] ]
LOCK_ATTRS = [{"supported_features": 1}, {}] LOCK_ATTRS = [{"supported_features": 1}, {}]
MEDIA_PLAYER_ATTRS = [{"supported_features": 0}, {}] MEDIA_PLAYER_ATTRS = [{"supported_features": 0}, {}]

View file

@ -28,9 +28,6 @@ from homeassistant.components.light import (
SERVICE_TOGGLE, SERVICE_TOGGLE,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
SERVICE_TURN_ON, SERVICE_TURN_ON,
SUPPORT_BRIGHTNESS,
SUPPORT_COLOR,
SUPPORT_COLOR_TEMP,
ColorMode, ColorMode,
) )
from homeassistant.const import ( from homeassistant.const import (
@ -278,10 +275,8 @@ async def test_brightness(
entity0.brightness = 255 entity0.brightness = 255
entity1 = platform.ENTITIES[1] entity1 = platform.ENTITIES[1]
entity1.supported_features = SUPPORT_BRIGHTNESS entity1.supported_color_modes = {ColorMode.BRIGHTNESS}
# Set color modes to none to trigger backwards compatibility in LightEntity entity1.color_mode = ColorMode.BRIGHTNESS
entity1.supported_color_modes = None
entity1.color_mode = None
assert await async_setup_component( assert await async_setup_component(
hass, hass,
@ -352,10 +347,8 @@ async def test_color_hs(hass: HomeAssistant, enable_custom_integrations: None) -
entity0.hs_color = (0, 100) entity0.hs_color = (0, 100)
entity1 = platform.ENTITIES[1] entity1 = platform.ENTITIES[1]
entity1.supported_features = SUPPORT_COLOR entity1.supported_color_modes = {ColorMode.HS}
# Set color modes to none to trigger backwards compatibility in LightEntity entity1.color_mode = ColorMode.HS
entity1.supported_color_modes = None
entity1.color_mode = None
assert await async_setup_component( assert await async_setup_component(
hass, hass,
@ -703,10 +696,8 @@ async def test_color_temp(
entity0.color_temp_kelvin = 2 entity0.color_temp_kelvin = 2
entity1 = platform.ENTITIES[1] entity1 = platform.ENTITIES[1]
entity1.supported_features = SUPPORT_COLOR_TEMP entity1.supported_color_modes = {ColorMode.COLOR_TEMP}
# Set color modes to none to trigger backwards compatibility in LightEntity entity1.color_mode = ColorMode.COLOR_TEMP
entity1.supported_color_modes = None
entity1.color_mode = None
assert await async_setup_component( assert await async_setup_component(
hass, hass,
@ -846,10 +837,8 @@ async def test_min_max_mireds(
entity0._attr_max_color_temp_kelvin = 5 entity0._attr_max_color_temp_kelvin = 5
entity1 = platform.ENTITIES[1] entity1 = platform.ENTITIES[1]
entity1.supported_features = SUPPORT_COLOR_TEMP entity1.supported_color_modes = {ColorMode.COLOR_TEMP}
# Set color modes to none to trigger backwards compatibility in LightEntity entity1.color_mode = ColorMode.COLOR_TEMP
entity1.supported_color_modes = None
entity1.color_mode = None
entity1._attr_min_color_temp_kelvin = 1 entity1._attr_min_color_temp_kelvin = 1
entity1._attr_max_color_temp_kelvin = 1234567890 entity1._attr_max_color_temp_kelvin = 1234567890
@ -1021,15 +1010,15 @@ async def test_supported_color_modes(
entity0 = platform.ENTITIES[0] entity0 = platform.ENTITIES[0]
entity0.supported_color_modes = {ColorMode.COLOR_TEMP, ColorMode.HS} entity0.supported_color_modes = {ColorMode.COLOR_TEMP, ColorMode.HS}
entity0.color_mode = ColorMode.UNKNOWN
entity1 = platform.ENTITIES[1] entity1 = platform.ENTITIES[1]
entity1.supported_color_modes = {ColorMode.RGBW, ColorMode.RGBWW} entity1.supported_color_modes = {ColorMode.RGBW, ColorMode.RGBWW}
entity1.color_mode = ColorMode.UNKNOWN
entity2 = platform.ENTITIES[2] entity2 = platform.ENTITIES[2]
entity2.supported_features = SUPPORT_BRIGHTNESS entity2.supported_color_modes = {ColorMode.BRIGHTNESS}
# Set color modes to none to trigger backwards compatibility in LightEntity entity2.color_mode = ColorMode.UNKNOWN
entity2.supported_color_modes = None
entity2.color_mode = None
assert await async_setup_component( assert await async_setup_component(
hass, hass,
@ -1051,7 +1040,6 @@ async def test_supported_color_modes(
state = hass.states.get("light.light_group") state = hass.states.get("light.light_group")
assert set(state.attributes[ATTR_SUPPORTED_COLOR_MODES]) == { assert set(state.attributes[ATTR_SUPPORTED_COLOR_MODES]) == {
"brightness",
"color_temp", "color_temp",
"hs", "hs",
"rgbw", "rgbw",
@ -1198,6 +1186,7 @@ async def test_color_mode2(
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("light.light_group") state = hass.states.get("light.light_group")
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [ColorMode.COLOR_TEMP]
assert state.attributes[ATTR_COLOR_MODE] == ColorMode.COLOR_TEMP assert state.attributes[ATTR_COLOR_MODE] == ColorMode.COLOR_TEMP
await hass.services.async_call( await hass.services.async_call(
@ -1208,7 +1197,8 @@ async def test_color_mode2(
) )
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("light.light_group") state = hass.states.get("light.light_group")
assert state.attributes[ATTR_COLOR_MODE] == ColorMode.BRIGHTNESS assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [ColorMode.COLOR_TEMP]
assert state.attributes[ATTR_COLOR_MODE] == ColorMode.COLOR_TEMP
async def test_supported_features(hass: HomeAssistant) -> None: async def test_supported_features(hass: HomeAssistant) -> None: