Motivation

Beim Projekt Wetter Server sollen Datums- und Zeitangeben gemacht werden. Bei einem ESP8266 mit Internet-Zugang liegt es nahe, einen NTP-Server zur Zeit-Synchronisation zu nutzen. Ein Beispiel, wie das funktionieren kann, findet man beim arduinoclub.de ARDUINO IDE ESP8266 NTP SERVER TIMEZONE.

Das Beispiel ist ein eigenständiges Programm und musste deshalb so umgeschrieben werden, dass die Funktionalität in eigene Programme eingebunden werden kann.

Die ebenfalls benutzte Bibliothek Time von Paul Stoffregen ist leider nicht objektorientiert aufgebaut. Hier besteht der Bedarf einer objektorientierten Kapselung. Monats- und Tagesnamen sind dort in Englisch hinterlegt, Deutsch wäre mir lieber. Weiterhin führen die Zeit-Synchronisationsmechanismen von Time die Synchronisation zu ungünstigen Zeiten durch, nämlich bei der Abfrage der aktuellen Zeit oder des Synchronisationszustands. Da hier ggf. der NTP-Server abgefragt werden muss, treten möglicherweise unvorhersehbare Methoden-Laufzeiten auf. Auch hier ist eine Überarbeitung notwendig.

Die im Folgenden beschriebene Bibliothek verwaltet eine mit einem NTP-Server synchronisierte Systemzeit und kapselt die für das Projekt benötigten Funktionalitäten von Time. Weitere Funktionen lassen sich, wenn notwendig, einfach ergänzen.

Hinweis: Die Bibliothek Time enthält die Datei "time.h". Diese hat keinen Inhalt, sondern bindet lediglich "TimeLib.h" ein. Es gibt jedoch eine gleichnamige Datei "time.h" in der Standard-Bibliothek des ESP8266-Systems. Je nach Projekt-Struktur führt dies dazu, dass gelegentlich die falsche Datei eingebunden wird. Es empfiehlt sich, "time.h" aus der Time-Bibliothek von Paul Stoffregen zu löschen und "TimeLib.h" direkt einzubinden.

In­halts­ver­zeich­nis

Verwendung

Klasse UrsSystemTimeServer

Klassen UrsTimeSource und UrsNTPTimeSource

Klasse UrsTimeElements

Implementierung

Klasse UrsSystemTimeServer

Klassen UrsTimeSource und UrsNTPTimeSource

Klasse UrsTimeElements

Download

Versionshistorie


Verwendung

Die wesentlichen Komponenten der Bibliothek sind die beiden folgenden Klassen:

Hinzu kommt die Klasse UrsTimeElements, die einen Zeitpunkt in aufgelöster Form repräsentiert. Für die Repräsentation der lokalen Zeitzone werden Objekte der Klasse Timezone aus der Timezone-Bibliothek verwand.

Klasse UrsSystemTimeServer

Zentrale Klasse ist die Klasse UrsSystemTimeServer. Bei der Instanziierung wird dem Objekt eine Zeitquelle (eine Instanz der UrsTimeSource-Klasse) zur Zeit-Synchronisation und eine Zeitzone (eine Instanz der Timezone-Klasse) zur Umrechnung in die lokale Zeit übergeben. Für die Zeitquelle kann die hinterlegte UrsNTPTimeSource verwandt werden. Als Zeitzone ist die Mitteleuropäische Zeit (MEZ) voreingestellt, kann aber überschrieben werden. Um eine Instanz der UrsNTPTimeSource zu erstellen (s.u.), ist die Angabe von mindestens einer NTP-Server-URL notwendig. Im Projekt Wetter Server werden die NTP-Server von T-Online ("ntp1.t-online.de") und des National Insitute of Standards and Technologie (NIST, "time.nist.gov") verwandt. Weiter Sever findet man ntp-server.de. Die Initialisierung für MEZ kann also wie folgt geschehen:

#include <UrsNTPTimeSource.h>
#include <UrsSystemTimeServer.h>

UrsNTPTimeSource NTPTimeSource("ntp1.t-online.de", "time.nist.gov");
UrsSystemTimeServer SystemTimeServer(NTPTimeSource);

Weiterhin ist es notwendig, in regelmäßigen Abständen UrsSystemTimeServer::handle() aufzurufen. handle() überprüft, ob eine Zeit-Synchronisation mit dem NTP-Server notwendig ist, und führt diese durch.

Die zeitlichen Synchronisationsabstände werden durch die beiden Werte von syncInterval (Standard = 300 s) und syncErrorInterval (Standard = 10 s) bestimmt. War die letzte Synchronisation erfolgreich, findet die nächste im Abstand von den in syncInterval angegebenen Sekunden statt, im Standard also alle fünf Minuten. Im Fehlerfall kommt die kürzere, in syncErrorInterval hinterlegte Wartezeit zur Geltung.

void loop() {
  SystemTimeServer.handle();
...
}

Die eigentliche Funktionalität wird durch die Methode UrsSystemTimeServer::localCurrentTime() bereit gestellt. localCurrentTime liefert die aktuelle Systemzeit in aufgelöster Form als Instanz der UrsTimeElements-Klasse.

String getCurrentTimeString() {
  char b[40] = "~";
  UrsTimeElements t = SystemTimeServer.localCurrentTime();

  if (SystemTimeServer.getState() != UrsSystemTimeState::timeNotSet)
      sprintf(b, "%s %02i.%02i.%i %02i:%02i %s", 
              t.dayShortStr().c_str(), t.day, t.month, t.year, t.hour, t.minute, t.TimeZone.c_str());
  return String(b);
}
// => "08.10.2017 13:31 MESZ"

Über setSyncInterval und setSyncErrorInterval lassen sich die zeitlichen Synchronisationsabstände anpassen. getState liefert Angaben zum Synchronisationszustand. Der Zustand wird von handle ermittelt. Wenn handle für eine lange Zeit nicht aufgerufen wurde, kann es sein, dass der Zustand veraltet ist.

debugOffset

Mit der Version 1.5 wurde eine zusätzliche Debug-Option geschaffen. Will man das Programmverhalten bei Tages- oder gar Jahrwechsel testen, sind die Turn-Around-Zeiten äußerst lang :-). Abhilfe schafft der Debug-Offset. Über die Methode setDebugOffsetFromTime(time_t UTC) kann die aktuelle Soll-Zeit eingestellt werden. Die Angabe erfolgt als UTC-Zeitstempel. Die Methode berechnet den Offset dieser Soll-Zeit. Bei jedem Abruf der aktuellen Zeit wird dieser Offset hinzuaddiert. Dadurch funktioniert auch die Synchronisation mit der Zeitquelle.

Die Angabe SystemTimeServer.setDebugOffsetFromTime(1521322185); stellt die interne Uhr auf 17.03.2018 21:29:45 Uhr. Dies entspricht der MEZ-Zeit 17.3.2018 22:29:45 Uhr. Der Tageswechsel erfolgt somit in der lokalen Zeit (MEZ) in 1h 30m 15s.

Funktion Beschreibung Anmerkung
UrsSystemTimeServer(UrsTimeSource& ts,
               Timezone& tz = MEZ)
Initialisiert eine neue Instanz der UrsSystemTimeServer-Klasse. Für die Zeitquelle ts kann eine Instanz der UrsNTPTimeSource-Klasse verwandt werden.
bool synchronize() Führt die Zeit-Synchronisation durch. true, wenn erfogreich.
void handle() Überprüft, ob eine Synchronisation notwendig ist, und führt diese durch. Die zeitlichen Synchronisationsabstände werden durch die Werte von syncInterval (Standard = 300 s) und syncErrorInterval (Standard = 10 s) bestimmt.
time_t now() Liefert die aktuelle UTC-Zeit POSIX-Format, Sekunden seit 1.1.1970 00:00
UrsTimeElements localCurrentTime() Liefert aktuelle lokale Zeit. Standard ist MEZ bzw. MESZ.
int currentOffsetUTC()  Liefert den aktuellen Zeitzonen-Offset zu UTC in Sekunden. Z.B. 60 für MEZ.
void setSyncInterval(uint32_t interval) Legt den Abstand in Sekunden zwischen zwei regulären Synchronisationsversuchen fest. Der Standard ist 300 (entspr. 5 Minuten).
void setSyncErrorInterval(uint32_t interval) Legt den Abstand in Sekunden zum nächsten Synchronisationsversuchen nach einem erfolglosen Synchronisationsversuch fest. Der Standard ist 10.
 void setDebugOffsetFromTime( time_t UTC) Stellt die interne Uhr für Programm-Tests auf den angegebenen UTC-Zeitstempel ein (Debug-Offset).  
uint32_t getDebugOffset() Ruft den Debug-Offset ab.  
UrsSystemTimeState getState() Liefert den aktuellen Zustand des Zeitservers. Der Zustand wird von handle ermittelt. Wenn handle für eine lange Zeit nicht aufgerufen wurde, kann es sein, dass der Zustand veraltet ist.

Klassen UrsTimeSource und UrsNTPTimeSource

Die abstrakte Klasse UrsTimeSource definiert die Schnittstelle für eine Zeitquelle. UrsNTPTimeSource, von UrsTimeSource abgeleitet, implementiert diese Schnittstelle für die Zeitsynchronisation mit einem NTP-Server.

Klasse UrsTimeSource

UrsTimeSource definiert die abstrakte Methode loadTime, die die aktuelle Zeit bei der Zeitquelle abfragt. Die abgefragte Zeit kann über getCurrent abgefragt werden.

Klasse UrsNTPTimeSource

UrsTimeSource ist von UrsTimeSource abgeleitet und implementiert die Methode loadTime. Zur Instanziierung muss mindestens die URL eines NTP-Servers angegeben werden:

#include <UrsNTPTimeSource.h>
...
UrsNTPTimeSource NTPTimeSource("ntp1.t-online.de", "time.nist.gov");

Im Projekt Wetter Server werden die NTP-Server von T-Online ("ntp1.t-online.de") und des National Insitute of Standards and Technologie (NIST, "time.nist.gov") verwandt. Weiter Sever findet man ntp-server.de.

Über die Methode addNTPServer können weitere NTP-Server-URL bis zu einer Gesamtzahl von zehn hinzugefügt werden.

Funktion Beschreibung Anmerkung
UrsNTPTimeSource()
UrsNTPTimeSource( String ntpServername [,...])
Initialisiert eine neue Instanz der UrsNTPTimeSource-Klasse. Über weitere Konstruktoren können bis zu drei Server angegeben werden.
bool addNTPServer(String ntpServername) Fügt einen weiteren Server zu der internen Server-Liste hinzu. Liefert true, wenn der Name erfolgreich hinzugefügt werden konnte. Die max. Gesamtzahl beträgt 10.
UrsTimeSourceState loadTime() Führt die Zeitsynchronisation durch. Es wird immer nur ein Server abgefragt. Wenn die Abfrage bei dem intern gewählten Server nicht erfolgreich war, wird dieser Server für die nächsten Abfragen gesperrt (Standard: 10 Abfragen). Die Reihenfolge mit der begonnen wird ist die, in der sie URLs hinzugefügt wurden (siehe entsprechenden Abschnitt im Kapitel Implemenierung).

Klasse UrsTimeElements

Die Klasse UrsTimeElements dient zur Darstellung eines Zeitpunkts in lokaler Zeit mit aufgelösten Elementen für Jahr, Monat, Tag, Stunde, Minute und Sekunde. Hinzu kommen Felder für die zu Grunde liegende Zeitzone und und den Synchronisationszustand des Zeitservers zum Zeitpunkt der Zeitabfrage. Die anderen Werte sind nur dann gültig, wenn dieser Zustand ≠ timeNotSet ist. Ist der Zustand timeNeedsSync, sind vorhergehende Synchronisationsversuche fehlgeschlagen und es muss mit höheren Ungenauigkeiten zu gerechnet werden.

Die Methoden setDefaultLanguage() und setDefaultFormat() legen Standardeinstellungen für die Sprache und das Datumsformat fest. Vom System voreigenstellt sind de für die Sprache und das internationale Datumsformat "%Y-%m-%d %H:%M:%S" ( Symbole s.u.).

Hinzu kommen die Methoden monthStr() und dayStr(), die die Monats- bzw. Tagesbezeichnung zurück liefern. monthShortStr() und dayShortStr() liefern Kurzbezeichnungen. Für alle vier Methoden stehen deutsche und englische Werte zur Verfügung (Enumeration UrsTimeLang).

String getCurrentTimeString {
  char b[40] = "~";
  UrsTimeElements t = SystemTimeServer.localCurrentTime();

  if (t.Status != UrsSystemTimeState::timeNotSet)
      sprintf(b, "%s %02i.%02i.%i %02i:%02i %s", 
              t.dayShortStr().c_str(), t.day, t.month, t.year, t.hour, t.minute, t.TimeZone.c_str());
  return String(b);
}
// => "08.10.2017 13:31 MESZ"

toString() liefert einen formatierten String des Datums. Ohne Formatangabe wird das Datum gemäß des eingestellten Standardformats ausgegeben. Die Ableitung von Printable erlaubt die direkte Ausgabe auf ein Print-Device.

UrsTimeElements t = SystemTimeServer.localCurrentTime();

if (t.Status != UrsSystemTimeState::timeNotSet)
  Serial.prinln(t);

// => "2017-10-08 13:31:26"
UrsTimeElements t = SystemTimeServer.localCurrentTime();

if (t.Status != UrsSystemTimeState::timeNotSet)
  Serial.prinln(t.toString("%A, der %d. %B %Y %H:%M:%S %Z"));

// => "Donnerstag, der 10. August 2017 13:31:26 MEZ"
Feld / Funktion Beschreibung Anmerkung
year ... second Die aufgelösten Zeitelemente. Das Jahr ist korrekte Jahreszahl hinterlegt, also z.B. 2017.
String TimeZone Die Bezeichnung der zu Grunde liegende Zeitzone. z.B. "MESZ"
int OffsetUTC Offset der Timezone zu UTC in Sekunden. z.B. 60 für "MEZ"
UrsSystemTimeState State Synchronisationszustand des Zeitservers bei der Abfrage der Zeit. Die anderen Werte sind nur dann gültig, State != timeNotSet ist. Ist der Zustand timeNeedsSync sind vorhergehende Synchronisationsversuche fehlgeschlagen und es muss mit höheren Ungenauigkeiten zu gerechnet werden.
void setDefaultLanguage (UrsTimeLang dl) Legt die Standard-Sprache fest. DieVoreinstellung für die Sprache ist Deutsch (UrsTimeLang::de).
Die Angabe UrsTimeLang::standard ändert die aktuell eingestellte Standardsprache nicht!
UrsTimeLang setDefaultLanguage() Ruft die aktuell eingestellte Standardsprache ab.  
 String monthStr(UrsTimeLang l = UrsTimeLang::standard) Liefert den Monatsnamen als String. z.B. "Januar".
Bei der Default-Angabe UrsTimeLang::standard für l wird die voreingestellte Standardsprache genommen (s.o. setDefaultLanguage).
String monthShortStr (UrsTimeLang l = UrsTimeLang::standard) Liefert die Monatskurzbezeichnung als String. z.B. "Jan".
Bei der Default-Angabe UrsTimeLang::standard für l wird die voreingestellte Standardsprache genommen (s.o. setDefaultLanguage).
String dayStr(UrsTimeLang l = UrsTimeLang::standard) Liefert den Tagesnamen als String. z.B. "Sonntag".
Bei der Default-Angabe UrsTimeLang::standard für l wird die voreingestellte Standardsprache genommen (s.o. setDefaultLanguage).
String dayShortStr (UrsTimeLang l = UrsTimeLang::standard) Liefert die Tagesskurzbezeichnung als String. z.B. "So".
Bei der Default-Angabe UrsTimeLang::standard für l wird die voreingestellte Standardsprache genommen (s.o. setDefaultLanguage).
Deutsche Bezeichnungen sind 2-stellig, englische 3-stellig!
void setDefaultFormat(String df) Legt das Standardformat für Datumsangaben fest. Voreingestellt ist das internationale Format "%Y-%m-%d %H:%M:%S".
String getDefaultFormat() Ruft das aktuell  eingestellte Standardformat ab.  
String toString(const String format, const UrsTimeLang l = UrsTimeLang::standard)
Liefert einen String gemäß der Angabe in format. Die Format-Symbole sind analog denen in strftime. Eine Auflistung der Symbole erfolgt anschließend.
Bei der Default-Angabe UrsTimeLang::standard für l wird die voreingestellte Standardsprache genommen (s.o. setDefaultLanguage). Dies ist relevant für die Symbole %a, %A, %b und %B.
String toString() Liefert einen String gemäß des eingestellten Standardformats. s.o. setDefaultFormat und setDefaultLanguage
size_t printTo(Print& p) Ausgabe auf p. Löst Printable::printTo() auf. Die Ausgabe erfolgt im aktuelle eingestellten Standardformat (s.o. setDefaultFormat und setDefaultLanguage).

 

Symbol Bedeutung Anmerkung
%a Abgekürzter Name des Wochentags Sprachenangabe möglich
%A Voller Wochentagsname Sprachenangabe möglich
%b Abgekürzter Name des Monats Sprachenangabe möglich
%B Vollständiger Monatsname Sprachenangabe möglich
%d Tag des Monats als Dezimalzahl (01…31)  
%H Stundenangabe im 24-Stunden-Format (00…23)  
%I Stundenangabe im 12-Stunden-Format (01…12)
%m Monatsangabe als Dezimalzahl (01…12)  
%M Minutenangabe als Dezimalzahl (00…59)  
%p A.M. / P.M. - Kennung der aktuellen Tageshälfte für 12-Stunden-Uhr  
%S Sekundenangabe als Dezimalzahl (00…59)  
%w Angabe des Wochentags als Dezimalzahl (0…6, Sonntag ist 0)  
%y Jahresangabe ohne Jahrhundert als Dezimalzahl (00…99)  
%Y Jahresangabe mit Jahrhundert als Dezimalzahl  
%z, %Z Zeitzonenname
%% Prozentzeichen  

Implementierung

Klasse UrsSystemTimeServer

Wesentliche Aufgabe dieser Klasse ist das Nachhalten eines aktuellen Zeitstempels. Dieser basiert i.W. auf der Prozessor-zeit, die über die Arduino-Methode millis() abgerufen werden kann. Im Feld sysTime wird die aktuelle UTC-Zeit im POSIX-Format (Sekunden seit 1.1.1970 00:00) nachgehalten. sysTime wird bei jedem Abruf  und regelmäßig beim Aufruf von handle() mit dem aktuellen Wert von millis() nachgefahren. Der letzte berücksichtigte Wert von millis() wird in prevMillis nachgehalten.

...
// Systemzeit nachfahren
while (millis() - prevMillis >= 1000) {
  sysTime++;
  prevMillis += 1000;
}
...

Die Synchronisation mit der Zeitquelle wird über die Methode handle() geregelt. handle muss regelmäßig aufgerufen werden, am besten in loop(). handle prüft, ob die Zeit für den nächsten Synchronisationsvorgang gekommen ist und führt in diesem Fall die Synchronisation durch. War sie erfolgreich, wird mit der nächste Synchronisation gewartet, bis die Anzahl an Sekunden verstrichen sind, die in syncInterval hinterlegt sind. Ansonsten wird syncErrorInterval verwandt.

void UrsSystemTimeServer::handle() {
  // Systemzeit nachfahren
  while (millis() - prevMillis >= 1000) {
    sysTime++;
    prevMillis += 1000;
  }

  if (sysTime >= nextSyncTime) { // Zeit ist abgelaufen
    UrsTimeSourceState st = timeSource.loadTime(); // Synchronisation durchführen
    if (st == UrsTimeSourceState::success) { // Erfolgreich?
      setTime(timeSource.getCurrent()); // Status wird von setTime gesetzt
      nextSyncTime = sysTime + syncInterval;
    }
    else {
      nextSyncTime = sysTime + syncErrorInterval;
      State = (State == UrsSystemTimeState::timeNotSet) ? UrsSystemTimeState::timeNotSet 
                                                        : UrsSystemTimeState::timeNeedsSync;
    }
  }
}

handle verwendet die Methode setTime(), um die Zeit im Server nachzufahren.

void UrsSystemTimeServer::setTime(time_t t) {
  sysTime = t;
  nextSyncTime = t + syncInterval;
  State = UrsSystemTimeState::timeSet;
  prevMillis = millis();  // Mit der Zählung der bereits berücksichtigten Zeit neu beginnen
}

Auf die aktuelle Systemzeit kann über die Methode now() zugegriffen werden. now fährt zunächst millis nach und liefert dann sysTime zurück.

time_t UrsSystemTimeServer::now() {
  // Systemzeit nachfahren
  while (millis() - prevMillis >= 1000) {
    sysTime++;
    prevMillis += 1000;
  }
  return sysTime;
}

Etwas aufwändiger ist die Rückgabe der aufgelösten Zeitelemente der lokalen Zeit.

UrsTimeElements UrsSystemTimeServer::localCurrentTime() {
  if (State == UrsSystemTimeState::timeNotSet) // Leeres Element zurückliefern
    return UrsTimeElements();

  // Zeiger auf eine TimeChangeRule-Instanz zur Rückmeldung der gültigen Zeitzonen-Bez. (Sommer-, Standardzeit)
  TimeChangeRule *tcr;

  time_t local = MEZ.toLocal(now(), &tcr); // UTC in lokale Zeit wandeln
  tmElements_t tme;
  breakTime(local, tme);  // time_t in seine Elemente auflösen

  return UrsTimeElements(tme.Second, tme.Minute, tme.Hour, tme.Wday, tme.Day, tme.Month, tme.Year + 1970,
                         State, tcr->abbrev);
}

Liegt keine gültige zeit vor (State == UrsSystemTimeState::timeNotSet) wird ein UrsTimeElements-Objekt mit entsprechendem State-Feld zurückgeliefert. Der parameterlose Konstruktor setzt State auf UrsSystemTimeState::timeNotSet.

Im zweiten Schritt wird die aktuelle UTC-Zeit per now() abgerufen und durch das hinterlegte Timezone-Objekt korrigiert (local = MEZ.toLocal(now(),…)). breakTime extrahiert die Zeitelemente. Diese werden an den Konstruktor von UrsTimeElements weiter gegeben.

Klassen UrsTimeSource und UrsNTPTimeSource

UrsTimeSource definiert die Schnittstelle für Zeitquellen:

enum class UrsTimeSourceState {
  success, // Eine Zeitabfrage wurde erfolgreich durchgeführt
  timeout, // Zeitüberschreitung bei der Abfrage
  error    // sonstiger Fehler, siehe abgeleitete Klasse
};

class UrsTimeSource {
protected:
  time_t current; // die letzte von loadTime ermittelte Zeit, Sekunden seit 1970

public:
    virtual UrsTimeSourceState loadTime() = 0; // Führt eine Zeit-Abfrage bei der Zeitquelle durch
    time_t getCurrent() { return current; }   // Liefert die zuletzt abgefragte Zeit
};

Die abstrakte Methode loadTime führt die Zeitermittlung durch und legt die abgefragte Zeit in current ab. loadTime liefert zurück, ob eine gültige Zeit ermittelt werden konnte.

UrsNTPTimeSource, von UrsTimeSource abgeleitet, übernimmt die Zeitanfrage bei einem oder mehreren NTP-Servern. Dazu wird loadTime überschrieben. Die Abfrage bei einem NTP-Server, kann insbesondere dann, wenn er nicht antwortet, recht lange dauern. Die standmäßig hinterlegte Timeout-Zeit ist 1,5 s (1500 ms). Bei max. zehn möglichen Servern kann es bis zu etwa 15 s dauern, bis alle Server durchprobiert wurden. Deshalb wird pro Abfrage immer nur ein Server abgefragt. War die Abfrage nicht erfolgreich wird der Server für einige weitere Abfragen gesperrt. Die nächste Abfrage erfolgt dadurch bei einem anderen Server.

 // Abzufragende NTP-Server:
static const uint8_t retryAfter = 10; // Anzahl Sperrzyklen
static const uint8_t maxServers = 10; // Maximalanzahl an verwaltbaren NTP-Servern
uint8_t servers = 0;            // Anzahl der aktuell registrierten Server
String serverNames[maxServers]; // Liste der Server-Namen
uint8_t serverReaminingLoops[maxServers]; // Anzahl verbleibender gesperrter Abfragen

...

UrsTimeSourceState UrsNTPTimeSource::loadTime() {
  for (uint8_t i = 0; i < servers; i++) {
    if (serverReaminingLoops[i] == 0) { // Server ist nicht gesperrt, ...
      if (getNtpTime(serverNames[i])) { // ... dann Server abfragen, ...
        return UrsTimeSourceState::success;
      }
      else { // Server bei nicht erfolgreicher Abfrage sperren
        serverReaminingLoops[i] = retryAfter;
        return UrsTimeSourceState::timeout;
      }
    }
    else
      serverReaminingLoops[i]--;        // ... ansonsten Sperrzeit verringern
  }
  return UrsTimeSourceState::timeout;
}

serverReaminingLoops wird bei einem Fehlversuch auf den Wert von retryAfter gesetzt. Bei jedem Abfrage wird dieser Wert verringert. Ist er bei Null angekommen, wird der Server wieder abgefragt. Wurde eine erfolgreiche Abfrage bei einem Server zu Beginn der Reihenfolge durchgeführt, werden die weiter hinter in der Reihenfolge liegende Server nicht nicht weiter betrachtet. Auch wird deren Sperrzeit nicht verringert.

Klasse UrsTimeElements

An dieser Klasse ist nichts besonderes. Sie dient lediglich zur Haltung der Zeit-Elemente.

Die privaten Methoden monthStrDE() u.ä. sind Kopien der entsprechenden Funktionen in der Bibliothek Time mit hinterlegten deutschen Texten. monthStr() entscheidet dann anhand der übergebenen Sprachenangabe, ob die Texte aus Time (englisch) oder aus UrsTime (deutsch) zurück geliefert werden.

String UrsTimeElements::monthStr(UrsTimeLang l) {
  uint8_t m = month;
  if (m > 12) m = 0;

  switch (l) {
  case UrsTimeLang::en:
    return  ::monthStr(m);
  case UrsTimeLang::de:
    return monthStrDE(m);
  default:
    return String();
  }
}

Download

Das ZIP-Archiv für Bibliothek UrsTime zum Download. Die entpackten Dateien ins Verzeichnis <user>\Documents\Arduino\libraries kopieren (siehe Installing Additional Arduino Libraries).

Das Archiv enthält die Bibliotheksdateien

Versionshistorie

Datum Version Änderung
2017-10-08 1.0 Basisversion
2017-10-11 1.1 Einige Fehlerkorrekturen
2017-12-16 1.2
  • Neue Methode 'UrsTimeElements toLocalTime(time_t timeStamp)' rechnet UNIX-Zeitstempel in lokale Zeit um.
  • toString erstellt aus UrsTimeElements mit Formatangeben analog strftime().
  • Einige Methoden und Methoden-Argumente mit const-Attribut vershehen.
  • Exceptions beim Zugriff auf PROGMEM bei monthStr() und dayStr() bei deutschen Texten behoben.
  • Default-Language und Default-Format bei UrsTimeElements eingeführt.
  • UrsTimeElements von Printable abgeleitet.
2018-03-12 1.3 Methode UrsSystemTimeServer::synchronize() hinzugefügt
2018-03-12 1.4 Die Sperren für Zeitserver entfernt. Synchronisationsintervalle werden von außen geregelt.
Konstruktor ohne Servername hinzugefügt.
2018-03-21 1.5
  • UrsTimeElements hat ein neues Feld OffsetUTC: Offset der Timezone zu UTC in Sekunden.
  • UrsSystemTimeServer, neue Methode: currentOffsetUTC(). Offset der eigestellten Timezone zu UTC in Sekunden.
  • debugOffset hinzugefügt.
2018-03-30 1.6 Es wurde fehlerhaft MEZ anstatt der übergebenen Zeitzone zur Umrechnung verwandt.
2020-07-28 1.7 Compiler-Warnungen behoben.