Time Service — ESP3D-X Reference
Section titled “Time Service — ESP3D-X Reference”Guard: ESP3D_TIMESTAMP_FEATURE
The time service manages system clock synchronization. When enabled, it can sync via NTP (internet time) or accept a manually provided timestamp. It belongs to the Network & Web Services group and requires an active WiFi STA connection for NTP operation.
| File | Role |
|---|---|
main/modules/time/esp3d_time_service.h | TimeService class declaration |
main/modules/time/esp3d_time_service.cpp | Full implementation |
Global instance
Section titled “Global instance”extern TimeService esp3dTimeService;A single singleton defined in the .cpp file. All callers use this instance directly.
Class declaration
Section titled “Class declaration”class TimeService final { public: TimeService(); ~TimeService(); bool begin(); void end(); void handle(); const char* getCurrentTime(); const char* getTimeZone(); bool updateTimeZone(bool fromsettings = false); bool setTime(const char* stime); bool setTimeZone(const char* stime); bool started(); bool isInternetTime(bool readfromsettings = false); private: int _get_time_zone_offset_min(); bool _started; uint64_t _dispatch_time; bool _is_internet_time; std::string _time_zone; std::string _server_url[CONFIG_LWIP_SNTP_MAX_SERVERS]; uint8_t _server_count;};Lifecycle
Section titled “Lifecycle”begin() → bool
Section titled “begin() → bool”- Calls
end()unconditionally to reset any prior state. - Applies the current timezone via
updateTimeZone(true)regardless of internet-time setting. - If
esp3d_use_internet_timeis not set, returnstrueimmediately (manual mode — timezone applied, SNTP not started). - Checks the active network mode. NTP is only started in WiFi STA mode (
ESP3DNetworkMode::wifi_sta). All other modes — off, AP, AP-config, AP-limited, BT-serial, BT-BLE — returnfalse. - Loads NTP server URLs from NVS keys
esp3d_time_server1,esp3d_time_server2,esp3d_time_server3(up toCONFIG_LWIP_SNTP_MAX_SERVERSservers; empty strings are skipped). - Configures
SNTP_OPMODE_POLLandSNTP_SYNC_MODE_IMMED, registers each server, callsesp_sntp_init(). - Records the start tick in
_dispatch_timeto begin the timeout countdown.
handle()
Section titled “handle()”Called from the main application loop. Only active when _started is true and _dispatch_time != 0 (waiting for NTP sync).
Poll interval: every TIMEOUT_NTP_REFRESH = 5 000 ms.
On each poll:
- Calls
time(nullptr)and checks whether the result is post-1970 (> 0). - On valid time: formats the timestamp and pushes it to
ESP3DValuesIndex::status_bar_label(whenESP3D_HAS_STATUS_BARis defined), then sets_dispatch_time = 0to stop polling. - On timeout (
elapsed > TIMEOUT_NTP_REQUEST= 180 000 ms): logs the failure, sets_dispatch_time = 0, and stops without further retry.
Stops SNTP (esp_sntp_stop()) if previously started, resets all private members to defaults, sets _started = false.
Timing constants
Section titled “Timing constants”| Constant | Value | Purpose |
|---|---|---|
TIMEOUT_NTP_REQUEST | 180 000 ms (3 min) | Maximum wait for a successful NTP sync after begin() |
TIMEOUT_NTP_REFRESH | 5 000 ms | Interval between handle() poll checks |
NTP configuration
Section titled “NTP configuration”| NVS setting key | Meaning |
|---|---|
esp3d_use_internet_time | true = NTP sync; false = manual-only |
esp3d_time_server1 | Primary NTP server URL |
esp3d_time_server2 | Secondary NTP server URL |
esp3d_time_server3 | Tertiary NTP server URL |
SNTP is configured with:
SNTP_OPMODE_POLL— periodic pollingSNTP_SYNC_MODE_IMMED— apply received time immediately (not gradual slew)
Timezone handling
Section titled “Timezone handling”Storage format (esp3d_timezone NVS key)
Section titled “Storage format (esp3d_timezone NVS key)”+HH:MM east of UTC (e.g. "+05:30" for IST)-HH:MM west of UTC (e.g. "-05:00" for EST)POSIX sign inversion
Section titled “POSIX sign inversion”The POSIX TZ environment variable uses the opposite sign from the UTC-offset convention. updateTimeZone() inverts the sign before calling setenv("TZ", ...) / tzset():
| NVS value | Resulting TZ string |
|---|---|
+05:30 | GMT-5:30 |
-05:00 | GMT+5:00 |
+00:00 | GMT-0:00 |
updateTimeZone(bool fromsettings = false) → bool
Section titled “updateTimeZone(bool fromsettings = false) → bool”fromsettings = true: readsesp3d_timezonefrom NVS first.fromsettings = false(default): uses the cached_time_zonemember.- Validates that the string matches
[+-]HH:MMformat. - Calls
setenv("TZ", converted, 1)thentzset(). - Returns
falseif the format is invalid orsetenvfails.
setTimeZone(const char* stime) → bool
Section titled “setTimeZone(const char* stime) → bool”Stores the string into _time_zone and calls updateTimeZone(). Does not persist to NVS — the caller must save to settings if persistence is required.
getTimeZone() → const char*
Section titled “getTimeZone() → const char*”Returns _time_zone.c_str(). Valid until the next setTimeZone() or end() call.
_get_time_zone_offset_min() → int (private)
Section titled “_get_time_zone_offset_min() → int (private)”Returns the timezone offset in minutes, with the sign negated for + zones (POSIX convention). Used by setTime() to compute the correct timeval when applying a manually provided timestamp.
Manual time
Section titled “Manual time”setTime(const char* stime) → bool
Section titled “setTime(const char* stime) → bool”Parses an ISO-8601 timestamp string and sets the system clock via settimeofday().
Accepted formats:
%Y-%m-%dT%H:%M:%S(with seconds)%Y-%m-%dT%H:%M(without seconds)
Any timezone suffix in the string is ignored; the stored _time_zone offset is applied instead via _get_time_zone_offset_min().
Returns false if parsing fails.
Current time output
Section titled “Current time output”getCurrentTime() → const char*
Section titled “getCurrentTime() → const char*”Returns the current local time formatted as:
%Y-%m-%d %H:%M:%SExample: "2026-09-01 14:32:07"
Warning: the return value points to an internal static buffer. It is overwritten on every call and is not thread-safe across concurrent callers.
Status bar integration
Section titled “Status bar integration”When ESP3D_HAS_STATUS_BAR is defined, handle() pushes the formatted time string to the observable system after a successful NTP sync:
esp3dValues.set(ESP3DValuesIndex::status_bar_label, getCurrentTime(), ESP3DValuesCbAction::Update);This update fires once — immediately after the first valid time is received — not on every poll tick.
Network mode constraints
Section titled “Network mode constraints”NTP startup is gated on the network mode at the time begin() is called:
| Network mode | NTP started |
|---|---|
wifi_sta | Yes |
wifi_ap | No |
wifi_ap_config | No |
wifi_ap_limited | No |
off | No |
bt_serial | No |
bt_ble | No |
In all non-STA modes begin() returns false. The timezone is still applied unconditionally.
State query
Section titled “State query”| Method | Returns |
|---|---|
started() | true if begin() succeeded and end() has not yet been called |
isInternetTime(bool readfromsettings = false) | true if NTP mode is active; reads from NVS when readfromsettings = true |
Settings keys summary
Section titled “Settings keys summary”| Key | Read by |
|---|---|
esp3d_use_internet_time | begin(), isInternetTime() |
esp3d_timezone | updateTimeZone() |
esp3d_time_server1 | begin() |
esp3d_time_server2 | begin() |
esp3d_time_server3 | begin() |
All reads go through ESP3DSettings (NVS-backed).
Related modules
Section titled “Related modules”| Module | Relationship |
|---|---|
| Connection management | Provides the active network mode queried in begin() to gate NTP startup |
| ESP3DSettings | NVS reads for all five settings keys |
| ESP3DValues | Receives status_bar_label push after successful NTP sync |
| mDNS | Advertises time = "ntp" / "manual" in the _device-info._tcp TXT record |