Update time() from DS3231

Hello-

I'm using an ESP8266 to collect data with timestamps which are sent to a server via HTTPS. I'm using certs rather than fingerprints, so system time needs to be fairly accurate. configTime() does this well, except if an internet connection is unavailable at startup. Then HTTPS doesn't work when the internet connection is restored.

So I'm using a DS3231. However, the DS3231 is not updating time() so I still need to call a second NTP request to get x.509 to work.

Simplified code is below, with the typical serial output, running on a ESP-12E.

At startup, time() is 0, as expected. After the RTC NTP update, time() is still 0 even though setTime() has been called. Next shows that the RTC is available and accurate. time() is only updated with configTime().

I'd like to eliminate configTime(). How can I set time() from the RTC? If configTime() can do it, I assume it can be done.

Thanks for any suggestions.

Code:

#include <Arduino.h>
#include <ESP8266WiFi.h>       // https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/readme.html

#define CFG_WIFI_ESSID "ssid"
#define CFG_WIFI_PASSWORD "password"

// ------------------------ Begin RTC
#include <WiFiUdp.h>
#include <DS323x_Generic.h>
DS323x rtc;

char timeServer[]         = "time.nist.gov";  // NTP server
unsigned int NTPlocalPort    = 2390;             // local port to listen for UDP packets
const int NTP_PACKET_SIZE = 48;       // NTP timestamp is in the first 48 bytes of the message
const int UDP_TIMEOUT     = 2000;     // timeout in miliseconds to wait for an UDP packet to arrive
byte packetBuffer[NTP_PACKET_SIZE];   // buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
WiFiUDP Udp;
// ------------------------ End RTC

void setup() {
  Wire.begin(0, 2);      // join i2c bus (SDA, SCL)
  Serial.begin(115200);
  Serial.println(__FILE__);

  WiFi.mode(WIFI_STA);
  WiFi.begin(CFG_WIFI_ESSID, CFG_WIFI_PASSWORD);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }

  Serial.println("WiFi Connected.");

  time_t timeNowUTC = time(nullptr);
  struct tm * timeInfo;
  timeInfo = localtime(&timeNowUTC);
  Serial.print("Start: ");
  Serial.println(asctime(timeInfo));

  // ------------------------ Begin NTP/RTC
  Udp.begin(NTPlocalPort);
  rtc.attach(Wire);
  // Get time from NTP once, then update RTC
  getNTPTime();
  // Give time for getNTPTime() to work. This doesn't help.
  delay(5000);
  // ------------------------ End NTP/RTC

  timeNowUTC = time(nullptr);
  timeInfo = localtime(&timeNowUTC);
  Serial.print("getNTPTime: ");
  Serial.println(asctime(timeInfo));

  DateTime now = rtc.now();
  time_t utc = now.get_time_t();
  struct tm * UTCtimeInfo = localtime(&utc);
  Serial.print("RTC Time: ");
  Serial.println(asctime(UTCtimeInfo));

  timeNowUTC = time(nullptr);
  timeInfo = localtime(&timeNowUTC);
  Serial.print("Time: ");
  Serial.println(asctime(timeInfo));

  // needed for x.509
  configTime("GMT", "time.nist.gov");

  timeNowUTC = time(nullptr);
  while (timeNowUTC < 8 * 3600 * 2) {
    delay(100);
    timeNowUTC = time(nullptr);
  }

  timeNowUTC = time(nullptr);
  timeInfo = localtime(&timeNowUTC);
  Serial.print("configTime: ");
  Serial.println(asctime(timeInfo));

}

void loop() {
}

// RTC Functions
// send an NTP request to the time server at the given address
void sendNTPpacket(char *ntpSrv)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request

  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(ntpSrv, 123); //NTP requests are to port 123

  Udp.write(packetBuffer, NTP_PACKET_SIZE);

  Udp.endPacket();
}

void getNTPTime(void)
{
  static bool gotCurrentTime = false;

  // Just get the correct time once
  if (!gotCurrentTime)
  {
    sendNTPpacket(timeServer); // send an NTP packet to a time server
    // wait to see if a reply is available
    delay(1000);

    if (Udp.parsePacket())
    {
//      Serial.println(F("Packet received"));
      // We've received a packet, read the data from it
      Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

      //the timestamp starts at byte 40 of the received packet and is four bytes,
      // or two words, long. First, esxtract the two words:

      unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
      unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
      // combine the four bytes (two words) into a long integer
      // this is NTP time (seconds since Jan 1 1900):
      unsigned long secsSince1900 = highWord << 16 | lowWord;

      // now convert NTP time into everyday time:
      // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
      const unsigned long seventyYears = 2208988800UL;
      // subtract seventy years:
      unsigned long epoch = secsSince1900 - seventyYears;

      // print Unix time:
      
      // Get the time_t from epoch
      time_t epoch_t = epoch;

      // set the system time to UTC
      // warning: assumes that compileTime() returns US EDT
      // adjust the following line accordingly if you're in another time zone
      setTime(epoch_t);

      // Update RTC
      // Can use either one of these functions
      
      // 1) DateTime(tmElements_t). Must create tmElements_t if not present
      //tmElements_t tm;
      //breakTime(epoch_t, tm);
      //rtc.now( DateTime(tm) );
      
      // 2) DateTime(year, month, day, hour, min, sec)
      //rtc.now( DateTime(year(epoch_t), month(epoch_t), day(epoch_t), hour(epoch_t), minute(epoch_t), second(epoch_t) ) );

      // 3) DateTime (time_t)
      //rtc.now( DateTime(epoch_t) );

      // 4) DateTime(unsigned long epoch). The best and easiest way
      rtc.now( DateTime((uint32_t) epoch) );

      gotCurrentTime = true;
      // set previousTimeUpdate
    }
    else
    {
      // wait ten seconds before asking for the time again
      // No. Just return.
      // delay(10000);
      return;
    }
  }
}

Output:

WiFi Connected.
Start: Thu Jan  1 00:00:06 1970

getNTPTime: Thu Jan  1 00:00:12 1970

RTC Time: Tue Feb 22 15:58:09 2022

Time: Thu Jan  1 00:00:12 1970

configTime: Tue Feb 22 15:58:10 2022

Why do you have all your code in setup()?

I recommend you remove all code from setup and structure your sketch in a way that it handles everything in loop(). This way you can keep track of the state of your system and restart things when you loose the internet connection, sync time on a regular basis and get a overall robust system that can run 24/365.

Thanks for that Klaus, but that is not the issue. I've simplified the code to isolate just the time functions. Notice there is nothing in loop(). I'm trying to demonstrate that the RTC is not updating time() like configTime() does.

For the record, the issue was posted and answered in setTime() does not set system time #1 as follows:

The setTime() function is one of the TimeLib library and it certainly can't know about every board to set the system time. You can post an issue there to ask for help.

Also check the similar issue in ESP8266 Forum TIMELIB : HOW TO SET TIME(NULLPTR) ?

You can also adapt this NTP-TZ-DST example to use.

It's your responsibility to set the system time yourself, if you'd like to use, when you already have the accurate time from RTC.

Just write RTC_ESP_Complex example for this system time updating purpose.

The terminal output when running on ESP8266_NODEMCU_ESP12E

Start RTC_ESP_Complex on ESP8266_NODEMCU_ESP12E
Timezone_Generic v1.9.1
DS323x_Generic v1.2.3
Connecting to HueNet1
...................
You're connected to the network, IP = 192.168.2.94
Packet received
Seconds since Jan 1 1900 = 3854581698
Unix time = 1645592898
The UTC time is 5:08:18
============================
05:08:18 Wed 23 Feb 2022 UTC
00:08:18 Wed 23 Feb 2022 EST
System Time UTC: Wed Feb 23 05:08:18 2022

============================
05:08:27 Wed 23 Feb 2022 UTC
00:08:27 Wed 23 Feb 2022 EST
System Time UTC: Wed Feb 23 05:08:28 2022

============================
05:08:37 Wed 23 Feb 2022 UTC
00:08:37 Wed 23 Feb 2022 EST
System Time UTC: Wed Feb 23 05:08:38 2022

============================
05:08:47 Wed 23 Feb 2022 UTC
00:08:47 Wed 23 Feb 2022 EST
System Time UTC: Wed Feb 23 05:08:48 2022

============================
05:08:57 Wed 23 Feb 2022 UTC
00:08:57 Wed 23 Feb 2022 EST
System Time UTC: Wed Feb 23 05:08:58 2022
1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.