Probleme mit NTP Client

Hallo, :slight_smile:
Habe unter Verwendung der Standard Library für den NTP Client von German Martin und dem Hinzufügen der Codezeilen (Siehe Code)
Code: [Select]

pinMode (13, OUTPUT); //Relais
digitalWrite (13, LOW);
delay (2000);
digitalWrite (13, HIGH);
delay (2000);

festgestellt, dass das Programm keine Wlan Verbindung aufbaut.
Verschiebe ich aber die obigen 4 Codezeilen am Ende der Setupfunktion funktioniert das Programm!
Hat jemand von euch eine Ahnung, was der Grund dafür ist? :astonished:
Vielen Dank! :wink:

/*
Copyright 2016 German Martin (gmag11@gmail.com). All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met :

1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and / or other materials
provided with the distribution.

THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING
      NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  The views and conclusions contained in the software and documentation are those of the
  authors and should not be interpreted as representing official policies, either expressed
  or implied, of German Martin
*/

/*
Name: NtpClient.ino
Created: 20/08/2016
Author: gmag11@gmail.com
Editor: http://www.visualmicro.com
*/

#include <TimeLib.h>
#include "WifiConfig.h"
#include <NtpClientLib.h>
#include <ESP8266WiFi.h>

#ifndef WIFI_CONFIG_H
#define YOUR_WIFI_SSID
#define YOUR_WIFI_PASSWD
#endif // !WIFI_CONFIG_H

#define ONBOARDLED 2 // Built in LED on ESP-12/ESP-07

int8_t timeZone = 1;
int8_t minutesTimeZone = 0;
bool wifiFirstConnected = false;

void onSTAConnected (WiFiEventStationModeConnected ipInfo) {
  Serial.printf ("Connected to %s\r\n", ipInfo.ssid.c_str ());
}


// Start NTP only after IP network is connected
void onSTAGotIP (WiFiEventStationModeGotIP ipInfo) {
  Serial.printf ("Got IP: %s\r\n", ipInfo.ip.toString ().c_str ());
  Serial.printf ("Connected: %s\r\n", WiFi.status () == WL_CONNECTED ? "yes" : "no");
  digitalWrite (ONBOARDLED, LOW); // Turn on LED
  wifiFirstConnected = true;
}

// Manage network disconnection
void onSTADisconnected (WiFiEventStationModeDisconnected event_info) {
  Serial.printf ("Disconnected from SSID: %s\n", event_info.ssid.c_str ());
  Serial.printf ("Reason: %d\n", event_info.reason);
  digitalWrite (ONBOARDLED, HIGH); // Turn off LED
  //NTP.stop(); // NTP sync can be disabled to avoid sync errors
}

void processSyncEvent (NTPSyncEvent_t ntpEvent) {
  if (ntpEvent) {
      Serial.print ("Time Sync error: ");
      if (ntpEvent == noResponse)
          Serial.println ("NTP server not reachable");
      else if (ntpEvent == invalidAddress)
          Serial.println ("Invalid NTP server address");
  } else {
      Serial.print ("Got NTP time: ");
      Serial.println (NTP.getTimeDateString (NTP.getLastNTPSync ()));
  }
}

boolean syncEventTriggered = false; // True if a time even has been triggered
NTPSyncEvent_t ntpEvent; // Last triggered event

void setup () {
  static WiFiEventHandler e1, e2, e3;

  Serial.begin (115200);
  Serial.println ();
  WiFi.mode (WIFI_STA);
  WiFi.begin (YOUR_WIFI_SSID, YOUR_WIFI_PASSWD);

  pinMode (ONBOARDLED, OUTPUT); // Onboard LED
  digitalWrite (ONBOARDLED, HIGH); // Switch off LED

    pinMode (13, OUTPUT);      //Relais
  digitalWrite (13, LOW);
  delay (2000);
  digitalWrite (13, HIGH);
  delay (2000);

  

  NTP.onNTPSyncEvent ([](NTPSyncEvent_t event) {
      ntpEvent = event;
      syncEventTriggered = true;
  });

  // Deprecated
  /*WiFi.onEvent([](WiFiEvent_t e) {
      Serial.printf("Event wifi -----> %d\n", e);
  });*/

  e1 = WiFi.onStationModeGotIP (onSTAGotIP);// As soon WiFi is connected, start NTP Client
  e2 = WiFi.onStationModeDisconnected (onSTADisconnected);
  e3 = WiFi.onStationModeConnected (onSTAConnected);



  
}

void loop () {
  static int i = 0;
  static int last = 0;

  if (wifiFirstConnected) {
      wifiFirstConnected = false;
      NTP.begin ("pool.ntp.org", timeZone, true, minutesTimeZone);
      NTP.setInterval (120);
  }

  if (syncEventTriggered) {
      processSyncEvent (ntpEvent);
      syncEventTriggered = false;
  }

  if ((millis () - last) > 5100) {    
      //Serial.println(millis() - last);
      last = millis ();
      Serial.print (i); Serial.print (" ");
      Serial.print (NTP.getTimeDateString ()); Serial.print (" ");
      Serial.print (NTP.isSummerTime () ? "Summer Time. " : "Winter Time. ");
      Serial.print ("WiFi is ");
      Serial.print (WiFi.isConnected () ? "connected" : "not connected"); Serial.print (". ");
      Serial.print ("Uptime: ");
      Serial.print (NTP.getUptimeString ()); Serial.print (" since ");
      Serial.println (NTP.getTimeDateString (NTP.getFirstSync ()).c_str ());

      Serial.println(hour());
      

      i++;
  }
  delay (0);
}

Tommy56:
Setze Deinen Code bitte in Codetags (</>-Button oben links im Forumseditor oder [code] davor und [/code] dahinter ohne *).
Das kannst Du auch noch nachträglich ändern.

Warum nimmst du nicht mal einen anderen PIN?

Warum muss es unbedingt eine externe Lib sein, wo doch im ESP8266 core for Arduino mit der #include "time.h" die Uhrzeit mit wenig Aufwand zu holen ist.

Gruß Fips

Danke für eure Antworten.
Ich habe nur D7 und D8 zur Verfügung. An den anderen Ports ist nämlich mein Display angeschlossen... und die Onboard Led ist durch den Wifi auch in Verwendung.
Danke für den Tipp. Möchte nicht nur die Uhrzeit sondern auch das Datum gleichzeitig anzeigen. Welche Lib würdet ihr mir dabei empfehlen? Sowoas zum Beispiel?

Die, die Dir Fips empfohlen hat.

Gruß Tommy

Mit der Zeit scheinst du schon eine Weile zu kämpfen.

LOOIIS:
Danke für den Tipp. Möchte nicht nur die Uhrzeit sondern auch das Datum gleichzeitig anzeigen.

Hast du gedacht die Uhrzeit gibt es einzeln?
Den Unix Timestamp gibt es nur komplett.

"quote author=LOOIIS link=msg=4162107 date=1557063540"
Der Zeitstempel von deinen letzten Beitrag in UTC 05.05.2019 13:39:00 Uhr

Ich hatte es ja schon geschrieben, die "time.h" ist empfehlenswert, da sie im ESP8266 core for Arduino schon dabei ist.

Wie kommt mit der "time.h" nun die Uhrzeit in den Esp8266?

Hier mal ein Beispiel von mir.

Gruß Fips

Hallo Fips,
Vielen Dank für deine ausführliche Antwort.
Wie du richtig festgestellt hast, beschäftige ich schon seit einiger Zeit mit dem NTP, leider nicht regelmäßig, sodass ich nicht immer am Ball bin...
Nett von dir, dass du uns deinen Beispiel-Sketch zur Verfügung stellst. Habe bereits angefangen den erwähnten NTP-Sketch Teil durch deinen zu ersetzen. Zudem versuche ich ihn zu verstehen, was mir leider noch nicht leicht fällt.
Frage:
-Wie stelle ich fest, ob die Zeit mit dem Internet synconisiert wurde oder nicht? Dies um zB zu überprüfen ob nach einem Trennung der Wlan Verbindung wieder erfolgreich eine Verbindung aufgebaut wurde und eine Zeitanpassung bzw. Aktualisierung stattgefunden hat. Da ja der interne Takt des Nodemcu etwas ungenau ist auf die Dauer.

LOOIIS:
Nett von dir, dass du uns deinen Beispiel-Sketch zur Verfügung stellst. Habe bereits angefangen den erwähnten NTP-Sketch Teil durch deinen zu ersetzen. Zudem versuche ich ihn zu verstehen, was mir leider noch nicht leicht fällt.

Ich lerne aus dem Forum, also gebe ich auch was zurück.

Einbauen geht am besten als Tab.

LOOIIS:
Frage:
-Wie stelle ich fest, ob die Zeit mit dem Internet synconisiert wurde oder nicht? Dies um zB zu überprüfen ob nach einem Trennung der Wlan Verbindung wieder erfolgreich eine Verbindung aufgebaut wurde und eine Zeitanpassung bzw. Aktualisierung stattgefunden hat. Da ja der interne Takt des Nodemcu etwas ungenau ist auf die Dauer.

Das habe ich für den Esp8266 auch noch nicht herausgefunden.
Der Esp32 hat eine Funktion dafür getLocalTime().

Also einfach mal auf die Uhr gucken.
Ich hole die Zeit von der Fritzbox, sollte die nicht erreichbar sein ist wahrscheinlich sowieso Stromausfall.

Gruß Fips

Möchte mit meinem Nodemcu eine Zeitschaltuhr bauen.
-Wie kann ich bei der Inbetriebnahme zB gewährleisten, dass die Zeit im Nodemcu eine mit dem Server abgeglichene Zeit ist bevor ich die Zeit für verschiedene Schaltvorgänge auswerten kann?
-Wie kann ich den Unterschied zwischen Sommer- und Winterzeit abfragen bzw. diesen zB durch ein Symbol auf dem Display darstellen?

Wenn Du prüfen willst, ob synchronisiert wurde, musst Du die NTP-Abfrage selbst machen.
Das ist kein kompletter Sketch, nur der NTP-Teil.

#include <TimeLib.h>  // https://github.com/PaulStoffregen/Time

char lastSyncStr[] = "00:00:00 00.00.0000";
char actualTime[] = "00:00:00 00.00.0000";

// den 5 gibt es nicht, der ist nur zum Fehlertest drin
static const char ntpServerName[][20] = {"1.de.pool.ntp.org","2.de.pool.ntp.org", "3.de.pool.ntp.org","4.de.pool.ntp.org","5.de.pool.ntp.org"};
time_t lastSyncTime;
time_t prevDisplay = 0; // when the digital clock was displayed
const int timeZone = 2;     // Central European Time + Sommerzeit
boolean newSync = false;
WiFiUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets


// das muss ins setup
void timeSetup() {
  Udp.begin(localPort);
  setSyncProvider(getNtpTime);
  setSyncInterval(3600); // einmal pro Stunde
}

/*-------- NTP code ----------*/

const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

// return 0 wenn kein Sync
time_t getNtpTime(){
  IPAddress ntpServerIP; // NTP server's ip address
  static uint8_t num = 0;  // Nummer des NTP-Pool-Servers 4 für Fehlertest
  
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  WiFi.hostByName(ntpServerName[num], ntpServerIP);
  sendNTPpacket(ntpServerIP);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      lastSyncTime = secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
      newSync = true;
      return lastSyncTime;
    }
  }
  num = ++num %4;
  now();
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address){
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  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(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

char *timeToStr(time_t t, char * buf) {
int ja;
  buf[0] = (hour(t) / 10) + '0'; // Zehner
  buf[1] = (hour(t) % 10) + '0'; // Einer
  buf[2] = ':';
  buf[3] = (minute(t) / 10) + '0';
  buf[4] = (minute(t) % 10) + '0';
  buf[5] = ':';
  buf[6] = (second(t) / 10) + '0';
  buf[7] = (second(t) % 10) + '0';
  buf[8] = ' '; // die abschließende 0
  buf[9] = (day(t) / 10) + '0'; // Zehner
  buf[10] = (day(t) % 10) + '0'; // Einer
  buf[11] = '.';
  buf[12] = (month(t) / 10) + '0';
  buf[13] = (month(t) % 10) + '0';
  buf[14] = '.';
  ja = year(t);
  buf[15] = (ja / 1000) + '0'; // Tausender
  ja = ja % 1000;             // Rest 3-stellig
  buf[16] = (ja / 100) + '0';  // Hunderter
  ja = ja % 100;              // Rest 2-stellig
  buf[17] = (ja / 10) + '0';   // Zehner
  buf[18] = (ja % 10) + '0';   // Einer
  buf[19] = 0; // die abschließende 0
  return buf;
}

Für die Sommerzeitumstellung must Du hier im Forum mal schauen. Da hat Jurs eine Funktion geschrieben.

Gruß Tommy

Wow, das ging aber sehr schnell 8)
Vielen Dank Tommy56 für deine ausführlichen Infos :wink:
Werde mich gleich damit beschäftigen.

Das ist eine Auskopplung aus meinem Weihnachtsstern, deswegen ging das ziemlich schnell.

Gruß Tommy

LOOIIS:
Möchte mit meinem Nodemcu eine Zeitschaltuhr bauen.
-Wie kann ich bei der Inbetriebnahme zB gewährleisten, dass die Zeit im Nodemcu eine mit dem Server abgeglichene Zeit ist bevor ich die Zeit für verschiedene Schaltvorgänge auswerten kann?

Die Zeit kam bei mir immer an.
Ausserdem gehen meine Esp.. im kalten nur eine Sekunde am Tag nach. Der im warmen Heizungsraum geht sogar nach 20 Stunden noch genau.

Wie genau sollen denn die Schaltzeiten deiner Zeitschaltuhr einstellbar sein? Jede Sekunde? in den meisten Fällen dürfte jede Minute ausreichend sein.

Wenn dir das zu unsicher ist, dann nimm halt die aufwändige Version um die Uhrzeit zu holen und auszuwerten.

LOOIIS:
-Wie kann ich den Unterschied zwischen Sommer- und Winterzeit abfragen bzw. diesen zB durch ein Symbol auf dem Display darstellen?

Das steht doch im Beispiel im Beitrag #5 drin.

Serial.println(tm.tm_isdst ? "Sommerzeit" : "Normalzeit");

Gruß Fips

Das unsinnige an der eingebauten time.h ist die Tatsache, dass die bei Nichterreichbarkeit des NTP-Servers (bewusst falsche Adresse) einfach mit einer unsinnigen Zeit (bei mir 23 Stunden später) weitermacht.
Das ist in meinen Augen nicht tolerierbar.

Gruß Tommy

Vielen Dank für eure Antworten!

@Derfips:
Bei mir hat es mit deinem Sketch auch keine Probleme gegeben. Ich möchte aber nur, dass zB bei Inbetriebnahme gewährleistet wird, dass bei Auswertung der Zeit gewährleistet wird, dass die Zeit wirklich von einem Server kommt und nicht bei 00:00 gestartet ist. Ich hoffe du kannst mich verstehen, was ich meine.
Vielen Dank für deine Hilfe!

@Tommy56:
Beschäftige mich derzeit mit deinem Sketch (NTP-Abfrage) / Weihnachtsstern-Projekt).
Bei nachfolgender Funktion habe ich leider Schwierigkeiten den Code nachzuvollziehen: :confused:

void timeActions() {
  if (timeStatus() != timeNotSet) {
    if (newSync) {
      timeToStr(lastSyncTime,lastSyncStr);
      newSync = false;
    }
    if (now() != prevDisplay) { //update the display only if time has changed
      prevDisplay = now();
      timeToStr(prevDisplay,actualTime);

Könntest du mir bitte dieses Teil der Funktion erklären? Welche Zeit kann ich auswerten; lastSynStr oder die actualTime?
Bezogen auf dieses Example welche Zeit wird in der Funktion void digitalClockDisplay() zB mit dem Befehl (hour() ausgewertet?
Vielen Dank für deine Hilfe!

Sorry für die Fragen, sollten die Antworten für euch Experten "logisch" sein. Anfänger lernen halt mal unter anderem durch lesen, fragen und tun.

Mein Code gibt beide Zeiten in der Website aus. actualTime und lastSyncTime.
Der Beispielcode gibt die aktuelle Zeit aus.

Gruß Tommy

Danke für deiner Antwort.