Библиотека для получения точного времени с 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) { }
}
Часовой пояс задаётся для всех операций со 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()); // вывод даты и времени строкой
}
}
По умолчанию библиотека работает с 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
- Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде
- Какой код загружался, какая работа от него ожидалась и как он работает в реальности
- В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код