Fyzikální kabinet FyzKAB

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 se na některá zapojení alespoň podívat. 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 wire a lze je 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 pristupu 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 (tak bacha!)
    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 ze 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 uzmí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), pátém týdnu (5), v neděli (0), ve dvě hodiny (02). Zimní čas se mění v 10. měsíci (M10), v páté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 (ledna = 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

UPOZORNĚNÍ:
Nesouhlasíme s vyřazením Newtonových zákonů, Ohmova zákona a zákona zachování energie z učiva fyziky základních škol v České republice!