Immer wieder die Uhrzeit

Hi zusammen,

ich hab mal wieder eine Frage zum Thema "Uhrzeitabgleich mit dem NTP-Server", das treibt mich noch in den Wahnsinn. Nun hat bei meinem ESP drei Wochen lang der Uhrzeit-Abgleich mit dem NTP-Server geklappt und heute stimmte die dann plötzlich nicht mehr.

Ich brings mal auf den Punkt: Wie schaffe ich es, dass eine falsche Uhrzeit innerhalb von Sekunden wieder korrekt aus dem Internet gezogen wird?

Zur Veranschaulichung hab ich mal folgenden Sketch zusammengebaut.
Wenn man den Button drückt, wird die Uhrzeit bewusst verstellt.
Wie schaffe ich es, dass nach dem Drücken des Buttons die Uhrzeit wieder korrigiert wird?

Hier der ganze Sketch:

#include <WiFi.h>
#include <time.h>
#include <WebServer.h>
WebServer server(80);

const char* ssid = "MeineSSID";
const char* password = "MeinPW";

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

tm timeinfo;
time_t now;

unsigned long millisMerker=0;
uint16_t monthDay = 0;
uint16_t currentMonth = 0;
uint16_t currentYear = 0;
uint16_t currentHour = 0;
uint16_t currentMinute = 0;
uint16_t currentSecond = 0;


// Dummyseite
const char indexPage[] PROGMEM = R"=====(
  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Expires" content="0">
  </head>
    <body>
      <button type="button" onclick="setTime()">Uhrzeit setzen</button>
    </body>
    <script>
      function setTime() {
          data="currentHour=5&currentMinute=10&currentSecond=30&monthDay=10&currentMonth=10&currentYear=2022";
          var url="/setTime?"+data;
          var xmlhttp = new XMLHttpRequest();
          xmlhttp.open('GET', url, true);
          xmlhttp.onreadystatechange = function() {
              if (xmlhttp.readyState == 4) {
                  if(xmlhttp.status == 200) {
                     console.log("Uhrzeit wurde geändert!");
                  }
              }
          };
          xmlhttp.send(null); 
        }
    </script>
  </html>
)=====";


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

  // Wifi-Verbindung herstellen
  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");
  Serial.println(WiFi.localIP());

  // NTP-Server und Zeitzone setzen
  configTime(0, 0, NTP_SERVER);
  setenv("TZ", TZ_INFO, 1);

  server.on("/", display_root);
  server.on("/setTime", setTime_man);
  server.begin();
}

void setTime_man() {
  currentHour = server.arg("currentHour").toInt();
  currentMinute = server.arg("currentMinute").toInt();
  currentSecond = server.arg("currentSecond").toInt();
  monthDay = server.arg("monthDay").toInt();
  currentMonth = server.arg("currentMonth").toInt();
  currentYear = server.arg("currentYear").toInt();

  // Falsche Werte setzen
  timeinfo.tm_year = currentYear - 1900;
  timeinfo.tm_mon = currentMonth - 1;
  timeinfo.tm_mday = monthDay;
  timeinfo.tm_hour = currentHour;
  timeinfo.tm_min = currentMinute;
  timeinfo.tm_sec = currentSecond;
  time_t t = mktime(&timeinfo);
  struct timeval now = { .tv_sec = t };
  settimeofday(&now, NULL);

  display_root();
}

void loop() {
  server.handleClient();
  showTime();
  delay(1000);
}

void display_root() {
  const char * httpType PROGMEM = "text/html";
  server.send_P(200,  httpType, indexPage);
}

void showTime() {
  time(&now);
  localtime_r(&now, &timeinfo);
  Serial.print(timeinfo.tm_mday);
  Serial.print('.');
  Serial.print(timeinfo.tm_mon + 1);
  Serial.print('.');
  Serial.print(timeinfo.tm_year +1900);
  Serial.print(' ');
  Serial.print(timeinfo.tm_hour);
  Serial.print(':');
  Serial.print(timeinfo.tm_min);
  Serial.print(':');
  Serial.println(timeinfo.tm_sec);
}

Ich war bisher immer der Meinung, dass mit diesen zwei Zeilen hier der Abgleich mit dem Internet sichergestellt ist:

time(&now);
localtime_r(&now, &timeinfo);

Aber soweit ich mitbekommen habe, erfolgt der Abgleich nur alle Stunde mal?
Kann man das beschleunigen? Oder hab ich grundsätzlich den Wurm drin ?
Wobei ich mich an dem Beispiel-Sketch "SimpleTime" des ESP32 gehalten habe.

Danke schon mal für eure Hilfe und frohe Ostern allen!

Gegenfrage: Woher weiß Dein ESP, dass die Uhrzeit falsch ist?
Wesentlich interessanter wäre eigentlich: Warum verstellt sich Deine Uhrzeit? Da ist doch irgendwo anders der Wurm drin. Bei mir war die über Monate hinweg nie falsch.

Gruß Tommy

Indem er beim NTP-Server die richtige Uhrzeit holt.
Und ich dachte, dass genau das hiermit gemacht wird:

Anscheinend nicht, ok.
Aber wie kann ich einen neuen Abgleich anstoßen?

Ich setze die Timezone immer nach


https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv

und hatte noch nie Probleme damit.

time(&now) macht nicht eine neue SNTP Zeitanfrage sondern holt sich nur die interne Zeit ins now.

Ich setze die Zeitzone ja auch:

Bei mir gings jetzt auch ein paar Wochen lang gut.
Aber heute morgen war eben dann komischerweise 08:31 anstatt 09:31 Uhr.
Und das blieb dann auch so.
Als ich den ESP dann neu gestartet habe, passte wieder alles.

Wie gesagt, habe ich 1:1 das SimpleTime-Beispiel verwendet.

Aber trotzdem muss es doch - für den Fall, dass sowas mal eintritt - die Möglichkeit geben, dass die Uhrzeit dann wieder schnell korrigiert wird.

Schließlich ist der ESP ja online, ich hab ihm einen NTP-Server + die Zeitzone genannt.

Wenn jemand Bock hat, kann er meinen Sketch ja mal kurz probieren.
Die Uhrzeit bleibt nach Drücken des Buttons falsch.

Es muss doch einen Befehl geben, mit dem man z.B. aktiv alle 10 Minuten die Uhrzeit holt.

Damit werfen Dich die Betreiber der Timeserver raus.

Gruß Tommy

OK...
Dann lass ich den Test-Sketch jetzt mal laufen und kuck, ob sich die Uhrzeit dann nach einer Stunde wieder fängt.

Ich habs:

#include <WiFi.h>
#include <time.h>
#include <WebServer.h>
WebServer server(80);

const char* ssid = "MeineSSID";
const char* password = "MeinPW";

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

tm timeinfo;
time_t now;

unsigned long millisMerker=0;
uint16_t monthDay = 0;
uint16_t currentMonth = 0;
uint16_t currentYear = 0;
uint16_t currentHour = 0;
uint16_t currentMinute = 0;
uint16_t currentSecond = 0;


// Dummyseite
const char indexPage[] PROGMEM = R"=====(
  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Expires" content="0">
  </head>
    <body>
      <button type="button" onclick="setTime()">Uhrzeit setzen</button>
      <button type="button" onclick="correctTime()">Uhrzeit korrigieren</button>
    </body>
    <script>
      function setTime() {
          data="currentHour=5&currentMinute=10&currentSecond=30&monthDay=10&currentMonth=10&currentYear=2022";
          var url="/setTime?"+data;
          var xmlhttp = new XMLHttpRequest();
          xmlhttp.open('GET', url, true);
          xmlhttp.onreadystatechange = function() {
              if (xmlhttp.readyState == 4) {
                  if(xmlhttp.status == 200) {
                     console.log("Uhrzeit wurde geändert!");
                  }
              }
          };
          xmlhttp.send(null); 
        }

        function correctTime() {
          var url="/correctTime";
          var xmlhttp = new XMLHttpRequest();
          xmlhttp.open('GET', url, true);
          xmlhttp.onreadystatechange = function() {
              if (xmlhttp.readyState == 4) {
                  if(xmlhttp.status == 200) {
                     console.log("Uhrzeit wurde korrigiert!");
                  }
              }
          };
          xmlhttp.send(null); 
        }
    </script>
  </html>
)=====";


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

  // Wifi-Verbindung herstellen
  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");
  Serial.println(WiFi.localIP());

  // NTP-Server und Zeitzone setzen
  configTime(0, 0, NTP_SERVER);
  setenv("TZ", TZ_INFO, 1);
  
  //showTime();

  server.on("/", display_root);
  server.on("/setTime", setTime_man);
  server.on("/correctTime", correctTime_man);
  server.begin();
}

void correctTime_man() {
  // NTP-Server und Zeitzone setzen
  Serial.println("Uhrzeit korrigieren!");
  configTime(0, 0, NTP_SERVER);
  setenv("TZ", TZ_INFO, 1);
  showTime();
  display_root();
}

void setTime_man() {
  currentHour = server.arg("currentHour").toInt();
  currentMinute = server.arg("currentMinute").toInt();
  currentSecond = server.arg("currentSecond").toInt();
  monthDay = server.arg("monthDay").toInt();
  currentMonth = server.arg("currentMonth").toInt();
  currentYear = server.arg("currentYear").toInt();

  // Falsche Werte setzen
  timeinfo.tm_year = currentYear - 1900;
  timeinfo.tm_mon = currentMonth - 1;
  timeinfo.tm_mday = monthDay;
  timeinfo.tm_hour = currentHour;
  timeinfo.tm_min = currentMinute;
  timeinfo.tm_sec = currentSecond;
  time_t t = mktime(&timeinfo);
  struct timeval now = { .tv_sec = t };
  settimeofday(&now, NULL);

  display_root();
}

void loop() {
  server.handleClient();
  showTime();
  delay(1000);
}

void display_root() {
  const char * httpType PROGMEM = "text/html";
  server.send_P(200,  httpType, indexPage);
}

void showTime() {
  time(&now);
  localtime_r(&now, &timeinfo);
  Serial.print(timeinfo.tm_mday);
  Serial.print('.');
  Serial.print(timeinfo.tm_mon + 1);
  Serial.print('.');
  Serial.print(timeinfo.tm_year +1900);
  Serial.print(' ');
  Serial.print(timeinfo.tm_hour);
  Serial.print(':');
  Serial.print(timeinfo.tm_min);
  Serial.print(':');
  Serial.println(timeinfo.tm_sec);
}

Sobald man ihm die Zeitzone wieder neu setzt, stimmt die Uhrzeit wieder.
Somit könnte man die Zeitzone wahrscheinlich bei jedem Aufruf von showTime() setzen.

Hat dein Router NTP? (zB Fritzbox) dann nimm doch deren NTP den darfst Du bombardieren ohne rausgeworfen werden

Ja, das stimmt.
Aber in dem Fall hat mich die Lösung interessiert, wie ich auch ohne Fritzbox zur Korrektur der Uhrzeit komme.

Yep.

So hat er direkt nach dem Drücken des Buttons wieder die korrekte Uhrzeit:

void showTime() {
  configTime(0, 0, NTP_SERVER);
  setenv("TZ", TZ_INFO, 1);
  time(&now);
  localtime_r(&now, &timeinfo);
  Serial.print(timeinfo.tm_mday);
  Serial.print('.');
  Serial.print(timeinfo.tm_mon + 1);
  Serial.print('.');
  Serial.print(timeinfo.tm_year +1900);
  Serial.print(' ');
  Serial.print(timeinfo.tm_hour);
  Serial.print(':');
  Serial.print(timeinfo.tm_min);
  Serial.print(':');
  Serial.println(timeinfo.tm_sec);
}

Bleibt die Frage, ob das dann zu Problemen führen kann, also dass einen der NTP rauswirft?

Ich denke ich machs so, dass einmal am Tag

configTime(0, 0, NTP_SERVER);
setenv("TZ", TZ_INFO, 1);

ausgeführt wird. Dann sollte ich auf der sicheren Seite sein.

Be allen NTP Server aus dem Inet kommt deine IP auf "schwarze Liste" je nach Sever auf 24 bis 48 Std. NTP Server haben begrenzte Kapazität deshalb ist das so. Normal reicht zeit Abgleich mal in 12 Std, oder mehr.

Ja, das ist ja völlig ok.
Aber bis gerade eben war mir noch nicht klar, wie ich überhaupt definieren kann, wann/wie oft abgeglichen wird. Denn ich denke das wird von der time.h library selber geregelt.

Aber jetzt weiß ich zumindest, dass das hier

configTime(0, 0, NTP_SERVER);
setenv("TZ", TZ_INFO, 1);

sofort die Uhrzeit korrigiert.

Nun kann ich diese zwei Zeilen alle 12 oder 24 Stunden ausführen und bin so hoffentlich ab sofort safe.

Trotzdem werd ich jetzt mal die Uhrzeit verstellen und prüfen, wie lange es OHNE die beiden oben genannten Zeilen dauert, bis sich die Uhrzeit wieder einfängt. Nur interessehalber.
Ich werde berichten :wink:

Du werkelst immer noch am Symptom rum, ohne auch nur einen Gedanken daran zu verschwenden, was die Ursache für Deine Zeitabweichung ist.
Aber gut, wenn Dich das glücklich macht. Mich würde es stören.

Gruß Tommy

Mich störts auch, Tommy!

Aber kuck dir doch meinen geposteten Beispielsketch an?
Genau so hatte ich die Uhrzeit-Geschichte integriert, also falls ein Fehler drin sein sollte, zeig ihn mir gerne - ich finde keinen.

Und bei mir gings ja jetzt auch einige Wochen gut.
Allerdings schalten wir bei uns im Haus ab und zu mal das WLAN aus.
Evtl. kam das Ding dann mal ins Schleudern?

So ungenau ist ESP egal ob 8266 oder 32 das er innerhalb Parr Std. eine Stunde ungenau ist

Wer macht denn so was, wenn er Sachen laufen hat, die vom WLAN abhängig sind? Ich weiß nicht ob es daran liegt, aber das könnte man ja einfach austesten. Ich nutze keine ESP32, sondern ESP8266 und die laufen sauber durch.

Gruß Tommy

Jemand, der einen Frau hat, die Nachts kein WLAN will :wink:
Soll aber nicht das Thema hier sein...

Aber so "abhängig" bin ich davon ja auch nicht.
Die Uhrzeit sollte ja über Nacht dann offline weiterlaufen und bekommt dann spätestens morgens um 6 Uhr, wenn ich aufstehe wieder eine WLAN-Spritze.

Wenn alles richtig programmiert wird, macht es der ESP32 auch.
Z.B. mein Radiowecker weckt mich auch zur richtigen Zeit, wenn das Web nicht da ist.

Wie gesagt bzw. geschrieben:
Kuck dir meinen geposteten Sketch an. Falls da was nicht passen sollte, freu ich mich über Verbesserungsvorschläge. Aber meiner Meinung nach sollte das so ok gehen.
Und es GING ja auch Wochen lang gut. Aber dann auf einmal stimmte dir Uhrzeit eben nicht mehr.

Und da hatte mich dann eben interessiert,

  • warum die sich nicht dann nicht mehr korrigiert hat (hätte sie wahrscheinlich dann irgendwann wieder)
  • wie man eine Korrektur anstoßen kann

Avber das weiß ich nun ja