Получение времени и даты с NTP сервера
В этом руководстве вы узнаете, как получить дату и время с NTP-сервера, используя ESP8266 NodeMCU с Arduino IDE. Получение даты и времени полезно в проектах регистрации данных для определения показаний временных меток. Чтобы получать время с NTP-сервера, ESP8266 должен иметь подключение к Интернету, и вам не нужно дополнительное оборудование (например, часы RTC).
NTP (протокол сетевого времени)
NTP расшифровывается как протокол сетевого времени и представляет собой сетевой протокол для синхронизации часов между компьютерными системами. Другими словами, он используется для синхронизации времени работы компьютера в сети.
Существуют NTP-серверы, такие как pool.ntp.org который любой желающий может использовать для запроса времени в качестве клиента. В этом случае ESP8266 является NTP-клиентом, который запрашивает время у NTP-сервера (pool.ntp.org ).
Установка библиотеки NtpClient
Для получения времени мы будем использовать библиотеку NtpClient. В вашей Arduino IDE перейдите в Sketch> Библиотека> Управление библиотеками. Должен открыться менеджер библиотеки.
Найдите NtpClient и установите библиотеку Фабриса Вайнбера, как показано на следующем рисунке.
Функции времени библиотеки NtpClient
Библиотека NtpClient поставляется со следующими функциями для возврата времени:
getDay() – возвращает число int, соответствующее дню недели (от 0 до 6), начинающемуся в воскресенье;
getHours() – возвращает число int с текущим часом (от 0 до 23) в 24-часовом формате;
getMinutes() – возвращает номер int с текущими минутами (от 0 до 59);
getSeconds() – возвращает номер int с текущей секундой;
getEpochTime() – возвращает неподписанный long с указанием времени эпохи (количество секунд, прошедших с 1 января 1970 года (полночь по Гринвичу);
getFormattedTime() – возвращает строку со временем в формате HH: MM:SS;
В этой библиотеке нет функций для возврата даты, но мы покажем вам в коде, как получить дату (день, месяц и год).
Код ESP8266 NodeMCU
Следующий код соединяет ESP8266 с NTP-сервером (pool.ntp.org ) запросить дату и время. Он отображает текущую дату и время в нескольких форматах на последовательном мониторе.
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
// Replace with your network credentials
const char *ssid = "REPLACE_WITH_YOUR_SSID";
const char *password = "REPLACE_WITH_YOUR_PASSWORD";
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
//Week Days
String weekDays[7]={"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
//Month names
String months[12]={"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
// Connect to Wi-Fi
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Initialize a NTPClient to get time
timeClient.begin();
// Set offset time in seconds to adjust for your timezone, for example:
// GMT +1 = 3600
// GMT +3 = 10800
// GMT +8 = 28800
// GMT -1 = -3600
// GMT 0 = 0
timeClient.setTimeOffset(10800);
}
void loop() {
timeClient.update();
time_t epochTime = timeClient.getEpochTime();
Serial.print("Epoch Time: ");
Serial.println(epochTime);
String formattedTime = timeClient.getFormattedTime();
Serial.print("Formatted Time: ");
Serial.println(formattedTime);
int currentHour = timeClient.getHours();
Serial.print("Hour: ");
Serial.println(currentHour);
int currentMinute = timeClient.getMinutes();
Serial.print("Minutes: ");
Serial.println(currentMinute);
int currentSecond = timeClient.getSeconds();
Serial.print("Seconds: ");
Serial.println(currentSecond);
String weekDay = weekDays[timeClient.getDay()];
Serial.print("Week Day: ");
Serial.println(weekDay);
//Get a time structure
struct tm *ptm = gmtime ((time_t *)&epochTime);
int monthDay = ptm->tm_mday;
Serial.print("Month day: ");
Serial.println(monthDay);
int currentMonth = ptm->tm_mon+1;
Serial.print("Month: ");
Serial.println(currentMonth);
String currentMonthName = months[currentMonth-1];
Serial.print("Month name: ");
Serial.println(currentMonthName);
int currentYear = ptm->tm_year+1900;
Serial.print("Year: ");
Serial.println(currentYear);
//Print complete date:
String currentDate = String(currentYear) + "-" + String(currentMonth) + "-" + String(monthDay);
Serial.print("Current date: ");
Serial.println(currentDate);
Serial.println("");
delay(2000);
}
Как работает код
Во-первых, включите необходимые библиотеки.
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
Введите свои сетевые учетные данные в следующие переменные, чтобы ESP8266 мог подключиться к вашему маршрутизатору, чтобы иметь доступ к Интернету для запроса даты и времени с NTP-сервера.
const char *ssid = "REPLACE_WITH_YOUR_SSID";
const char *password = "REPLACE_WITH_YOUR_PASSWORD";
Определите NTP-клиент для получения даты и времени.
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
Мы запросим время у pool.ntp.org , который представляет собой кластер временных серверов, которые любой желающий может использовать для запроса времени. Затем мы создаем два массива для хранения названий дней недели и месяцев.
//Week Days
String weekDays[7]={"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
//Month names
String months[12]={"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
Блок Setup ()
В setup () инициализируйте последовательный монитор для отображения информации.
Serial.begin(115200);
Затем подключите ESP8266 к Интернету.
// Connect to Wi-Fi
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Инициализируйте NtpClient.
timeClient.begin();
Установка часового пояса
Вы можете использовать методsetTimeOffset()
, чтобы настроить время для вашего часового пояса в секундах.
timeClient.setTimeOffset(3600);
Вот несколько примеров для разных часовых поясов:
- GMT +1 = 3600
- GMT +3 = 10800
- GMT +8 = 28800
- GMT -1 = -3600
- GMT 0 = 0
timeClient.setTimeOffset(10800);
Основной цикл loop()
В loop() вызовите функцию update(), чтобы получить текущую дату и время с NTP-сервера.
timeClient.update();
Получение времени
Затем мы можем использовать функции, предоставляемые библиотекой, для получения времени. Например, чтобы получить время эпохи:
unsigned long epochTime = timeClient.getEpochTime();
Serial.print("Epoch Time: ");
Serial.println(epochTime);
Функция getFormattedTime() возвращает время в формате HH:MM:SS.
String formattedTime = timeClient.getFormattedTime();
Serial.print("Formatted Time: ");
Serial.println(formattedTime);
Вы можете получить часы, минуты или секунды отдельно, используя функции ,getHours(), getMinutes() и getSeconds() следующим образом:
int currentHour = timeClient.getHours();
Serial.print("Hour: ");
Serial.println(currentHour);
int currentMinute = timeClient.getMinutes();
Serial.print("Minutes: ");
Serial.println(currentMinute);
int currentSecond = timeClient.getSeconds();
Serial.print("Seconds: ");
Serial.println(currentSecond);
Получение даты
Функция getDay() возвращает число от 0 до 6, в котором 0 соответствует воскресенью, а 6 - субботе. Итак, мы можем получить доступ к названию дня недели из массива, который мы создали ранее, следующим образом
String weekDay = weekDays[timeClient.getDay()];
Serial.print("Week Day: ");
Serial.println(weekDay);
Клиент NTP не поставляется с функциями для получения даты. Итак, нам нужно создать временную структуру (struct tm)
, а затем получить доступ к ее элементам, чтобы получить информацию о дате.
struct tm *ptm = gmtime ((time_t *)&epochTime);
Временная структура содержит следующие элементы:
- tm_sec: секунды после минуты;
- tm_min: минуты после часа;
- tm_hour: часы с полуночи;
- tm_mday: день месяца;
- tm_year: годы с 1900 года;
- tm_wday: дни с воскресенья;
- tm_yday: дни с 1 января;
- tm_isdst: флаг перехода на летнее время;
В следующих строках указывается день месяца следующим образом:
int monthDay = ptm->tm_mday;
Serial.print("Month day: ");
Serial.println(monthDay);
Чтобы получить другие элементы, вы используете аналогичный подход. Например, за месяц:
int currentMonth = ptm->tm_mon+1;
Serial.print("Month: ");
Serial.println(currentMonth);
Поскольку tm_mday начинается с 0, мы добавляем 1 к месяцу, чтобы январь соответствовал 1, февраль - 2 и так далее.
Затем мы можем получить название месяца, используя массив месяцев, который мы создали ранее. Нумерация массивов начинается с 0, поэтому мы вычитаем 1.
String currentMonthName = months[currentMonth-1];
Serial.print("Month name: ");
Serial.println(currentMonthName);
Чтобы получить год, нам нужно добавить 1900, потому что tm_year сохраняет количество лет после 1900.
int currentYear = ptm->tm_year+1900;
Serial.print("Year: ");
Serial.println(currentYear);
Наконец, мы создаем строку с именем currentDate, которая содержит текущую дату в формате ГГГГ-ММ-ДД.
String currentDate = String(currentYear) + "-" + String(currentMonth) + "-" + String(monthDay);
Serial.print("Current date: ");
Serial.println(currentDate);
Демонстрация работы
После ввода ваших сетевых учетных данных и изменения переменных, чтобы настроить время в соответствии с вашим часовым поясом, протестируйте пример.
Загрузите код на свою плату ESP8266. Убедитесь, что выбраны правильная плата и COM-порт.
Откройте последовательный монитор со скоростью передачи 115200 бод. Дата и время должны отображаться в нескольких форматах, как показано ниже.
Подведение итогов
В этом уроке вы узнали, как получить дату и время с NTP-сервера с помощью ESP8266. Это особенно полезно для проектов регистрации данных, имеющих доступ к Интернету.