ESP32 NTP время – настройка часовых поясов и летнего времени
В этом руководстве вы узнаете, как правильно получать время на ESP32 для вашего часового пояса с учётом перехода на летнее время (если это применимо). ESP32 запрашивает время у NTP-сервера, и оно автоматически корректируется для вашего часового пояса с учётом или без учёта летнего времени.
Быстрый ответ: вызовите setenv(«TZ», timezone, 1), где timezone – одна из строк часовых поясов, перечисленных здесь. Затем вызовите tzset() для обновления часового пояса.
Если вы только начинаете, рекомендуем сначала ознакомиться со следующим руководством, чтобы узнать, как получить дату и время с NTP-сервера:
В предыдущем руководстве мы показали вариант настройки часового пояса. Однако тот пример не учитывает переход на летнее время. Продолжайте читать это руководство, чтобы узнать, как правильно настроить часовой пояс и летнее время.
Благодарим одного из наших читателей (Hardy Maxa), который поделился этой информацией с нами.
Настройка часового пояса ESP32 с учётом летнего времени
Согласно документации:
«Для установки локального часового пояса используйте POSIX-функции setenv и tzset. Сначала вызовите setenv, чтобы установить переменную окружения TZ в правильное значение в зависимости от местоположения устройства. Формат строки времени описан в документации libc. Затем вызовите tzset, чтобы обновить данные библиотеки C для нового часового пояса. После выполнения этих шагов функция localtime будет возвращать правильное местное время с учётом смещения часового пояса и летнего времени.»
Вы можете просмотреть список строковых переменных часовых поясов здесь.
Например, я живу в Порту. Часовой пояс – Europe/Lisbon. Из списка строковых переменных часовых поясов я вижу, что строковая переменная для моего местоположения – WET0WEST,M3.5.0/1,M10.5.0, поэтому после подключения к NTP-серверу, чтобы получить время для моего местоположения, мне нужно вызвать:
setenv("TZ","WET0WEST,M3.5.0/1,M10.5.0",1);
А затем:
tzset();
Давайте рассмотрим демонстрационный скетч, чтобы понять, как это работает и как использовать это в вашем проекте ESP32.
Пример скетча ESP32 с часовым поясом и DST
Следующий пример был предоставлен одним из наших подписчиков (Hardy Maxa), мы лишь внесли несколько изменений.
Скопируйте следующий код в вашу Arduino IDE.
// RTC demo for ESP32, that includes TZ and DST adjustments
// Get the POSIX style TZ format string from https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
// Created by Hardy Maxa
// Complete project details at: https://RandomNerdTutorials.com/esp32-ntp-timezones-daylight-saving/
#include <WiFi.h>
#include "time.h"
const char * ssid="REPLACE_WITH_YOUR_SSID";
const char * wifipw="REPLACE_WITH_YOUR_PASSWORD";
void setTimezone(String timezone){
Serial.printf(" Setting Timezone to %s\n",timezone.c_str());
setenv("TZ",timezone.c_str(),1); // Now adjust the TZ. Clock settings are adjusted to show the new local time
tzset();
}
void initTime(String timezone){
struct tm timeinfo;
Serial.println("Setting up time");
configTime(0, 0, "pool.ntp.org"); // First connect to NTP server, with 0 TZ offset
if(!getLocalTime(&timeinfo)){
Serial.println(" Failed to obtain time");
return;
}
Serial.println(" Got the time from NTP");
// Now we can set the real timezone
setTimezone(timezone);
}
void printLocalTime(){
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
Serial.println("Failed to obtain time 1");
return;
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S zone %Z %z ");
}
void startWifi(){
WiFi.begin(ssid, wifipw);
Serial.println("Connecting Wifi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("Wifi RSSI=");
Serial.println(WiFi.RSSI());
}
void setTime(int yr, int month, int mday, int hr, int minute, int sec, int isDst){
struct tm tm;
tm.tm_year = yr - 1900; // Set date
tm.tm_mon = month-1;
tm.tm_mday = mday;
tm.tm_hour = hr; // Set time
tm.tm_min = minute;
tm.tm_sec = sec;
tm.tm_isdst = isDst; // 1 or 0
time_t t = mktime(&tm);
Serial.printf("Setting time: %s", asctime(&tm));
struct timeval now = { .tv_sec = t };
settimeofday(&now, NULL);
}
void setup(){
Serial.begin(115200);
Serial.setDebugOutput(true);
startWifi();
initTime("WET0WEST,M3.5.0/1,M10.5.0"); // Set for Melbourne/AU
printLocalTime();
}
void loop() {
int i;
// put your main code here, to run repeatedly:
Serial.println("Lets show the time for a bit. Starting with TZ set for Melbourne/Australia");
for(i=0; i<10; i++){
delay(1000);
printLocalTime();
}
Serial.println();
Serial.println("Now - change timezones to Berlin");
setTimezone("CET-1CEST,M3.5.0,M10.5.0/3");
for(i=0; i<10; i++){
delay(1000);
printLocalTime();
}
Serial.println();
Serial.println("Now - Lets change back to Lisbon and watch Daylight savings take effect");
setTimezone("WET0WEST,M3.5.0/1,M10.5.0");
printLocalTime();
Serial.println();
Serial.println("Now change the time. 1 min before DST takes effect. (1st Sunday of Oct)");
Serial.println("AEST = Australian Eastern Standard Time. = UTC+10");
Serial.println("AEDT = Australian Eastern Daylight Time. = UTC+11");
setTime(2021,10,31,0,59,50,0); // Set it to 1 minute before daylight savings comes in.
for(i=0; i<20; i++){
delay(1000);
printLocalTime();
}
Serial.println("Now change the time. 1 min before DST should finish. (1st Sunday of April)");
setTime(2021,3,28,1,59,50,1); // Set it to 1 minute before daylight savings comes in. Note. isDst=1 to indicate that the time we set is in DST.
for(i=0; i<20; i++){
delay(1000);
printLocalTime();
}
// Now lets watch the time and see how long it takes for NTP to fix the clock
Serial.println("Waiting for NTP update (expect in about 1 hour)");
while(1) {
delay(1000);
printLocalTime();
}
}
Как работает код
Сначала вам нужно подключить библиотеку WiFi для подключения ESP32 к интернету (NTP-серверу) и библиотеку time для работы со временем.
#include <WiFi.h>
#include "time.h"
Для установки часового пояса мы создали функцию setTimezone(), которая принимает в качестве аргумента строку часового пояса.
void setTimezone(String timezone){
Внутри этой функции мы вызываем setenv() для параметра TZ (часовой пояс), чтобы установить часовой пояс тем значением, которое вы передали в качестве аргумента функции setTimezone().
setenv("TZ",timezone.c_str(),1); // Now adjust the TZ. Clock settings are adjusted to show the new local time
После этого вызываем функцию tzset(), чтобы изменения вступили в силу.
tzset();
Мы не будем подробно описывать остальные функции, объявленные в коде, так как они уже были объяснены в предыдущем руководстве:
setup()
В setup() мы инициализируем Wi-Fi, чтобы ESP32 мог подключиться к интернету для связи с NTP-сервером.
initWifi();
Затем вызываем функцию initTime() и передаём в качестве аргумента строку часового пояса. В нашем случае – для часового пояса Lisbon/PT.
initTime("WET0WEST,M3.5.0/1,M10.5.0"); // Set for Lisbon/PT
После этого выводим текущее местное время.
printLocalTime();
loop()
В loop() показываем местное время в течение десяти секунд.
Serial.println("Lets show the time for a bit. Starting with TZ set for Lisbon/Portugal");
for(i=0; i<10; i++){
delay(1000);
printLocalTime();
}
Если в какой-то момент в вашем коде вам нужно сменить часовой пояс, вы можете сделать это, вызвав функцию setTimezone() и передав в качестве аргумента строку часового пояса. Например, следующие строки меняют часовой пояс на Берлин и отображают время в течение десяти секунд.
Serial.println();
Serial.println("Now - change timezones to Berlin");
setTimezone("CET-1CEST,M3.5.0,M10.5.0/3");
for(i=0; i<10; i++){
delay(1000);
printLocalTime();
}
Затем мы возвращаемся к нашему местному времени, снова вызывая функцию setTimezone() со строковой переменной часового пояса Lisbon/PT.
Serial.println();
Serial.println("Now - Lets change back to Lisbon and watch Daylight savings take effect");
setTimezone("WET0WEST,M3.5.0/1,M10.5.0");
printLocalTime();
Чтобы проверить, работает ли переход на летнее/зимнее время, мы изменим время на 10 секунд до перехода на зимнее время. В нашем случае это происходит в последнее воскресенье октября (для вашего местоположения это может быть иначе).
Serial.println();
Serial.println("Now change the time. 1 min before DST takes effect. (Last Sunday of Oct)");
setTime(2021,10,31,0,59,50,0); // Set it to 1 minute before daylight savings comes in.
Затем показываем время некоторое время, чтобы убедиться, что оно корректируется с учётом DST.
for(i=0; i<20; i++){
delay(1000);
printLocalTime();
}
После этого снова изменим время, чтобы проверить, происходит ли переход на летнее время. В нашем случае это последнее воскресенье марта.
Serial.println("Now change the time. 1 min before DST should finish. (Last Sunday of March)");
setTime(2021,3,28,1,59,50,1); // Set it to 1 minute before daylight savings comes in. Note. isDst=1 to indicate that the time we set is in DST.
Показываем время некоторое время, чтобы убедиться, что произошёл переход на летнее время.
for(i=0; i<20; i++){
delay(1000);
printLocalTime();
}
Демонстрация
Теперь давайте протестируем код. После ввода ваших сетевых данных загрузите код на ESP32.
После этого откройте Serial Monitor на скорости 115200 бод и нажмите кнопку RST на ESP32, чтобы запустить выполнение кода.
Сначала отображается ваше местное время с часовым поясом, который вы установили в коде.
После этого произойдёт смена на другой часовой пояс, который вы указали в коде. В нашем случае мы установили Берлин.
Затем вы должны увидеть переход на зимнее время. В нашем случае, когда наступает 2 часа ночи, часы переводятся на один час назад.
Мы также проверяем, корректируется ли время при переходе на летнее время. В примере ниже вы можете видеть, что часы переводятся на один час вперёд для установки летнего времени.
Заключение
Это краткое руководство научило вас настраивать часовой пояс с учётом летнего времени с помощью функций setenv() и tzset().
Надеемся, что это руководство оказалось для вас полезным. У нас есть другие руководства, связанные со временем, которые могут вам понравиться:
Getting Date and Time with ESP32 on Arduino IDE (NTP Client)
ESP32 Data Logging Temperature to MicroSD Card (with NTP time)
Источник: Random Nerd Tutorials – ESP32 NTP Time – Setting Up Timezones and Daylight Saving Time