First Commit
This commit is contained in:
741
libraries/NtpClientLib/src/NTPClientLib.cpp
Normal file
741
libraries/NtpClientLib/src/NTPClientLib.cpp
Normal file
@@ -0,0 +1,741 @@
|
||||
/*
|
||||
Copyright 2016 German Martin (gmag11@gmail.com). All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met :
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
of conditions and the following disclaimer in the documentation and / or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those of the
|
||||
authors and should not be interpreted as representing official policies, either expressed
|
||||
or implied, of German Martin
|
||||
*/
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
#include "NtpClientLib.h"
|
||||
|
||||
#define DBG_PORT Serial
|
||||
|
||||
#ifdef DEBUG_NTPCLIENT
|
||||
#define DEBUGLOG(...) DBG_PORT.printf(__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUGLOG(...)
|
||||
#endif
|
||||
|
||||
NTPClient::NTPClient () {
|
||||
}
|
||||
|
||||
bool NTPClient::setNtpServerName (String ntpServerName) {
|
||||
uint8_t strLen = ntpServerName.length ();
|
||||
if (strLen > SERVER_NAME_LENGTH || strLen <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ntpServerName.toCharArray (_ntpServerName, SERVER_NAME_LENGTH);
|
||||
DEBUGLOG ("NTP server set to %s\n", _ntpServerName);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NTPClient::setNtpServerName (char* ntpServerName) {
|
||||
char *name = ntpServerName;
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
if (!strlen (name)) {
|
||||
return false;
|
||||
}
|
||||
DEBUGLOG ("NTP server set to %s\n", name);
|
||||
memset (_ntpServerName, 0, SERVER_NAME_LENGTH);
|
||||
strcpy (_ntpServerName, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
String NTPClient::getNtpServerName () {
|
||||
return String (_ntpServerName);
|
||||
}
|
||||
|
||||
char* NTPClient::getNtpServerNamePtr () {
|
||||
return _ntpServerName;
|
||||
}
|
||||
|
||||
bool NTPClient::setDSTZone (uint8_t dstZone) {
|
||||
if (dstZone < DST_ZONE_COUNT) {
|
||||
_dstZone = dstZone;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t NTPClient::getDSTZone () {
|
||||
return _dstZone;
|
||||
}
|
||||
|
||||
bool NTPClient::setTimeZone (int8_t timeZone, int8_t minutes) {
|
||||
if ((timeZone >= -12) && (timeZone <= 14) && (minutes >= -59) && (minutes <= 59)) {
|
||||
// Do the maths to change current time, but only if we are not yet sync'ed,
|
||||
// we don't want to trigger the UDP query with the now() below
|
||||
if (_lastSyncd > 0) {
|
||||
int8_t timeDiff = timeZone - _timeZone;
|
||||
int8_t minDiff = minutes - _minutesOffset;
|
||||
setTime (now () + timeDiff * SECS_PER_HOUR + minDiff * SECS_PER_MIN);
|
||||
}
|
||||
_timeZone = timeZone;
|
||||
_minutesOffset = minutes;
|
||||
DEBUGLOG ("NTP time zone set to: %d\r\n", timeZone);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if NETWORK_TYPE == NETWORK_W5100 || NETWORK_TYPE == NETWORK_WIFI101
|
||||
boolean sendNTPpacket (IPAddress address, UDP *udp) {
|
||||
uint8_t ntpPacketBuffer[NTP_PACKET_SIZE]; //Buffer to store request message
|
||||
|
||||
// set all bytes in the buffer to 0
|
||||
memset (ntpPacketBuffer, 0, NTP_PACKET_SIZE);
|
||||
// Initialize values needed to form NTP request
|
||||
// (see URL above for details on the packets)
|
||||
ntpPacketBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
ntpPacketBuffer[1] = 0; // Stratum, or type of clock
|
||||
ntpPacketBuffer[2] = 6; // Polling Interval
|
||||
ntpPacketBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
||||
ntpPacketBuffer[12] = 49;
|
||||
ntpPacketBuffer[13] = 0x4E;
|
||||
ntpPacketBuffer[14] = 49;
|
||||
ntpPacketBuffer[15] = 52;
|
||||
// all NTP fields have been given values, now
|
||||
// you can send a packet requesting a timestamp:
|
||||
udp->beginPacket (address, DEFAULT_NTP_PORT); //NTP requests are to port 123
|
||||
udp->write (ntpPacketBuffer, NTP_PACKET_SIZE);
|
||||
udp->endPacket ();
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t NTPClient::getTime () {
|
||||
IPAddress timeServerIP; //NTP server IP address
|
||||
uint8_t ntpPacketBuffer[NTP_PACKET_SIZE]; //Buffer to store response message
|
||||
|
||||
|
||||
DEBUGLOG ("Starting UDP\n");
|
||||
udp->begin (DEFAULT_NTP_PORT);
|
||||
//DEBUGLOG ("UDP port: %d\n",udp->localPort());
|
||||
while (udp->parsePacket () > 0); // discard any previously received packets
|
||||
#if NETWORK_TYPE == NETWORK_W5100
|
||||
DNSClient dns;
|
||||
dns.begin (Ethernet.dnsServerIP ());
|
||||
int8_t dnsResult = dns.getHostByName (getNtpServerName ().c_str (), timeServerIP);
|
||||
if (dnsResult <= 0) {
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (invalidAddress);
|
||||
return 0; // return 0 if unable to get the time
|
||||
}
|
||||
#else
|
||||
WiFi.hostByName (getNtpServerName ().c_str (), timeServerIP);
|
||||
#endif
|
||||
DEBUGLOG ("NTP Server IP: %s\r\n", timeServerIP.toString ().c_str ());
|
||||
sendNTPpacket (timeServerIP, udp);
|
||||
uint32_t beginWait = millis ();
|
||||
while (millis () - beginWait < ntpTimeout) {
|
||||
int size = udp->parsePacket ();
|
||||
if (size >= NTP_PACKET_SIZE) {
|
||||
DEBUGLOG ("-- Receive NTP Response\n");
|
||||
udp->read (ntpPacketBuffer, NTP_PACKET_SIZE); // read packet into the buffer
|
||||
time_t timeValue = decodeNtpMessage (ntpPacketBuffer);
|
||||
if (timeValue != 0) {
|
||||
setSyncInterval (getLongInterval ());
|
||||
if (!_firstSync) {
|
||||
// if (timeStatus () == timeSet)
|
||||
_firstSync = timeValue;
|
||||
}
|
||||
//getFirstSync (); // Set firstSync value if not set before
|
||||
DEBUGLOG ("Sync frequency set low\n");
|
||||
udp->stop ();
|
||||
setLastNTPSync (timeValue);
|
||||
DEBUGLOG ("Successful NTP sync at %s\n", getTimeDateString (getLastNTPSync ()).c_str ());
|
||||
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (timeSyncd);
|
||||
return timeValue;
|
||||
} else {
|
||||
DEBUGLOG ("-- No valid NTP data :-(\n");
|
||||
udp->stop ();
|
||||
setSyncInterval (getShortInterval ()); // Retry connection more often
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (noResponse);
|
||||
return 0; // return 0 if unable to get the time
|
||||
}
|
||||
}
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
ESP.wdtFeed ();
|
||||
yield ();
|
||||
#endif
|
||||
}
|
||||
DEBUGLOG ("-- No NTP Response :-(\n");
|
||||
udp->stop ();
|
||||
if (timeStatus () != timeSet) {
|
||||
setSyncInterval (getShortInterval ()); // Retry connection more often if sync is needed and we get no response
|
||||
}
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (noResponse);
|
||||
return 0; // return 0 if unable to get the time
|
||||
}
|
||||
#elif NETWORK_TYPE == NETWORK_ESP8266 || NETWORK_TYPE == NETWORK_ESP32
|
||||
void NTPClient::s_dnsFound (const char *name, const ip_addr_t *ipaddr, void *callback_arg) {
|
||||
reinterpret_cast<NTPClient*>(callback_arg)->dnsFound (ipaddr);
|
||||
}
|
||||
|
||||
#if NETWORK_TYPE == NETWORK_ESP8266
|
||||
IPAddress getIPClass (const ip_addr_t *ipaddr) {
|
||||
|
||||
if (!ipaddr) {
|
||||
DEBUGLOG ("%s - IP address not found\n", __FUNCTION__);
|
||||
return IPAddress (0, 0, 0, 0);
|
||||
}
|
||||
|
||||
IPAddress ip;
|
||||
#ifdef ESP8266
|
||||
ip = IPAddress (ipaddr->addr);
|
||||
#elif defined ESP32
|
||||
ip = IPAddress (ipaddr->u_addr.ip4.addr);
|
||||
#endif
|
||||
DEBUGLOG ("%s - IPAddress: %s\n", __FUNCTION__, ip.toString ().c_str ());
|
||||
return ip;
|
||||
}
|
||||
|
||||
void NTPClient::dnsFound (const ip_addr_t *ipaddr) {
|
||||
//IPAddress ip;
|
||||
|
||||
dnsStatus = DNS_SOLVED;
|
||||
responseTimer2.detach ();
|
||||
ntpServerIPAddress = getIPClass (ipaddr);
|
||||
DEBUGLOG ("%s - %s\n", __FUNCTION__, ntpServerIPAddress.toString ().c_str ());
|
||||
if (ipaddr != NULL && ntpServerIPAddress != (uint32_t)(0)) {
|
||||
time_t newTime = getTime();
|
||||
DEBUGLOG ("%s - Get time\n", __FUNCTION__);
|
||||
if (newTime) setTime(newTime);
|
||||
}
|
||||
}
|
||||
|
||||
void NTPClient::processDNSTimeout () {
|
||||
status = unsyncd;
|
||||
dnsStatus = DNS_IDLE;
|
||||
//timer1_disable ();
|
||||
responseTimer2.detach ();
|
||||
DEBUGLOG ("%s - DNS response Timeout\n", __FUNCTION__);
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (invalidAddress);
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR NTPClient::s_processDNSTimeout (void* arg) {
|
||||
reinterpret_cast<NTPClient*>(arg)->processDNSTimeout ();
|
||||
}
|
||||
#endif
|
||||
|
||||
time_t NTPClient::getTime () {
|
||||
//IPAddress ntpServerIPAddress; //NTP server IP address
|
||||
|
||||
#if NETWORK_TYPE == NETWORK_ESP8266
|
||||
err_t error = ERR_OK;
|
||||
uint16_t dnsTimeout = 5000;
|
||||
ip_addr_t ipaddress;
|
||||
//char ntpPacketBuffer[NTP_PACKET_SIZE]; //Buffer to store response message
|
||||
DEBUGLOG ("%s\n", __FUNCTION__);
|
||||
//timeServerIP = IPAddress (ipaddress.addr); // ip address format conversion test
|
||||
//ipaddress.addr = (uint32_t)timeServerIP;
|
||||
if (dnsStatus == DNS_IDLE)
|
||||
{
|
||||
DEBUGLOG ("%s - Resolving DNS of %s\n", __FUNCTION__, getNtpServerName ().c_str ());
|
||||
error = dns_gethostbyname (getNtpServerName ().c_str (), &ipaddress, (dns_found_callback)&s_dnsFound, this);
|
||||
DEBUGLOG ("%s - DNS result: %d\n", __FUNCTION__, (int)error);
|
||||
if (error == ERR_INPROGRESS) {
|
||||
dnsStatus = DNS_REQUESTED;
|
||||
DEBUGLOG ("%s - DNS Resolution in progress\n", __FUNCTION__);
|
||||
responseTimer2.once_ms (dnsTimeout, &NTPClient::s_processDNSTimeout, static_cast<void*>(this));
|
||||
return 0;
|
||||
} else if (error == ERR_OK) {
|
||||
dnsStatus = DNS_SOLVED;
|
||||
ntpServerIPAddress = getIPClass (&ipaddress);
|
||||
} else {
|
||||
DEBUGLOG ("%s - DNS Resolution error\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
DEBUGLOG ("%s - DNS name IP solved: %s\n", __FUNCTION__, ntpServerIPAddress.toString ().c_str ());
|
||||
if (error == ERR_OK && dnsStatus == DNS_SOLVED) {
|
||||
dnsStatus = DNS_IDLE;
|
||||
#elif NETWORK_TYPE == NETWORK_ESP32
|
||||
int error = WiFi.hostByName (getNtpServerName ().c_str (), ntpServerIPAddress);
|
||||
if (error) {
|
||||
#endif
|
||||
DEBUGLOG ("%s - Starting UDP. IP: %s\n", __FUNCTION__, ntpServerIPAddress.toString ().c_str ());
|
||||
if (ntpServerIPAddress == (uint32_t)(0)) {
|
||||
DEBUGLOG ("%s - IP address unset. Aborting.\n", __FUNCTION__);
|
||||
//DEBUGLOG ("%s - DNS Status: %d\n", __FUNCTION__, dnsStatus);
|
||||
return 0;
|
||||
}
|
||||
if (udp->connect (ntpServerIPAddress, DEFAULT_NTP_PORT)) {
|
||||
udp->onPacket (std::bind (&NTPClient::processPacket, this, _1));
|
||||
DEBUGLOG ("%s - Sending UDP packet\n", __FUNCTION__);
|
||||
if (sendNTPpacket (udp)) {
|
||||
DEBUGLOG ("%s - NTP request sent\n", __FUNCTION__);
|
||||
status = ntpRequested;
|
||||
responseTimer.once_ms (ntpTimeout, &NTPClient::s_processRequestTimeout, static_cast<void*>(this));
|
||||
/*timer1_attachInterrupt (s_processRequestTimeout);
|
||||
timer1_enable (TIM_DIV256, TIM_EDGE, TIM_SINGLE);
|
||||
timer1_write ((uint32_t)(312.5*ntpTimeout));*/
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (requestSent);
|
||||
return 0;
|
||||
} else {
|
||||
DEBUGLOG ("%s - NTP request error\n", __FUNCTION__);
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (errorSending);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (noResponse);
|
||||
return 0; // return 0 if unable to get the time
|
||||
}
|
||||
} else {
|
||||
DEBUGLOG ("%s - HostByName error %d\n", __FUNCTION__, (int)error);
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (invalidAddress);
|
||||
return 0; // return 0 if unable to get the time
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void dumpNTPPacket (byte *data, size_t length) {
|
||||
//byte *data = packet.data ();
|
||||
//size_t length = packet.length ();
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
DEBUGLOG ("%02X ", data[i]);
|
||||
if ((i + 1) % 16 == 0) {
|
||||
DEBUGLOG ("\n");
|
||||
} else if ((i + 1) % 4 == 0) {
|
||||
DEBUGLOG ("| ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean NTPClient::sendNTPpacket (AsyncUDP *udp) {
|
||||
AsyncUDPMessage ntpPacket = AsyncUDPMessage ();
|
||||
|
||||
uint8_t ntpPacketBuffer[NTP_PACKET_SIZE]; //Buffer to store request message
|
||||
// set all bytes in the buffer to 0
|
||||
memset (ntpPacketBuffer, 0, NTP_PACKET_SIZE);
|
||||
// Initialize values needed to form NTP request
|
||||
// (see URL above for details on the packets)
|
||||
ntpPacketBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
ntpPacketBuffer[1] = 0; // Stratum, or type of clock
|
||||
ntpPacketBuffer[2] = 6; // Polling Interval
|
||||
ntpPacketBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
||||
ntpPacketBuffer[12] = 49;
|
||||
ntpPacketBuffer[13] = 0x4E;
|
||||
ntpPacketBuffer[14] = 49;
|
||||
ntpPacketBuffer[15] = 52;
|
||||
// all NTP fields have been given values, now
|
||||
// you can send a packet requesting a timestamp:
|
||||
ntpPacket.write (ntpPacketBuffer, NTP_PACKET_SIZE);
|
||||
if (udp->send (ntpPacket)) {
|
||||
DEBUGLOG ("\n");
|
||||
dumpNTPPacket (ntpPacket.data (), ntpPacket.length ());
|
||||
DEBUGLOG ("\nUDP packet sent\n");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void NTPClient::processPacket (AsyncUDPPacket& packet) {
|
||||
uint8_t *ntpPacketBuffer;
|
||||
int size;
|
||||
|
||||
if (status == ntpRequested) {
|
||||
size = packet.length ();
|
||||
if (size >= NTP_PACKET_SIZE) {
|
||||
//timer1_disable ();
|
||||
responseTimer.detach ();
|
||||
ntpPacketBuffer = packet.data ();
|
||||
time_t timeValue = decodeNtpMessage (ntpPacketBuffer);
|
||||
setTime (timeValue);
|
||||
status = syncd;
|
||||
setSyncInterval (getLongInterval ());
|
||||
if (!_firstSync) {
|
||||
// if (timeStatus () == timeSet)
|
||||
_firstSync = timeValue;
|
||||
}
|
||||
setLastNTPSync (timeValue);
|
||||
DEBUGLOG ("Sync frequency set low\n");
|
||||
DEBUGLOG ("Successful NTP sync at %s\n", getTimeDateString (getLastNTPSync ()).c_str ());
|
||||
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (timeSyncd);
|
||||
} else {
|
||||
DEBUGLOG ("Response Error\n");
|
||||
status = unsyncd;
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (responseError);
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUGLOG ("Unrequested response\n");
|
||||
}
|
||||
|
||||
DEBUGLOG ("UDP packet received\n");
|
||||
DEBUGLOG ("UDP Packet Type: %s, From: %s:%d, To: %s:%d, Length: %u, Data:\n\n",
|
||||
packet.isBroadcast () ? "Broadcast" : packet.isMulticast () ? "Multicast" : "Unicast",
|
||||
packet.remoteIP ().toString ().c_str (),
|
||||
packet.remotePort (),
|
||||
packet.localIP ().toString ().c_str (),
|
||||
packet.localPort (),
|
||||
packet.length ());
|
||||
//reply to the client
|
||||
dumpNTPPacket (packet.data (), packet.length ());
|
||||
DEBUGLOG ("\n");
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR NTPClient::processRequestTimeout () {
|
||||
status = unsyncd;
|
||||
//timer1_disable ();
|
||||
responseTimer.detach ();
|
||||
DEBUGLOG ("NTP response Timeout\n");
|
||||
if (onSyncEvent)
|
||||
onSyncEvent (noResponse);
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR NTPClient::s_processRequestTimeout (void* arg) {
|
||||
NTPClient* self = reinterpret_cast<NTPClient*>(arg);
|
||||
self->processRequestTimeout ();
|
||||
}
|
||||
#endif
|
||||
|
||||
int8_t NTPClient::getTimeZone () {
|
||||
return _timeZone;
|
||||
}
|
||||
|
||||
int8_t NTPClient::getTimeZoneMinutes () {
|
||||
return _minutesOffset;
|
||||
}
|
||||
|
||||
/*void NTPClient::setLastNTPSync(time_t moment) {
|
||||
_lastSyncd = moment;
|
||||
}*/
|
||||
|
||||
time_t NTPClient::s_getTime () {
|
||||
return NTP.getTime ();
|
||||
}
|
||||
|
||||
#if NETWORK_TYPE == NETWORK_W5100
|
||||
bool NTPClient::begin (String ntpServerName, int8_t timeZone, bool daylight, int8_t minutes, EthernetUDP* udp_conn) {
|
||||
#elif NETWORK_TYPE == NETWORK_WIFI101
|
||||
bool NTPClient::begin (String ntpServerName, int8_t timeZone, bool daylight, int8_t minutes, WiFiUDP* udp_conn) {
|
||||
#elif NETWORK_TYPE == NETWORK_ESP8266 || NETWORK_TYPE == NETWORK_ESP32
|
||||
bool NTPClient::begin (String ntpServerName, int8_t timeZone, bool daylight, int8_t minutes, AsyncUDP* udp_conn) {
|
||||
#endif
|
||||
if (!setNtpServerName (ntpServerName)) {
|
||||
DEBUGLOG ("Time sync not started\r\n");
|
||||
return false;
|
||||
}
|
||||
if (!setTimeZone (timeZone, minutes)) {
|
||||
DEBUGLOG ("Time sync not started\r\n");
|
||||
return false;
|
||||
}
|
||||
if (udp_conn) {
|
||||
udp = udp_conn;
|
||||
} else if (!udp) { // Check if upd connection was already created
|
||||
#if NETWORK_TYPE == NETWORK_W5100
|
||||
udp = new EthernetUDP ();
|
||||
#elif NETWORK_TYPE == NETWORK_WIFI101
|
||||
udp = new WiFiUDP ();
|
||||
#else
|
||||
udp = new AsyncUDP ();
|
||||
#endif
|
||||
}
|
||||
|
||||
//_timeZone = timeZone;
|
||||
setDayLight (daylight);
|
||||
_lastSyncd = 0;
|
||||
|
||||
if (_shortInterval == 0 && _longInterval == 0) {
|
||||
if (!setInterval (DEFAULT_NTP_SHORTINTERVAL, DEFAULT_NTP_INTERVAL)) {
|
||||
DEBUGLOG ("Time sync not started\r\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DEBUGLOG ("Time sync started\r\n");
|
||||
|
||||
setSyncInterval (getShortInterval ());
|
||||
setSyncProvider (s_getTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NTPClient::~NTPClient () {
|
||||
stop ();
|
||||
}
|
||||
|
||||
bool NTPClient::stop () {
|
||||
setSyncProvider (NULL);
|
||||
// Free up connection resources
|
||||
if (udp) {
|
||||
#if NETWORK_TYPE == NETWORK_ESP8266 || NETWORK_TYPE == NETWORK_ESP32
|
||||
udp->close ();
|
||||
#else
|
||||
udp->stop ();
|
||||
#endif
|
||||
delete (udp);
|
||||
udp = 0;
|
||||
}
|
||||
DEBUGLOG ("Time sync disabled\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NTPClient::setInterval (int interval) {
|
||||
if (interval >= 10) {
|
||||
if (_longInterval != interval) {
|
||||
_longInterval = interval;
|
||||
DEBUGLOG ("Sync interval set to %d\n", interval);
|
||||
if (timeStatus () == timeSet)
|
||||
setSyncInterval (interval);
|
||||
}
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NTPClient::setInterval (int shortInterval, int longInterval) {
|
||||
if (shortInterval >= 10 && longInterval >= 10) {
|
||||
_shortInterval = shortInterval;
|
||||
_longInterval = longInterval;
|
||||
if (timeStatus () != timeSet) {
|
||||
setSyncInterval (shortInterval);
|
||||
} else {
|
||||
setSyncInterval (longInterval);
|
||||
}
|
||||
DEBUGLOG ("Short sync interval set to %d\n", shortInterval);
|
||||
DEBUGLOG ("Long sync interval set to %d\n", longInterval);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
int NTPClient::getInterval () {
|
||||
return _longInterval;
|
||||
}
|
||||
|
||||
int NTPClient::getShortInterval () {
|
||||
return _shortInterval;
|
||||
}
|
||||
|
||||
void NTPClient::setDayLight (bool daylight) {
|
||||
|
||||
// Do the maths to change current time, but only if we are not yet sync'ed,
|
||||
// we don't want to trigger the UDP query with the now() below
|
||||
if (_lastSyncd > 0) {
|
||||
if ((_daylight != daylight) && isSummerTimePeriod (now ())) {
|
||||
if (daylight) {
|
||||
setTime (now () + SECS_PER_HOUR);
|
||||
} else {
|
||||
setTime (now () - SECS_PER_HOUR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_daylight = daylight;
|
||||
DEBUGLOG ("--Set daylight saving %s\n", daylight ? "ON" : "OFF");
|
||||
|
||||
}
|
||||
|
||||
bool NTPClient::getDayLight () {
|
||||
return _daylight;
|
||||
}
|
||||
|
||||
String NTPClient::getTimeStr (time_t moment) {
|
||||
char timeStr[10];
|
||||
sprintf (timeStr, "%02d:%02d:%02d", hour (moment), minute (moment), second (moment));
|
||||
|
||||
return timeStr;
|
||||
}
|
||||
|
||||
String NTPClient::getDateStr (time_t moment) {
|
||||
char dateStr[12];
|
||||
sprintf (dateStr, "%02d/%02d/%4d", day (moment), month (moment), year (moment));
|
||||
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
String NTPClient::getTimeDateString (time_t moment) {
|
||||
return getTimeStr (moment) + " " + getDateStr (moment);
|
||||
}
|
||||
|
||||
time_t NTPClient::getLastNTPSync () {
|
||||
return _lastSyncd;
|
||||
}
|
||||
|
||||
void NTPClient::onNTPSyncEvent (onSyncEvent_t handler) {
|
||||
onSyncEvent = handler;
|
||||
}
|
||||
|
||||
time_t NTPClient::getUptime () {
|
||||
_uptime = _uptime + (millis () - _uptime);
|
||||
return _uptime / 1000;
|
||||
}
|
||||
|
||||
String NTPClient::getUptimeString () {
|
||||
uint16_t days;
|
||||
uint8_t hours;
|
||||
uint8_t minutes;
|
||||
uint8_t seconds;
|
||||
|
||||
time_t uptime = getUptime ();
|
||||
|
||||
seconds = uptime % SECS_PER_MIN;
|
||||
uptime -= seconds;
|
||||
minutes = (uptime % SECS_PER_HOUR) / SECS_PER_MIN;
|
||||
uptime -= minutes * SECS_PER_MIN;
|
||||
hours = (uptime % SECS_PER_DAY) / SECS_PER_HOUR;
|
||||
uptime -= hours * SECS_PER_HOUR;
|
||||
days = uptime / SECS_PER_DAY;
|
||||
|
||||
char uptimeStr[20];
|
||||
sprintf (uptimeStr, "%4u days %02d:%02d:%02d", days, hours, minutes, seconds);
|
||||
|
||||
return uptimeStr;
|
||||
}
|
||||
|
||||
time_t NTPClient::getLastBootTime () {
|
||||
if (timeStatus () == timeSet) {
|
||||
return (now () - getUptime ());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_t NTPClient::getFirstSync () {
|
||||
/*if (!_firstSync) {
|
||||
if (timeStatus () == timeSet) {
|
||||
_firstSync = now () - getUptime ();
|
||||
}
|
||||
}*/
|
||||
return _firstSync;
|
||||
}
|
||||
|
||||
bool NTPClient::summertime (int year, byte month, byte day, byte hour, byte weekday, byte tzHours)
|
||||
// input parameters: "normal time" for year, month, day, hour, weekday and tzHours (0=UTC, 1=MEZ)
|
||||
{
|
||||
if (DST_ZONE_EU == _dstZone) {
|
||||
if ((month < 3) || (month > 10)) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
|
||||
if ((month > 3) && (month < 10)) return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
|
||||
if ((month == 3 && ((hour + 24 * day) >= (1 + tzHours + 24 * (31 - (5 * year / 4 + 4) % 7)))) || ((month == 10 && (hour + 24 * day) < (1 + tzHours + 24 * (31 - (5 * year / 4 + 1) % 7)))))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DST_ZONE_USA == _dstZone) {
|
||||
|
||||
// always false for Jan, Feb and Dec
|
||||
if ((month < 3) || (month > 11)) return false;
|
||||
|
||||
// always true from Apr to Oct
|
||||
if ((month > 3) && (month < 11)) return true;
|
||||
|
||||
// first sunday of current month
|
||||
uint8_t first_sunday = (7 + day - weekday) % 7 + 1;
|
||||
|
||||
// Starts at 2:00 am on the second sunday of Mar
|
||||
if (3 == month) {
|
||||
if (day < 7 + first_sunday) return false;
|
||||
if (day > 7 + first_sunday) return true;
|
||||
return (hour > 2);
|
||||
}
|
||||
|
||||
// Ends a 2:00 am on the first sunday of Nov
|
||||
// We are only getting here if its Nov
|
||||
if (day < first_sunday) return true;
|
||||
if (day > first_sunday) return false;
|
||||
return (hour < 2);
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
boolean NTPClient::isSummerTimePeriod (time_t moment) {
|
||||
return summertime (year (), month (), day (), hour (), weekday (), getTimeZone ());
|
||||
}
|
||||
|
||||
void NTPClient::setLastNTPSync (time_t moment) {
|
||||
_lastSyncd = moment;
|
||||
}
|
||||
|
||||
uint16_t NTPClient::getNTPTimeout () {
|
||||
return ntpTimeout;
|
||||
}
|
||||
|
||||
boolean NTPClient::setNTPTimeout (uint16_t milliseconds) {
|
||||
|
||||
if (milliseconds >= MIN_NTP_TIMEOUT) {
|
||||
ntpTimeout = milliseconds;
|
||||
DEBUGLOG ("Set NTP timeout to %u ms\n", milliseconds);
|
||||
return true;
|
||||
}
|
||||
DEBUGLOG ("NTP timeout should be higher than %u ms. You've tried to set %u ms\n", MIN_NTP_TIMEOUT, milliseconds);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
time_t NTPClient::decodeNtpMessage (uint8_t *messageBuffer) {
|
||||
unsigned long secsSince1900;
|
||||
// convert four bytes starting at location 40 to a long integer
|
||||
secsSince1900 = (unsigned long)messageBuffer[40] << 24;
|
||||
secsSince1900 |= (unsigned long)messageBuffer[41] << 16;
|
||||
secsSince1900 |= (unsigned long)messageBuffer[42] << 8;
|
||||
secsSince1900 |= (unsigned long)messageBuffer[43];
|
||||
|
||||
DEBUGLOG ("Secs: %lu \n", secsSince1900);
|
||||
|
||||
if (secsSince1900 == 0) {
|
||||
DEBUGLOG ("--Timestamp is Zero\n");
|
||||
return 0;
|
||||
}
|
||||
#define SEVENTY_YEARS 2208988800UL
|
||||
time_t timeTemp = secsSince1900 - SEVENTY_YEARS + _timeZone * SECS_PER_HOUR + _minutesOffset * SECS_PER_MIN;
|
||||
|
||||
if (_daylight) {
|
||||
if (summertime (year (timeTemp), month (timeTemp), day (timeTemp), hour (timeTemp), weekday (timeTemp), _timeZone)) {
|
||||
timeTemp += SECS_PER_HOUR;
|
||||
DEBUGLOG ("Summer Time\n");
|
||||
} else {
|
||||
DEBUGLOG ("Winter Time\n");
|
||||
}
|
||||
} else {
|
||||
DEBUGLOG ("No daylight\n");
|
||||
}
|
||||
return timeTemp;
|
||||
}
|
||||
|
||||
NTPClient NTP;
|
||||
537
libraries/NtpClientLib/src/NtpClientLib.h
Normal file
537
libraries/NtpClientLib/src/NtpClientLib.h
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
Copyright 2016 German Martin (gmag11@gmail.com). All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met :
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
of conditions and the following disclaimer in the documentation and / or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those of the
|
||||
authors and should not be interpreted as representing official policies, either expressed
|
||||
or implied, of German Martin
|
||||
*/
|
||||
/*
|
||||
Name: NtpClientLib
|
||||
Created: 17/08/2016
|
||||
Author: Germán Martín (gmag11@gmail.com)
|
||||
Maintainer:Germán Martín (gmag11@gmail.com)
|
||||
Editor: http://www.visualmicro.com
|
||||
|
||||
Library to get system sync from a NTP server
|
||||
*/
|
||||
|
||||
#ifndef _NtpClientLib_h
|
||||
#define _NtpClientLib_h
|
||||
|
||||
//#define DEBUG_NTPCLIENT //Uncomment this to enable debug messages over serial port
|
||||
|
||||
#if defined ESP8266 || defined ESP32
|
||||
#include <functional>
|
||||
using namespace std;
|
||||
using namespace placeholders;
|
||||
|
||||
extern "C" {
|
||||
#include "lwip/init.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/dns.h"
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <TimeLib.h>
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#define NETWORK_W5100 (1) // Arduino Ethernet Shield
|
||||
#define NETWORK_ENC28J60 (2) // Alternate Ethernet Shield
|
||||
#define NETWORK_WIFI101 (3) // WiFi Shield 101 or MKR1000
|
||||
#define NETWORK_ESP8266 (100) // ESP8266 boards, not for Arduino using AT firmware
|
||||
#define NETWORK_ESP32 (101) // ESP32 boards
|
||||
|
||||
#define DEFAULT_NTP_SERVER "pool.ntp.org" // Default international NTP server. I recommend you to select a closer server to get better accuracy
|
||||
#define DEFAULT_NTP_PORT 123 // Default local udp port. Select a different one if neccesary (usually not needed)
|
||||
#define DEFAULT_NTP_INTERVAL 1800 // Default sync interval 30 minutes
|
||||
#define DEFAULT_NTP_SHORTINTERVAL 15 // Sync interval when sync has not been achieved. 15 seconds
|
||||
#define DEFAULT_NTP_TIMEZONE 0 // Select your local time offset. 0 if UTC time has to be used
|
||||
#define MIN_NTP_TIMEOUT 100 // Minumum admisible ntp timeout
|
||||
|
||||
#define DST_ZONE_EU (0)
|
||||
#define DST_ZONE_USA (1)
|
||||
#define DST_ZONE_COUNT (2)
|
||||
#define DEFAULT_DST_ZONE DST_ZONE_EU
|
||||
|
||||
#define SERVER_NAME_LENGTH 40
|
||||
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
#define NETWORK_TYPE NETWORK_ESP8266
|
||||
#elif defined ARDUINO_ARCH_SAMD || defined ARDUINO_ARCH_ARC32
|
||||
#define NETWORK_TYPE NETWORK_WIFI101 // SET YOUR NETWORK INTERFACE
|
||||
#elif defined ARDUINO_ARCH_AVR
|
||||
#define NETWORK_TYPE NETWORK_W5100
|
||||
#elif defined ARDUINO_ARCH_ESP32 || defined ESP32
|
||||
#define NETWORK_TYPE NETWORK_ESP32
|
||||
#endif
|
||||
|
||||
#if NETWORK_TYPE == NETWORK_W5100
|
||||
//#include <SPI.h>
|
||||
#include <EthernetUdp.h>
|
||||
#include <Ethernet.h>
|
||||
#include <Dns.h>
|
||||
//#include <Dhcp.h>
|
||||
#elif NETWORK_TYPE == NETWORK_WIFI101
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <WiFi101.h>
|
||||
#elif NETWORK_TYPE == NETWORK_ESP8266
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncUDP.h>
|
||||
#include <Ticker.h>
|
||||
#elif NETWORK_TYPE == NETWORK_ESP32
|
||||
#include <WiFi.h>
|
||||
#include <AsyncUDP.h>
|
||||
#include <Ticker.h>
|
||||
#else
|
||||
#error "Incorrect platform. Only ARDUINO and ESP8266 MCUs are valid."
|
||||
#endif // NETWORK_TYPE
|
||||
|
||||
typedef enum NTPSyncEvent {
|
||||
timeSyncd = 0, // Time successfully got from NTP server
|
||||
noResponse = -1, // No response from server
|
||||
invalidAddress = -2, // Address not reachable
|
||||
#if NETWORK_TYPE == NETWORK_ESP8266 || NETWORK_TYPE == NETWORK_ESP32
|
||||
requestSent = 1, // NTP request sent, waiting for response
|
||||
errorSending = -3, // An error happened while sending the request
|
||||
responseError = -4, // Wrong response received
|
||||
#endif
|
||||
} NTPSyncEvent_t;
|
||||
|
||||
#if NETWORK_TYPE == NETWORK_ESP8266 || NETWORK_TYPE == NETWORK_ESP32
|
||||
typedef enum NTPStatus {
|
||||
syncd = 0, // Time synchronized correctly
|
||||
unsyncd = -1, // Time may not be valid
|
||||
ntpRequested = 1, // NTP request sent, waiting for response
|
||||
} NTPStatus_t; // Only for internal library use
|
||||
|
||||
typedef enum DNSStatus {
|
||||
DNS_IDLE = 0, // Idle state
|
||||
DNS_REQUESTED = 1, // DNS resolution requested, waiting for response
|
||||
DNS_SOLVED = 2,
|
||||
} DNSStatus_t; // Only for internal library use//
|
||||
#endif
|
||||
|
||||
#if defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32
|
||||
#include <functional>
|
||||
typedef std::function<void (NTPSyncEvent_t)> onSyncEvent_t;
|
||||
#else
|
||||
typedef void (*onSyncEvent_t)(NTPSyncEvent_t);
|
||||
#endif
|
||||
|
||||
class NTPClient {
|
||||
public:
|
||||
/**
|
||||
* Construct NTP client.
|
||||
*/
|
||||
NTPClient ();
|
||||
|
||||
/**
|
||||
* NTP client Class destructor
|
||||
*/
|
||||
~NTPClient ();
|
||||
|
||||
/**
|
||||
* Starts time synchronization.
|
||||
* @param[in] NTP server name as String.
|
||||
* @param[in] Time offset from UTC.
|
||||
* @param[in] true if this time zone has dayligth saving.
|
||||
* @param[in] Minutes offset added to hourly offset (optional).
|
||||
* @param[in] UDP connection instance (optional).
|
||||
* @param[out] true if everything went ok.
|
||||
*/
|
||||
#if NETWORK_TYPE == NETWORK_W5100
|
||||
bool begin (String ntpServerName = DEFAULT_NTP_SERVER, int8_t timeOffset = DEFAULT_NTP_TIMEZONE, bool daylight = false, int8_t minutes = 0, EthernetUDP* udp_conn = NULL);
|
||||
#elif NETWORK_TYPE == NETWORK_WIFI101
|
||||
bool begin (String ntpServerName = DEFAULT_NTP_SERVER, int8_t timeOffset = DEFAULT_NTP_TIMEZONE, bool daylight = false, int8_t minutes = 0, WiFiUDP* udp_conn = NULL);
|
||||
#elif NETWORK_TYPE == NETWORK_ESP8266 || NETWORK_TYPE == NETWORK_ESP32
|
||||
bool begin (String ntpServerName = DEFAULT_NTP_SERVER, int8_t timeOffset = DEFAULT_NTP_TIMEZONE, bool daylight = false, int8_t minutes = 0, AsyncUDP* udp_conn = NULL);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets NTP server name.
|
||||
* @param[in] New NTP server name.
|
||||
* @param[out] True if everything went ok.
|
||||
*/
|
||||
bool setNtpServerName (String ntpServerName);
|
||||
bool setNtpServerName (char* ntpServerName);
|
||||
|
||||
/**
|
||||
* Sets NTP server name. DEPRECATED, only for compatibility with older versions
|
||||
* @param[in] New NTP server name.
|
||||
* @param[in] Server index (0-2).
|
||||
* @param[out] True if everything went ok.
|
||||
*/
|
||||
bool setNtpServerName (String ntpServerName, int idx) {
|
||||
if (idx < 0 || idx > 2)
|
||||
return false;
|
||||
return setNtpServerName (ntpServerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets NTP server name
|
||||
* @param[out] NTP server name.
|
||||
*/
|
||||
String getNtpServerName ();
|
||||
|
||||
/**
|
||||
* Gets NTP server name in char array format
|
||||
* @param[out] NTP server name.
|
||||
*/
|
||||
char* getNtpServerNamePtr ();
|
||||
|
||||
/**
|
||||
* Gets NTP server name. DEPRECATED, only for compatibility with older versions
|
||||
* @param[in] Server index (0-2).
|
||||
* @param[out] NTP server name.
|
||||
*/
|
||||
String getNtpServerName (int idx) {
|
||||
if (idx < 0 || idx > 2)
|
||||
return "";
|
||||
return getNtpServerName ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a NTP time request to server. Returns a time in UNIX time format. Normally only called from library.
|
||||
* Kept in public section to allow direct NTP request.
|
||||
* @param[out] Time in UNIX time format.
|
||||
*/
|
||||
time_t getTime ();
|
||||
|
||||
/**
|
||||
* Sets timezone.
|
||||
* @param[in] New time offset in hours (-11 <= timeZone <= +13).
|
||||
* @param[out] True if everything went ok.
|
||||
*/
|
||||
bool setTimeZone (int8_t timeZone, int8_t minutes = 0);
|
||||
|
||||
/**
|
||||
* Gets timezone.
|
||||
* @param[out] Time offset in hours (plus or minus).
|
||||
*/
|
||||
int8_t getTimeZone ();
|
||||
|
||||
/**
|
||||
* Gets minutes fraction of timezone.
|
||||
* @param[out] Minutes offset (plus or minus) added to hourly offset.
|
||||
*/
|
||||
int8_t getTimeZoneMinutes ();
|
||||
|
||||
/**
|
||||
* Sets DST zone.
|
||||
* @param[in] New DST zone (DST_ZONE_EU || DST_ZONE_USA).
|
||||
* @param[out] True if everything went ok.
|
||||
*/
|
||||
bool setDSTZone (uint8_t dstZone);
|
||||
|
||||
/**
|
||||
* Gets DST zone.
|
||||
* @param[out] DST zone.
|
||||
*/
|
||||
uint8_t getDSTZone ();
|
||||
|
||||
/**
|
||||
* Stops time synchronization.
|
||||
* @param[out] True if everything went ok.
|
||||
*/
|
||||
bool stop ();
|
||||
|
||||
/**
|
||||
* Changes sync period.
|
||||
* @param[in] New interval in seconds.
|
||||
* @param[out] True if everything went ok.
|
||||
*/
|
||||
bool setInterval (int interval);
|
||||
|
||||
/**
|
||||
* Changes sync period in sync'd and not sync'd status.
|
||||
* @param[in] New interval while time is not first adjusted yet, in seconds.
|
||||
* @param[in] New interval for normal operation, in seconds.
|
||||
* @param[out] True if everything went ok.
|
||||
*/
|
||||
bool setInterval (int shortInterval, int longInterval);
|
||||
|
||||
/**
|
||||
* Gets sync period.
|
||||
* @param[out] Interval for normal operation, in seconds.
|
||||
*/
|
||||
int getInterval ();
|
||||
|
||||
/**
|
||||
* Changes sync period not sync'd status.
|
||||
* @param[out] Interval while time is not first adjusted yet, in seconds.
|
||||
*/
|
||||
int getShortInterval ();
|
||||
|
||||
/**
|
||||
* Gets sync period.
|
||||
* @param[out] Interval for normal operation in seconds.
|
||||
*/
|
||||
int getLongInterval () { return getInterval (); }
|
||||
|
||||
/**
|
||||
* Set daylight time saving option.
|
||||
* @param[in] true is daylight time savings apply.
|
||||
*/
|
||||
void setDayLight (bool daylight);
|
||||
|
||||
/**
|
||||
* Get daylight time saving option.
|
||||
* @param[out] true is daylight time savings apply.
|
||||
*/
|
||||
bool getDayLight ();
|
||||
|
||||
/**
|
||||
* Convert current time to a String.
|
||||
* @param[out] String constructed from current time.
|
||||
* TODO: Add internationalization support
|
||||
*/
|
||||
String getTimeStr () { return getTimeStr (now ()); }
|
||||
|
||||
/**
|
||||
* Convert a time in UNIX format to a String representing time.
|
||||
* @param[out] String constructed from current time.
|
||||
* @param[in] time_t object to convert to extract time.
|
||||
* TODO: Add internationalization support
|
||||
*/
|
||||
String getTimeStr (time_t moment);
|
||||
|
||||
/**
|
||||
* Convert current date to a String.
|
||||
* @param[out] String constructed from current date.
|
||||
* TODO: Add internationalization support
|
||||
*/
|
||||
String getDateStr () { return getDateStr (now ()); }
|
||||
|
||||
/**
|
||||
* Convert a time in UNIX format to a String representing its date.
|
||||
* @param[out] String constructed from current date.
|
||||
* @param[in] time_t object to convert to extract date.
|
||||
* TODO: Add internationalization support
|
||||
*/
|
||||
String getDateStr (time_t moment);
|
||||
|
||||
/**
|
||||
* Convert current time and date to a String.
|
||||
* @param[out] String constructed from current time.
|
||||
* TODO: Add internationalization support
|
||||
*/
|
||||
String getTimeDateString () { return getTimeDateString (now ()); }
|
||||
|
||||
/**
|
||||
* Convert current time and date to a String.
|
||||
* @param[in] time_t object to convert to String.
|
||||
* @param[out] String constructed from current time.
|
||||
* TODO: Add internationalization support
|
||||
*/
|
||||
String getTimeDateString (time_t moment);
|
||||
|
||||
/**
|
||||
* Gets last successful sync time in UNIX format.
|
||||
* @param[out] Last successful sync time. 0 equals never.
|
||||
*/
|
||||
time_t getLastNTPSync ();
|
||||
|
||||
/**
|
||||
* Get uptime in human readable String format.
|
||||
* @param[out] Uptime.
|
||||
*/
|
||||
String getUptimeString ();
|
||||
|
||||
/**
|
||||
* Get uptime in UNIX format, time since MCU was last rebooted.
|
||||
* @param[out] Uptime. 0 equals never.
|
||||
*/
|
||||
time_t getUptime ();
|
||||
|
||||
/**
|
||||
* Get first boot time in UNIX format, time when MCU was last rebooted.
|
||||
* @param[out] Uptime. 0 equals never.
|
||||
*/
|
||||
time_t getLastBootTime ();
|
||||
|
||||
/**
|
||||
* Get first successful synchronization time after boot.
|
||||
* @param[out] First sync time.
|
||||
*/
|
||||
time_t getFirstSync ();
|
||||
|
||||
/**
|
||||
* Get configured response timeout for NTP requests.
|
||||
* @param[out] NTP Timeout.
|
||||
*/
|
||||
uint16_t getNTPTimeout ();
|
||||
|
||||
/**
|
||||
* Configure response timeout for NTP requests.
|
||||
* @param[out] error code. false if faulty.
|
||||
*/
|
||||
boolean setNTPTimeout (uint16_t milliseconds);
|
||||
|
||||
/**
|
||||
* Set a callback that triggers after a sync trial.
|
||||
* @param[in] function with void(NTPSyncEvent_t) or std::function<void(NTPSyncEvent_t)> (only for ESP8266)
|
||||
* NTPSyncEvent_t equals 0 is there is no error
|
||||
*/
|
||||
void onNTPSyncEvent (onSyncEvent_t handler);
|
||||
|
||||
/**
|
||||
* True if current time is inside DST period (aka. summer time). False otherwise of if NTP object has DST
|
||||
* calculation disabled
|
||||
* @param[out] True = summertime enabled and time in summertime period
|
||||
* False = sumertime disabled or time ouside summertime period
|
||||
*/
|
||||
boolean isSummerTime () {
|
||||
if (_daylight)
|
||||
return isSummerTimePeriod (now ());
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if given time is inside DST period (aka. summer time). False otherwise.
|
||||
* @param[in] time to make the calculation with
|
||||
* @param[out] True = time in summertime period
|
||||
* False = time ouside summertime period
|
||||
*/
|
||||
boolean isSummerTimePeriod (time_t moment);
|
||||
|
||||
protected:
|
||||
|
||||
#if NETWORK_TYPE == NETWORK_W5100
|
||||
EthernetUDP *udp;
|
||||
#elif NETWORK_TYPE == NETWORK_WIFI101
|
||||
WiFiUDP *udp;
|
||||
#elif NETWORK_TYPE == NETWORK_ESP8266 || NETWORK_TYPE == NETWORK_ESP32
|
||||
AsyncUDP *udp; ///< UDP connection object
|
||||
IPAddress ntpServerIPAddress;
|
||||
#endif
|
||||
bool _daylight; ///< Does this time zone have daylight saving?
|
||||
int8_t _timeZone = 0; ///< Keep track of set time zone offset
|
||||
int8_t _minutesOffset = 0; ///< Minutes offset for time zones with decimal numbers
|
||||
uint8_t _dstZone = DEFAULT_DST_ZONE; ///< Daylight save time zone
|
||||
char _ntpServerName[SERVER_NAME_LENGTH]; ///< Name of NTP server on Internet or LAN
|
||||
int _shortInterval = DEFAULT_NTP_SHORTINTERVAL; ///< Interval to set periodic time sync until first synchronization.
|
||||
int _longInterval = DEFAULT_NTP_INTERVAL; ///< Interval to set periodic time sync
|
||||
time_t _lastSyncd = 0; ///< Stored time of last successful sync
|
||||
time_t _firstSync = 0; ///< Stored time of first successful sync after boot
|
||||
unsigned long _uptime = 0; ///< Time since boot
|
||||
uint16_t ntpTimeout = 1500; ///< Response timeout for NTP requests
|
||||
onSyncEvent_t onSyncEvent; ///< Event handler callback
|
||||
|
||||
#if NETWORK_TYPE == NETWORK_ESP8266 || NETWORK_TYPE == NETWORK_ESP32
|
||||
NTPStatus_t status = unsyncd; ///< Sync status
|
||||
DNSStatus_t dnsStatus = DNS_IDLE; ///< DNS request status
|
||||
Ticker responseTimer; ///< Timer to trigger response timeout
|
||||
Ticker responseTimer2; ///< Timer to trigger response timeout
|
||||
|
||||
/**
|
||||
* Get packet response and update time as of its data
|
||||
* @param[in] UDP response packet.
|
||||
*/
|
||||
void processPacket (AsyncUDPPacket& packet);
|
||||
|
||||
/**
|
||||
* Send NTP request to server
|
||||
* @param[in] UDP connection.
|
||||
* @param[out] false in case of any error.
|
||||
*/
|
||||
boolean sendNTPpacket (AsyncUDP *udp);
|
||||
|
||||
/**
|
||||
* Process internal state in case of a response timeout. If a response comes later is is asumed as non valid.
|
||||
*/
|
||||
void ICACHE_RAM_ATTR processRequestTimeout ();
|
||||
|
||||
/**
|
||||
* Static method for Ticker argument.
|
||||
*/
|
||||
static void ICACHE_RAM_ATTR s_processRequestTimeout (void* arg);
|
||||
|
||||
static void s_dnsFound (const char *name, const ip_addr_t *ipaddr, void *callback_arg);
|
||||
void dnsFound (const ip_addr_t *ipaddr);
|
||||
static void ICACHE_RAM_ATTR s_processDNSTimeout (void* arg);
|
||||
void processDNSTimeout ();
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Function that gets time from NTP server and convert it to Unix time format
|
||||
* @param[out] Time form NTP in Unix Time Format.
|
||||
*/
|
||||
static time_t s_getTime ();
|
||||
|
||||
/**
|
||||
* Calculates the daylight saving for a given date.
|
||||
* @param[in] Year.
|
||||
* @param[in] Month.
|
||||
* @param[in] Day.
|
||||
* @param[in] Hour.
|
||||
* @param[in] Weekday (1 for sunday).
|
||||
* @param[in] Time zone offset.
|
||||
* @param[out] true if date and time are inside summertime period.
|
||||
*/
|
||||
bool summertime (int year, byte month, byte day, byte hour, byte weekday, byte tzHours);
|
||||
|
||||
/**
|
||||
* Helper function to add leading 0 to hour, minutes or seconds if < 10.
|
||||
* @param[in] Digit to evaluate the need of leading 0.
|
||||
* @param[out] Result digit with leading 0 if needed.
|
||||
*/
|
||||
//String printDigits(int digits);
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* Decode NTP response contained in buffer.
|
||||
* @param[in] Pointer to message buffer.
|
||||
* @param[out] Decoded time from message, 0 if error ocurred.
|
||||
*/
|
||||
time_t decodeNtpMessage (uint8_t *messageBuffer);
|
||||
|
||||
/**
|
||||
* Set last successful synchronization time.
|
||||
* @param[out] Last sync time.
|
||||
*/
|
||||
void setLastNTPSync (time_t moment);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Sends NTP request packet to given IP address.
|
||||
* @param[in] NTP server's IP address.
|
||||
* @param[out] True if everything went ok.
|
||||
*/
|
||||
//bool sendNTPpacket(IPAddress &address);
|
||||
//#endif
|
||||
};
|
||||
|
||||
extern NTPClient NTP;
|
||||
|
||||
#endif // _NtpClientLib_h
|
||||
Reference in New Issue
Block a user