Commit 69c37eaf authored by Eric Duminil's avatar Eric Duminil
Browse files

Updated NTP lib.

Broken, because custom code is missing
parent 6b079f75
Pipeline #5753 canceled with stage
...@@ -25,7 +25,7 @@ NTPClient::NTPClient(UDP& udp) { ...@@ -25,7 +25,7 @@ NTPClient::NTPClient(UDP& udp) {
this->_udp = &udp; this->_udp = &udp;
} }
NTPClient::NTPClient(UDP& udp, int timeOffset) { NTPClient::NTPClient(UDP& udp, long timeOffset) {
this->_udp = &udp; this->_udp = &udp;
this->_timeOffset = timeOffset; this->_timeOffset = timeOffset;
} }
...@@ -35,24 +35,45 @@ NTPClient::NTPClient(UDP& udp, const char* poolServerName) { ...@@ -35,24 +35,45 @@ NTPClient::NTPClient(UDP& udp, const char* poolServerName) {
this->_poolServerName = poolServerName; this->_poolServerName = poolServerName;
} }
NTPClient::NTPClient(UDP& udp, const char* poolServerName, int timeOffset) { NTPClient::NTPClient(UDP& udp, IPAddress poolServerIP) {
this->_udp = &udp;
this->_poolServerIP = poolServerIP;
this->_poolServerName = NULL;
}
NTPClient::NTPClient(UDP& udp, const char* poolServerName, long timeOffset) {
this->_udp = &udp; this->_udp = &udp;
this->_timeOffset = timeOffset; this->_timeOffset = timeOffset;
this->_poolServerName = poolServerName; this->_poolServerName = poolServerName;
} }
NTPClient::NTPClient(UDP& udp, const char* poolServerName, int timeOffset, unsigned long updateInterval) { NTPClient::NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset){
this->_udp = &udp;
this->_timeOffset = timeOffset;
this->_poolServerIP = poolServerIP;
this->_poolServerName = NULL;
}
NTPClient::NTPClient(UDP& udp, const char* poolServerName, long timeOffset, unsigned long updateInterval) {
this->_udp = &udp; this->_udp = &udp;
this->_timeOffset = timeOffset; this->_timeOffset = timeOffset;
this->_poolServerName = poolServerName; this->_poolServerName = poolServerName;
this->_updateInterval = updateInterval; this->_updateInterval = updateInterval;
} }
NTPClient::NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset, unsigned long updateInterval) {
this->_udp = &udp;
this->_timeOffset = timeOffset;
this->_poolServerIP = poolServerIP;
this->_poolServerName = NULL;
this->_updateInterval = updateInterval;
}
void NTPClient::begin() { void NTPClient::begin() {
this->begin(NTP_DEFAULT_LOCAL_PORT); this->begin(NTP_DEFAULT_LOCAL_PORT);
} }
void NTPClient::begin(int port) { void NTPClient::begin(unsigned int port) {
this->_port = port; this->_port = port;
this->_udp->begin(this->_port); this->_udp->begin(this->_port);
...@@ -60,37 +81,15 @@ void NTPClient::begin(int port) { ...@@ -60,37 +81,15 @@ void NTPClient::begin(int port) {
this->_udpSetup = true; this->_udpSetup = true;
} }
bool NTPClient::isValid(byte * ntpPacket)
{
//Perform a few validity checks on the packet
if((ntpPacket[0] & 0b11000000) == 0b11000000) //Check for LI=UNSYNC
return false;
if((ntpPacket[0] & 0b00111000) >> 3 < 0b100) //Check for Version >= 4
return false;
if((ntpPacket[0] & 0b00000111) != 0b100) //Check for Mode == Server
return false;
if((ntpPacket[1] < 1) || (ntpPacket[1] > 15)) //Check for valid Stratum
return false;
if( ntpPacket[16] == 0 && ntpPacket[17] == 0 &&
ntpPacket[18] == 0 && ntpPacket[19] == 0 &&
ntpPacket[20] == 0 && ntpPacket[21] == 0 &&
ntpPacket[22] == 0 && ntpPacket[22] == 0) //Check for ReferenceTimestamp != 0
return false;
return true;
}
bool NTPClient::forceUpdate() { bool NTPClient::forceUpdate() {
#ifdef DEBUG_NTPClient #ifdef DEBUG_NTPClient
Serial.println("Update from NTP Server"); Serial.println("Update from NTP Server");
#endif #endif
// flush any existing packets // flush any existing packets
while(this->_udp->parsePacket() != 0) while(this->_udp->parsePacket() != 0)
this->_udp->flush(); this->_udp->flush();
this->sendNTPPacket(); this->sendNTPPacket();
// Wait till data is there or timeout... // Wait till data is there or timeout...
...@@ -99,20 +98,14 @@ bool NTPClient::forceUpdate() { ...@@ -99,20 +98,14 @@ bool NTPClient::forceUpdate() {
do { do {
delay ( 10 ); delay ( 10 );
cb = this->_udp->parsePacket(); cb = this->_udp->parsePacket();
if(cb > 0)
{
this->_udp->read(this->_packetBuffer, NTP_PACKET_SIZE);
if(!this->isValid(this->_packetBuffer))
cb = 0;
}
if (timeout > 100) return false; // timeout after 1000 ms if (timeout > 100) return false; // timeout after 1000 ms
timeout++; timeout++;
} while (cb == 0); } while (cb == 0);
this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time
this->_udp->read(this->_packetBuffer, NTP_PACKET_SIZE);
unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]); unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]); unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]);
// combine the four bytes (two words) into a long integer // combine the four bytes (two words) into a long integer
...@@ -121,73 +114,53 @@ bool NTPClient::forceUpdate() { ...@@ -121,73 +114,53 @@ bool NTPClient::forceUpdate() {
this->_currentEpoc = secsSince1900 - SEVENZYYEARS; this->_currentEpoc = secsSince1900 - SEVENZYYEARS;
return true; return true; // return true after successful update
} }
bool NTPClient::update() { bool NTPClient::update() {
if ((millis() - this->_lastUpdate >= this->_updateInterval) // Update after _updateInterval if ((millis() - this->_lastUpdate >= this->_updateInterval) // Update after _updateInterval
|| this->_lastUpdate == 0) { // Update if there was no update yet. || this->_lastUpdate == 0) { // Update if there was no update yet.
if (!this->_udpSetup) this->begin(); // setup the UDP client if needed if (!this->_udpSetup || this->_port != NTP_DEFAULT_LOCAL_PORT) this->begin(this->_port); // setup the UDP client if needed
return this->forceUpdate(); return this->forceUpdate();
} }
return true; return false; // return false if update does not occur
}
bool NTPClient::isTimeSet() const {
return (this->_lastUpdate != 0); // returns true if the time has been set, else false
} }
unsigned long NTPClient::getEpochTime() { unsigned long NTPClient::getEpochTime() const {
return this->_timeOffset + // User offset return this->_timeOffset + // User offset
this->_currentEpoc + // Epoc returned by the NTP server this->_currentEpoc + // Epoch returned by the NTP server
((millis() - this->_lastUpdate) / 1000); // Time since last update ((millis() - this->_lastUpdate) / 1000); // Time since last update
} }
int NTPClient::getDay() { int NTPClient::getDay() const {
return (((this->getEpochTime() / 86400L) + 4 ) % 7); //0 is Sunday return (((this->getEpochTime() / 86400L) + 4 ) % 7); //0 is Sunday
} }
int NTPClient::getHours() { int NTPClient::getHours() const {
return ((this->getEpochTime() % 86400L) / 3600); return ((this->getEpochTime() % 86400L) / 3600);
} }
int NTPClient::getMinutes() { int NTPClient::getMinutes() const {
return ((this->getEpochTime() % 3600) / 60); return ((this->getEpochTime() % 3600) / 60);
} }
int NTPClient::getSeconds() { int NTPClient::getSeconds() const {
return (this->getEpochTime() % 60); return (this->getEpochTime() % 60);
} }
void NTPClient::getFormattedTime(char *formatted_time, unsigned long secs) { String NTPClient::getFormattedTime() const {
unsigned long rawTime = secs ? secs : this->getEpochTime(); unsigned long rawTime = this->getEpochTime();
unsigned int hours = (rawTime % 86400L) / 3600; unsigned long hours = (rawTime % 86400L) / 3600;
unsigned int minutes = (rawTime % 3600) / 60; String hoursStr = hours < 10 ? "0" + String(hours) : String(hours);
unsigned int seconds = rawTime % 60;
unsigned long minutes = (rawTime % 3600) / 60;
snprintf(formatted_time, 9, "%02d:%02d:%02d", hours, minutes, seconds); String minuteStr = minutes < 10 ? "0" + String(minutes) : String(minutes);
}
unsigned long seconds = rawTime % 60;
// Based on https://github.com/PaulStoffregen/Time/blob/master/Time.cpp String secondStr = seconds < 10 ? "0" + String(seconds) : String(seconds);
void NTPClient::getFormattedDate(char *formatted_date, unsigned long secs) {
unsigned long rawTime = (secs ? secs : this->getEpochTime()) / 86400L; // in days
unsigned long days = 0, year = 1970;
uint8_t month;
static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31};
while((days += (LEAP_YEAR(year) ? 366 : 365)) <= rawTime)
year++;
rawTime -= days - (LEAP_YEAR(year) ? 366 : 365); // now it is days in this year, starting at 0
days=0;
for (month=0; month<12; month++) {
uint8_t monthLength;
if (month==1) { // february
monthLength = LEAP_YEAR(year) ? 29 : 28;
} else {
monthLength = monthDays[month];
}
if (rawTime < monthLength) break;
rawTime -= monthLength;
}
month++; // jan is month 1
rawTime++; // first day is day 1
char formatted_time[9]; return hoursStr + ":" + minuteStr + ":" + secondStr;
this->getFormattedTime(formatted_time, secs);
snprintf(formatted_date, 23, "%4lu-%02d-%02lu %s%+03d", year, month, rawTime, formatted_time, this->_timeOffset / 3600);
} }
void NTPClient::end() { void NTPClient::end() {
...@@ -204,28 +177,36 @@ void NTPClient::setUpdateInterval(unsigned long updateInterval) { ...@@ -204,28 +177,36 @@ void NTPClient::setUpdateInterval(unsigned long updateInterval) {
this->_updateInterval = updateInterval; this->_updateInterval = updateInterval;
} }
void NTPClient::setPoolServerName(const char* poolServerName) {
this->_poolServerName = poolServerName;
}
void NTPClient::sendNTPPacket() { void NTPClient::sendNTPPacket() {
// set all bytes in the buffer to 0 // set all bytes in the buffer to 0
memset(this->_packetBuffer, 0, NTP_PACKET_SIZE); memset(this->_packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request // Initialize values needed to form NTP request
// (see URL above for details on the packets)
this->_packetBuffer[0] = 0b11100011; // LI, Version, Mode this->_packetBuffer[0] = 0b11100011; // LI, Version, Mode
this->_packetBuffer[1] = 0; // Stratum, or type of clock this->_packetBuffer[1] = 0; // Stratum, or type of clock
this->_packetBuffer[2] = 6; // Polling Interval this->_packetBuffer[2] = 6; // Polling Interval
this->_packetBuffer[3] = 0xEC; // Peer Clock Precision this->_packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion // 8 bytes of zero for Root Delay & Root Dispersion
this->_packetBuffer[12] = 0x49; this->_packetBuffer[12] = 49;
this->_packetBuffer[13] = 0x4E; this->_packetBuffer[13] = 0x4E;
this->_packetBuffer[14] = 0x49; this->_packetBuffer[14] = 49;
this->_packetBuffer[15] = 0x52; this->_packetBuffer[15] = 52;
// all NTP fields have been given values, now // all NTP fields have been given values, now
// you can send a packet requesting a timestamp: // you can send a packet requesting a timestamp:
this->_udp->beginPacket(this->_poolServerName, 123); //NTP requests are to port 123 if (this->_poolServerName) {
this->_udp->beginPacket(this->_poolServerName, 123);
} else {
this->_udp->beginPacket(this->_poolServerIP, 123);
}
this->_udp->write(this->_packetBuffer, NTP_PACKET_SIZE); this->_udp->write(this->_packetBuffer, NTP_PACKET_SIZE);
this->_udp->endPacket(); this->_udp->endPacket();
} }
void NTPClient::setEpochTime(unsigned long secs) { void NTPClient::setRandomPort(unsigned int minValue, unsigned int maxValue) {
this->_currentEpoc = secs; randomSeed(analogRead(0));
this->_port = random(minValue, maxValue);
} }
...@@ -7,8 +7,6 @@ ...@@ -7,8 +7,6 @@
#define SEVENZYYEARS 2208988800UL #define SEVENZYYEARS 2208988800UL
#define NTP_PACKET_SIZE 48 #define NTP_PACKET_SIZE 48
#define NTP_DEFAULT_LOCAL_PORT 1337 #define NTP_DEFAULT_LOCAL_PORT 1337
#define LEAP_YEAR(Y) ( (Y>0) && !(Y%4) && ( (Y%100) || !(Y%400) ) )
class NTPClient { class NTPClient {
private: private:
...@@ -16,8 +14,9 @@ class NTPClient { ...@@ -16,8 +14,9 @@ class NTPClient {
bool _udpSetup = false; bool _udpSetup = false;
const char* _poolServerName = "pool.ntp.org"; // Default time server const char* _poolServerName = "pool.ntp.org"; // Default time server
int _port = NTP_DEFAULT_LOCAL_PORT; IPAddress _poolServerIP;
int _timeOffset = 0; unsigned int _port = NTP_DEFAULT_LOCAL_PORT;
long _timeOffset = 0;
unsigned long _updateInterval = 60000; // In ms unsigned long _updateInterval = 60000; // In ms
...@@ -27,14 +26,28 @@ class NTPClient { ...@@ -27,14 +26,28 @@ class NTPClient {
byte _packetBuffer[NTP_PACKET_SIZE]; byte _packetBuffer[NTP_PACKET_SIZE];
void sendNTPPacket(); void sendNTPPacket();
bool isValid(byte * ntpPacket);
public: public:
NTPClient(UDP& udp); NTPClient(UDP& udp);
NTPClient(UDP& udp, int timeOffset); NTPClient(UDP& udp, long timeOffset);
NTPClient(UDP& udp, const char* poolServerName); NTPClient(UDP& udp, const char* poolServerName);
NTPClient(UDP& udp, const char* poolServerName, int timeOffset); NTPClient(UDP& udp, const char* poolServerName, long timeOffset);
NTPClient(UDP& udp, const char* poolServerName, int timeOffset, unsigned long updateInterval); NTPClient(UDP& udp, const char* poolServerName, long timeOffset, unsigned long updateInterval);
NTPClient(UDP& udp, IPAddress poolServerIP);
NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset);
NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset, unsigned long updateInterval);
/**
* Set time server name
*
* @param poolServerName
*/
void setPoolServerName(const char* poolServerName);
/**
* Set random local port
*/
void setRandomPort(unsigned int minValue = 49152, unsigned int maxValue = 65535);
/** /**
* Starts the underlying UDP client with the default local port * Starts the underlying UDP client with the default local port
...@@ -44,7 +57,7 @@ class NTPClient { ...@@ -44,7 +57,7 @@ class NTPClient {
/** /**
* Starts the underlying UDP client with the specified local port * Starts the underlying UDP client with the specified local port
*/ */
void begin(int port); void begin(unsigned int port);
/** /**
* This should be called in the main loop of your application. By default an update from the NTP Server is only * This should be called in the main loop of your application. By default an update from the NTP Server is only
...@@ -61,10 +74,17 @@ class NTPClient { ...@@ -61,10 +74,17 @@ class NTPClient {
*/ */
bool forceUpdate(); bool forceUpdate();
int getDay(); /**
int getHours(); * This allows to check if the NTPClient successfully received a NTP packet and set the time.
int getMinutes(); *
int getSeconds(); * @return true if time has been set, else false
*/
bool isTimeSet() const;
int getDay() const;
int getHours() const;
int getMinutes() const;
int getSeconds() const;
/** /**
* Changes the time offset. Useful for changing timezones dynamically * Changes the time offset. Useful for changing timezones dynamically
...@@ -78,28 +98,17 @@ class NTPClient { ...@@ -78,28 +98,17 @@ class NTPClient {
void setUpdateInterval(unsigned long updateInterval); void setUpdateInterval(unsigned long updateInterval);
/** /**
* @return secs argument (or 0 for current time) formatted like `hh:mm:ss` * @return time formatted like `hh:mm:ss`
*/ */
void getFormattedTime(char *formatted_time, unsigned long secs = 0); String getFormattedTime() const;
/** /**
* @return time in seconds since Jan. 1, 1970 * @return time in seconds since Jan. 1, 1970
*/ */
unsigned long getEpochTime(); unsigned long getEpochTime() const;
/**
* @return secs argument (or 0 for current date) formatted to ISO 8601
* like `2004-02-12T15:19:21+00:00`
*/
void getFormattedDate(char *formatted_date, unsigned long secs = 0);
/** /**
* Stops the underlying UDP client * Stops the underlying UDP client
*/ */
void end(); void end();
/**
* Replace the NTP-fetched time with seconds since Jan. 1, 1970
*/
void setEpochTime(unsigned long secs);
}; };
# NTPClient # NTPClient
[![Build Status](https://travis-ci.org/arduino-libraries/NTPClient.svg?branch=master)](https://travis-ci.org/arduino-libraries/NTPClient) [![Check Arduino status](https://github.com/arduino-libraries/NTPClient/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/arduino-libraries/NTPClient/actions/workflows/check-arduino.yml)
[![Compile Examples status](https://github.com/arduino-libraries/NTPClient/actions/workflows/compile-examples.yml/badge.svg)](https://github.com/arduino-libraries/NTPClient/actions/workflows/compile-examples.yml)
[![Spell Check status](https://github.com/arduino-libraries/NTPClient/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/NTPClient/actions/workflows/spell-check.yml)
Connect to a NTP server, here is how: Connect to a NTP server, here is how:
...@@ -22,7 +24,7 @@ WiFiUDP ntpUDP; ...@@ -22,7 +24,7 @@ WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP); NTPClient timeClient(ntpUDP);
// You can specify the time server pool and the offset, (in seconds) // You can specify the time server pool and the offset, (in seconds)
// additionaly you can specify the update interval (in milliseconds). // additionally you can specify the update interval (in milliseconds).
// NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000); // NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);
void setup(){ void setup(){
...@@ -45,3 +47,6 @@ void loop() { ...@@ -45,3 +47,6 @@ void loop() {
delay(1000); delay(1000);
} }
``` ```
## Function documentation
`getEpochTime` returns the Unix epoch, which are the seconds elapsed since 00:00:00 UTC on 1 January 1970 (leap seconds are ignored, every day is treated as having 86400 seconds). **Attention**: If you have set a time offset this time offset will be added to your epoch timestamp.
...@@ -12,9 +12,13 @@ begin KEYWORD2 ...@@ -12,9 +12,13 @@ begin KEYWORD2
end KEYWORD2 end KEYWORD2
update KEYWORD2 update KEYWORD2
forceUpdate KEYWORD2 forceUpdate KEYWORD2
isTimeSet KEYWORD2
getDay KEYWORD2 getDay KEYWORD2
getHours KEYWORD2 getHours KEYWORD2
getMinutes KEYWORD2 getMinutes KEYWORD2
getSeconds KEYWORD2 getSeconds KEYWORD2
getFormattedTime KEYWORD2 getFormattedTime KEYWORD2
getEpochTime KEYWORD2 getEpochTime KEYWORD2
setTimeOffset KEYWORD2
setUpdateInterval KEYWORD2
setPoolServerName KEYWORD2
name=NTPClient name=NTPClient
version=3.1.0 version=3.2.0
author=Fabrice Weinberg author=Fabrice Weinberg
maintainer=Fabrice Weinberg <fabrice@weinberg.me> maintainer=Fabrice Weinberg <fabrice@weinberg.me>
sentence=An NTPClient to connect to a time server sentence=An NTPClient to connect to a time server
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment