Čas a synchronizácia času

modul hodín reálneho času, synchronizácia pomocou protokolu NTP, štandard UTC, štandard ISO 8601

Práca s časom v jazyku MicroPython

Na prácu s časom a dátumom v jazyku MicroPython máme k dispozícii modul time. Tento modul je mikro implementáciou modulu time zo štandardnej knižnice jazyka Python, ktorý má rovnakú funkcionalitu. Ak teda poznáte modul time zo štandardnej knižnice jazyka, práca s modulom time bude pre vás úplne prirodzená.

Modul time poskytuje funkcie pre získanie aktuálneho času a dútumu, pre meranie časových intervalov a taktiež funkcie pre pozastavenie kódu.

Zistenie aktuálneho času

Aktuálny čas je možné zistiť zavolaním funkcie localtime() z modulu time. Táto funkcia vráti n-ticu pozostávajúcu z 8 prvkov, ktorých význam je nasledovný (v poradí prvkov n-tice):

  • year - rok
  • month - mesiac (1 - 12)
  • mday - deň v mesiaci (1 - 31)
  • hour - hodina (0 - 23)
  • minute - minúta (0 - 59)
  • second - sekunda (0 - 59)
  • weekday - deň v týždni (0 - 6, pričom hodnota 0 pripadá na pondelok)
  • yearday - deň v roku (1 - 366)

Príklad použitia sa nachádza v nasledujúcom výpise:

>>> import time
>>> time.localtime()
(2024, 10, 31, 11, 3, 25, 3, 305)

Zistenie počiatku epochy

Moduly RTC reprezentujú čas ako počet sekúnd od počiatku epochy. Tento modul teda obsahuje len počítadlo, ktoré každú sekundu zvýši o 1. Keď potom chceme zistiť, aký je aktuálny čas, dôjde k prevedeniu tohto počtu sekúnd na zodpovedajúci dátum a čas, ktorý dostaneme po zavolaní napr. funkcie localtime().

Za počiatok epochy považujeme dátum 1.1.1970, ktorý tiež poznáme pod názvom Unixový čas. Pokiaľ RTC modul počíta čas od tohto dátumu, hodnota 0 sekúnd zodpovedá presne dátumu 1.1.1970 o 00:00:00.

Ak chceme zisiť, aký počiatok epochy používa RTC modul vášho zariadenia, môžeme tak urobiť zavolaním funkcie gmtime() alebo localtime() z modulu time s parametrom 0:

>>> import time
>>> time.gmtime(0)
(1970, 1, 1, 0, 0, 0, 3, 1)
>>> time.localtime(0)
(1970, 1, 1, 0, 0, 0, 3, 1)

Podľa výpisu je možné povedať, že 1. január 1970 pripadá na štvrtok (deň v týždni má hodnotu 3) a je to prvý deň v roku. To si môžeme overiť napríklad príkazom cal v príkazovom riadku OS Linux:

$ cal 1 1 1970
     január 1970
Po Ut St Št Pi So Ne
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Zistenie počtu sekúnd od počiatku epochy

  • (slide) Ak chceme na mikrokontroléri získať aktuálny čas v počte sekúnd od počiatku epochy, zavoláme funkciu time(), ktorá sa nachádzame v module utime:

    >>> import time
    >>> time.time()
    669375512

Konverzia na štruktúru reprezentujúcu čas

  • Spätne konvertovať čas z počtu sekúnd od počiatku epochy na 8 prvkovú nticu je možné pomocou funkcie gmtime():

    >>> import time
    >>> secs = time.time()
    >>> time.gmtime(secs)
    (2021, 3, 18, 9, 46, 33, 3, 77)

Modul hodín reálneho času (RTC)

Aby mohol mikrokontrolér pracovať s aktuálnym časom, potrebuje modul hodín reálneho času (z angl. real time clock, skrátene RTC).

Niektoré mikrokontroléry, ako napr. ESP32 alebo RP2040, sú už RTC modulom vybavené. Nakoľko však nemajú k RTC modulom vyvedené aj osobitné napájanie, je pre mnohé riešenia aj tak potrebný externý RTC modul so samostatným napájaním.

Podpora pre hodiny reálneho času sa nachádza priamo v jazyku MicroPython - v module machine sa nachádza trieda RTC. Takže ak chceme začať s modulom pracovať, stačí vytvoriť inštanciu tejto triedy:

>>> from machine import RTC
>>> rtc = RTC()

Zistenie aktuálneho dátumu a času

Pre získanie aktuálneho času stačí nad inštanciou RTC zavolať metódu .datetime():

>>> rtc.datetime()
(2021, 1, 1, 5, 0, 2, 32, 184)

Výsledkom volania bude n-tica, ktorá obsahuje 8 prvkov. Ich význam je nasledovný (zľava doprava):

  • year - rok
  • month - mesiac
  • day - deň
  • weekday - deň v týždni, pričom hodnota 0 pripadá na pondelok
  • hours - hodiny
  • minutes - minúty
  • seconds - sekundy
  • subseconds - subsekundy, čiastkové sekundy

Manuálne nastavenie dátumu a času

Ak potrebujeme nastaviť aktuálny čas ručne, môžeme na to použiť opäť metódu .datetime() nad inštanciou triedy RTC. Jej parametrom bude n-tica, ktorá obsahuje aktuálny dátum a čas v tvare (year, month, day, weekday, hours, minutes, seconds, subseconds):

>>> # aktuálny dátum a čas pred nastavením
>>> rtc.datetime()
(2021, 1, 1, 5, 0, 2, 32, 184)
>>> # nastavenie aktuálneho dátumu a času
>>> rtc.datetime((2024, 3, 13, 4, 22, 0, 0, 0))
>>> rtc.datetime()
(2024, 3, 13, 4, 22, 0, 3, 964)

Udržanie času po reštartovaní

Ak mikrokontrolér reštartnete tzv. mäkkým reštartom (z angl. soft reset), informácia o aktuálnom čase sa nestratí, pretože si ho bude modul hodín reálneho času pamätať:

>>> machine.reset()
...
>>> rtc = machine.RTC()
>>> rtc.datetime()
(2020, 3, 13, 4, 22, 2, 36, 700)

Pokiaľ nemá mikrokontrolér externý modul hodín reálneho času a odpojíme ho od zdroja elektrického napätia (napr. odpojením USB kábla), dôjde k vynulovaniu hodín reálneho času:

>>> rtc = machine.RTC()
>>> rtc.datetime()
(2021, 1, 1, 5, 0, 0, 13, 980)

Synchronizácia času pomocou protokolu NTP

Pomocou protokolu NTP je možné synchronizovať čas zariadenia prostredníctvom internetu. Pre zabezpečenie synchronizácie stačí, ak je zariadenie pripojené do internetu a má modul ntptime.

Pri práci s modulom ntptime nás budú zaujímať dve veci:

  • premenná host - Adresa NTP servera, voči ktorému sa bude zariadenie synchronizovať. Predvolenou hodnotou je pool.ntp.org, ktorý reprezentuje virtuálny klaster časových serverov poskytujúcich čas miliónom klientov. Pokiaľ je zariadenie pripojené priamo k internetu, nie je nutné túto hodnotu meniť.

  • funkcia settime() - Po zavolaní tejto funkcie dôjde k zosynchronizovaniu času. Nastavený čas bude v UTC. V prípade, že zariadenie nebude pripojené k internetu v dobe synchronizácie, dôjde k vyvolaniu výnimky OSError.

Príklad použitia modulu sa nachádza v nasledujúcom výpise:

>>> # pred synchronizáciou...
>>> import time
>>> time.localtime()
(2021, 1, 1, 1, 26, 0, 4, 1)
>>> # synchronizácia
>>> import ntptime
>>> ntptime.settime()
>>> time.localtime()
(2024, 10, 31, 17, 23, 19, 3, 305)

Práca s externým modulom RTC

V prípade, že používate externý RTC modul, na prácu s ním potrebujete potrebnú knižnicu. Ak hľadáte príslušný modul pre váš RTC modul, dobrý odrazový mostík môže zoznam Awesome MicroPython a v ňom časť venovaná RTC modulom.

Formátovanie času a dátumu

Na formátovanie času sa používa v rozličných jazykoch funkcia strftime(). Pomocou tejto funkcie je možné naformátovať dátum a čas ľubovoľne. Táto funkcia sa však v štandardnom firmvéri MicroPython-u nenachádza. Je ju však možné doinštalovať osobitne z projektu micropython-lib.

Pre vlastné projekty si je teda potrebné vytvoriť vlastný formátovač času. Príkladom môže byť funkcia v nasledujúcom výpise, ktorá vráti čas v štandarde ISO 8601.

def to_iso8601(ts: int = None) -> str:
    dt = gmtime(ts)
    return f'{dt[0]:04}-{dt[1]:02}-{dt[2]:02}T{dt[3]:02}:{dt[4]:02}:{dt[5]:02}Z'

Ďalšie zdroje