Skip to content

Conversation

@kylephillipsau
Copy link

@kylephillipsau kylephillipsau commented Jan 15, 2026

Adds an option to apply the most recent scheduled preset when the device boots after NTP sync.

Currently, timed presets only trigger at the exact scheduled minute. If you power on at 9pm with an 8pm preset, nothing happens until 8pm the next day. This checks what preset should be active and applies it.

New checkbox in Time & Macros: "Apply scheduled preset on boot" (enabled by default).

Also refactored checkTimers() to share validation logic with the new code.

My use case: WLED bulbs on a wall switch that I wanted to go red after 8pm to reduce melatonin suppression before sleep.

Addresses #2546

Summary by CodeRabbit

  • New Features

    • Added an "Apply scheduled preset on boot" checkbox in Time settings to optionally apply the most recent scheduled preset after a restart (off by default).
  • Improvements

    • Unified timer evaluation across all timer types; after time sync on boot, the device can detect and apply the most recent missed preset for today (includes hourly and sunrise/sunset presets).

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

Walkthrough

Adds a persisted "apply scheduled preset on boot" flag with UI and config I/O; centralizes timer minute-of-day computation; refactors timer checks to use it; and applies the most-recent applicable timer preset after the first NTP sync via a new applyBootTimerPreset() routine.

Changes

Cohort / File(s) Summary
Global state
wled00/wled.h
Adds bootTimerApplied and applyTimerOnBoot globals with default values.
Config serialization
wled00/cfg.cpp
Deserialize/serialize applyTimerOnBoot from/to config (tm["aob"] / timers["aob"]).
Settings handling (HTTP/API)
wled00/set.cpp
Reads TB parameter when saving settings to set applyTimerOnBoot.
UI (settings page & XML)
wled00/data/settings_time.htm, wled00/xml.cpp
Adds TB checkbox ("Apply scheduled preset on boot") to time-controlled presets UI and emits it in settings XML bound to applyTimerOnBoot.
Timer logic & declarations
wled00/ntp.cpp, wled00/fcn_declare.h
Adds static int getTimerMinuteOfDay(unsigned i) and applyBootTimerPreset(); refactors checkTimers() to use minute-of-day checks; invokes applyBootTimerPreset() after NTP sync; declares void applyBootTimerPreset() in header.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding functionality to apply the most recent time-controlled preset when the device boots.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

I use WLED bulbs that are controlled by a wall switch, so they power
cycle frequently. I wanted them to automatically switch to red light
after 8pm to reduce melatonin suppression before sleep.

The existing time-controlled presets only trigger at the exact scheduled
minute, not when powering on after that time has passed. This change adds
a one-time check after NTP sync that finds and applies the most recent
preset that should have triggered today.

Changes:
- Add getTimerMinuteOfDay() helper to reduce duplication between
  checkTimers() and the new boot-time logic
- Add applyBootTimerPreset() called after first NTP sync
- Add "Apply scheduled preset on boot" checkbox in Time settings UI
- Setting is enabled by default and persisted in config

Addresses wled#2546
@kylephillipsau kylephillipsau force-pushed the feature/apply-timer-preset-on-boot branch from 5084308 to 32bed66 Compare January 15, 2026 11:12
@softhack007
Copy link
Member

453-468: Clarify tie-breaking behavior for simultaneous timers.
When multiple timers are scheduled for the same minute, the current loop selects the last one iterated (highest index). This is a valid approach, but consider whether this matches user expectations or if it should match checkTimers() behavior (which would apply all matching timers).
If the current "last wins" behavior is intentional, a brief comment would help future maintainers understand the design choice.

@kylephillipsau please also check if this comment by the rabbit makes sense.

Match checkTimers() behavior where all matching presets are applied
in order and the last one sticks. Changed > to >= and added comment
explaining the design choice.
@kylephillipsau
Copy link
Author

That makes sense, thanks for letting me know. I have updated > to >= so the highest index wins on ties, which matches the checkTimers() behavior. I have included a comment alongside the function to explain why.

@DedeHai
Copy link
Collaborator

DedeHai commented Jan 15, 2026

seems like a good addition to have. It should not be enabled by default for backwards compatibility though.
Also know that once #5140 is merged, this will need quite some rework.

@kylephillipsau
Copy link
Author

That's a fair point, thank you. I just changed the default value to false in b24e7db.
I had a squiz over #5140 . The core logic in applyBootTimerPreset() should translate fairly directly to iterating the new Timer vector instead of the current arrays. I'm happy to rebase and adapt this once that's merged.

Update comment from "if time changed" to "NTP sync succeeded"
for better clarity about when this code executes.
@kylephillipsau
Copy link
Author

Hey @softhack007,

Thank you for bringing that up. I traced through the codebase to verify the behavior.

checkNTPResponse() only executes when a valid NTP UDP packet is received and
validated. The scenarios you mentioned each go through different code paths:

  • Location/timezone changed - This is handled in set.cpp, it forces NTP resync via
    ntpLastSyncTime = NTP_NEVER
  • RTC usermod - calls toki.setTime() directly in setup, which never touches
    checkNTPResponse()
  • JSON/webUI time set - uses setTimeFromAPI(), a separate path in ntp.cpp
  • NTP re-sync - the bootTimerApplied guard flag prevents re-execution, which follows the same pattern as countdownOverTriggered

Since only the NTP packet receipt triggers this path, and the guard flag handles re-syncs, the implementation should behave correctly.

I updated the comment to read "NTP sync succeeded" which I think captures the intent more clearly.

@softhack007 softhack007 self-requested a review January 16, 2026 23:27
Copy link
Member

@softhack007 softhack007 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me - no more questions ;-) I did not find time to test the code on hardware, though.

@softhack007
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 16, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@softhack007
Copy link
Member

softhack007 commented Jan 16, 2026

@kylephillipsau kylephillipsau force-pushed the feature/apply-timer-preset-on-boot branch from 5084308 to 32bed66
2 days ago

@kylephillipsau on last thing - for your next PR: please avoid force-push while you have a PR open for upstream WLED. We lost the complete review history that came before your force-push (in this PR only), plus coderabbitai just self-disabled for some strange reason and it does not respond to my prompts any more.


Edit: we can live with the "damage" that was done by accident in this PR, as I think its good for merging. Just for the future please remember "force-push considered harmful" 😉

@blazoncek
Copy link
Contributor

What about playlists specifically crafted to apply certain presets at defined times after a trigger time? Those would be broken.

I.e. playlist to apply preset/effect A at 7:00 with duration TA then preset/effect B with duration TB, ending with preset C. One may not want this sequence to play at 8:00, only preset C would be wanted.

@kylephillipsau
Copy link
Author

Yeah, that's a really good point. As you noted in #2546, playlist content only exists in the presets.json, which isn't feasible to read and parse to determine playlist behavior at boot time. If a timer triggers a playlist, it would start from the beginning rather than resume mid-sequence.

Since this feature is disabled by default, users with time-sequenced playlists can leave it off. For the simpler use cases this targets (e.g. warm white after sunset and red at night), it works as expected.

If this behavior is acceptable, I can add a note in the UI description to clarify it. Otherwise if it feels incomplete, I'm happy to defer until a better way to address this can be identified.

@blazoncek
Copy link
Contributor

read and parse to determine playlist behavior at boot time

Why not? My comment was made 3 years ago when I was still fresh with WLED. Playlists are actually simple to parse. Each entry has duration assigned (most often but there may be exceptions) so you sum durations until time is greater than current time.

The only drawback I see is that if a user has boot preset assigned, it will start, only to be replaced a few seconds later by "last timed preset". The "few seconds later" may be very variable as you never know how long will it take to connect to WiFi and receive NTP response. A bit awkward and solvable by removing boot preset, but still. The reality is that user may not always want last timed preset to play (emphasis on always). I.e. I may not want to play last timed preset in the morning but would want to in the afternoon.

users with time-sequenced playlists can leave it off

Let's assume users want the behaviour but have mixed presets and playlists scheduled. Life is not simple, unfortunately.

There are of course other arguments "pro et contra" so the choice to enable this behaviour should definitely be in the hands of enduser. In general I am in favour of this PR but would really like to see most aspects to be considered and implemented correctly if possible.

It would also be beneficial if this PR be combined with #5140 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants