fix: drop the stored auto-reset delay when autoreset_control_seconds is 0

set_auto_reset_manual_control_times() returned early for a time of 0, so
the delay stored by a previous configuration stayed in the manager. The
manager outlives config entry reloads, so after changing the option to 0
lights kept being auto-reset with the old delay until Home Assistant was
restarted.

Remove the light's stored delay instead, and add a regression test that
reloads a profile with the option set to 0 while another profile keeps
the manager alive.

Fixes #1631

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
BrawnyBravo 2026-10-09 21:59:40 -07:00
commit b541696b4e
2 changed files with 63 additions and 4 deletions

View file

@ -2390,9 +2390,11 @@ class AdaptiveLightingManager:
lights: list[str],
time: float,
) -> None:
"""Set the time after which the lights are automatically reset."""
if time == 0:
return
"""Set the time after which the lights are automatically reset.
A time of 0 disables the auto reset. The manager outlives config entry
reloads, so drop any previously stored time instead of keeping it.
"""
for light in lights:
old_time = self.auto_reset_manual_control_times.get(light)
if (old_time is not None) and (old_time != time):
@ -2404,7 +2406,10 @@ class AdaptiveLightingManager:
old_time,
time,
)
self.auto_reset_manual_control_times[light] = time
if time == 0:
self.auto_reset_manual_control_times.pop(light, None)
else:
self.auto_reset_manual_control_times[light] = time
def get_manual_control_attributes(
self,

View file

@ -1004,6 +1004,60 @@ async def test_reload_cancels_old_manual_reset_and_keeps_service_tracking(hass):
await hass.async_block_till_done()
async def test_disabling_autoreset_takes_effect_on_reload(hass):
"""Setting 'autoreset_control_seconds' to 0 must drop the old delay (#1631)."""
await setup_lights(hass)
entry, switch = await setup_switch(
hass,
{CONF_LIGHTS: [ENTITY_LIGHT_1], CONF_AUTORESET_CONTROL: 60},
)
# A second profile keeps the shared manager alive across the reload.
other_entry, _ = await setup_switch(
hass,
{CONF_NAME: "other", CONF_LIGHTS: [ENTITY_LIGHT_2]},
)
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: ENTITY_LIGHT_1, ATTR_BRIGHTNESS: 77},
blocking=True,
)
await hass.async_block_till_done()
assert switch.manager.auto_reset_manual_control_times[ENTITY_LIGHT_1] == 60
old_timer = switch.manager.auto_reset_manual_control_timers[ENTITY_LIGHT_1]
assert old_timer.is_running()
# Updating the options reloads the entry; the manager survives the reload.
hass.config_entries.async_update_entry(
entry,
options={CONF_AUTORESET_CONTROL: 0},
)
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.LOADED
new_switch = hass.data[DOMAIN][entry.entry_id][SWITCH_DOMAIN]
assert new_switch is not switch
assert new_switch.manager is switch.manager
assert not old_timer.is_running()
assert ENTITY_LIGHT_1 not in new_switch.manager.auto_reset_manual_control_times
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: ENTITY_LIGHT_1, ATTR_BRIGHTNESS: 99},
blocking=True,
)
await hass.async_block_till_done()
assert new_switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
assert ENTITY_LIGHT_1 not in new_switch.manager.auto_reset_manual_control_timers
assert (
hass.states.get(new_switch.entity_id).attributes["autoreset_time_remaining"]
== {}
)
assert await hass.config_entries.async_unload(entry.entry_id)
assert await hass.config_entries.async_unload(other_entry.entry_id)
await hass.async_block_till_done()
async def test_manual_control_expiry_does_not_adapt_disabled_profile(hass):
"""Expiry clears ownership without sending light commands for a disabled profile."""
switch, _ = await setup_lights_and_switch(