ESP32学习笔记(41)——SNTP接口使用
Posted Leung_ManWah
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ESP32学习笔记(41)——SNTP接口使用相关的知识,希望对你有一定的参考价值。
一、SNTP简介
简单网络时间协议(Simple Network Time Protocol),由 NTP 改编而来,主要用来同步因特网中的计算机时钟。
SNTP 协议是用来同步本地的时间到 unix 时间戳。通常嵌入式设备上电,连接 AP(access point),获取 IP 地址后,就需要使用 SNTP 协议获取全球时间。以便于下一步的应用交互和使用。
SNTP 工作原理比较简单, 通俗来说,就是设备向 SNTP server 发送一包 SNTP 请求,服务器收到请求后回复一包 SNTP reply。其中 SNTP reply 中就含有 unix 时间戳。
二、API说明
以下 SNTP 接口位于 lwip/include/apps/esp_sntp.h。
2.1 sntp_setoperatingmode
2.2 sntp_setservername
2.3 sntp_set_time_sync_notification_cb
2.4 sntp_init
2.5 sntp_get_sync_status
三、示例代码
根据 examples\\protocols\\sntp 中的例程修改
在 menuconfig 中配置 SSID 和密码
核心部分:
//设置单播模式
sntp_setoperatingmode(SNTP_OPMODE_POLL);
//设置访问服务器
sntp_setservername(0, "pool.ntp.org");
//初始化SNTP模块
sntp_init();
完整代码:
/* LwIP SNTP example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_sleep.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "esp_sntp.h"
static const char *TAG = "example";
static void obtain_time(void);
static void initialize_sntp(void);
void time_sync_notification_cb(struct timeval *tv)
{
ESP_LOGI(TAG, "Notification of a time synchronization event");
}
void app_main(void)
{
time_t now;
struct tm timeinfo;
time(&now);
localtime_r(&now, &timeinfo);
// Is time set? If not, tm_year will be (1970 - 1900).
if (timeinfo.tm_year < (2021 - 1900)) {
ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
obtain_time();
// update 'now' variable with current time
time(&now);
}
char strftime_buf[64];
while (1)
{
// update 'now' variable with current time
time(&now);
// Set timezone to China Standard Time
setenv("TZ", "CST-8", 1);
tzset();
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf);
vTaskDelay(10000 / portTICK_PERIOD_MS);
}
}
static void obtain_time(void)
{
ESP_ERROR_CHECK( nvs_flash_init() );
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK( esp_event_loop_create_default() );
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
initialize_sntp();
// wait for time to be set
time_t now = 0;
struct tm timeinfo = { 0 };
int retry = 0;
const int retry_count = 10;
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
time(&now);
localtime_r(&now, &timeinfo);
ESP_ERROR_CHECK( example_disconnect() );
}
static void initialize_sntp(void)
{
ESP_LOGI(TAG, "Initializing SNTP");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org");
sntp_set_time_sync_notification_cb(time_sync_notification_cb);
sntp_init();
}
查看打印:
四、注意事项
sntp_setservername
除了可以设置域名, 也可以设置 IP 地址, 例如sntp_setservername(0, "120.25.115.20");
- 如果有必要, 请多设置几个
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 修改为 3ESP32
请在 make menuconfig -> Component config -> LWIP -> SNTP -> Maximum bumber of NTP servers 修改为 3配置多个
SNTP server
时, 不是同时发送多个SNTP
请求报文, 而是轮循方式. 第一个处理超时后, 进行和第二个SNTP server
交互, 这样依次进行到最后一个, 最后一个处理超时后, 会再和第一个SNTP server
交互
-
更新时间请求间隔
SNTP_UPDATE_DELAY
,到下一次发起更新时间请求的间隔时间,单位是ms,最小不能小于15s,也是通过make menuconfig
修改CONFIG_LWIP_SNTP_UPDATE_DELAY
。
在 make menuconfig -> Component config -> LWIP -> SNTP -> Request interval to update time (ms).
-
最好不在任何 callback 或中断处理函数中调用
obtain_time()
, callback/中断中, 调用任何阻塞的 API, 理论上都有死锁的可能. -
任何有校验服务器证书的
TLS
过程 (本地有CA
证书), 请务必开启SNTP
功能, 否则会因为校验服务器证书有效期失败而导致TLS
握手失败 -
NTP.ORG.cn中国NTP授时快速域名服务提供商
新加坡 | sgp.ntp.org.cn | 韩国 | kr.ntp.org.cn |
---|---|---|---|
中国 | cn.ntp.org.cn | 中国教育网 | edu.ntp.org.cn |
中国香港 | hk.ntp.org.cn | 中国台湾 | tw.ntp.org.cn |
美国 | us.ntp.org.cn | 韩国 | kr.ntp.org.cn |
日本 | jp.ntp.org.cn | 德国 | de.ntp.org.cn |
印度尼西亚 | ina.ntp.org.cn |
- 时区:
- CST-8:这时区的表示有点混
CST却同时可以代表如下 4 个不同的时区:
Central Standard Time (USA) UT-6:00
Central Standard Time (Australia) UT+9:30
China Standard Time UT+8:00
Cuba Standard Time UT-4:00
setenv("TZ", "CST-8", 1);
- GMT:(Greenwich Mean Time)是格林尼治平时
GMT+8正好是中国的标准时区
setenv("TZ", "GMT+8", 1);
- 在成功获取了网络时间后,必须调用
sntp_stop()
; 停止NTP请求,不然设备重启后会造成获取网络时间失败的现象,大概是服务器时根据心跳时间来删除客户端的,如果不是stop结束的客户端,下次连接服务器时就会出错
• 由 Leung 写于 2021 年 7 月 30日
• 参考:ESP8266/ESP32 基础篇: 时间同步 SNTP 介绍和使用
ESP32 SNTP配置
ESP32的SDK开发之获取SNTP网络时间
以上是关于ESP32学习笔记(41)——SNTP接口使用的主要内容,如果未能解决你的问题,请参考以下文章
ESP32学习笔记(25)——OTA(空中升级)接口使用(简化API)
ESP32学习笔记(36)——BluFi(蓝牙配网)接口使用