ESP8266/ESP32 基础篇: 时间同步 SNTP 介绍和使用

简介

SNTP 协议是用来同步本地的时间到 unix 时间戳. 通常嵌入式设备上电, 连接 AP(access point), 获取 IP 地址后, 就需要使用 SNTP 协议获取全球时间. 以便于下一步的应用交互和使用.

SNTP 工作原理比较简单, 通俗来说, 就是设备向 SNTP server 发送一包 SNTP 请求, 服务器收到请求后回复一包 SNTP reply. 其中 SNTP reply 中就含有 unix 时间戳.

参考代码

#include <stdio.h>
#include <time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lwip/apps/sntp.h"
#include "esp_log.h"

static const char *TAG = "sntp";

static void esp_initialize_sntp(void)
{
    ESP_LOGI(TAG, "Initializing SNTP");
    sntp_setoperatingmode(SNTP_OPMODE_POLL);
    sntp_setservername(0, "ntp1.aliyun.com");
    sntp_init();
}

void esp_wait_sntp_sync(void)
{
    char strftime_buf[64];
    esp_initialize_sntp();

    // wait for time to be set
    time_t now = 0;
    struct tm timeinfo = { 0 };
    int retry = 0;

    while (timeinfo.tm_year < (2019 - 1900)) {
        ESP_LOGD(TAG, "Waiting for system time to be set... (%d)", ++retry);
        vTaskDelay(100 / portTICK_PERIOD_MS);
        time(&now);
        localtime_r(&now, &timeinfo);
    }

    // set timezone to China Standard Time
    setenv("TZ", "CST-8", 1);
    tzset();

    strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
    ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf);
}

// 应用层直接调用 esp_wait_sntp_sync() 即可.

使用说明

A). 代码中 SNTP APIs 说明请参考 lwip 官方文档.

B). sntp_setservername 除了可以设置域名, 也可以设置 IP 地址, 例如 sntp_setservername(0, "120.25.115.20");

C). 如果有必要, 请多设置几个 SNTP server, 防止某个 SNTP server 暂时关闭服务而导致产品部分功能无法使用, 例如:

    sntp_setservername(0, "ntp1.aliyun.com");
    sntp_setservername(1, "210.72.145.44");		// 国家授时中心服务器 IP 地址
    sntp_setservername(2, "1.cn.pool.ntp.org");        

说明:
默认情况下, ESP8266/ESP32 只允许开启一个 SNTP server(节省资源考虑), 如果用户需开启多个 SNTP server, 请配置:

  • ESP8266 请在 make menuconfig -> Component config -> LWIP -> DHCP -> Maximum bumber of NTP servers 修改为 3
  • ESP32 请在 make menuconfig -> Component config -> LWIP -> SNTP -> Maximum bumber of NTP servers 修改为 3

D). 配置多个 SNTP server 时, 不是同时发送多个 SNTP 请求报文, 而是轮循方式. 第一个处理超时后, 进行和第二个 SNTP server 交互, 这样依次进行到最后一个, 最后一个处理超时后, 会再和第一个 SNTP server 交互.

E). 最好不在任何 callback 或中断处理函数中调用 esp_wait_sntp_sync(), callback/中断中, 调用任何阻塞的 API, 理论上都有死锁的可能.

F). 任何有校验服务器证书的 TLS 过程 (本地有 CA 证书), 请务必开启 SNTP 功能, 否则会因为校验服务器证书有效期失败而导致 TLS 握手失败.

SNTP 调试

ESP8266 上, 可以在 make menuconfig -> Component config -> LWIP -> Enable lwip Debug -> Enable debugging for SNTP 开启.
当然也可以把 UDP, 甚至 IP 层的 debug 打开.

SNTP 交互抓包展示

SNTP 请求报文:
在这里插入图片描述
SNTP 回复报文:
在这里插入图片描述

SNTP 协议请参考 SNTP RFC 文档.

发布了57 篇原创文章 · 获赞 76 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/espressif/article/details/103001337