ESP32 DS3231 RTC updaten mit NTP Zeit

Moin Moin,

Ich suche einer Möglichkeit in meinen Code die heruntergeladene NTP Zeit jeden Monat auf mein RTC DS3231 zu aktualisieren. Ich habe schon hinbekommen das ich die Deutsche Zeitzone bekomme dennoch weiß ich jetzt nicht mehr weiter wie ich diese im richtigen Format auf mein RTC Update. :cry: Es wäre nett wenn man mir meinen Code vervollständigen könnte da ich dieses Projekt endlich abschließen will.

Danke schon einmal im Vorraus.

// Date and time functions using a DS3231 RTC connected via I2C and Wire lib
#include "RTClib.h"
#include "Wire.h"
#include "WiFi.h"
#include "time.h"

RTC_DS3231 rtc;

String time_str;
const char* ssid      = "Test";
const char* password  = "27042026";

void WiFi_Setup(){
  
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected!");
}


void setup() {
  
  Wire.begin(21,22);
  Serial.begin(115200);
  WiFi_Setup();
  // Init and get the time
  configTime(0, 0, "pool.ntp.org");

}

void loop() {

    //Set timezone to Berlin
    setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
    Serial.println("GER/Berlin Time = "+printLocalTime());
    delay(2000);

}

   String printLocalTime(){
    struct tm timeinfo;
   if(!getLocalTime(&timeinfo)){
     Serial.println("Failed to obtain time");
   return "Time Error";
   }
    //See http://www.cplusplus.com/reference/ctime/strftime/
   char output[80];
    strftime(output, 80, "%y-%b-%dT%H:%M:%S", &timeinfo);
    time_str = String(output);
   return String(output);
  }

Wenn Du die aktuelle Zeit von NTP hast, hast Du alle Zeitbestandteile. Dann schaue mal in der DS3231-Lib, wie deren Zeit gestzt wird.

Ich würde das immer nach einer erfolgreichen Aktualisierung von NTP machen.

Für genauere Infos würden wir Deinen Sketch benötigen.

Gruß Tommy

Ich habe mein kompletten Sketch so wie ich ihn bis jetzt zum laufen gebracht habe in meinen ersten Post reinkopiert, aber ich werde es nochmal detailliert einfügen.

Ich hoffe ich habe dir damit alle nötigen Informationen gesendet.
Vielen Dank für die schnelle Antwort.

Additional Board Manager: https://dl.espressif.com/dl/package_esp32_index.json

// Date and time functions using a DS3231 RTC connected via I2C and Wire lib
#include "RTClib.h" //https://github.com/adafruit/RTClib
#include "Wire.h" //https://github.com/espressif/arduino-esp32/blob/master/libraries/Wire/src/Wire.h
#include "WiFi.h" //https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFi
#include "time.h" //https://github.com/PaulStoffregen/Time

RTC_DS3231 rtc;

String time_str;
const char* ssid      = "Test";
const char* password  = "27042026";

void WiFi_Setup(){
  
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected!");
}


void setup() {
  
  Wire.begin(21,22);
  Serial.begin(115200);
  WiFi_Setup();
  // Init and get the time
  configTime(0, 0, "pool.ntp.org");

}

void loop() {

    //Set timezone to Berlin
    setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
    Serial.println("GER/Berlin Time = "+printLocalTime());
    delay(2000);

}

   String printLocalTime(){
    struct tm timeinfo;
   if(!getLocalTime(&timeinfo)){
     Serial.println("Failed to obtain time");
   return "Time Error";
   }
    //See http://www.cplusplus.com/reference/ctime/strftime/
   char output[80];
    strftime(output, 80, "%y-%b-%dT%H:%M:%S", &timeinfo);
    time_str = String(output);
   return String(output);
  }

Sorry, aber mir ist nicht klar wozu du die RTC benötigst, wenn du die NTP-Zeit hast.

Ich möchte ein Update intervall einstellen und dann wieder vom WiFi trennen und WiFi ausschalten um Strom zu sparen.

GaLeMa00:
Ich möchte ein Update intervall einstellen und dann wieder vom WiFi trennen und WiFi ausschalten um Strom zu sparen.

Ok, das ist dann klar.
Da ich keine batteriebetriebenen Geräte einsetze, fehlt mir leider die Erfahrung.

HotSystems:
Sorry, aber mir ist nicht klar wozu du die RTC benötigst, wenn du die NTP-Zeit hast.

Wenn mal keine Internetverbindung da ist :wink:

Ich würde dann über millis einmal pro Tag die RTC aktualisieren.
Wie Du bei der NTP-Abfrage mit bekommst, ob die überhaupt erfolgreich war, hat Fips mal ausgetestet.
Im Zweifel aktualisierst Du die RTC mit sich selbst = kein Fehler.

Das war bei der alten Variante mit setSyncProvider besser, da konnte man sich mit einer eigenen Routine dazwischen hängen, die den NTP abgefragt hat, bei Erfolg die RTC aktualisiert hat und ansonsten den Wert der RTC als Time geliefert hat.

Gruß Tommy

Also ich ziehe immer die Zeit über NTP, um ebenfalls die Dauer des DeepSleeps zu berechnen. Wenn das nicht gehen sollte, gebe ich immer "60" zurück.
Dann versucht der ESP das jede Minute erneut, bis die Zeit erfolgreich gezogen werden konnte.

Hatte ich so bei meinem eInk-Display gemacht.

Tommy56:
Ich würde dann über millis einmal pro Tag die RTC aktualisieren.

Mal ne andere Idee, die hier schon läuft - Ich verzichte komplett auf millis().

Wenn RTC.Stunde >22 UND RTC.Minute > 50 UND Statusvariable==false dann Sync via NTP, bis NTP komplett.
Ist NTP komplett, setze Uhrzeit und Statusvariable=true.
Wenn RTC.Stunde != 23 UND Statusvariable==true setze Statusvariable wieder false.

Das fasst auch ab, wenn die Uhrzeit ganz weit vor läuft und synct erneut.
Wird die Uhr um 23:51 wieder auf 21 Uhr irgendwas zurück gesetzt, wird um 23:50 erneut gesynct.

Wer eine noch genauere Sync braucht, muss zusätzlich mit den Minuten vergleichen.

Das lässt sich auch umbauen auf einen Sync jede Stunde. Dann läuft auch eine 1302 "zeitnah" in einer warmen Umgebung.

GaLeMa00:
#include "time.h" //GitHub - PaulStoffregen/Time: Time library for Arduino

Das ist ein Trugschluss!!
Die Lib von Paul Stoffregen kennt die von dir im Sketch verwendeten Funktionen gar nicht.
Die benuzte "time.h" befindet sich im Esp32 Core.

Tommy56:
Wie Du bei der NTP-Abfrage mit bekommst, ob die überhaupt erfolgreich war, hat Fips mal ausgetestet.

Hatte ich für den Esp8266 geschrieben, der Core für den Esp32 bringt das Feature schon mit.

Gruß Fips

Hallo zusammen,

Ich habe den ganzen Code nochmal über den Haufen geworfen und habe mit Hilfe von den Code von Andreas Spiess es hinbekommen die Unix Time vom NTP mit einer kleinen Korrektion auf den RTC zu übertragen.#299 Tricks to get NTP time for the ESP32 and the ESP8266 incl. Summer- and Daylight Saving time - YouTube

Jetzt werde ich noch noch einbinden das die RTC Zeit 1mal im Monat oder später mit der vom NTP verglichen wird und dann falls die differenz zu groß ist upzudaten. :smiley:

/*
  This is an example file for using the time function in ESP8266 or ESP32 tu get NTP time
  It offers two functions:
  - getNTPtime(struct tm * info, uint32_t ms) where info is a structure which contains time
  information and ms is the time the service waits till it gets a response from NTP.
  Each time you cann this function it calls NTP over the net.
  If you do not want to call an NTP service every second, you can use
  - getTimeReducedTraffic(int ms) where ms is the the time between two physical NTP server calls. Betwwn these calls,
  the time structure is updated with the (inaccurate) timer. If you call NTP every few minutes you should be ok
  The time structure is called tm and has teh following values:
  Definition of struct tm:
  Member  Type  Meaning Range
  tm_sec  int seconds after the minute  0-61*
  tm_min  int minutes after the hour  0-59
  tm_hour int hours since midnight  0-23
  tm_mday int day of the month  1-31
  tm_mon  int months since January  0-11
  tm_year int years since 1900
  tm_wday int days since Sunday 0-6
  tm_yday int days since January 1  0-365
  tm_isdst  int Daylight Saving Time flag
  because the values are somhow akwardly defined, I introduce a function makeHumanreadable() where all values are adjusted according normal numbering.
  e.g. January is month 1 and not 0 And Sunday or monday is weekday 1 not 0 (according definition of MONDAYFIRST)
  Showtime is an example on how you can use the time in your sketch
  The functions are inspired by work of G6EJD ( https://www.youtube.com/channel/UCgtlqH_lkMdIa4jZLItcsTg )
*/

#ifdef ESP8266
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
#include <time.h>
#include <RTClib.h>
// #include <credentials.h>

/*
  The credentials.h file at least has to contain:
  char mySSID[]="your SSID";
  char myPASSWORD[]="your Password";
  It has to be placed in the libraries folder
  If you do not want a credentials file. delete the line: #include <credentials.h>
*/

RTC_DS3231 rtc;

const char* ssid = "Honor";
const char* password = "27042026";


const char* NTP_SERVER = "ch.pool.ntp.org";
const char* TZ_INFO    = "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00";  // enter your time zone (https://remotemonitoringsystems.ca/time-zone-abbreviations.php)

tm timeinfo;
time_t now;
long unsigned lastNTPtime;
unsigned long lastEntryTime;


void setup() {
  Serial.begin(115200);
  Serial.println("\n\nNTP Time Test\n");
  WiFi.begin(ssid, password);

  int counter = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    if (++counter > 100) ESP.restart();
    Serial.print ( "." );
  }
  Serial.println("\n\nWiFi connected\n\n");

  configTime(0, 0, NTP_SERVER);
  // See https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv for Timezone codes for your region
  setenv("TZ", TZ_INFO, 1);

  if (getNTPtime(10)) {  // wait up to 10sec to sync
  } else {
    Serial.println("Time not set");
    ESP.restart();
  }
  showTime(timeinfo);
  lastNTPtime = time(&now);
  lastEntryTime = millis();

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, let's set the time!");
    rtc.adjust(DateTime(uint32_t(now + 7203)));
  }
}



void loop() {
  // getTimeReducedTraffic(3600);
  getNTPtime(10);
  showTime(timeinfo);
  delay(1000);
  DateTime now = rtc.now();

    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.println();
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
    delay(3000);
}

bool getNTPtime(int sec) {

  {
    uint32_t start = millis();
    do {
      time(&now);
      localtime_r(&now, &timeinfo);
      Serial.print(".");
      delay(10);
    } while (((millis() - start) <= (1000 * sec)) && (timeinfo.tm_year < (2016 - 1900)));
    if (timeinfo.tm_year <= (2016 - 1900)) return false;  // the NTP call was not successful
    Serial.print("now ");  Serial.println(now);
    char time_output[30];
    strftime(time_output, 30, "%a  %d-%m-%y %T", localtime(&now));
    Serial.println(time_output);
    Serial.println();
  }
  return true;
}



// This function is obsolete because the time() function only calls the NTP server every hour. So you can always use getNTPtime()
// It can be deleted and only stays here for the video

/*
  void getTimeReducedTraffic(int sec) {
  tm *ptm;
  if ((millis() - lastEntryTime) < (1000 * sec)) {
    now = lastNTPtime + (int)(millis() - lastEntryTime) / 1000;
  } else {
    lastEntryTime = millis();
    lastNTPtime = time(&now);
    now = lastNTPtime;
    Serial.println("Get NTP time");
  }
  ptm = localtime(&now);
  timeinfo = *ptm;
  }
*/

void showTime(tm localTime) {
  Serial.print(localTime.tm_mday);
  Serial.print('/');
  Serial.print(localTime.tm_mon + 1);
  Serial.print('/');
  Serial.print(localTime.tm_year - 100);
  Serial.print('-');
  Serial.print(localTime.tm_hour);
  Serial.print(':');
  Serial.print(localTime.tm_min);
  Serial.print(':');
  Serial.print(localTime.tm_sec);
  Serial.print(" Day of Week ");
  if (localTime.tm_wday == 0)   Serial.println(7);
  else Serial.println(localTime.tm_wday);
}


/*
 // Shorter way of displaying the time
  void showTime(tm localTime) {
  Serial.printf(
    "%04d-%02d-%02d %02d:%02d:%02d, day %d, %s time\n",
    localTime.tm_year + 1900,
    localTime.tm_mon + 1,
    localTime.tm_mday,
    localTime.tm_hour,
    localTime.tm_min,
    localTime.tm_sec,
    (localTime.tm_wday > 0 ? localTime.tm_wday : 7 ),
    (localTime.tm_isdst == 1 ? "summer" : "standard")
  );
  }
*/

Also ich würde 1 Mal täglich die RTC nach der NTP stellen.

Gruß Tommy

GaLeMa00:
Ich habe den ganzen Code nochmal über den Haufen geworfen ...

Danke für die Rückmeldung :slight_smile:

Vermutlich wirst Du die genaue Zeit verwenden wollen, da könnten Dir möglicherweise die Tabs von Fips Anregungen geben. Von mir gibt es eine Einführung zu den Tabs.