Получение даты и времени с NTP-сервера с помощью ESP8266 NodeMCU

Получение даты и времени с NTP-сервера с помощью ESP8266 NodeMCU

Время от времени вы сталкиваетесь с идеей, где поддержание точного времени является главным приоритетом. Например, рассмотрим реле, которое должно быть активировано в определённое время, или регистратор данных, который должен сохранять значения через точные интервалы.

Первое, что приходит на ум — использовать микросхему RTC (часы реального времени). Однако, поскольку эти микросхемы не являются идеально точными, вам придётся регулярно выполнять ручную корректировку, чтобы поддерживать их синхронизацию.

Вместо этого предпочтительнее использовать Network Time Protocol (NTP) — протокол сетевого времени. Если ваш проект на ESP8266 имеет доступ к Интернету, вы можете получать дату и время (с точностью до нескольких миллисекунд от UTC) БЕСПЛАТНО. Кроме того, вам не потребуется никакое дополнительное оборудование.

Руководство по ESP8266 для чтения даты и времени с NTP-сервера

Что такое NTP?

NTP — это аббревиатура от Network Time Protocol. Это стандартный интернет-протокол (IP) для синхронизации часов компьютеров по сети.

Этот протокол синхронизирует все сетевые устройства с координированным всемирным временем (UTC) с точностью до нескольких миллисекунд (50 миллисекунд через публичный Интернет и менее 5 миллисекунд в среде LAN).

Координированное всемирное время (UTC) — это глобальный стандарт времени, аналогичный GMT (среднее время по Гринвичу). UTC не меняется; оно одинаково во всём мире.

Идея состоит в том, чтобы использовать NTP для установки часов компьютера на UTC, а затем применить любое смещение местного часового пояса или смещение летнего времени. Это позволяет нам синхронизировать часы наших компьютеров независимо от местоположения или различий в часовых поясах.

Архитектура NTP

NTP использует иерархическую архитектуру. Каждый уровень в иерархии называется стратой (stratum).

Иерархическая архитектура NTP со стратами

На самом верху находятся высокоточные устройства хранения времени, такие как атомные часы, GPS или радиочасы, известные как аппаратные часы страты 0.

Серверы страты 1 имеют прямое подключение к аппаратным часам страты 0 и поэтому обеспечивают наиболее точное время.

Каждая страта в иерархии синхронизируется со стратой выше и выступает в качестве сервера для компьютеров в нижних стратах.

Как работает NTP?

NTP может работать несколькими способами. Наиболее распространённая конфигурация — работа в режиме клиент-сервер.

Основной принцип работы заключается в следующем:

  1. Клиентское устройство, такое как ESP8266, подключается к NTP-серверу через протокол пользовательских датаграмм (UDP) на порту 123.

  2. Затем клиент отправляет пакет запроса на NTP-сервер.

  3. В ответ на этот запрос NTP-сервер отправляет пакет с меткой времени. Пакет с меткой времени содержит различные данные, такие как временная метка UNIX, точность, задержка или часовой пояс.

  4. Затем клиент может извлечь из него текущую дату и время.

Работа NTP-сервера — передача пакетов запроса и метки времени

Подготовка Arduino IDE

Перед тем как приступить к этому руководству, у вас должно быть установлено дополнение ESP8266 в вашей Arduino IDE. Если вы ещё не установили его, следуйте руководству ниже.

Руководство по программированию ESP8266 в Arduino IDE

Установка платы ESP8266 в Arduino IDE — Существует несколько платформ разработки, доступных для программирования ESP8266. Вы можете выбрать Arduino IDE — предназначенную для тех, кто знаком с Arduino, Espruino…

Установка библиотеки NTP Client

Библиотека NTP Client упрощает процесс получения времени и даты с NTP-сервера. Выполните приведённые ниже шаги, чтобы установить эту библиотеку в вашей Arduino IDE.

Перейдите в Sketch > Include Library > Manage Libraries… Подождите, пока менеджер библиотек загрузит индекс библиотек и обновит список установленных библиотек.

Установка библиотеки Arduino — выбор Manage Libraries в Arduino IDE

Отфильтруйте поиск, введя „ntpclient“. Найдите NTPClient от Fabrice Weinberg. Нажмите на эту запись, а затем выберите Install.

Установка библиотеки NTP Client в Arduino IDE

Получение даты и времени с NTP-сервера

Приведённый ниже скетч покажет вам, как именно получить дату и время с NTP-сервера.

#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

const char *ssid     = "YOUR_SSID";
const char *password = "YOUR_PASS";

const long utcOffsetInSeconds = 3600;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);

void setup(){
  Serial.begin(115200);

  WiFi.begin(ssid, password);

  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 );
    Serial.print ( "." );
  }

  timeClient.begin();
}

void loop() {
  timeClient.update();

  Serial.print(daysOfTheWeek[timeClient.getDay()]);
  Serial.print(", ");
  Serial.print(timeClient.getHours());
  Serial.print(":");
  Serial.print(timeClient.getMinutes());
  Serial.print(":");
  Serial.println(timeClient.getSeconds());
  //Serial.println(timeClient.getFormattedTime());

  delay(1000);
}

Перед тем как начать загрузку скетча, вам нужно внести несколько изменений, чтобы убедиться, что он будет работать для вас.

  • Измените следующие две переменные, указав ваши сетевые учётные данные, чтобы ESP8266 мог подключиться к существующей сети.

const char* ssid       = "YOUR_SSID";
const char* password   = "YOUR_PASS";
  • Настройте смещение UTC для вашего часового пояса (в секундах). Обратитесь к списку смещений времени UTC. Вот несколько примеров для различных часовых поясов:

    • Для UTC -5.00 : -5 * 60 * 60 : -18000

    • Для UTC +1.00 : 1 * 60 * 60 : 3600

    • Для UTC +0.00 : 0 * 60 * 60 : 0

const long utcOffsetInSeconds = 3600;

После загрузки скетча нажмите кнопку RST на вашем NodeMCU. Монитор последовательного порта должен отображать дату и время каждую секунду.

ESP8266 считывает дату и время с NTP-сервера — вывод на мониторе последовательного порта

Объяснение кода

Давайте кратко рассмотрим код, чтобы понять, как он работает. Для начала мы подключаем библиотеки, необходимые для этого проекта.

  • NTPClient.h — это библиотека времени, которая корректно обрабатывает синхронизацию с NTP-сервером.

  • ESP8266WiFi.h — это библиотека, содержащая специфичные для ESP8266 методы WiFi, которые мы будем использовать для подключения к сети.

  • WiFiUdp.h — библиотека, обрабатывающая задачи протокола UDP, такие как открытие UDP-порта, отправка и получение UDP-пакетов и так далее.

#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

Определяется несколько констант, таких как SSID, пароль WiFi и смещение UTC. Также определяется двумерный массив daysOfTheWeek.

const char *ssid     = "YOUR_SSID";
const char *password = "YOUR_PASS";
const long utcOffsetInSeconds = 3600;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

Кроме того, указывается адрес NTP-сервера. pool.ntp.org — это отличный открытый NTP-проект для подобных задач.

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);

pool.ntp.org автоматически выбирает серверы времени, которые физически находятся ближе к вам. Однако, если вы хотите выбрать конкретный сервер, используйте одну из подзон pool.ntp.org.

Регион

Имя хоста

Весь мир

pool.ntp.org

Азия

asia.pool.ntp.org

Европа

europe.pool.ntp.org

Северная Америка

north-america.pool.ntp.org

Океания

oceania.pool.ntp.org

Южная Америка

south-america.pool.ntp.org

В секции setup мы сначала устанавливаем последовательную связь с ПК, а затем подключаемся к WiFi-сети, вызывая функцию WiFi.begin().

Serial.begin(115200);

WiFi.begin(ssid, password);

while ( WiFi.status() != WL_CONNECTED ) {
  delay ( 500 );
  Serial.print ( "." );
}

Как только ESP8266 подключён к сети, мы используем функцию begin() для инициализации NTP-клиента.

timeClient.begin();

Теперь мы просто вызываем функцию update() для получения текущей даты и времени. Эта функция отправляет пакет запроса на NTP-сервер и разбирает полученный пакет с меткой времени в читаемый формат.

timeClient.update();

Вы можете получить текущую дату и время, вызывая методы объекта NTP Client.

Serial.print(daysOfTheWeek[timeClient.getDay()]);
Serial.print(", ");
Serial.print(timeClient.getHours());
Serial.print(":");
Serial.print(timeClient.getMinutes());
Serial.print(":");
Serial.println(timeClient.getSeconds());