mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-11 14:24:03 +02:00
Extract _has_color_mode_changed() function that checks original attributes BEFORE conversion, enabling detection of all mode switches: - color_temp → RGB ✓ - color_temp → XY ✓ - RGB → color_temp ✓ - RGB → XY ✓ - XY → color_temp ✓ - XY → RGB ✓ This improves on PR #1282 by detecting mode changes in both directions.
This commit is contained in:
parent
41e13bc944
commit
4feaf2c291
2 changed files with 180 additions and 32 deletions
|
|
@ -694,6 +694,58 @@ def _add_missing_attributes(
|
|||
return old_attributes, new_attributes
|
||||
|
||||
|
||||
def _has_color_mode_changed(
|
||||
light: str,
|
||||
old_attributes: dict[str, Any],
|
||||
new_attributes: dict[str, Any],
|
||||
context: Context,
|
||||
) -> bool:
|
||||
"""Check if the light's color mode changed (e.g., color_temp to RGB or vice versa).
|
||||
|
||||
This must be called BEFORE _add_missing_attributes() to detect mode changes
|
||||
using the original attributes. See issue #1275.
|
||||
"""
|
||||
old_has_color_temp = old_attributes.get(ATTR_COLOR_TEMP_KELVIN) is not None
|
||||
old_has_rgb = old_attributes.get(ATTR_RGB_COLOR) is not None
|
||||
old_has_xy = old_attributes.get(ATTR_XY_COLOR) is not None
|
||||
|
||||
new_has_color_temp = new_attributes.get(ATTR_COLOR_TEMP_KELVIN) is not None
|
||||
new_has_rgb = new_attributes.get(ATTR_RGB_COLOR) is not None
|
||||
new_has_xy = new_attributes.get(ATTR_XY_COLOR) is not None
|
||||
|
||||
# Determine old and new color modes
|
||||
# Priority: color_temp > rgb > xy (matching typical light behavior)
|
||||
if old_has_color_temp:
|
||||
old_mode = "color_temp"
|
||||
elif old_has_rgb:
|
||||
old_mode = "rgb"
|
||||
elif old_has_xy:
|
||||
old_mode = "xy"
|
||||
else:
|
||||
old_mode = None
|
||||
|
||||
if new_has_color_temp:
|
||||
new_mode = "color_temp"
|
||||
elif new_has_rgb:
|
||||
new_mode = "rgb"
|
||||
elif new_has_xy:
|
||||
new_mode = "xy"
|
||||
else:
|
||||
new_mode = None
|
||||
|
||||
# Check if mode changed
|
||||
if old_mode is not None and new_mode is not None and old_mode != new_mode:
|
||||
_LOGGER.debug(
|
||||
"Light mode of %s changed from %s to %s with context.id='%s'",
|
||||
light,
|
||||
old_mode,
|
||||
new_mode,
|
||||
context.id,
|
||||
)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _attributes_have_changed(
|
||||
light: str,
|
||||
old_attributes: dict[str, Any],
|
||||
|
|
@ -706,6 +758,17 @@ def _attributes_have_changed(
|
|||
# so we must protect for `None` here
|
||||
# see https://github.com/home-assistant/core/pull/101946
|
||||
|
||||
# Check for color mode changes BEFORE attribute conversion
|
||||
# This detects external changes like Hue scenes switching from color_temp to RGB
|
||||
# See: https://github.com/basnijholt/adaptive-lighting/issues/1275
|
||||
if adapt_color and _has_color_mode_changed(
|
||||
light,
|
||||
old_attributes,
|
||||
new_attributes,
|
||||
context,
|
||||
):
|
||||
return True
|
||||
|
||||
if adapt_color:
|
||||
old_attributes, new_attributes = _add_missing_attributes(
|
||||
old_attributes,
|
||||
|
|
@ -767,30 +830,6 @@ def _attributes_have_changed(
|
|||
)
|
||||
return True
|
||||
|
||||
if adapt_color and (
|
||||
(
|
||||
old_attributes.get(ATTR_COLOR_TEMP_KELVIN)
|
||||
and not new_attributes.get(ATTR_COLOR_TEMP_KELVIN)
|
||||
)
|
||||
or (
|
||||
old_attributes.get(ATTR_RGB_COLOR)
|
||||
and not new_attributes.get(ATTR_RGB_COLOR)
|
||||
)
|
||||
):
|
||||
last_mode = (
|
||||
"color_temp" if old_attributes.get(ATTR_COLOR_TEMP_KELVIN) else "rgb"
|
||||
)
|
||||
current_mode = (
|
||||
"color_temp" if new_attributes.get(ATTR_COLOR_TEMP_KELVIN) else "rgb"
|
||||
)
|
||||
_LOGGER.debug(
|
||||
"Light mode of %s changed from %s to %s with context.id='%s'",
|
||||
light,
|
||||
last_mode,
|
||||
current_mode,
|
||||
context.id,
|
||||
)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1010,26 +1010,36 @@ def test_attributes_have_changed():
|
|||
new_attributes=attrs,
|
||||
**kwargs,
|
||||
)
|
||||
_LOGGER.debug("Test switch from color_temp to rgb_color")
|
||||
assert not _attributes_have_changed(
|
||||
# Test color mode switches - feature added to detect external changes
|
||||
# (e.g., when Hue scenes change light from color_temp to RGB mode)
|
||||
# See: https://github.com/basnijholt/adaptive-lighting/issues/1275
|
||||
#
|
||||
# All mode switches are now detected bidirectionally by checking original
|
||||
# attributes BEFORE conversion in _has_color_mode_changed().
|
||||
_LOGGER.debug(
|
||||
"Test switch from color_temp to rgb_color - should detect mode change",
|
||||
)
|
||||
assert _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 1, ATTR_COLOR_TEMP_KELVIN: 2702},
|
||||
new_attributes={ATTR_BRIGHTNESS: 1, ATTR_RGB_COLOR: (255, 166, 87)},
|
||||
**kwargs,
|
||||
)
|
||||
_LOGGER.debug("Test switch from rgb_color to color_temp")
|
||||
assert not _attributes_have_changed(
|
||||
_LOGGER.debug(
|
||||
"Test switch from rgb_color to color_temp - should detect mode change",
|
||||
)
|
||||
assert _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 1, ATTR_RGB_COLOR: (255, 166, 87)},
|
||||
new_attributes={ATTR_BRIGHTNESS: 1, ATTR_COLOR_TEMP_KELVIN: 2702},
|
||||
**kwargs,
|
||||
)
|
||||
_LOGGER.debug("Test switch from color_temp to color_xy")
|
||||
assert not _attributes_have_changed(
|
||||
_LOGGER.debug("Test switch from color_temp to color_xy - should detect mode change")
|
||||
assert _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 1, ATTR_COLOR_TEMP_KELVIN: 2702},
|
||||
new_attributes={ATTR_BRIGHTNESS: 1, ATTR_XY_COLOR: (0.526, 0.387)},
|
||||
**kwargs,
|
||||
)
|
||||
_LOGGER.debug("Test switch from color_xy to color_temp")
|
||||
assert not _attributes_have_changed(
|
||||
_LOGGER.debug("Test switch from color_xy to color_temp - should detect mode change")
|
||||
assert _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 1, ATTR_XY_COLOR: (0.526, 0.387)},
|
||||
new_attributes={ATTR_BRIGHTNESS: 1, ATTR_COLOR_TEMP_KELVIN: 2702},
|
||||
**kwargs,
|
||||
|
|
@ -2349,3 +2359,102 @@ async def test_simple_switch_state_after_async_added_to_hass(hass):
|
|||
# State should still be correct after async_added_to_hass
|
||||
assert switch_true._state is True
|
||||
assert switch_false._state is False
|
||||
|
||||
|
||||
def test_attributes_have_changed_light_mode_switch():
|
||||
"""Test detection of external light mode changes (color_temp vs rgb vs xy).
|
||||
|
||||
Regression test for https://github.com/basnijholt/adaptive-lighting/issues/1275
|
||||
|
||||
When a user activates a Hue Scene (or similar) via an external app, the light
|
||||
may switch from color_temp mode to RGB/XY mode (or vice versa). This should be
|
||||
detected as an external change so AL doesn't immediately override it.
|
||||
|
||||
The _has_color_mode_changed() function checks the original attributes BEFORE
|
||||
any conversion, enabling bidirectional mode change detection.
|
||||
"""
|
||||
context = Context()
|
||||
base_kwargs = {
|
||||
"light": "light.test",
|
||||
"adapt_brightness": True,
|
||||
"context": context,
|
||||
}
|
||||
|
||||
# Test 1: adapt_color=True - all mode changes should be detected
|
||||
kwargs_adapt_color = {**base_kwargs, "adapt_color": True}
|
||||
|
||||
# color_temp → RGB
|
||||
assert _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_COLOR_TEMP_KELVIN: 4000},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_RGB_COLOR: (255, 0, 0)},
|
||||
**kwargs_adapt_color,
|
||||
), "Should detect color_temp → RGB mode switch"
|
||||
|
||||
# color_temp → XY
|
||||
assert _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_COLOR_TEMP_KELVIN: 4000},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_XY_COLOR: (0.64, 0.33)},
|
||||
**kwargs_adapt_color,
|
||||
), "Should detect color_temp → XY mode switch"
|
||||
|
||||
# RGB → color_temp
|
||||
assert _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_RGB_COLOR: (255, 0, 0)},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_COLOR_TEMP_KELVIN: 4000},
|
||||
**kwargs_adapt_color,
|
||||
), "Should detect RGB → color_temp mode switch"
|
||||
|
||||
# RGB → XY
|
||||
assert _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_RGB_COLOR: (255, 0, 0)},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_XY_COLOR: (0.64, 0.33)},
|
||||
**kwargs_adapt_color,
|
||||
), "Should detect RGB → XY mode switch"
|
||||
|
||||
# XY → color_temp
|
||||
assert _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_XY_COLOR: (0.64, 0.33)},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_COLOR_TEMP_KELVIN: 4000},
|
||||
**kwargs_adapt_color,
|
||||
), "Should detect XY → color_temp mode switch"
|
||||
|
||||
# XY → RGB
|
||||
assert _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_XY_COLOR: (0.64, 0.33)},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_RGB_COLOR: (255, 0, 0)},
|
||||
**kwargs_adapt_color,
|
||||
), "Should detect XY → RGB mode switch"
|
||||
|
||||
# No mode change - same type with same values shouldn't be detected
|
||||
assert not _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_COLOR_TEMP_KELVIN: 4000},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_COLOR_TEMP_KELVIN: 4000},
|
||||
**kwargs_adapt_color,
|
||||
), "Same color_temp should not be detected as change"
|
||||
|
||||
assert not _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_RGB_COLOR: (255, 0, 0)},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_RGB_COLOR: (255, 0, 0)},
|
||||
**kwargs_adapt_color,
|
||||
), "Same RGB should not be detected as change"
|
||||
|
||||
assert not _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_XY_COLOR: (0.64, 0.33)},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_XY_COLOR: (0.64, 0.33)},
|
||||
**kwargs_adapt_color,
|
||||
), "Same XY should not be detected as change"
|
||||
|
||||
# Test 2: adapt_color=False - mode changes should NOT be detected
|
||||
kwargs_no_adapt = {**base_kwargs, "adapt_color": False}
|
||||
|
||||
assert not _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_COLOR_TEMP_KELVIN: 4000},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_RGB_COLOR: (255, 0, 0)},
|
||||
**kwargs_no_adapt,
|
||||
), "Mode change should not be detected when adapt_color=False"
|
||||
|
||||
assert not _attributes_have_changed(
|
||||
old_attributes={ATTR_BRIGHTNESS: 128, ATTR_RGB_COLOR: (255, 0, 0)},
|
||||
new_attributes={ATTR_BRIGHTNESS: 128, ATTR_COLOR_TEMP_KELVIN: 4000},
|
||||
**kwargs_no_adapt,
|
||||
), "RGB → color_temp should not be detected when adapt_color=False"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue