ESP
DIYer
32
LAB

Moderní mikrokontrolér v rukou „bastlíře“

NTP s letním časem pro ESP32

Na webových stránkách Wernera Rothschopfa je k nalezení několik zajímavých postřehů k programování modulu Arduino a také modulů ESP32. Určitě doporučujeme podívat se alespoň na některá zapojení. Dnes jsme si z jeho stránek dovolili „vytáhnout“ zajímavé řešení NTP klienta, který zohledňuje platnost letního času. A jelikož toto řešení je nejen hezké, ale i jednoduché, pojďme se na něj podívat.

letni cas

Příklad NTP s automatickým nastavením letního času:

Následující výpis programu je vytvořen v jazyce wiring a lze jej do modulu ESP32 přeložit a zapsat prostředím Arduino IDE.

/* Konfigurace NTP */
// zvolime nejvhodnejsi NTP server pro svoji zemi
#define MY_NTP_SERVER "at.pool.ntp.org"

// zvolime sve casove pasmo
// https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
#define MY_TZ "CET-1CEST,M3.5.0,M10.5.0/3"

#include <WiFi.h>   // pro pristup k internetu potrebujeme wifi
#include <time.h>   // time() pro cteni casu

const char* ssid = "YOUR_SSID";       // nazev wifi site, ke ktere se chcete pripojit
const char* password = "YOUR_PASS";   // heslo pro pripojeni k wifi siti

/* Globals */
time_t now;         // cas v UNIX podobe (epocha)
tm tm;              // struktura tm uchovava cas lepsim zpusobem

void showTime() {
   time(&now);    // nacte aktualni cas
   localtime_r(&now, &tm);   // aktualizuje strukturu tm aktualnim casem
   Serial.print("Rok: ");
   Serial.println(tm.tm_year + 1900);   // n tm je pocet roku od 1900
   Serial.print("Mesic: ");
   Serial.println(tm.tm_mon + 1); // leden = 0
   Serial.print("Den: ");
   Serial.println(tm.tm_mday); // den v mesici (0-31)
   Serial.print("Hodina: ");
   Serial.println(tm.tm_hour); // hodina od pulnoci (0-23)
   Serial.print("Minuty: ");
   Serial.println(tm.tm_min); // minuty (0-59)
   Serial.print("Sekundy: ");
   Serial.println(tm.tm_sec); // sekundy (0-59)
   Serial.print("Den tydne: ");
   Serial.println (tm.tm_wday); // Den v tydnu od nedele (0-6)
   if (tm.tm_isdst == 1)   // priznak letniho casu
      Serial.print("LETNI");
   else
      Serial.print("ZIMNI");
   Serial.println("CAS");
   Serial.println("---------");
}

void setup() {
   Serial.begin(115200);
   configTime(0, 0, MY_NTP_SERVER);   // 0, 0 protoze dale pouzijeme TZ
   setenv("TZ", MY_TZ, 1);   // nastaveni promenne s casovym pasmem
   tzset();

   // start Wifi
   WiFi.begin(ssid, password);
   while (WiFi.status() != WL_CONNECTED) {   // nez se pripoji, tiskni tecky
      delay(500);
      Serial.print(".");
   }
   Serial.println(" CONNECTED");
}

void loop() {
   showTime();
   delay(1000);   // cekani a pak znova
}

Části kódu, které jsou důležité pro načtení času z NTP serveru i s ohledem na letní čas, jsou zeleně zvýrazněny. Jinak se jedná o standardní načtení času z NTP serveru, podobně jako bylo ukázáno v předchozím článku ESP32: Získání času a data z NTP serveru.

Základním nastavením programu je dvojice řetězců, které definují NTP server (MY_NTP_SERVER), na který chcete odeslat požadavek na získání času, a definice časového pásma (MY_TZ). Časové pásmo je vybráno podle seznamu z CSV souboru (zones.csv) zmíněného v kódu (URL uvedeno v komentáři kódu). Pro náš účel je časové pásmo nastaveno pro střední Evropu (Prahu) "CET-1CEST,M3.5.0/02,M10.5.0/03".

Tento záznam obsahuje všechny informace pro modul ESP32 a jeho výpočet místního času včetně letního času. Zde konkrétně se letní čas mění ve třetím měsíci (M3), posledním týdnu (5), v neděli (0), ve dvě hodiny (02). Zimní čas se mění v 10. měsíci (M10), v posledním týdnu (5), v neděli (0), ve tři hodiny (03).

Aby vše fungovalo, potřebujeme do kódu zahrnout časovou knihovnu Time, pro kterou využijeme dvě globální proměnné now a tm.

Proměnná now se používá pro uložení časového razítka. Tato proměnná obsahuje sekundy od 1. ledna 1970. Protože jsou lidé zvyklí pracovat s datem/časem ve formátu dnů, měsíců, let … atd., použijeme strukturu tm. Její vytěžování na jednotlivé dílčí části si ukážeme dále.

V proceduře setup() jsou pro naše účely důležité následující 3 řádky kódu:

configTime(0, 0, MY_NTP_SERVER);   // 0, 0 protoze dále pouzijeme TZ
setenv("TZ", MY_TZ, 1);     // nastaveni promenne s casovym pasmem
tzset();

Pomocí těchto 3 řádků definujete své časové pásmo a server NTP. Tím máme hotovo!

Pochopitelně abychom si mohli ukázat funkci kódu, je třeba nějaký čas načíst a vypsat jej na sériový monitor. K tomu slouží procedura showTime(), ve které se nejdříve načte aktuální čas a aktualizuje se proměnná now. Pomocí funkce localtime_r převedeme časové razítko z proměnné now do struktury tm. Struktura obsahuje následující důležité dílčí proměnné:

proměnná význam rozsah hodnot
tm_sec počet sekund akt. času 0–59
tm_min počet minut akt. času 0–59*
tm_hour počet hodin akt. času 0–23
tm_mday den v měsíci 1–31
tm_mon pořadí měsíce (ledn = 0) 0–11
tm_year počet roků od roku 1900 0–?
tm_wday den v týdnu (neděle = 0) 0–6
tm_yday den v roce (od 1. ledna) 0–365
tm_isdst příznak letního/zimního času 1 / 0

* skutečný rozsah tm_sec je 0–61, tento extra rozsah je přizpůsoben pro určité systémy potřebující přestupné sekundy. My se však budeme pohybovat ve standardním rozsahu 0…59.

Test programu:

Před přeložením programu a jeho zápisu do modulu ESP32 je třeba nastavit přístupové údaje ke zvolené Wi-Fi pomocí proměnných ssid a password, tedy zadat jméno Wi-Fi sítě a platné přístupové heslo.

Pro spuštění programu se každou vteřinu vypisují časové údaje na sériový port, kde je můžeme načítat kupříkladu vestavěným sériovým monitorem prostředí Arduino IDE – viz následující obrázek.

vystup programu na seriovem monitoru

Jak vidíme v okně sériového monitoru prostředí Arduino IDE, modul ESP32 vypisuje v pravidelných intervalech jednotlivé položky struktury tm. Údaje zcela odpovídají okamžiku vzniku tohoto článku. 👍

Text inspirován článkem: https://werner.rothschopf.net/microcontroller/202103_arduino_esp32_ntp_en.htm

Pošli signál autorovi: