一、SNTP簡介
簡單網(wǎng)絡(luò)時間協(xié)議(Simple Network Time Protocol),由 NTP 改編而來爽撒,主要用來同步因特網(wǎng)中的計算機時鐘垮衷。
SNTP 協(xié)議是用來同步本地的時間到 unix 時間戳队腐。通常嵌入式設(shè)備上電哥童,連接 AP(access point),獲取 IP 地址后,就需要使用 SNTP 協(xié)議獲取全球時間任斋。以便于下一步的應(yīng)用交互和使用。
SNTP 工作原理比較簡單, 通俗來說耻涛,就是設(shè)備向 SNTP server 發(fā)送一包 SNTP 請求废酷,服務(wù)器收到請求后回復(fù)一包 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
三卓研、示例代碼
根據(jù) examples\protocols\sntp 中的例程修改
在 menuconfig 中配置 SSID 和密碼
核心部分:
//設(shè)置單播模式
sntp_setoperatingmode(SNTP_OPMODE_POLL);
//設(shè)置訪問服務(wù)器
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
除了可以設(shè)置域名, 也可以設(shè)置 IP 地址, 例如sntp_setservername(0, "120.25.115.20");
- 如果有必要, 請多設(shè)置幾個
SNTP server
奏赘,防止某個SNTP server
暫時關(guān)閉服務(wù)而導(dǎo)致產(chǎn)品部分功能無法使用, 例如:
sntp_setservername(0, "ntp1.aliyun.com");
sntp_setservername(1, "210.72.145.44"); // 國家授時中心服務(wù)器 IP 地址
sntp_setservername(2, "1.cn.pool.ntp.org");
說明:
默認(rèn)情況下,ESP8266/ESP32
只允許開啟一個SNTP server
(節(jié)省資源考慮), 如果用戶需開啟多個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
時, 不是同時發(fā)送多個SNTP
請求報文, 而是輪循方式. 第一個處理超時后, 進(jìn)行和第二個SNTP server
交互, 這樣依次進(jìn)行到最后一個, 最后一個處理超時后, 會再和第一個SNTP server
交互
- 更新時間請求間隔
SNTP_UPDATE_DELAY
寥闪,到下一次發(fā)起更新時間請求的間隔時間,單位是ms磨淌,最小不能小于15s疲憋,也是通過make menuconfig
修改CONFIG_LWIP_SNTP_UPDATE_DELAY
。
在 make menuconfig -> Component config -> LWIP -> SNTP -> Request interval to update time (ms).
- 最好不在任何 callback 或中斷處理函數(shù)中調(diào)用
obtain_time()
, callback/中斷中, 調(diào)用任何阻塞的 API, 理論上都有死鎖的可能. - 任何有校驗服務(wù)器證書的
TLS
過程 (本地有CA
證書), 請務(wù)必開啟SNTP
功能, 否則會因為校驗服務(wù)器證書有效期失敗而導(dǎo)致TLS
握手失敗 - NTP.ORG.cn中國NTP授時快速域名服務(wù)提供商
新加坡 | sgp.ntp.org.cn | 韓國 | kr.ntp.org.cn |
---|---|---|---|
中國 | cn.ntp.org.cn | 中國教育網(wǎng) | 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 |
- 時區(qū):
- CST-8:這時區(qū)的表示有點混
CST卻同時可以代表如下 4 個不同的時區(qū):
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正好是中國的標(biāo)準(zhǔn)時區(qū)
setenv("TZ", "GMT+8", 1);
- 在成功獲取了網(wǎng)絡(luò)時間后梁只,必須調(diào)用
sntp_stop()
; 停止NTP請求柜某,不然設(shè)備重啟后會造成獲取網(wǎng)絡(luò)時間失敗的現(xiàn)象,大概是服務(wù)器時根據(jù)心跳時間來刪除客戶端的敛纲,如果不是stop結(jié)束的客戶端喂击,下次連接服務(wù)器時就會出錯
? 由 Leung 寫于 2021 年 7 月 30 日
? 參考:ESP8266/ESP32 基礎(chǔ)篇: 時間同步 SNTP 介紹和使用
ESP32 SNTP配置
ESP32的SDK開發(fā)之獲取SNTP網(wǎng)絡(luò)時間