ESP32/ESP8266: Запуск ежедневной задачи в определенное время (Arduino IDE)
В этом руководстве мы покажем, как получить дату и время с помощью ESP32 или ESP8266, чтобы запускать одну или несколько задач каждый день в точное время. Для этого приложения ваши платы ESP будут получать время с помощью протокола сетевого времени (NTP), поэтому они должны быть подключены к Интернету. Платы ESP будут программироваться с помощью Arduino IDE.
Необходимые условия
Перед началом работы убедитесь, что у вас установлено дополнение для плат ESP32 или ESP8266 в Arduino IDE:
Установка платы ESP32 в Arduino IDE 2 (Windows, Mac OS X, Linux)
Установка платы ESP8266 NodeMCU в Arduino IDE 2 (Windows, Mac OS X, Linux)
Для этого руководства вам понадобится только плата ESP32 или ESP8266:
NTP (Network Time Protocol)
Для отслеживания времени мы будем использовать NTP. NTP расшифровывается как Network Time Protocol (протокол сетевого времени) – это сетевой протокол для синхронизации часов между компьютерными системами. Другими словами, он используется для синхронизации времени компьютерных часов в сети.
Существуют NTP-серверы, такие как pool.ntp.org, которые любой может использовать для запроса времени в качестве клиента. В этом случае ESP32/ESP8266 является NTP-клиентом, который запрашивает время у NTP-сервера (pool.ntp.org).
Если вы хотите узнать больше о взаимодействии NTP-клиента и сервера с платами ESP, вы можете прочитать следующие руководства:
ESP32 NTP клиент-сервер: получение даты и времени (Arduino IDE)
ESP8266 NodeMCU NTP клиент-сервер: получение даты и времени (Arduino IDE)
В этом руководстве вы будете использовать стандартную библиотеку time.h, которая поставляется вместе с фреймворком Arduino, поэтому вам не нужно устанавливать дополнительные библиотеки.
ESP32/ESP8266: Запуск ежедневной задачи в определенное время – Код
Чтобы получить дату и время с помощью плат ESP, вам не нужно устанавливать никаких библиотек. Вы просто подключаете библиотеку time.h в свой код.
Следующий код получает дату и время от NTP-сервера, выводит результаты в Serial Monitor и проверяет, была ли выполнена ежедневная задача или нет.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
https://RandomNerdTutorials.com/esp32-esp8266-run-daily-task/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <time.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Timezone string for your region, example: https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
const char* timezone = "WET0WEST,M3.5.0/1,M10.5.0"; // WET0WEST,M3.5.0/1,M10.5.0 = Europe/Lisbon
// Time that the daily task runs in 24 hour format
const int taskHour = 16; // Hour example in 24 hour format: 16 = 4 PM
const int taskMinute = 5; // 5 minutes
// Store the day when the task last ran to ensure it only runs once per day
int lastRunDay = -1;
unsigned long lastNTPUpdate = 0; // Timestamp for the last NTP sync
const unsigned long ntpSyncInterval = 30 * 60 * 1000; // Sync every 30 minutes (in ms)
void syncTime() {
Serial.print("Synchronizing time with NTP server...");
configTime(0, 0, "pool.ntp.org", "time.nist.gov"); // UTC offset set to 0
time_t now = time(nullptr);
while (now < 24 * 3600) { // Wait until time is valid
delay(100);
now = time(nullptr);
}
Serial.println(" Time synchronized!");
// Set timezone
setenv("TZ", timezone, 1);
tzset();
lastNTPUpdate = millis(); // Record the time of the last sync
}
void setup() {
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(".");
}
Serial.println("");
Serial.println("WiFi connected.");
syncTime();
}
void loop() {
time_t now = time(nullptr);
struct tm timeinfo;
localtime_r(&now, &timeinfo);
// Current time and date
Serial.printf("Current time: %02d:%02d:%02d, Date: %04d-%02d-%02d\n",
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday);
// Check if it's time to run the daily task
if (timeinfo.tm_hour == taskHour && timeinfo.tm_min == taskMinute && lastRunDay != timeinfo.tm_mday) {
dailyTask();
// Set the day to ensure it only runs once per day
lastRunDay = timeinfo.tm_mday;
}
// Resynchronize with NTP every 30 minutes
if (millis() - lastNTPUpdate > ntpSyncInterval) {
syncTime();
}
delay(1000); // Run loop every second
}
void dailyTask() {
Serial.println("#########\nDoing daily task...\n#########");
// ENTER YOUR TASK HERE
}
Как работает код
Давайте кратко рассмотрим код, чтобы понять, как он работает. Сначала подключаем библиотеки для подключения к Wi-Fi и получения времени.
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <time.h>
Настройка SSID и пароля
Введите ваши сетевые учетные данные в следующие переменные, чтобы ESP32/ESP8266 мог установить интернет-соединение и получить дату и время от NTP-сервера.
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Установка переменной timezone
Затем вам нужно определить переменную timezone для получения правильного времени для вашего местоположения.
const char* timezone = "WET0WEST,M3.5.0/1,M10.5.0";
Например, автор живет в Порту. Часовой пояс – Europe/Lisbon. Из списка строковых переменных часовых поясов видно, что строковая переменная часового пояса для этого местоположения – WET0WEST,M3.5.0/1,M10.5.0. Вы можете проверить список строковых переменных часовых поясов здесь.
Установка часа и минуты запуска задачи
Установите час и минуту, когда вы хотите запускать ежедневную задачу. Время для ежедневной задачи устанавливается в 24-часовом формате, поэтому taskHour, установленный на 16, соответствует 4 часам дня.
const int taskHour = 16;
const int taskMinute = 5;
Другие переменные
Сохраняем день, когда задача была последний раз запущена, чтобы убедиться, что она выполняется только один раз в день:
int lastRunDay = -1;
Метка времени последней синхронизации NTP и как часто вы хотите синхронизировать время с NTP-сервером:
unsigned long lastNTPUpdate = 0;
const unsigned long ntpSyncInterval = 30 * 60 * 1000; // Sync every 30 minutes (in ms)
setup()
В setup() вы инициализируете Serial-соединение на скорости 115200 бод для вывода результатов:
Serial.begin(115200);
Следующие строки подключают плату ESP к вашему роутеру для установления интернет-соединения.
// Connect to Wi-Fi
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Наконец, вызываем функцию syncTime() для синхронизации вашей платы с NTP-сервером.
syncTime();
syncTime()
Функция syncTime() подключается к NTP-серверу, получает дату и время и обновляет время с правильным часовым поясом, определенным ранее.
void syncTime() {
Serial.print("Synchronizing time with NTP server...");
configTime(0, 0, "pool.ntp.org", "time.nist.gov"); // UTC offset set to 0
time_t now = time(nullptr);
while (now < 24 * 3600) { // Wait until time is valid
delay(100);
now = time(nullptr);
}
Serial.println(" Time synchronized!");
// Set timezone
setenv("TZ", timezone, 1);
tzset();
lastNTPUpdate = millis(); // Record the time of the last sync
}
loop()
В loop() мы подготавливаем переменные времени и даты. Мы также выводим переменные в Serial Monitor для целей отладки:
time_t now = time(nullptr);
struct tm timeinfo;
localtime_r(&now, &timeinfo);
// Current time and date
Serial.printf("Current time: %02d:%02d:%02d, Date: %04d-%02d-%02d\n",
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday);
Эта часть кода проверяет, наступило ли точное время для запуска ежедневной задачи:
if (timeinfo.tm_hour == taskHour && timeinfo.tm_min == taskMinute && lastRunDay != timeinfo.tm_mday) {
dailyTask();
// Set the day to ensure it only runs once per day
lastRunDay = timeinfo.tm_mday;
}
Наконец, проверяем, прошло ли 30 минут, и если да, то необходимо синхронизировать время. Мы также добавляем задержку для запуска цикла каждую секунду.
// Resynchronize with NTP every 30 minutes
if (millis() - lastNTPUpdate > ntpSyncInterval) {
syncTime();
}
delay(1000); // Run loop every second
dailyTask()
Вы можете изменить функцию dailyTask(), чтобы добавить нужный код для вашего проекта, который будет выполняться в указанное время:
void dailyTask() {
Serial.println("#########\nDoing daily task...\n#########");
// ENTER YOUR TASK HERE
}
Демонстрация
На данный момент код только выводит сообщение в Serial Monitor Arduino IDE, когда задача выполняется. Вам следует изменить код для выполнения любой другой полезной задачи. Вот пример того, как это должно выглядеть:
ESP32/ESP8266: Запуск нескольких ежедневных задач – Код
На основе предыдущего примера вы можете продублировать некоторые разделы кода для запуска нескольких ежедневных задач в определенное время суток. По сути, вы добавляете два целевых времени и проверяете, была ли каждая задача уже выполнена в текущий день, используя две переменные. Вот полный пример:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
https://RandomNerdTutorials.com/esp32-esp8266-run-daily-task/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <time.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Timezone string for your region, example: https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
const char* timezone = "WET0WEST,M3.5.0/1,M10.5.0"; // WET0WEST,M3.5.0/1,M10.5.0 = Europe/Lisbon
// Time that the daily task runs in 24 hour format
const int task1Hour = 8; // Task 1 at 8:15 AM
const int task1Minute = 15;
const int task2Hour = 18; // Task 2 at 6:45 PM
const int task2Minute = 45;
// Store the day when the task last ran to ensure it only runs once per day
int lastRunDayTask1 = -1;
int lastRunDayTask2 = -1;
unsigned long lastNTPUpdate = 0; // Timestamp for the last NTP sync
const unsigned long ntpSyncInterval = 30 * 60 * 1000; // Sync every 30 minutes (in ms)
void syncTime() {
Serial.print("Synchronizing time with NTP server...");
configTime(0, 0, "pool.ntp.org", "time.nist.gov"); // UTC offset set to 0
time_t now = time(nullptr);
while (now < 24 * 3600) { // Wait until time is valid
delay(100);
now = time(nullptr);
}
Serial.println(" Time synchronized!");
// Set timezone
setenv("TZ", timezone, 1);
tzset();
lastNTPUpdate = millis(); // Record the time of the last sync
}
void setup() {
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(".");
}
Serial.println("");
Serial.println("WiFi connected.");
syncTime();
}
void loop() {
time_t now = time(nullptr);
struct tm timeinfo;
localtime_r(&now, &timeinfo);
// Current time and date
Serial.printf("Current time: %02d:%02d:%02d, Date: %04d-%02d-%02d\n",
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday);
// Check if it's time to run the daily task #1
if (timeinfo.tm_hour == task1Hour && timeinfo.tm_min == task1Minute && lastRunDayTask1 != timeinfo.tm_mday) {
dailyTask1();
// Set the day to ensure it only runs once per day
lastRunDayTask1 = timeinfo.tm_mday;
}
// Check if it's time to run the daily task #2
if (timeinfo.tm_hour == task2Hour && timeinfo.tm_min == task2Minute && lastRunDayTask2 != timeinfo.tm_mday) {
dailyTask2();
// Set the day to ensure it only runs once per day
lastRunDayTask2 = timeinfo.tm_mday;
}
// Resynchronize with NTP every 30 minutes
if (millis() - lastNTPUpdate > ntpSyncInterval) {
syncTime();
}
delay(1000); // Run loop every second
}
void dailyTask1() {
Serial.println("#########\nDoing daily task #1...\n#########");
// ENTER YOUR TASK HERE
}
void dailyTask2() {
Serial.println("#########\nDoing daily task #2...\n#########");
// ENTER YOUR TASK HERE
}
Не забудьте ввести ваши сетевые учетные данные, часовой пояс, желаемое время выполнения задач и изменить функции dailyTask для запуска вашей ежедневной задачи. По умолчанию в этом новом коде задача #1 будет выполняться в 8:15 утра, а задача #2 – в 6:45 вечера.
Заключение
Это краткое руководство научило вас создавать простой код, который может запускать одну или несколько задач на ваших платах ESP в нужное время.
Мы надеемся, что это руководство было полезным. У нас есть другие руководства, связанные со временем, которые могут вам понравиться:
ESP32 NTP клиент-сервер: получение даты и времени (Arduino IDE)
ESP8266 NodeMCU NTP клиент-сервер: получение даты и времени (Arduino IDE)
ESP32 регистрация данных температуры на MicroSD-карту (с NTP временем)
ESP32: руководство по модулю DS1307 Real Time Clock (RTC) (Arduino IDE)
Узнайте больше об ESP32 с нашими ресурсами:
—
Источник: :doc:`ESP32/ESP8266: Run Daily Task at Specific Time (Arduino IDE) <../esp32-esp8266-run-daily-task/index>` – Random Nerd Tutorials, Rui Santos & Sara Santos