acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

NTP_Time.h (12549B)

      1 //====================================================================================
      2 //                                  Libraries
      3 //====================================================================================
      4 
      5 // Time library:
      6 // https://github.com/PaulStoffregen/Time
      7 #include <Time.h>
      8 
      9 // Time zone correction library:
     10 // https://github.com/JChristensen/Timezone
     11 #include <Timezone.h>
     12 
     13 // Choose library to load
     14 #ifdef ARDUINO_ARCH_ESP8266
     15 // ESP8266
     16 #include <ESP8266WiFi.h>
     17 #elif (defined(ARDUINO_ARCH_MBED) || defined(ARDUINO_ARCH_RP2040)) && !defined(ARDUINO_RASPBERRY_PI_PICO_W)
     18 // RP2040 Nano Connect
     19 #include <WiFiNINA.h>
     20 #else
     21 // ESP32
     22 #include <WiFi.h>
     23 #endif
     24 
     25 #include <WiFiUdp.h>
     26 
     27 // A UDP instance to let us send and receive packets over UDP
     28 WiFiUDP udp;
     29 
     30 //====================================================================================
     31 //                                  Settings
     32 //====================================================================================
     33 
     34 #define TIMEZONE UK // See below for other "Zone references", UK, usMT etc
     35 
     36 #ifdef ESP32 // Temporary fix, ESP8266 fails to communicate with some servers...
     37 // Try to use pool url instead so the server IP address is looked up from those available
     38 // (use a pool server in your own country to improve response time and reliability)
     39 //const char* ntpServerName = "time.nist.gov";
     40 //const char* ntpServerName = "pool.ntp.org";
     41 const char* ntpServerName = "time.google.com";
     42 #else
     43 // Try to use pool url instead so the server IP address is looked up from those available
     44 // (use a pool server in your own country to improve response time and reliability)
     45 // const char* ntpServerName = "time.nist.gov";
     46 const char* ntpServerName = "pool.ntp.org";
     47 //const char* ntpServerName = "time.google.com";
     48 #endif
     49 
     50 // Try not to use hard-coded IP addresses which might change, you can if you want though...
     51 //IPAddress timeServerIP(129, 6, 15, 30);   // time-c.nist.gov NTP server
     52 //IPAddress timeServerIP(24, 56, 178, 140); // wwv.nist.gov NTP server
     53 IPAddress timeServerIP;                     // Use server pool
     54 
     55 // Example time zone and DST rules, see Timezone library documents to see how
     56 // to add more time zones https://github.com/JChristensen/Timezone
     57 
     58 // Zone reference "UK" United Kingdom (London, Belfast)
     59 TimeChangeRule BST = {"BST", Last, Sun, Mar, 1, 60};        //British Summer (Daylight saving) Time
     60 TimeChangeRule GMT = {"GMT", Last, Sun, Oct, 2, 0};         //Standard Time
     61 Timezone UK(BST, GMT);
     62 
     63 // Zone reference "euCET" Central European Time (Frankfurt, Paris)
     64 TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};     //Central European Summer Time
     65 TimeChangeRule  CET = {"CET ", Last, Sun, Oct, 3, 60};      //Central European Standard Time
     66 Timezone euCET(CEST, CET);
     67 
     68 // Zone reference "ausET" Australia Eastern Time Zone (Sydney, Melbourne)
     69 TimeChangeRule aEDT = {"AEDT", First, Sun, Oct, 2, 660};    //UTC + 11 hours
     70 TimeChangeRule aEST = {"AEST", First, Sun, Apr, 3, 600};    //UTC + 10 hours
     71 Timezone ausET(aEDT, aEST);
     72 
     73 // Zone reference "usET US Eastern Time Zone (New York, Detroit)
     74 TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2, -240};  //Eastern Daylight Time = UTC - 4 hours
     75 TimeChangeRule usEST = {"EST", First, Sun, Nov, 2, -300};   //Eastern Standard Time = UTC - 5 hours
     76 Timezone usET(usEDT, usEST);
     77 
     78 // Zone reference "usCT" US Central Time Zone (Chicago, Houston)
     79 TimeChangeRule usCDT = {"CDT", Second, dowSunday, Mar, 2, -300};
     80 TimeChangeRule usCST = {"CST", First, dowSunday, Nov, 2, -360};
     81 Timezone usCT(usCDT, usCST);
     82 
     83 // Zone reference "usMT" US Mountain Time Zone (Denver, Salt Lake City)
     84 TimeChangeRule usMDT = {"MDT", Second, dowSunday, Mar, 2, -360};
     85 TimeChangeRule usMST = {"MST", First, dowSunday, Nov, 2, -420};
     86 Timezone usMT(usMDT, usMST);
     87 
     88 // Zone reference "usAZ" Arizona is US Mountain Time Zone but does not use DST
     89 Timezone usAZ(usMST, usMST);
     90 
     91 // Zone reference "usPT" US Pacific Time Zone (Las Vegas, Los Angeles)
     92 TimeChangeRule usPDT = {"PDT", Second, dowSunday, Mar, 2, -420};
     93 TimeChangeRule usPST = {"PST", First, dowSunday, Nov, 2, -480};
     94 Timezone usPT(usPDT, usPST);
     95 
     96 
     97 //====================================================================================
     98 //                                  Variables
     99 //====================================================================================
    100 TimeChangeRule *tz1_Code;   // Pointer to the time change rule, use to get the TZ abbrev, e.g. "GMT"
    101 
    102 time_t utc = 0;
    103 
    104 bool timeValid = false;
    105 
    106 unsigned int localPort = 2390;      // local port to listen for UDP packets
    107 
    108 const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
    109 
    110 byte packetBuffer[ NTP_PACKET_SIZE ]; //buffer to hold incoming and outgoing packets
    111 
    112 uint8_t lastMinute = 0;
    113 
    114 uint32_t nextSendTime = 0;
    115 uint32_t newRecvTime = 0;
    116 uint32_t lastRecvTime = 0;
    117 
    118 uint32_t newTickTime = 0;
    119 uint32_t lastTickTime = 0;
    120 
    121 bool ntp_start = 1;
    122 
    123 uint32_t no_packet_count = 0;
    124 
    125 
    126 //====================================================================================
    127 //                                    Function prototype
    128 //====================================================================================
    129 
    130 void syncTime(void);
    131 void displayTime(void);
    132 void printTime(time_t zone, char *tzCode);
    133 String timeString();
    134 void decodeNTP(void);
    135 void sendNTPpacket(IPAddress& address);
    136 
    137 //====================================================================================
    138 //                                    Update Time
    139 //====================================================================================
    140 void syncTime(void)
    141 {
    142   if (ntp_start) {  // Run once
    143 
    144     // Call once for ESP32 and ESP8266
    145     #if !defined(ARDUINO_ARCH_MBED)
    146     WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    147     #endif
    148 
    149     while (WiFi.status() != WL_CONNECTED) {
    150       Serial.print(".");
    151       #if defined(ARDUINO_ARCH_MBED) || defined(ARDUINO_ARCH_RP2040)
    152       if (WiFi.status() != WL_CONNECTED) WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    153       #endif
    154       delay(500);
    155     }
    156     Serial.println();
    157 
    158     udp.begin(localPort); ntp_start = 0;
    159   }
    160 
    161   // Don't send too often so we don't trigger Denial of Service
    162   if (nextSendTime < millis()) {
    163 
    164     // Wait 1 hour for next sync
    165     nextSendTime = millis() + 60 * 60 * 1000;
    166 
    167     // Get a random server from the pool
    168     WiFi.hostByName(ntpServerName, timeServerIP);
    169 
    170     sendNTPpacket(timeServerIP); // send an NTP packet to a time server
    171     decodeNTP();
    172 
    173     if ( no_packet_count > 0 )  {
    174       // Wait 1 minute for next sync
    175       nextSendTime = millis() + 60 * 1000;
    176     }
    177     else {
    178       // Wait 1 hour for next sync
    179       nextSendTime = millis() + 60 * 60 * 1000;
    180     }
    181   }
    182 }
    183 
    184 //====================================================================================
    185 // Send an NTP request to the time server at the given address
    186 //====================================================================================
    187 void sendNTPpacket(IPAddress& address)
    188 {
    189   // Serial.println("sending NTP packet...");
    190   // set all bytes in the buffer to 0
    191   memset(packetBuffer, 0, NTP_PACKET_SIZE);
    192   // Initialize values needed to form NTP request
    193   // (see URL above for details on the packets)
    194   packetBuffer[0] = 0b11100011;   // LI, Version, Mode
    195   packetBuffer[1] = 0;            // Stratum, or type of clock
    196   packetBuffer[2] = 6;            // Polling Interval
    197   packetBuffer[3] = 0xEC;         // Peer Clock Precision
    198 
    199   // 8 bytes of zero for Root Delay & Root Dispersion
    200 
    201   packetBuffer[12]  = 49;
    202   packetBuffer[13]  = 0x4E;
    203   packetBuffer[14]  = 49;
    204   packetBuffer[15]  = 52;
    205 
    206   // all NTP fields have been given values, now
    207   // you can send a packet requesting a timestamp:
    208   udp.beginPacket(address, 123); //NTP requests are to port 123
    209   udp.write(packetBuffer, NTP_PACKET_SIZE);
    210   udp.endPacket();
    211 }
    212 
    213 //====================================================================================
    214 // Decode the NTP message and print status to serial port
    215 //====================================================================================
    216 void decodeNTP(void)
    217 {
    218   timeValid = false;
    219   uint32_t waitTime = millis() + 500;
    220   while (millis() < waitTime && !timeValid)
    221   {
    222     yield();
    223     if (udp.parsePacket())
    224     {
    225       newRecvTime = millis();
    226 
    227       // We've received a packet, read the data from it
    228       udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
    229 
    230       Serial.print("\nNTP response time was : ");
    231       Serial.print(500 - (waitTime - newRecvTime));
    232       Serial.println(" ms");
    233 
    234       Serial.print("Time since last sync is: ");
    235       Serial.print((newRecvTime - lastRecvTime) / 1000.0);
    236       Serial.println(" s");
    237       lastRecvTime = newRecvTime;
    238 
    239       // The timestamp starts at byte 40 of the received packet and is four bytes,
    240       // or two words, long. First, extract the two words:
    241       unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    242       unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    243 
    244       // Combine the four bytes (two words) into a long integer
    245       // this is NTP time (seconds since Jan 1 1900):
    246       unsigned long secsSince1900 = highWord << 16 | lowWord;
    247 
    248       // Now convert NTP Unix time (Seconds since Jan 1 1900) into everyday time:
    249       // UTC time starts on Jan 1 1970. In seconds the difference is 2208988800:
    250       utc = secsSince1900 - 2208988800UL;
    251 
    252       setTime(utc);      // Set system clock to utc time (not time zone compensated)
    253 
    254       timeValid = true;
    255 
    256       // Print the hour, minute and second:
    257       Serial.print("Received NTP UTC time : ");
    258 
    259       uint8_t hh = hour(utc);
    260       Serial.print(hh); // print the hour (86400 equals secs per day)
    261 
    262       Serial.print(':');
    263       uint8_t mm = minute(utc);
    264       if (mm < 10 ) Serial.print('0');
    265       Serial.print(mm); // print the minute (3600 equals secs per minute)
    266 
    267       Serial.print(':');
    268       uint8_t ss = second(utc);
    269       if ( ss < 10 ) Serial.print('0');
    270       Serial.println(ss); // print the second
    271 
    272       time_secs = hh * 3600 + mm * 60 + ss; // Update the clock time
    273     }
    274   }
    275 
    276   // Keep a count of missing or bad NTP replies
    277 
    278   if ( timeValid ) {
    279     no_packet_count = 0;
    280   }
    281   else
    282   {
    283     Serial.println("\nNo NTP reply, trying again in 1 minute...");
    284     no_packet_count++;
    285   }
    286 
    287   if (no_packet_count >= 10) {
    288     no_packet_count = 0; // Reset to one hour to try later
    289     // TODO: Flag the lack of sync on the display
    290     Serial.println("\nNo NTP packet in last 10 minutes");
    291   }
    292 }
    293 //====================================================================================
    294 //                                  Time string: 00:00:00
    295 //====================================================================================
    296 String timeString(uint32_t t_secs)
    297 {
    298   String timeNow = "";
    299 
    300   uint8_t h = t_secs / 3600;
    301   if ( h < 10) timeNow += "0";
    302   timeNow += h;
    303 
    304   timeNow += ":";
    305   uint8_t m = (t_secs - ( h * 3600 )) / 60;
    306   if (m < 10) timeNow += "0";
    307   timeNow += m;
    308 
    309   timeNow += ":";
    310   uint8_t s = t_secs - ( h * 3600 ) - ( m * 60 );
    311   if (s < 10) timeNow += "0";
    312   timeNow += s;
    313 
    314   return timeNow;
    315 }
    316 //====================================================================================
    317 //                                  Debug use only
    318 //====================================================================================
    319 void printTime(time_t t, char *tzCode)
    320 {
    321   String dateString = dayStr(weekday(t));
    322   dateString += " ";
    323   dateString += day(t);
    324   if (day(t) == 1 || day(t) == 21 || day(t) == 31) dateString += "st";
    325   else if (day(t) == 2 || day(t) == 22) dateString += "nd";
    326   else if (day(t) == 3 || day(t) == 23) dateString += "rd";
    327   else dateString += "th";
    328 
    329   dateString += " ";
    330   dateString += monthStr(month(t));
    331   dateString += " ";
    332   dateString += year(t);
    333 
    334   // Print time to serial port
    335   Serial.print(hour(t));
    336   Serial.print(":");
    337   Serial.print(minute(t));
    338   Serial.print(":");
    339   Serial.print(second(t));
    340   Serial.print(" ");
    341   // Print time t
    342   Serial.print(tzCode);
    343   Serial.print(" ");
    344 
    345   // Print date
    346   Serial.print(day(t));
    347   Serial.print("/");
    348   Serial.print(month(t));
    349   Serial.print("/");
    350   Serial.print(year(t));
    351   Serial.print("  ");
    352 
    353   // Now test some other functions that might be useful one day!
    354   Serial.print(dayStr(weekday(t)));
    355   Serial.print(" ");
    356   Serial.print(monthStr(month(t)));
    357   Serial.print(" ");
    358   Serial.print(dayShortStr(weekday(t)));
    359   Serial.print(" ");
    360   Serial.print(monthShortStr(month(t)));
    361   Serial.println();
    362 }
    363 
    364 //====================================================================================