Uniot Core
0.8.1
Loading...
Searching...
No Matches
SimpleNTP.h
Go to the documentation of this file.
1#pragma once
2
3#include <Logger.h>
4#include <WiFiUdp.h>
5#include <time.h>
6
7namespace uniot {
18class SimpleNTP {
19 public:
27 typedef void (*SyncTimeCallback)(time_t epoch);
28
34 static constexpr const char *servers[] = {"time.google.com", "time.nist.gov", "pool.ntp.org"};
35
41 SimpleNTP() : mSyncTimeCallback(nullptr) {}
42
49 mSyncTimeCallback = callback;
50 }
51
61 time_t getNtpTime() {
62 WiFiUDP udp;
63 const unsigned short localUdpPort = 1234;
64 if (!udp.begin(localUdpPort)) {
65 UNIOT_LOG_ERROR("Failed to initialize UDP on port %d.", localUdpPort);
66 return 0;
67 }
68
69 while (udp.parsePacket() != 0) {
70 udp.flush();
71 }
72
73 if (!_sendNTPPacket(udp)) {
74 udp.stop();
75 return 0;
76 }
77
78 int maxRetries = 200;
79 bool responseReceived = _waitForResponse(udp, 1500, maxRetries, 10);
80 if (!responseReceived) {
81 UNIOT_LOG_ERROR("No UDP response received from NTP server after %d attempts.", maxRetries);
82 udp.stop();
83 return 0;
84 }
85
86 time_t currentEpoch = _processNTPResponse(udp);
87 if (!currentEpoch) {
88 udp.stop();
89 return 0;
90 }
91
92 if (mSyncTimeCallback) {
93 mSyncTimeCallback(currentEpoch);
94 }
95 udp.stop();
96
97 return currentEpoch;
98 }
99
100 private:
111 bool _sendNTPPacket(WiFiUDP &udp) {
112 uint8_t packet[48];
113 memset(packet, 0, sizeof(packet));
114 packet[0] = 0b11100011; // LI, Version, Mode
115 packet[1] = 0; // Stratum, or type of clock
116 packet[2] = 6; // Polling Interval
117 packet[3] = 0xEC; // Peer Clock Precision
118 // 8 bytes of zero for Root Delay & Root Dispersion
119 packet[12] = 49;
120 packet[13] = 0x4E;
121 packet[14] = 49;
122 packet[15] = 52;
123
124 const char *selectedServer = servers[random(0, sizeof(servers) / sizeof(servers[0]))];
125
126 const unsigned short ntpUdpPort = 123;
127 udp.beginPacket(selectedServer, ntpUdpPort);
128 size_t bytesWritten = udp.write(packet, sizeof(packet));
129 if (bytesWritten != sizeof(packet)) {
130 UNIOT_LOG_ERROR("Failed to write NTP packet to UDP");
131 return false;
132 }
133 udp.endPacket();
134 UNIOT_LOG_TRACE("NTP packet sent to %s:%d.", selectedServer, ntpUdpPort);
135 return true;
136 }
137
151 bool _waitForResponse(WiFiUDP &udp, unsigned long timeout, int maxRetries, unsigned long retryDelay) {
152 UNIOT_LOG_TRACE("Waiting for NTP response with timeout %lu ms and max %d retries.", timeout, maxRetries);
153 unsigned long startTime = millis();
154
155 for (int attempt = 1; attempt <= maxRetries; ++attempt) {
156 unsigned long currentTime = millis();
157 if (currentTime - startTime >= timeout) {
158 UNIOT_LOG_WARN("NTP response wait timed out on attempt %d.", attempt);
159 return false;
160 }
161
162 int packetSize = udp.parsePacket();
163 if (packetSize >= 48) {
164 UNIOT_LOG_TRACE("NTP response received on attempt %d.", attempt);
165 return true;
166 }
167
168 delay(retryDelay);
169 }
170
171 return false;
172 }
173
184 time_t _processNTPResponse(WiFiUDP &udp) {
185 uint8_t packet[48];
186 int len = udp.read(packet, sizeof(packet));
187 if (len < 48) {
188 UNIOT_LOG_ERROR("Incomplete NTP packet received. Expected 48 bytes, got %d bytes.", len);
189 return 0;
190 }
191
192 // Extract the timestamp from the NTP packet
193 unsigned long highWord = word(packet[40], packet[41]);
194 unsigned long lowWord = word(packet[42], packet[43]);
195 unsigned long secsSince1900 = (highWord << 16) | lowWord;
196
197 // Convert NTP time to Unix epoch time
198 time_t currentEpoch = secsSince1900 - 2208988800UL;
199 UNIOT_LOG_TRACE("NTP time (epoch): %ld", currentEpoch);
200
201 return currentEpoch;
202 }
203
207 SyncTimeCallback mSyncTimeCallback;
208};
209
210} // namespace uniot
void(* SyncTimeCallback)(time_t epoch)
Callback function type for time synchronization events.
Definition SimpleNTP.h:27
static constexpr const char * servers[]
Array of NTP server hostnames to try connecting to.
Definition SimpleNTP.h:34
SimpleNTP()
Default constructor.
Definition SimpleNTP.h:41
time_t getNtpTime()
Requests and retrieves current time from NTP server.
Definition SimpleNTP.h:61
void setSyncTimeCallback(SyncTimeCallback callback)
Sets the callback function for time synchronization events.
Definition SimpleNTP.h:48
#define UNIOT_LOG_TRACE(...)
Log an TRACE level message Used for general information about system operation. Only compiled if UNIO...
Definition Logger.h:314
#define UNIOT_LOG_WARN(...)
Log an WARN level message Used for warnings about potentially problematic situations....
Definition Logger.h:247
#define UNIOT_LOG_ERROR(...)
Log an ERROR level message Used for critical errors that may prevent normal operation....
Definition Logger.h:226
Contains all classes and functions related to the Uniot Core.