Skip to content

feat(clock): persist software clock to NVS on boards without an RTC#2591

Merged
bmorcelli merged 1 commit into
BruceDevices:devfrom
parsazolfaghar:feat/persistent-clock-nvs
Jun 26, 2026
Merged

feat(clock): persist software clock to NVS on boards without an RTC#2591
bmorcelli merged 1 commit into
BruceDevices:devfrom
parsazolfaghar:feat/persistent-clock-nvs

Conversation

@parsazolfaghar

Copy link
Copy Markdown
Contributor

What

Persist the software clock to NVS on boards without an RTC chip, and restore it on boot.

Why

Boards like the T-Deck have no RTC, so a time set via manual/NTP/GPS is lost on a full
power-off and the clock resets to the build default on the next boot. This periodically
saves the current epoch to NVS and restores it at startup, so the clock comes back close
to correct even without WiFi/GPS at boot time.

Addresses part of #1866.

How

  • Adds restore_persisted_time() + time_persist_task() in main.cpp, guarded by
    #if !defined(HAS_RTC) so RTC builds are completely unaffected.
  • Stored in NVS (via Preferences), not the user filesystem, so it survives FS
    reformats and custom/non-standard partition layouts.
  • First save fires within ~60s of the clock being set, then at most every 5 min
    (bounds NVS wear; worst-case staleness ~5 min).
  • On boot it restores the saved epoch (with a post-2025-01-01 sanity check) before the
    rest of setup().

Behavior / limitations

Without an RTC, elapsed time during a power-off cannot be tracked, so the clock restores
the last-known time and will be behind by however long the device was off; it re-syncs
to exact time via NTP/GPS when available. This is a best-effort "don't reset to the default
date" fallback, not a hardware-RTC replacement.

Testing

Built and tested on a LilyGO T-Deck Plus (lilygo-t-deck-pro): set the time, fully
power-cycled, and the clock restored the last-known time instead of resetting to the build
default. Confirmed it survives a custom/dual-boot partition layout (NVS-backed). A 30-minute
power-off returned ~30 minutes behind, as expected for a no-RTC software clock. RTC builds
are unaffected (compiled out via !defined(HAS_RTC)).

@bmorcelli

Copy link
Copy Markdown
Member

This is indeed a good idea, although it loses time sync every reboot, but will at least keep date info, important in file metadata..

Rebase it to dev brench and add these new funtions changes into the ones in src/core/utils.* as clock functions reside there and intefrate with the updateClockTimezone() if needed 😉

@Ninja-jr

Copy link
Copy Markdown
Contributor

This is indeed a good idea, although it loses time sync every reboot, but will at least keep date info, important in file metadata..

Rebase it to dev brench and add these new funtions changes into the ones in src/core/utils.* as clock functions reside there and intefrate with the updateClockTimezone() if needed 😉

Or...just an idea, but if it's about the reboot time making it slightly lose sync, one could calculate the average reboot time (of course it depends on devices and if quick boot is enabled or not) and add that when re-syncing time. If quick boot option on then add just the quick boot time.

Of course still not perfect but it would probably be more accurate.

This probably won't solve the problem on a prolonged power off still, but that one would be hard to solve anyway. Wouldn't need a full power off, but rather a deep sleep with periodic rts sync...but that would be a big battery drainer anyway.

Per review on BruceDevices#2591: rebased onto dev, and moved the persistence into
src/core/utils.* alongside the clock functions (called from init_clock()).

Boards without an RTC (e.g. T-Deck) lose a set time on a full power-off and
reset to the build default. This periodically saves the current epoch to NVS
and restores it in init_clock() so the clock comes back close to correct, with
date info intact for file metadata; it re-syncs exactly via NTP/GPS when
available. Stored in NVS (not the user FS) so it survives FS reformats and
custom partition layouts. Guarded by !defined(HAS_RTC); RTC builds unaffected.
Hardware-tested on a LilyGO T-Deck Plus.
@parsazolfaghar
parsazolfaghar force-pushed the feat/persistent-clock-nvs branch from 57cc1bc to beef469 Compare June 25, 2026 19:22
@parsazolfaghar
parsazolfaghar changed the base branch from main to dev June 25, 2026 19:22
@parsazolfaghar

Copy link
Copy Markdown
Contributor Author

Thanks for the review! Done both:

  • Rebased onto dev (PR retargeted).
  • Moved the functions into src/core/utils.* alongside the clock functions — restorePersistedClock() + the save task now live there and are called once from init_clock() on the non-RTC path, overriding the default date with the last-saved epoch. Guarded by !defined(HAS_RTC) so RTC builds are unaffected.

Let me know if you'd like any further tweaks.

@bmorcelli
bmorcelli merged commit 45e1ea8 into BruceDevices:dev Jun 26, 2026
7 checks passed
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.

3 participants