Zápisník experimentátora
Hierarchy: ESP8266
Urobil som zopár experimentov s NTP serverom a ESP8266. Stiahnutie času a konverzia do UTC je dobre popísaná priamo v demo príkladoch. Konverzia času do časovej zóny a používanie letného času nie je skoro nikde dokumentované. V tomto príklade sa naučíme takúto konverziu urobiť. Využijeme na to knižnice, ktoré pre nás pripravili šikovní programátori.
Ja som využil NodeMCU (v. 0.9), ale rovnaké výsledky by ste dosiahli s ľubovolnou doskou, na ktorej je ESP8266.
Celé zapojenie som testoval v IDE 1.8.2.
Celý trik prevodu NTP času do lokálneho času je ukrytý vo vhodnom použití knižníc.
Program vypisuje v pravidelných intervaloch aktuálny čas v niekoľkých časových zónach. Priklad výpisu je v ukážke.
sending NTP packet... packet received, length=48 Seconds since Jan 1 1900 = 3709508909 Unix time = 1500520109 03:08:29 Thu 20 Jul 2017 UTC Universal Coordinated Time 05:08:29 Thu 20 Jul 2017 CEST Bratislava 23:08:29 Wed 19 Jul 2017 EDT New York 13:08:29 Thu 20 Jul 2017 AEST Sydney
Úvodná časť programu je kompletne prevzatá zo vzorového príkladu k ESP8266. Zmenené je iba nastavenie hesla. Nie je priamo v programe, ale uložené bezpečne mimo neho. Podrobnosti nájdete v blogu o vkladaní makier do programu v Arduine.
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <TimeLib.h>
#include <Timezone.h>
// Safe stored password
// http://www.arduinoslovakia.eu/blog/2017/6/vlozenie-definicie-makra-do-programu-v-arduine?lang=en
#if defined(_SSID)
const char* ssid = _SSID;
const char* pass = _PWD;
#else
char ssid[] = "*************"; // your network SSID (name)
char pass[] = "********"; // your network password
#endif
unsigned int localPort = 2390; // local port to listen for UDP packets
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;
Nasledujú časové zóny. Autor knižnice Arduino Timezone Library
navrhol pohodlný spôsob na definíciu ľubovoľnej časovej zóny. Potrebujete len poznať pravidlo prechodu času z letného na zimný a naopak a o zvyšok sa postarajú triedy TimeChangeRule
a Timezone
.
//Central European Time (Frankfurt, Paris)
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; //Central European Summer Time
TimeChangeRule CET = {"CET", Last, Sun, Oct, 3, 60}; //Central European Standard Time
Timezone CE(CEST, CET);
//Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = {"AEDT", First, Sun, Oct, 2, 660}; //UTC + 11 hours
TimeChangeRule aEST = {"AEST", First, Sun, Apr, 3, 600}; //UTC + 10 hours
Timezone ausET(aEDT, aEST);
//US Eastern Time Zone (New York, Detroit)
TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2, -240}; //Eastern Daylight Time = UTC - 4 hours
TimeChangeRule usEST = {"EST", First, Sun, Nov, 2, -300}; //Eastern Standard Time = UTC - 5 hours
Timezone usET(usEDT, usEST);
Teraz väčšinu kódu preskočím a sústredím sa iba na prevod samotného času, ktorý sme získali z NTP servera. Jeho funkcia sa dá uhádnuť zo samotného zdrojového kódu. Najprv sa prevedie čas zo základu v roku 1900 na základ v roku 1970. A potom sa vyžiada konverzia do konkrétnej časovej zóny. Výsledok sa vypíše funkciou printTime
. Vidíte, že to nie je nič zložité.
Pokiaľ píšete program, ktorý má reagovať na lokálny čas, je pre vás výhodné čas skladovať v UTC (napríklad v integrovanom obvode DS1307) a len vtedy, keď je to potrebné, si ho pretransformovať, porovnať s definovaným časom akcie a vykonať akciu.
udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
Serial.print("Seconds since Jan 1 1900 = " );
Serial.println(secsSince1900);
// now convert NTP time into everyday time:
Serial.print("Unix time = ");
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears;
// print Unix time:
Serial.println(epoch);
TimeChangeRule *tcr;
time_t utc;
utc = epoch;
printTime(utc, "UTC", "Universal Coordinated Time");
printTime(CE.toLocal(utc, &tcr), tcr -> abbrev, "Bratislava");
printTime(usET.toLocal(utc, &tcr), tcr -> abbrev, "New York");
printTime(ausET.toLocal(utc, &tcr), tcr -> abbrev, "Sydney");
Zdrojový kód sa nachádza na serveri GitHub.
20.07.2017