Merge commit '9e29a21197' into fix/group-target-resolution

This commit is contained in:
Bas Nijholt 2026-09-06 12:02:52 -07:00
commit 94bfa9eb69
11 changed files with 235 additions and 7 deletions

View file

@ -13,8 +13,10 @@ from homeassistant.components.adaptive_lighting.const import (
BASIC_OPTIONS,
CONF_EXPAND_LIGHT_GROUPS,
CONF_INITIAL_TRANSITION,
CONF_MANUAL_CONTROL_ON_EXTERNAL_TURN_ON,
CONF_SUNRISE_TIME,
CONF_SUNSET_TIME,
DEFAULT_MANUAL_CONTROL_ON_EXTERNAL_TURN_ON,
DEFAULT_NAME,
DOMAIN,
NONE_STR,
@ -151,6 +153,10 @@ async def test_options_schema_has_each_setting_once(hass):
advanced = _advanced_section(result)
assert advanced.options == {"collapsed": True}
assert (
_schema_defaults(advanced.schema)[CONF_MANUAL_CONTROL_ON_EXTERNAL_TURN_ON]
is DEFAULT_MANUAL_CONTROL_ON_EXTERNAL_TURN_ON
)
assert {key.schema for key in schema if key.schema != "advanced"} == BASIC_OPTIONS
assert {key.schema for key in advanced.schema.schema} == set(
DEFAULT_DATA,

View file

@ -40,6 +40,7 @@ from homeassistant.components.adaptive_lighting.const import (
CONF_EXPAND_LIGHT_GROUPS,
CONF_INITIAL_TRANSITION,
CONF_MANUAL_CONTROL,
CONF_MANUAL_CONTROL_ON_EXTERNAL_TURN_ON,
CONF_MAX_BRIGHTNESS,
CONF_MAX_COLOR_TEMP,
CONF_MIN_BRIGHTNESS,
@ -4865,6 +4866,152 @@ async def test_automation_turn_on_from_off_not_marked_as_manual_control(hass):
)
@pytest.mark.parametrize("intercept", [True, False])
async def test_manual_control_on_external_turn_on_allows_tracked_service_call(
hass,
intercept,
):
"""Test a real HA turn-on remains eligible for initial adaptation."""
switch, _ = await setup_lights_and_switch(
hass,
{
CONF_MANUAL_CONTROL_ON_EXTERNAL_TURN_ON: True,
CONF_DETECT_NON_HA_CHANGES: True,
CONF_INTERCEPT: intercept,
CONF_MIN_BRIGHTNESS: 50,
CONF_MAX_BRIGHTNESS: 50,
},
)
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: ENTITY_LIGHT_1},
blocking=True,
)
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: ENTITY_LIGHT_1, ATTR_BRIGHTNESS: 200},
blocking=True,
context=Context(id=f"ha_turn_on_{intercept}"),
)
await hass.async_block_till_done()
state = hass.states.get(ENTITY_LIGHT_1)
assert state.state == STATE_ON
assert state.attributes[ATTR_BRIGHTNESS] == 128
assert (
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
== LightControlAttributes.NONE
)
@pytest.mark.parametrize("intercept", [True, False])
@pytest.mark.parametrize(
(
"manual_control_on_external_turn_on",
"detect_non_ha_changes",
"expected_manual_control",
"expected_adaptation",
),
[
(True, True, LightControlAttributes.ALL, False),
(True, False, LightControlAttributes.ALL, False),
(False, True, LightControlAttributes.NONE, True),
(False, False, LightControlAttributes.ALL, False),
],
)
async def test_manual_control_on_external_turn_on_external_state_change(
hass,
freezer,
intercept,
manual_control_on_external_turn_on,
detect_non_ha_changes,
expected_manual_control,
expected_adaptation,
):
"""Test an unmatched off-to-on state event follows the opt-in policy."""
switch, _ = await setup_lights_and_switch(
hass,
{
"manual_control_on_external_turn_on": manual_control_on_external_turn_on,
CONF_DETECT_NON_HA_CHANGES: detect_non_ha_changes,
CONF_INTERCEPT: intercept,
CONF_MIN_BRIGHTNESS: 50,
CONF_MAX_BRIGHTNESS: 50,
},
)
external_attributes = dict(hass.states.get(ENTITY_LIGHT_1).attributes)
external_attributes[ATTR_BRIGHTNESS] = 200
hass.states.async_set(
ENTITY_LIGHT_1,
STATE_OFF,
external_attributes,
context=Context(id=f"unmatched_turn_off_{intercept}"),
)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_OFF
freezer.tick(6)
hass.states.async_set(
ENTITY_LIGHT_1,
STATE_ON,
external_attributes,
context=Context(id=f"unmatched_turn_on_{intercept}"),
)
await hass.async_block_till_done()
assert (
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
== expected_manual_control
)
last_service_data = switch.manager.last_service_data.get(ENTITY_LIGHT_1)
if expected_adaptation:
assert last_service_data[ATTR_BRIGHTNESS] == 128
else:
assert last_service_data is None
assert hass.states.get(ENTITY_LIGHT_1).attributes[ATTR_BRIGHTNESS] == 200
@pytest.mark.parametrize("intercept", [True, False])
async def test_manual_control_on_external_turn_on_keeps_non_ha_change_detection(
hass,
intercept,
):
"""Test the option does not disable manual tracking for an on light."""
switch, (light, *_) = await setup_lights_and_switch(
hass,
{
CONF_MANUAL_CONTROL_ON_EXTERNAL_TURN_ON: True,
CONF_DETECT_NON_HA_CHANGES: True,
CONF_INTERCEPT: intercept,
CONF_MIN_BRIGHTNESS: 50,
CONF_MAX_BRIGHTNESS: 50,
},
)
await switch._update_attrs_and_maybe_adapt_lights(
context=switch.create_context("test"),
transition=0,
)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_LIGHT_1).attributes[ATTR_BRIGHTNESS] == 128
set_light_brightness(light, 200)
light.async_write_ha_state()
await switch._update_attrs_and_maybe_adapt_lights(
context=switch.create_context("test"),
transition=0,
)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_LIGHT_1).attributes[ATTR_BRIGHTNESS] == 200
assert (
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
== LightControlAttributes.BRIGHTNESS
)
@pytest.mark.parametrize("intercept", [True, False])
async def test_adapt_only_on_bare_turn_on_respects_pause_changed_mode(hass, intercept):
"""Test that adapt_only_on_bare_turn_on respects take_over_control_mode=PAUSE_CHANGED.