Files
crosspoint-reader-mod/chat-summaries/2026-02-17_clock-fix-ntp-sleep-summary.md
cottongin dfbc931c14 mod: Phase 1 - bring forward mod-exclusive files with ActivityManager migration
Brings ~55 mod-exclusive files to the upstream-based mod/master-resync branch:

Activities (migrated to new ActivityManager pattern):
- Clock/Time: SetTimeActivity, SetTimezoneOffsetActivity, NtpSyncActivity
- Dictionary: DictionaryDefinitionActivity, DictionarySuggestionsActivity,
  DictionaryWordSelectActivity, LookedUpWordsActivity
- Bookmark: EpubReaderBookmarkSelectionActivity
- Book management: BookManageMenuActivity, EndOfBookMenuActivity
- OPDS: OpdsServerListActivity, OpdsSettingsActivity
- Utility: DirectoryPickerActivity, NumericStepperActivity

Utilities (unchanged):
- BookManager, BookSettings, BookmarkStore, BootNtpSync
- Dictionary, LookupHistory, TimeSync, OpdsServerStore

Libraries: PlaceholderCover, TableData, ChapterXPathIndexer
Scripts: inject_mod_version, generate_book_icon, preview_placeholder_cover
Docs: KOReader sync XPath mapping

Migration changes:
- ActivityWithSubactivity -> Activity base class
- Callback constructors -> finish()/setResult() pattern
- enterNewActivity() -> startActivityForResult()
- Activity::RenderLock&& -> RenderLock&&

These files won't compile yet - they reference mod settings and I18n
strings that will be added in subsequent phases.

Made-with: Cursor
2026-03-07 15:10:00 -05:00

2.8 KiB

Clock Bug Fix, NTP Auto-Sync, and Sleep Persistence

Date: 2026-02-17

Task Description

Three clock-related improvements:

  1. Fix SetTimeActivity immediately dismissing when opened
  2. Add automatic NTP time sync on WiFi connection
  3. Verify time persistence across deep sleep modes

Changes Made

1. Bug Fix: SetTimeActivity immediate dismiss (src/activities/settings/SetTimeActivity.cpp)

  • Root cause: loop() used wasReleased() for Back, Confirm, Left, and Right buttons. The parent SettingsActivity enters this subactivity on a wasPressed() event, so the button release from the original press immediately triggered the exit path.
  • Fix: Changed all four wasReleased() calls to wasPressed(), matching the pattern used by all other subactivities (e.g., LanguageSelectActivity).

2. Shared NTP Utility (src/util/TimeSync.h, src/util/TimeSync.cpp)

  • Created TimeSync namespace with three functions:
    • startNtpSync() -- non-blocking: configures and starts SNTP service
    • waitForNtpSync(int timeoutMs = 5000) -- blocking: starts SNTP and polls until sync completes or timeout
    • stopNtpSync() -- stops the SNTP service

3. NTP on WiFi Connection (src/activities/network/WifiSelectionActivity.cpp)

  • Added #include "util/TimeSync.h" and call to TimeSync::startNtpSync() in checkConnectionStatus() right after WL_CONNECTED is detected. This is non-blocking so it doesn't delay the UI flow.

4. KOReaderSync refactor (src/activities/reader/KOReaderSyncActivity.cpp)

  • Removed the local syncTimeWithNTP() anonymous namespace function and #include <esp_sntp.h>
  • Replaced both call sites with TimeSync::waitForNtpSync() (blocking, since KOReader needs accurate time for API requests)
  • Added #include "util/TimeSync.h"

5. Boot time debug log (src/main.cpp)

  • Added #include <ctime> and a debug log in setup() that prints the current RTC time on boot (or "not set" if epoch). This helps verify time persistence across deep sleep during testing.

Sleep Persistence Notes

  • ESP32-C3's default ESP-IDF config uses both RTC and high-resolution timers for timekeeping
  • The RTC timer continues during deep sleep, so time() / gettimeofday() return correct wall-clock time after wake (with drift from the internal ~150kHz RC oscillator)
  • Time does NOT survive a full power-on reset (RTC timer resets)
  • NTP auto-sync on WiFi connection handles drift correction

Build Verification

  • pio run -e mod -- SUCCESS (RAM: 31.0%, Flash: 78.8%)

Follow-up Items

  • Test on hardware: set time manually, sleep, wake, verify time in serial log
  • Test NTP: connect to WiFi from Settings, verify time updates automatically
  • Consider adding TimeSync::stopNtpSync() call when WiFi is disconnected (currently SNTP just stops getting responses, which is harmless)