Skip to content

Библиотека для получения точного времени с NTP сервера для esp8266/esp32

License

Notifications You must be signed in to change notification settings

GyverLibs/GyverNTP

Repository files navigation

latest PIO Foo Foo Foo

Foo

GyverNTP

Библиотека для получения точного времени с NTP сервера для esp8266/esp32

  • Работает на стандартной библиотеке WiFiUdp.h
  • Учёт времени ответа сервера и задержки соединения
  • Получение времени с точностью до миллисекунд
  • Интеграция с библиотекой Stamp для распаковки unix в часы, минуты итд.
  • Автоматическая синхронизация
  • Поддержание хода времени на базе millis() между синхронизациями
  • Секундный таймер для удобства автоматизации
  • Обработка ошибок
  • Асинхронный режим

Совместимость

Все платформы

Зависимости

Содержание

Инициализация

GyverNTP;                 // параметры по умолчанию (gmt 0, период 3600 секунд (1 час))
GyverNTP(gmt);            // часовой пояс в часах (например Москва 3)
GyverNTP(gmt, period);    // часовой пояс в часах и период обновления в секундах

Начиная с версии 2.1.0 доступен глобальный объект NTP, свой создавать не нужно

Использование

// Наследует StampTicker

// установить часовой пояс в часах или минутах
void setGMT(int16_t gmt);

// установить период обновления в секундах
void setPeriod(uint16_t prd);

// установить хост (умолч. "pool.ntp.org")
void setHost(const String& host);

// запустить
bool begin();

// запустить и установить часовой пояс в часах или минутах
bool begin(int16_t gmt);

// остановить
void end();

// включить асинхронный режим (по умолч. true)
void asyncMode(bool async);

// получить пинг сервера, мс
int16_t ping();

// не учитывать пинг соединения (умолч. false)
void ignorePing(bool ignore);

// вернёт true, если tick ожидает ответа сервера в асинхронном режиме
bool busy();

// получить статус последнего действия
Status status();

// true - не было ошибок связи и есть соединение с Интернет
bool online();

// вернёт true при изменении статуса
bool statusChanged();

// подключить обработчик смены статуса вида void f()
void attachStatus(StatusHandler cb);

// отключить обработчик смены статуса
void detachStatus();

// подключить обработчик первой успешной синхронизации вида void f()
void attachSync(SyncHandler cb);

// отключить обработчик первой успешной синхронизации
void detachSync();

// ============== ТИКЕР ===============
// тикер, обновляет время по своему таймеру. Вернёт true на каждой секунде, если синхронизирован
bool tick();

// вручную запросить и обновить время с сервера. true при успехе
bool updateNow();

Особенности

  • GyverNTP работает с WiFi UDP для esp8266/esp32, но может использоваться любой другой UDP клиент (см. ниже)
  • Существует глобальный объект NTP (как Serial, Wire И проч.)
  • Нужно вызывать tick() в главном цикле программы loop(), он синхронизирует время с сервера по своему таймеру и обеспечивает работу секундного таймера
  • Если основной цикл программы сильно загружен, а время нужно получать с максимальной точностью (несколько мс), то можно выключить асинхронный режим asyncMode(false)
  • Библиотека продолжает считать время после пропадания синхронизации. По моим тестам esp "уходит" на ~1.7 секунды за сутки, поэтому стандартный период синхронизации выбран 1 час
  • Наследуется класс StampTicker, который обеспечивает счёт времени и работу секундного таймера

Минимальный пример

#include <GyverNTP.h>

void setup() {
  NTP.begin(3);  // запустить и указать часовой пояс
}

void loop() {
  NTP.tick();  // вызывать тикер в loop
}

Секундный таймер

Для удобства автоматизации событий по таймеру в библиотеку встроен секундный таймер, он срабатывает в 0 миллисекунд каждой секунды. По условию таймера NTP гарантированно синхронизирован и выдаёт корректное время:

void loop() {
  if (NTP.tick()) {
    // новая секунда!
    Serial.println(NTP.toString());
  }

  // или так
  // NTP.tick();
  // if (NTP.newSecond()) {}
}

Также можно подключить обработчик на секунду:

void newSecond() {
  // ваш код
}

void setup() {
  NTP.attachSecond(newSecond);
}

void loop() {
  NTP.tick();  // вызывать тикер в loop
}

Рассинхронизация

Если период синхронизации очень большой или в системе надолго пропадает связь, часы рассинхронизируются и будут синхронизированы при следующем обращении к серверу. Если время ушло больше, чем на 1 секунду, то поведение будет следующим:

  • Если внутренние часы "спешат" - секундный таймер перестанет срабатывать, пока реальное время не догонит внутреннее
  • Если внутренние часы "отстают" - таймер будет вызываться каждую итерацию loop с прибавлением времени, пока внутреннее время не догонит реальное

Это сделано для того, чтобы при синхронизации не потерялись секунды - библиотека обработает каждую секунду и не будет повторяться, что очень важно для алгоритмов автоматизации.

Проверка онлайна

NTP работает по UDP - очень легковесному и "дешёвому" протоколу связи, обращение к серверу правтически не занимает времени. Благодаря этому NTP можно использовать для проверки связи с Интернет - там, где стандартный TCP клиент зависнет на несколько секунд, NTP асинхронно сообщит о потере связи. В рамках GyverNTP это можно использовать так:

void setup() {
  NTP.begin(3);
  NTP.setPeriod(5000); // синхронизация каждые 5 секунд
}

void loop() {
  NTP.tick();

  // вернёт true при смене статуса
  if (NTP.statusChanged()) {
    Serial.println(NTP.online());
    // здесь флаг online можно использовать для передачи в другие библиотеки
    // например FastBot2
    // bot.setOnline(NTP.online());
  }
}

Получение времени

GyverNTP наследует StampCore, то есть получать время можно множеством способов:

// каждую секунду
if (NTP.tick()) {

  Serial.println(NTP.toString());     // вывод даты и времени строкой
  Serial.println(NTP.dateToString()); // вывод даты строкой

  // можно сравнивать напрямую с unix
  if (NTP >= 12345) { }
  if (NTP == 123456) { }

  NTP.getUnix();  // unix секунды

  // парсинг unix на дату и время
  NTP.second();   // секунды
  NTP.minute();   // минуты и так далее

  // эффективнее использовать парсер Datime
  Datime dt(NTP);  // NTP само конвертируется в Datime

  dt.year;
  dt.month;
  dt.day;
  dt.hour;
  dt.minute;
  dt.second;
  dt.weekDay;
  dt.yearDay;

  // для автоматизации внутри суток удобно использовать 
  // секунды с начала суток, daySeconds()
  NTP.daySeconds();

  // для удобства также есть класс DaySeconds, позволяющий задать время внутри суток
  DaySeconds ds(5, 10, 0);  // 5 часов, 10 минут, 0 секунд

  // GyverNTP может сравниваться напрямую с DaySeconds
  if (NTP == ds) { }
}

GMT (часовой пояс)

Часовой пояс задаётся для всех операций со Stamp/Datime в программе! Установка часового пояса в объекте NTP равносильна вызову setStampZone() - установка глобального часового пояса для библиотеки Stamp

Пример

// пример выводит время каждую секунду
#include <GyverNTP.h>

// список серверов, если "pool.ntp.org" не работает
//"ntp1.stratum2.ru"
//"ntp2.stratum2.ru"
//"ntp.msk-ix.ru"

void setup() {
  Serial.begin(115200);
  WiFi.begin("WIFI_SSID", "WIFI_PASS");
  while (WiFi.status() != WL_CONNECTED) delay(100);
  Serial.println("Connected");

  NTP.begin(3);  // Москва +3
}

void loop() {
  NTP.tick();
  
  if (NTP.newSecond()) {
    Serial.println(NTP.toString());      // вывод даты и времени строкой
  }
}

Другой UDP клиент

По умолчанию библиотека работает с WiFiUDP для esp8266/32, но может работать и с другими UDP клиентами: подключается в GyverNTPClient

#include <GyverNTPClient.h>
#include <WiFiUdp.h>

WiFiUDP udp;
GyverNTPClient ntp(udp);

void setup() {
    Serial.begin(115200);
    WiFi.begin("AlexMain", "lolpass12345");
    while (WiFi.status() != WL_CONNECTED) delay(100);
    Serial.println("Connected");

    ntp.begin(3);
}

void loop() {
    if (ntp.tick()) {
        Serial.println(ntp.toString());
    }
}

Версии

  • v1.0
  • v1.1 - мелкие улучшения и gmt в минутах
  • v1.2 - оптимизация, улучшена стабильность, добавлен асинхронный режим
  • v1.2.1 - изменён стандартный период обновления
  • v1.3 - ускорена синхронизация при запуске в асинхронном режиме
  • v1.3.1 - заинклудил WiFi библиотеку в файл
  • v2.0 - добавлена зависимость от Stamp, больше возможностей, проверка онлайна для других библиотек
  • v2.1 - добавлен глобальный объект NTP

Установка

  • Библиотеку можно найти по названию GyverNTP и установить через менеджер библиотек в:
    • Arduino IDE
    • Arduino IDE v2
    • PlatformIO
  • Скачать библиотеку .zip архивом для ручной установки:
    • Распаковать и положить в C:\Program Files (x86)\Arduino\libraries (Windows x64)
    • Распаковать и положить в C:\Program Files\Arduino\libraries (Windows x32)
    • Распаковать и положить в Документы/Arduino/libraries/
    • (Arduino IDE) автоматическая установка из .zip: Скетч/Подключить библиотеку/Добавить .ZIP библиотеку… и указать скачанный архив
  • Читай более подробную инструкцию по установке библиотек здесь

Обновление

  • Рекомендую всегда обновлять библиотеку: в новых версиях исправляются ошибки и баги, а также проводится оптимизация и добавляются новые фичи
  • Через менеджер библиотек IDE: найти библиотеку как при установке и нажать "Обновить"
  • Вручную: удалить папку со старой версией, а затем положить на её место новую. "Замену" делать нельзя: иногда в новых версиях удаляются файлы, которые останутся при замене и могут привести к ошибкам!

Баги и обратная связь

При нахождении багов создавайте Issue, а лучше сразу пишите на почту alex@alexgyver.ru
Библиотека открыта для доработки и ваших Pull Request'ов!

При сообщении о багах или некорректной работе библиотеки нужно обязательно указывать:

  • Версия библиотеки
  • Какой используется МК
  • Версия SDK (для ESP)
  • Версия Arduino IDE
  • Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде
  • Какой код загружался, какая работа от него ожидалась и как он работает в реальности
  • В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код

About

Библиотека для получения точного времени с NTP сервера для esp8266/esp32

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages