fix: re-adapt lights right after the auto-reset timer fires (#1506)

When the auto-reset timer fired, its callback called manager.reset(),
which pops the timer and calls timer.cancel() - cancelling the very task
that was running the callback. The manual_control flag was cleared, but
the re-adaptation that should follow was silently cancelled, so the light
only changed on the next interval pass (with the normal transition).

_AsyncSingleShotTimer.cancel() now never cancels the task that is
currently running its own callback. The trailing assert in the callback
is removed because it is reachable now and could trip when a new manual
change comes in while the re-adaptation is still running. The existing
auto-reset test also checks that a light.turn_on with the 'autoreset'
context is sent.

Fixes #1233

Co-authored-by: Dennis-Dekker <>
Co-authored-by: Bas Nijholt <bas@nijho.lt>
This commit is contained in:
Dennis Dekker 2026-09-06 09:01:50 +02:00 • committed by GitHub
commit c620d1480a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 26 additions and 3 deletions

View file

@ -2266,7 +2266,6 @@ class AdaptiveLightingManager:
transition=switch.initial_transition,
force=True,
)
assert self.manual_control[light] == LightControlAttributes.NONE
self._handle_timer(light, self.auto_reset_manual_control_timers, delay, reset)
@ -3007,9 +3006,17 @@ class _AsyncSingleShotTimer:
def cancel(self) -> None:
"""Cancel the timer."""
if self.task:
# Never cancel the task that is currently running our own callback, e.g.
# when the auto-reset callback calls manager.reset(), which cancels the
# timer it is running in. That used to silently cancel the rest of the
# callback (the re-adaptation), see issue #1233.
try:
current_task = asyncio.current_task()
except RuntimeError: # no running event loop
current_task = None
if self.task and self.task is not current_task:
self.task.cancel()
self.callback = None
self.callback = None
def remaining_time(self) -> float:
"""Return the remaining time before the timer expires."""