RTC DS1302 with NTP and ESP32 almost working

Dear,

I have an esp32 and a DS1302 module and I want to update this DS1302 using NTP

This code almost does it right but notice that the date and time are wrong. Could it be a time zone problem ? I'm in Brazil.

Or is it this line now.unixtime()

With it gives error in compilation because this code was for DS3231

#include <Wire.h>
#include <ThreeWire.h>
#include <WiFi.h>
#include <RtcDS1302.h>
#include "RTClib.h"
#include "time.h"

const char* ssid       = "XXXXXXXX";
const char* password   = "xxxxxx";

int ano,mes,dia,hora,minuto,segundo;

const int RstPino = 25;            //pino Reset (RTC DS1302)
const int DatPino = 26;            //pino Data  (RTC DS1302)
const int ClkPino = 27;            //pino Clock (RTC DS1302)

ThreeWire myWire(26, 27, 25);      //26 data, 27 clock e 25 reset do módulo RTC DS1302
RtcDS1302<ThreeWire> Rtc(myWire);
char daysOfTheWeek[7][12] = {"Domingo", "Segunda", "Terca", "Quarta", "Quinta", "Sexta", "Sabado"};

// NTP server to request time
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600; //0;
const int   daylightOffset_sec = 3600; //0;

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

// Function that gets time from NTP Server and syncs RTC clock
unsigned long getTime() {

  struct tm timeinfo;
  getLocalTime(&timeinfo);

  dia = timeinfo.tm_mday;
  mes = timeinfo.tm_mon + 1;
  ano = timeinfo.tm_year + 1900;
  hora = timeinfo.tm_hour;
  minuto = timeinfo.tm_min;
  segundo = timeinfo.tm_sec;

  Rtc.SetDateTime(RtcDateTime(dia,mes,ano,hora,minuto,segundo));

//disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);

}

void setup() {

  Serial.begin(115200);
  
  Rtc.Begin();
  RtcDateTime now = Rtc.GetDateTime();
  delay(20);
// Compilar com a data e a hora do sistema:
//  RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__); // Variável recebe data e hora da compilação
//  Rtc.SetDateTime(compiled);  //informações compiladas substituem as informações anteriores 
  
  //Wifi
  initWiFi();

  //Time Server
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  getTime();
}

void loop() {

    RtcDateTime now = Rtc.GetDateTime();

    Serial.print(daysOfTheWeek[now.DayOfWeek()]);
    Serial.print(',');
    Serial.print(now.Day() < 10 ? "0" : "");
    Serial.print(now.Day(), DEC);
    Serial.print('/');
    Serial.print(now.Month() < 10 ? "0" : "");
    Serial.print(now.Month(), DEC);
    Serial.print('/');
    Serial.print(now.Year(), DEC);
    Serial.print(',');
    Serial.print(now.Hour() < 10 ? "0" : "");
    Serial.print(now.Hour(), DEC);
    Serial.print(':');
    Serial.print(now.Minute() < 10 ? "0" : "");
    Serial.print(now.Minute(), DEC);
    Serial.print(':');
    Serial.print(now.Second() < 10 ? "0" : "");
    Serial.println(now.Second(), DEC);            //deixar somente print se for descomentar o que está logo
    
//  Serial.print(now.unixtime());

  delay(1000);

}

I just sorted out the time and time zone

// NTP server to request time
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = -10800;   //-3
const int daylightOffset_sec = -10800;  //-3

But the date I think must be another value.

I decided to print on the serial monitor the information coming directly from the NPT before being treated by the RTC DS1302, and lo and behold: it is correct, both the date and the time.

So why is the date wrong in the RTC DS1302 information ? (time is right)

#include <ThreeWire.h>
#include <WiFi.h>
#include <RtcDS1302.h>
#include "time.h"

const char* ssid       = "XXXXXXX";
const char* password   = "xxxxxxx";

int ano,mes,dia,hora,minuto,segundo;

const int RstPino = 25;            //pino Reset (RTC DS1302)
const int DatPino = 26;            //pino Data  (RTC DS1302)
const int ClkPino = 27;            //pino Clock (RTC DS1302)

ThreeWire myWire(26, 27, 25);      //26 data, 27 clock e 25 reset do módulo RTC DS1302
RtcDS1302<ThreeWire> Rtc(myWire);
char daysOfTheWeek[7][12] = {"Domingo", "Segunda", "Terca", "Quarta", "Quinta", "Sexta", "Sabado"};

// NTP server to request time
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = -3600*3;
const int   daylightOffset_sec = 0;

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

// Function that gets time from NTP Server and syncs RTC clock
unsigned long getTime() {

  struct tm timeinfo;
  getLocalTime(&timeinfo);

  dia = timeinfo.tm_mday;
  mes = timeinfo.tm_mon;
  ano = timeinfo.tm_year;
  hora = timeinfo.tm_hour;
  minuto = timeinfo.tm_min;
  segundo = timeinfo.tm_sec;

  Rtc.SetDateTime(RtcDateTime(dia,mes,ano,hora,minuto,segundo));

//disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}

void setup() {

  Serial.begin(115200);
  
  Rtc.Begin();
  RtcDateTime now = Rtc.GetDateTime();
  delay(20);
// Compilar com a data e a hora do sistema:
//  RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__); // Variável recebe data e hora da compilação
//  Rtc.SetDateTime(compiled);  //informações compiladas substituem as informações anteriores 
  
  //Wifi
  initWiFi();

  //Time Server
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  getTime();
}

void loop() {

    RtcDateTime now = Rtc.GetDateTime();

    Serial.print(daysOfTheWeek[now.DayOfWeek()]);
    Serial.print(',');
    Serial.print(now.Day() < 10 ? "0" : "");
    Serial.print(now.Day(), DEC);
    Serial.print('/');
    Serial.print(now.Month() < 10 ? "0" : "");
    Serial.print(now.Month(), DEC);
    Serial.print('/');
    Serial.print(now.Year(), DEC);
    Serial.print(',');
    Serial.print(now.Hour() < 10 ? "0" : "");
    Serial.print(now.Hour(), DEC);
    Serial.print(':');
    Serial.print(now.Minute() < 10 ? "0" : "");
    Serial.print(now.Minute(), DEC);
    Serial.print(':');
    Serial.print(now.Second() < 10 ? "0" : "");
    Serial.println(now.Second(), DEC);
    
  delay(1000);

}

I already changed the order day, month, year.

did not solve

Why would you use an external RTC at all?
When you have internet-time you have the actual time

additionally the ESP32 has an internal RTC itself

Here is a Demo-Code that combines

connecting to WiFi but only on first power up (can be simulated through uploading the code)
synchronising with NTP-Time
by the way the WiFi-routers from AVM can be used as a local NTP-server which reacts much quicker than some external

const char* ntpServer = "fritz.box";

setting up the internal RTC of the ESP32 and then goes into deepsleep-mode to demonstrate the RTC is running and is keeping time through the deepsleep
then on second and all consecutive boots don't synchronise again with NTP
but print RTC time

/*
Here is a Demo-Code that combines

connecting to WiFi but only on first power up (can be simulated through uploading the code)
synchronising with NTP-Time
by the way the WiFi-routers from AVM can be used as a local NTP-server which reacts much quicker than some external NTP-server

setting up the internal RTC of the ESP32 and then goes into deepsleep-mode to demonstrate the RTC is running and is keeping time through the deepsleep
then on second and all consecutive boots do't synchronise again with with but print RTC time
*/

#include <WiFi.h>
#include <ESP32Time.h>
#include <time.h>                   // time() ctime()

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  15        /* Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int bootCount = 0;

ESP32Time rtc;
ESP32Time rtc1(-3600);  // offset GMT-1
ESP32Time rtc2(7200);   // offset GMT+2

const unsigned long WaitBeforeSleep = 10000;
unsigned long sleepTimer;

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;

const char *ssid     = "Your-SSID";
const char *password = "your-password";

//const char *ssid     = "";
//const char *password = "";

// a lot of home-wlan-routers can be used as a NTP-server too
const char* ntpServer = "fritz.box";
const long  gmtOffset_sec = 0;
const int   daylightOffset_sec = 7200;

time_t now;                         // this is the epoch
tm myTimeInfo;                      // the structure tm holds time information in a more convient way

void print_wakeup_reason() {
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();
  switch (wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}


void setRTC() {
  time(&now);                       // read the current time
  localtime_r(&now, &myTimeInfo);           // update the structure tm with the current time

  int year   = myTimeInfo.tm_year + 1900;
  int month  = myTimeInfo.tm_mon + 1;
  int day    = myTimeInfo.tm_mday;
  int hour   = myTimeInfo.tm_hour;
  int minute = myTimeInfo.tm_min;
  int second = myTimeInfo.tm_sec;

  rtc.setTime(second, minute, hour, day, month, year);
}

void printRTC_Times() {
  Serial.println(rtc.getTime("RTC0: %A, %B %d %Y %H:%M:%S"));   // (String) returns time with specified format
  Serial.println(rtc1.getTime("RTC1: %A, %B %d %Y %H:%M:%S"));   // (String) returns time with specified format
  Serial.println(rtc2.getTime("RTC2: %A, %B %d %Y %H:%M:%S"));   // (String) returns time with specified format
}


void showTime() {
  time(&now);                       // read the current time
  localtime_r(&now, &myTimeInfo);           // update the structure tm with the current time
  Serial.print("year:");
  Serial.print(myTimeInfo.tm_year + 1900);  // years since 1900
  Serial.print("\tmonth:");
  Serial.print(myTimeInfo.tm_mon + 1);      // January = 0 (!)
  Serial.print("\tday:");
  Serial.print(myTimeInfo.tm_mday);         // day of month
  Serial.print("\thour:");
  Serial.print(myTimeInfo.tm_hour);         // hours since midnight  0-23
  Serial.print("\tmin:");
  Serial.print(myTimeInfo.tm_min);          // minutes after the hour  0-59
  Serial.print("\tsec:");
  Serial.print(myTimeInfo.tm_sec);          // seconds after the minute  0-61*
  Serial.print("\twday");
  Serial.print(myTimeInfo.tm_wday);         // days since Sunday 0-6
  if (myTimeInfo.tm_isdst == 1)             // Daylight Saving Time flag
    Serial.print("\tDST");
  else
    Serial.print("\tstandard");

  Serial.println();
}

void connectToWifi() {
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    BlinkHeartBeatLED(OnBoard_LED, 333);
    delay(332);
    Serial.print(".");
  }
  Serial.print("\n connected.");
  Serial.println(WiFi.localIP() );

}

void synchroniseWith_NTP_Time() {
  Serial.print("configTime uses ntpServer ");
  Serial.println(ntpServer);
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  Serial.print("synchronising time");

  while (myTimeInfo.tm_year + 1900 < 2000 ) {
    time(&now);                       // read the current time
    localtime_r(&now, &myTimeInfo);
    BlinkHeartBeatLED(OnBoard_LED, 100);
    delay(100);
    Serial.print(".");
  }
  Serial.print("\n time synchronsized \n");
  showTime();
}


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println(__FILE__);
  Serial.print( F("  compiled ") );
  Serial.print(__DATE__);
  Serial.print( F(" ") );
  Serial.println(__TIME__);
}

boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("\n Setup-Start \n");
  PrintFileNameDateTime();

  if (bootCount < 1) {
    Serial.println("bootcount < 1 new power on");
    connectToWifi();
    synchroniseWith_NTP_Time();
  }
  else {
    Serial.println("not powerup");
  }
  bootCount++;
  Serial.println("Boot number: " + String(bootCount));
  //Print the wakeup reason for ESP32
  print_wakeup_reason();
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +  " Seconds");
  Serial.print("Going to sleep in ");
  Serial.print(WaitBeforeSleep / 1000);
  Serial.println(" seconds");
  sleepTimer = millis();
}

void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 100);

  if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
    showTime();
    printRTC_Times();
  }

  if ( TimePeriodIsOver(sleepTimer, WaitBeforeSleep) ) {
    Serial.println("execute esp_deep_sleep_start()");
    Serial.print("will be back in ");
    Serial.print(TIME_TO_SLEEP);
    Serial.println(" seconds");
    
    esp_deep_sleep_start();
    Serial.println("This will never be printed");
  }

}

best regards Stefan

Which, however, is not especially useful as such, since it has no battery backup capability.

If you use an ESP32-board like this one

Which is optimised for lowest power in deepsleep-mode
The current goes down to 15 µA in deepsleep-mode which should give a pretty long battery-lifetime

A combination of detecting is there power coming from Vin with one IO-pin and if not going to deep-sleep reducing the current to 15µA and wake-up on IO-pin state-change
could do the thing
Though the wiring-effort is the aprox. same as adding a coin-cell external RTC

Fair enough. Sure, and if you were really clever, you could also incorporate calibration and temperature compensation in software (custom because I doubt the RTC API supports it directly). The processor does have a temp sensor, right? But it would be tricky to make that happen during sleep states.

Does it work when you use the example from the library ?

I just had this problem the other day. I think your problem is that the NTP server gives you a Unix timestamp, which is the seconds since 1 January 1970.

However, the RTC libraries will normally calculate a timestamp, which is seconds since 1st January 2000. This is more efficient, as the 8-bit register for the year is between 00-99 on the RTC.

This is my working code using this library

I am using a different RTC (DS3234) which uses SPI, but it should be easy to adjust the code to work with DS1307.

The variable "timeZoneAdj" also needs to be adjusted. This is the seconds difference between UTC time and your local time.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/epoch-unix-time-esp32-arduino/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/
const uint8_t DS3234_CS_PIN = 5;

#include <SPI.h>
#include <RtcDS3234.h>

RtcDS3234<SPIClass> Rtc(SPI, DS3234_CS_PIN);

#include <WiFi.h>
#include "time.h"

// Replace with your network credentials
const char* ssid = "#############";
const char* password = "#############";

// NTP server to request epoch time
const char* ntpServer = "pool.ntp.org";


// Function that gets current epoch time
unsigned long getTime() {
  time_t now;
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    //Serial.println("Failed to obtain time");
    return (0);
  }
  time(&now);
  return now;
}

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void setup() {
  Serial.begin(115200);

  SPI.begin();
  Rtc.Begin();

  initWiFi();
  configTime(0, 0, ntpServer);

  int32_t timeZoneAdj = -18000; //seconds between UTC time and local time.

  uint32_t unixTimeFromInternet = getTime(); //gets seconds since Jan 1970 timestamp

  Serial.println("adjusting RTC to NTP time");
  
  RtcDateTime timeToSet;
  timeToSet.InitWithEpoch32Time(unixTimeFromInternet);
  Rtc.SetDateTime(timeToSet + timeZoneAdj);

  RtcDateTime now = Rtc.GetDateTime();
  uint32_t unixTimeFromRTC = now.Epoch32Time(); //get timestamp from RTC

  Serial.println();
  Serial.print("UNIX Time from internet (J1970 epoch): ");
  Serial.println(unixTimeFromInternet);
  printDateTime(unixTimeFromInternet - c_Epoch32OfOriginYear + timeZoneAdj); //c_Epoch32OfOriginYear = seconds between 1 Jan 1970 to 1 Jan 2000

  Serial.println();
  Serial.print("UNIX Time on RTC (J1970 epoch): ");
  Serial.println(unixTimeFromRTC);

  printDateTime(now);
  Serial.println();

}

void loop() {

}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt)
{
  char datestring[20];

  snprintf_P(datestring,
             countof(datestring),
             PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
             dt.Month(),
             dt.Day(),
             dt.Year(),
             dt.Hour(),
             dt.Minute(),
             dt.Second() );
  Serial.println(datestring);
}

Good !!
This code works. Thanks.

Hugs to other colleagues.

Health and peace.

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