#include #include #include #include "sntp_timp.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" #include "esp_idf_version.h" #include "esp_sntp.h" #include "esp_netif_sntp.h" #include "sys/time.h" #include "esp_timer.h" static const char *TAG = "sntp_timp"; #define SNTP_TIME_VALID_UNIX_TS 1700000000 #define SNTP_WAIT_POLL_MS 200 #define SNTP_REFRESH_PERIOD_MS 1000 extern void set_var_sntp_time(const char *value) __attribute__((weak)); static TaskHandle_t s_time_refresh_task = NULL; static time_t get_current_time(void); static void publish_sntp_time_var(const char *value) { if (set_var_sntp_time != NULL) { set_var_sntp_time(value); } } static void format_current_time(char *buffer, size_t buffer_size) { time_t now = get_current_time(); struct tm timeinfo; localtime_r(&now, &timeinfo); strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S", &timeinfo); } static void sntp_time_refresh_task(void *arg) { (void)arg; char time_text[32]; for (;;) { format_current_time(time_text, sizeof(time_text)); publish_sntp_time_var(time_text); vTaskDelay(pdMS_TO_TICKS(SNTP_REFRESH_PERIOD_MS)); } } // =========================== 时间相关函数 =========================== static void set_timezone(void) { // 设置中国标准时间(北京时间) setenv("TZ", "CST-8", 1); tzset(); ESP_LOGI(TAG, "时区设置为北京时间 (CST-8)"); } static time_t get_current_time(void) { // 使用POSIX函数获取时间 return time(NULL); } static void print_current_time(void) { char buffer[64]; format_current_time(buffer, sizeof(buffer)); ESP_LOGI(TAG, "当前时间: %s", buffer); } static esp_err_t start_time_refresh_task_if_needed(void) { if (s_time_refresh_task != NULL) { return ESP_OK; } BaseType_t ok = xTaskCreate(sntp_time_refresh_task, "sntp_time", 3072, NULL, 3, &s_time_refresh_task); return (ok == pdPASS) ? ESP_OK : ESP_ERR_NO_MEM; } static void configure_sntp_servers(void) { ESP_LOGI(TAG, "初始化SNTP服务"); #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) esp_sntp_setoperatingmode(SNTP_OPMODE_POLL); esp_sntp_setservername(0, "cn.pool.ntp.org"); // 中国 NTP 服务器 esp_sntp_setservername(1, "ntp1.aliyun.com"); // 阿里云 NTP 服务器 #else sntp_setoperatingmode(SNTP_OPMODE_POLL); sntp_setservername(0, "cn.pool.ntp.org"); sntp_setservername(1, "cn.pool.ntp.org"); sntp_setservername(2, "ntp1.aliyun.com"); #endif } static esp_err_t wait_for_time_sync(uint32_t timeout_ms) { int64_t start_ms = esp_timer_get_time() / 1000; for (;;) { time_t now = get_current_time(); if (now >= SNTP_TIME_VALID_UNIX_TS) { return ESP_OK; } int64_t elapsed_ms = (esp_timer_get_time() / 1000) - start_ms; if (elapsed_ms >= (int64_t)timeout_ms) { return ESP_ERR_TIMEOUT; } vTaskDelay(pdMS_TO_TICKS(SNTP_WAIT_POLL_MS)); } } esp_err_t sntp_timp_sync_time(uint32_t timeout_ms) { if (timeout_ms == 0) { timeout_ms = 10000; } set_timezone(); if (esp_sntp_enabled()) { esp_sntp_stop(); } configure_sntp_servers(); esp_sntp_init(); esp_err_t ret = wait_for_time_sync(timeout_ms); if (ret == ESP_OK) { print_current_time(); char time_text[32]; format_current_time(time_text, sizeof(time_text)); publish_sntp_time_var(time_text); esp_err_t task_ret = start_time_refresh_task_if_needed(); if (task_ret != ESP_OK) { ESP_LOGW(TAG, "创建时间刷新任务失败: %s", esp_err_to_name(task_ret)); } } else { ESP_LOGW(TAG, "SNTP 对时超时(%lu ms)", (unsigned long)timeout_ms); } return ret; }