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

МикроконтроллерESP32, благодаря встроенным возможностям Wi-Fi, является популярной платформой для проектов Интернета вещей (IoT). Во многих таких приложениях, особенно связанных с регистрацией данных (data logging) или планированием задач, требуется точная синхронизация времени. Получение актуальной даты и времени необходимо для присвоения временных меток событиям или измерениям. Одним из наиболее распространенных и эффективных методов синхронизации времени для устройств, подключенных к сети, является использование протокола сетевого времени (NTP - Network Time Protocol).

Данный урок демонстрирует процесс настройки ESP32 в качестве NTP-клиента для запроса точного времени с публичных NTP-серверов с использованием среды разработки Arduino IDE. Преимущество этого подхода заключается в отсутствии необходимости использования дополнительных аппаратных модулей, таких как часы реального времени (RTC), при условии наличия у ESP32 активного интернет-соединения.

Протокол сетевого времени (NTP - Network Time Protocol).

Перед выполнением инструкций, изложенных в данном руководстве, убедитесь, что в вашей среде Arduino IDE установлено дополнение для поддержки плат ESP32. Инструкции по установке можно найти в официальной документации или соответствующих руководствах:

Протокол сетевого времени (NTP - Network Time Protocol).

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

Существуют общедоступные NTP-серверы, такие как pool.ntp.org, которые предоставляют услуги синхронизации времени любому устройству (клиенту). В рассматриваемом сценарии ESP32 выступает в роли NTP-клиента, который отправляет запрос на сервер pool.ntp.org для получения текущего времени.

Диаграмма взаимодействия:

[ESP32 (NTP Client)] -------- NTP Request --------> [pool.ntp.org (NTP Server)]
[ESP32 (NTP Client)] <------- NTP Response -------- [pool.ntp.org (NTP Server)]
(Содержит точное время)

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

Для получения даты и времени с использованием ESP32 и Arduino IDE не требуется установка сторонних библиотек для работы с NTP. Необходимые функции входят в состав стандартной библиотеки time.h, которая является частью ESP32 core для Arduino. Вам потребуется только библиотека WiFi.h для установления сетевого соединения.

Следующий программный код демонстрирует получение даты и времени с NTP-сервера и вывод результатов в Монитор последовательного порта Arduino IDE. Код основан на примере, поставляемом с библиотекой time.h.

Исходный код

/*
* Клиент-сервер NTP на ESP32: Получение даты и времени.
* https://arduino-tex.ru/news/211/klient-server-ntp-na-esp32-poluchenie-daty-i-vremeni.html
*/

#include <WiFi.h>  // Библиотека для работы с Wi-Fi
#include "time.h"  // Стандартная библиотека C для работы со временем

// --- Параметры сети Wi-Fi ---
const char* ssid = "YOUR_SSID";          // Замените на имя вашей Wi-Fi сети
const char* password = "YOUR_PASSWORD";  // Замените на пароль вашей Wi-Fi сети

// --- Параметры NTP ---
const char* ntpServer = "pool.ntp.org";  // Адрес публичного NTP сервера
// Смещение относительно времени по Гринвичу (GMT) в секундах.
// Пример: для GMT+3 установите 3 * 3600. Для Москвы (UTC+3) значение 10800.
const long gmtOffset_sec = 10800;
// Смещение для перехода на летнее время в секундах.
// Обычно 1 час (3600 секунд) или 0, если летнее время не используется.
const int daylightOffset_sec = 0;

// Прототип функции для вывода времени
void printLocalTime();

// --- Функция начальной настройки ---
void setup() {
  Serial.begin(115200);  // Инициализация последовательного порта для вывода отладочной информации

  // Подключение к сети Wi-Fi
  Serial.print("Подключение к Wi-Fi сети: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);              // Начать процесс подключения
  while (WiFi.status() != WL_CONNECTED) {  // Ожидание успешного подключения
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("Wi-Fi подключено.");
  Serial.print("IP адрес: ");
  Serial.println(WiFi.localIP());  // Вывод полученного IP-адреса

  // Инициализация и получение времени с NTP сервера
  // configTime(смещение_GMT_сек, смещение_летнего_времени_сек, адрес_NTP_сервера)
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

  // Первоначальный вывод времени после синхронизации
  printLocalTime();

  // Отключение Wi-Fi после получения времени (опционально, для экономии энергии)
  // Если время требуется обновлять периодически, Wi-Fi отключать не следует.
  // WiFi.disconnect(true);
  // WiFi.mode(WIFI_OFF);
  // Serial.println("Wi-Fi отключен.");
}

// --- Основной цикл программы ---
void loop() {
  // Задержка в 1 секунду (1000 миллисекунд)
  delay(1000);
  // Вывод текущего локального времени каждую секунду
  printLocalTime();
}

// --- Функция для получения и вывода локального времени ---
void printLocalTime() {
  struct tm timeinfo;  // Структура для хранения компонентов времени

  // Попытка получить локальное время.
  // getLocalTime() возвращает false, если время еще не синхронизировано.
  if (!getLocalTime(&timeinfo)) {
    Serial.println("Не удалось получить время с NTP сервера.");
    return;  // Выход из функции, если время не получено
  }

  // Вывод времени в стандартном формате: День недели, Месяц День Год Час:Минута:Секунда
  // Функция strftime форматирует время из структуры tm в строку согласно спецификаторам формата.
  char timeStringBuff[50];  // Буфер для отформатированной строки времени
  strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
  Serial.println(timeStringBuff);  // Вывод полной строки времени

  // --- (Опционально) Детальный вывод компонентов времени ---
  Serial.print("День недели: ");
  strftime(timeStringBuff, sizeof(timeStringBuff), "%A", &timeinfo);  // %A - полное название дня недели
  Serial.println(timeStringBuff);

  Serial.print("Месяц: ");
  strftime(timeStringBuff, sizeof(timeStringBuff), "%B", &timeinfo);  // %B - полное название месяца
  Serial.println(timeStringBuff);

  Serial.print("День месяца: ");
  strftime(timeStringBuff, sizeof(timeStringBuff), "%d", &timeinfo);  // %d - день месяца (01-31)
  Serial.println(timeStringBuff);

  Serial.print("Год: ");
  strftime(timeStringBuff, sizeof(timeStringBuff), "%Y", &timeinfo);  // %Y - год (4 цифры)
  Serial.println(timeStringBuff);

  Serial.print("Час (24ч): ");
  strftime(timeStringBuff, sizeof(timeStringBuff), "%H", &timeinfo);  // %H - час (00-23)
  Serial.println(timeStringBuff);

  Serial.print("Час (12ч): ");
  strftime(timeStringBuff, sizeof(timeStringBuff), "%I", &timeinfo);  // %I - час (01-12)
  Serial.println(timeStringBuff);

  Serial.print("Минута: ");
  strftime(timeStringBuff, sizeof(timeStringBuff), "%M", &timeinfo);  // %M - минута (00-59)
  Serial.println(timeStringBuff);

  Serial.print("Секунда: ");
  strftime(timeStringBuff, sizeof(timeStringBuff), "%S", &timeinfo);  // %S - секунда (00-59)
  Serial.println(timeStringBuff);

  // --- (Опционально) Пример сохранения компонентов времени в переменные ---
  Serial.println("Переменные времени:");
  char timeHour[3];  // Буфер для часов (2 цифры + нуль-терминатор)
  strftime(timeHour, sizeof(timeHour), "%H", &timeinfo);
  Serial.print("Час сохраненный в переменную: ");
  Serial.println(timeHour);

  char timeWeekDay[10];  // Буфер для дня недели (макс. ~9 символов + нуль-терминатор)
  strftime(timeWeekDay, sizeof(timeWeekDay), "%A", &timeinfo);
  Serial.print("День недели сохраненный в переменную: ");
  Serial.println(timeWeekDay);
  Serial.println();  // Пустая строка для разделения выводов
}

Анализ кода.

Рассмотрим ключевые части приведенного кода:

  1. Подключение библиотек:
    #include <WiFi.h> // Для управления Wi-Fi соединением
    #include "time.h" // Стандартная библиотека C для работы со временем
    Библиотека WiFi.h необходима для подключения ESP32 к сети Интернет. Библиотека time.h предоставляет функции для работы со временем, включая получение времени от NTP-сервера (configTime, getLocalTime) и его форматирование (strftime).
  2. Настройка SSID и пароля:
    const char* ssid = "YOUR_SSID";
    const char* password = "YOUR_PASSWORD";
    В этих константных строках необходимо указать имя (SSID) и пароль вашей Wi-Fi сети. Эти данные используются функцией WiFi.begin() для установления соединения.
  3. Параметры NTP и времени: Для конфигурации NTP-клиента и корректного отображения местного времени используются следующие переменные:
    • NTP-сервер (ntpServer):
       const char* ntpServer = "pool.ntp.org";
      Указывает адрес пула NTP-серверов. pool.ntp.org — это распределенная сеть серверов времени, обеспечивающая надежность и доступность. Можно использовать и другие региональные пулы (например, ru.pool.ntp.org) или конкретные адреса NTP-серверов.
    • Смещение GMT (gmtOffset_sec):
      const long gmtOffset_sec = 10800;
      Определяет разницу в секундах между вашим часовым поясом и временем по Гринвичу (GMT/UTC). Важно: Установите это значение в соответствии с вашим часовым поясом. Например, для Москвы (UTC+3) значение будет 3 * 3600 = 10800. Для Центральноевропейского времени (CET, UTC+1) значение будет 1 * 3600 = 3600. Информацию о смещениях часовых поясов можно найти в интернете.
    • Смещение летнего времени (daylightOffset_sec):
      const int daylightOffset_sec = 0;
      Определяет смещение в секундах для учета перехода на летнее время. Обычно это значение равно 3600 (1 час) или 0, если в вашем регионе летнее время не используется или вы не хотите его учитывать. Система автоматически применяет это смещение в соответствующие периоды (если базовое ядро ESP32 содержит актуальные правила перехода).
  4. Функция setup():
    • Инициализация Serial.begin(115200) настраивает последовательный порт для вывода сообщений.
    • Блок кода, начинающийся с WiFi.begin(ssid, password), устанавливает соединение с указанной Wi-Fi сетью. Цикл while (WiFi.status() != WL_CONNECTED) ожидает завершения подключения.
    • Ключевая функция configTime(gmtOffset_sec, daylightOffset_sec, ntpServer) инициализирует внутреннюю систему времени ESP32, указывая ей использовать NTP-сервер и заданные смещения для расчета локального времени.
    • Вызов printLocalTime() осуществляется для немедленного вывода времени после успешной инициализации.
    • (Опционально): Строки WiFi.disconnect(true); и WiFi.mode(WIFI_OFF); могут быть использованы для отключения Wi-Fi модуля после получения времени, что полезно для снижения энергопотребления в проектах с батарейным питанием, где постоянное подключение не требуется.
  5. Функция loop(): В основном цикле программы с помощью delay(1000) создается пауза в 1 секунду, после чего вызывается функция printLocalTime() для регулярного обновления и вывода текущего времени в Монитор последовательного порта.
  6. Функция printLocalTime():
    • Создается экземпляр структуры struct tm timeinfo;. Структура tm определена в time.h и используется для хранения компонентов даты и времени (секунды, минуты, часы, день, месяц, год и т.д.).
      • Структура tm (согласно документации C):
        • tm_sec: Секунды после минуты (0-59)
        • tm_min: Минуты после часа (0-59)
        • tm_hour: Часы с полуночи (0-23)
        • tm_mday: День месяца (1-31)
        • tm_mon: Месяцы с января (0-11)
        • tm_year: Годы с 1900
        • tm_wday: Дни с воскресенья (0-6)
        • tm_yday: Дни с 1 января (0-365)
        • tm_isdst: Флаг летнего времени (положительное значение, если активно, 0 если нет, отрицательное - если информация недоступна)
    • Функция getLocalTime(&timeinfo) пытается заполнить структуру timeinfo текущим локальным временем, рассчитанным на основе последней синхронизации с NTP и заданных смещений. Она возвращает true в случае успеха и false, если время еще не было успешно синхронизировано (например, сразу после запуска или при отсутствии сети).
    • При неуспешном получении времени выводится сообщение об ошибке.
    • Функция strftime(buffer, bufferSize, format, &timeinfo) используется для форматирования даты и времени из структуры timeinfo в строку (buffer) в соответствии с заданным форматом (format).
    • Используются различные спецификаторы формата для вывода отдельных компонентов даты и времени:
      • %A: Полное название дня недели (на английском, например, "Monday")
      • %B: Полное название месяца (на английском, например, "January")
      • %d: День месяца как число с ведущим нулем (01-31)
      • %Y: Год в 4-значном формате (например, 2023)
      • %H: Час в 24-часовом формате (00-23)
      • %I: Час в 12-часовом формате (01-12)
      • %M: Минута как число с ведущим нулем (00-59)
      • %S: Секунда как число с ведущим нулем (00-59)
      • (Существуют и другие спецификаторы, например, %a - сокращенный день недели, %b - сокращенный месяц, %y - год (2 цифры), и т.д. См. документацию по strftime).
    • Демонстрируется сохранение отдельных компонентов времени (например, часа %H) в символьные массивы (строки) с помощью strftime. Это может быть полезно для дальнейшей обработки или использования в логике программы. Обратите внимание на размер буфера, который должен быть достаточным для хранения строки и терминатора (\0).

Демонстрация.

  1. Замените YOUR_SSID и YOUR_PASSWORD на реальные данные вашей Wi-Fi сети.
  2. Установите правильные значения для gmtOffset_sec и daylightOffset_sec в соответствии с вашим географическим положением и правилами перехода на летнее время.
  3. Выберите правильную плату ESP32 и COM-порт в меню "Инструменты" Arduino IDE.
  4. Скомпилируйте и загрузите скетч на плату ESP32.
  5. Откройте Монитор последовательного порта (Serial Monitor), установив скорость 115200 бод.
  6. После подключения к Wi-Fi и успешной синхронизации с NTP-сервером, вы увидите в Мониторе последовательного порта вывод текущей даты и времени, обновляемый каждую секунду.

Пример вывода в Мониторе последовательного порта.

Пример вывода в Мониторе последовательного порта


Заключение.

В данном руководстве был рассмотрен метод получения точной даты и времени на микроконтроллере ESP32 с использованием протокола NTP и среды разработки Arduino IDE. Были продемонстрированы настройка Wi-Fi соединения, конфигурация параметров NTP (адрес сервера, смещение GMT, учет летнего времени) и использование стандартных функций библиотеки time.h для получения и форматирования времени.

Этот подход является эффективным решением для проектов, требующих временных меток или синхронизации по времени, при условии наличия доступа к сети Интернет. Он устраняет необходимость в дополнительных аппаратных часах реального времени (RTC), упрощая схему и снижая стоимость устройства.

Важно помнить, что данный метод полностью зависит от наличия активного интернет-соединения для первоначальной синхронизации и периодических обновлений. Если ваш проект требует надежного отсчета времени даже при отсутствии сети, необходимо использовать альтернативные решения, такие как внешние модули RTC (например, DS1307, DS3231), которые имеют собственный источник питания (батарейку) и продолжают отсчет времени автономно.

Дополнительная информация к данному уроку:

Понравился урок: Клиент-сервер NTP на ESP32: Получение даты и времени (Arduino IDE)? Не забудь поделиться с друзьями в соц. сетях.

А также подписаться на наш канал на YouTube, вступить в группу Вконтакте, в Telegram.

Спасибо за внимание!

Технологии начинаются с простого!

Фотографии к статье

Файлы для скачивания

Код из урока Код из урока.ino7 Kb 31 Скачать

Комментарии

Ваше Имя*


Разработка проектов