2. 6. 2017

WeMos D1 mini: Jak dostat z NTP datum a čas

Dneska se podíváme jak si s Wemos d1 mini z internetu dostat datum a čas pro svůj projekt. Zvláštní, jak moc návodů ukazuje, jak přes NTP (Nework Time Protocol) získat čas, ale datum už ne.


Po důkladném kopání v hlubinách sítě jde zjistit, že NTP server umí poslat číslo počet vteřin od 1.1.1900. Unixový čas je počítán od 1.1.1970. Většinou je to označováno jako epoch, nebo epoch 0. Podle wikipedie v roce 2038 dojde k přetečení zásobníku pro 32bit číslo počítající vteřiny od začátku epoch. Tím údajně může vzniknout problém stejně jako tomu mělo dojít v roce 2000 neboli y2k.

Někteří y2k nepamatují, takže o půlnoci na přelomu tisíciletí se měly zhroutit počítačové sítě a operační systémy protože do té doby se prý s rokem pracovalo jako s dvouciferným číslem. Tedy po roce 99 by přišel rok 00. Potíž možná byla v tom, že 1.1.2000 byla sobota, ale 1.1.1900 bylo pondělí.
Podle mě to byla jen bublina aby se lidi báli další "katastrofy". Kdyby tohle nikdo "neošéfoval", tak by podle všeho měla přestat jít elektřina, doprava by zkolabovala a letadla by padaly z oblohy... Trochu přehnané, což?
Nic z toho se ale tehdy nestalo, buď to někdo opravdu dobře vyřešil a nebo to prostě byla jen fáma k postrašení lidí. Mimochodem v roce 1999 byla v americe zvýšená poptávka po domácích bunkrech a lidi brali obchody s potravinama útokem aby přežili katastrofu. Takže to byl i poměrně luxusní marketingový tah.

WeMos D1 mini

Potřebujeme:

Jakékoliv ESP8266, já mám WeMos D1 mini a wifi router přes který se pak připojíme k internetu. To je po hw stránce vše.
Knihovny NTPClient od gmag11 pro připojení k NTP serveru a knihovnu Time od PaulStoffregen na které tato knihovna závisí. Pro upload kódu je potřeba v menu Nástroje zvolit použitou desku ať je to Wemos d1, nebo cokoliv s ESP8266, nebo ESP32 co máme po ruce na otestování funkce.

Pár příkazů které potřebujeme znát:

NTP.getTimeDateString(); // formát řetězce je hh:mm:ss dd/MM/rrrr
NTP.isSummerTime(); // letní = 1, zimní = 0
NTP.getUptimeString(); // čas od spuštění esp/wemos
NTP.getFirstSync(); // datum a čas první synchronizace času s NTP

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

#define YOUR_WIFI_SSID "tvoje_wifi_SSID"
#define YOUR_WIFI_PASSWD "heslo_k_wifi"

int8_t timeZone = 1; // nacházíme se v časové zóně 1

// Start NTP až ESP získá svoji IP adresu
void onSTAGotIP(WiFiEventStationModeGotIP ipInfo) {
  Serial.printf("Got IP: %s\r\n", ipInfo.ip.toString().c_str());
  NTP.begin("pool.ntp.org", timeZone, true); // adresa NTP serveru
  NTP.setInterval(63); // sekundy za jak dlouho dojde k aktualizaci času z NTP
}

// 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);
  //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 event has been triggered
NTPSyncEvent_t ntpEvent; // Last triggered event

void setup()
{
  static WiFiEventHandler e1, e2;

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

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

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

void loop(){
  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());
  delay(2000);
}

Aby se mi s časem a datumem líp pracovalo, tak používám příkaz strtok k rozdělení řetězce na jednotlivé části času a datumu. Bohužel se mi nepodařilo zjistit, jak jednoduše rozdělit string, umím jen char array. Jestli kdokoliv zná lepší způsob, tak budu ráda za koment.
Kód můžeme vložit na konec smyčky loop před delay, nebo nahradit všechno co je v hlavní smyčce loop.

String TimeDateS = NTP.getTimeDateString(); //uložení času a data do string
   Serial.println(TimeDateS);
   char TimeDateCH[20];
   TimeDateS.toCharArray(TimeDateCH, 20); // převede string na char
   bool summertime = NTP.isSummerTime();

   if (strlen(TimeDateCH) > 1) {//rozdělení času a data
     byte Hodiny = atoi(strtok(TimeDateCH, "/ :"));
     byte Minuty = atoi(strtok(NULL, "/ :"));
     byte Sekundy = atoi(strtok(NULL, "/ :"));
     byte Den = atoi(strtok(NULL, "/ :"));
     byte Mesic = atoi(strtok(NULL, "/ :"));
     int Rok = atoi(strtok(NULL, "/ :"));
     Serial.println("Vlastni format casu a data"); 
     Serial.print(Hodiny); Serial.print(":");
     Serial.print(Minuty); Serial.print(":");
     Serial.print(Sekundy); Serial.print(" ");
     Serial.print(Den); Serial.print(".");
     Serial.print(Mesic); Serial.print(".");
     Serial.print(Rok); Serial.print(" ");
     Serial.println(summertime ? "Letni cas. " : "Zimni cas. ");
   } 

Tak to bude pro dnešek všechno. Ještě sketche ke stažení. Ten druhý sketch obsahuje i rozdělení času a data na jednotlivé části. Plus přikládám odkaz na svůj e-shop, kde si můžete ESP moduly zakoupit.

9 komentářů:

  1. přeji hezký den.
    potřeboval bych poradit kde stáhnout Timelib.h
    žádná ze stažených po kompilaci nefunguje.
    Děkuji

    OdpovědětVymazat
    Odpovědi
    1. Ahoj, moje chyba, po důkladnějším pátrání je knihovna Time dostupná zde: https://github.com/michaelmargolis/arduino_time
      Byla součástí knihovny k hodinám DS1307 kterou jsem kdysi zkoušela. Knihovna Time mi tedy zbyla po smazání nefunkční knihovny hodin a mylně jsem se domnívala, že je součástí IDE.
      Napiš prosím jestli ti bude fungovat abych mohla opravit článek. Díky.

      Vymazat
    2. Takže knihovnu jsem stáhnul a v zip přidal.
      výsledek je ale ten, že se odkazuje na nějaký tick, který nemůže nalézt.

      C:\Documents and Settings\ZUZIK\Dokumenty\Arduino\libraries\TimeLib-master/TimeLib.h:27:23: fatal error: Tick/Tick.h: No such file or directory

      #include "Tick/Tick.h"


      Já jsem tam měl jinou knihovnu a to timelib-master, ta obsahuje složku ITCK, ale v ní žádný tick.h není je to prázdná složka.

      tak nevím co s tím.

      ^

      compilation terminated.

      exit status 1
      Nastala chyba při kompilaci u desky NodeMCU 1.0 (ESP-12E Module).

      Vymazat
    3. a ještě dotaz, jak se dá odstranit knihovna ze seznamu?
      Ještě jsem to nikdy nepotřeboval, ale asi by to bylo v tuto chvili potřeba.

      R.

      Vymazat
    4. Asi to bude chtít odstranit nepotřebný knihovny a v kódu se na ně neodkazovat tím #include

      Standartně jsou uložený v dokumentech, tam by mělo stačit ji smáznout. Restart IDE a pak by se už neměly načítat. Pokud se nepletu, tak bývaly schovaný ještě někde jinde, ale už nevím kde. Používám portable IDE a tam je všechno v jedný složce pohromadě.

      Vymazat
  2. Přeji hezký večer.
    Udělal jsem veškeré kroky, ale nevede to k cíly. Napadlo mě, jestli by jste mi nemohla přes nějaké uložiště poslat funkční sestavu knihoven.(jestli to není tajné).
    Myslím že problém bude asi v tom, že nemám všechny knihovny stejné jako vy nebo ve verzích nebo tak.
    Udělal jsem si to stejně jako vy (portable IDE) a je to fakt perfektní.
    Odzkoušel jsem i to přidání a mazání knihoven a jede to.
    Tak zvažte nad tím.

    Děkuji.
    R.S.

    OdpovědětVymazat
    Odpovědi
    1. Skutečně to s knihovnou Time (z ds1307) co jsem našla předtím nejde a háček je v tom, že knihovna NTPClient od gmag11 je vyložene závislá na knihovně Time od PaulStoffregen. Ke stažení na této adrese. https://github.com/PaulStoffregen/Time
      Poté už mě to fungovalo. Opravila jsem to i v textu článku, tak snad se tentokrát zadaří to rozběhnout.

      Omlouvám se za chybu a za nepozornost. To je tak, když mám v IDE příliš mnoho knihoven které jsem testovala na každej kousek hw pro e-shop.
      Zuza

      Vymazat
  3. Dobrý den,tak jsem dnes vyzkoušel váš vzorový sketch a při kompilaci mi to ještě vyžádalo knihovnu ESPAsyncUDP.h, kterou jsem stáhl na adrese > https://github.com/me-no-dev/ESPAsyncUDP/blob/master/src/ESPAsyncUDP.h <. Následně už vše jelo jak má. Díky za pěkný článek

    OdpovědětVymazat
    Odpovědi
    1. Zdravím, autor knihovny nejspíš přidal nějakou funkci s návazností z jiné knihovny. V době psaní článku nebyly jiné potřeba. Už to pár roků je, asi bych měla psát i použité verze knihoven. Díky za upozornění.

      Vymazat