当前位置:   article > 正文

ESP32通过HTTP及SNTP同步网络时间_esp32 ntp

esp32 ntp

1、获取毫秒级时间 和普通系统函数相同

  1. int get_sys_time_ms(void)
  2. {
  3. struct timeval tv_now;
  4. gettimeofday(&tv_now, NULL);
  5. int64_t time_us = (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec;
  6. return (int)(time_us/1000);
  7. }

2、延时毫秒级时间

  1. void my_delay_ms(u32 time_ms)
  2. {
  3. vTaskDelay(time_ms / portTICK_RATE_MS);
  4. }

SNTP校时

SNTP 指 简单网络时间协议(Simple Network Time Protocol),一个合格的物联网设备,少不了一个准确的钟。通过SNTP,可以使ESP32设备通过网络校准本地时间。使用起来也非常简单!

二、示例

1、场景一:最基础方式

最简单+基础的方式

  1. sntp_setoperatingmode(SNTP_OPMODE_POLL);
  2. sntp_setservername(0, "ntp.aliyun.com");
  3. sntp_init();

但此时,你的ESP32要已联网,否则肯定是获取不了的。

接下来,你可以通过sntp_get_sync_status()轮询检测同步是否完毕,官方示例提供了这样的代码。除此之外。我们也可以通过回调来完成。更新成功之后,我们就随时可以获取系统时间了:

首先设置时区方法(这只影响下文时间转换,不影响时间同步。如果你有自己的方法,则可以通过自己的方式设置):

设置时区---时区缩写:

标准时间代码

与GMT的偏移量

描述

NZDT

+13:00

新西兰夏令时

IDLE

+12:00

国际日期变更线,东边

NZST

+12:00

新西兰标准时间

NZT

+12:00

新西兰时间

AESST

+11:00

澳大利亚东部夏时制

CST(ACSST)

+10:30

中澳大利亚标准时间

CADT

+10:30

中澳大利亚夏时制

SADT

+10:30

南澳大利亚夏时制

EST(EAST)

+10:00

东澳大利亚标准时间

GST

+10:00

关岛标准时间

LIGT

+10:00

澳大利亚墨尔本时间

CAST

+9:30

中澳大利亚标准时间

SAT(SAST)

+9:30

南澳大利亚标准时间

WDT(AWSST)

+9:00

澳大利亚西部标准夏令时

JST

+9:00

日本标准时间,(USSR Zone 8)

KST

+9:00

韩国标准时间

MT

+8:30

毛里求斯时间

WST(AWST)

+8:00

澳大利亚西部标准时间

CCT

+8:00

中国沿海时间(北京时间)

JT

+7:30

爪哇时间

IT

+3:30

伊朗时间

BT

+3:00

巴格达时间

EETDST

+3:00

东欧夏时制

CETDST

+2:00

中欧夏时制

EET

+2:00

东欧,(USSR Zone 1)

FWT

+2:00

法国冬时制

IST

+2:00

以色列标准时间

MEST

+2:00

中欧夏时制

METDST

+2:00

中欧白昼时间

SST

+2:00

瑞典夏时制

BST

+1:00

英国夏时制

CET

+1:00

中欧时间

DNT

+1:00

Dansk Normal Tid

FST

+1:00

法国夏时制

MET

+1:00

中欧时间

MEWT

+1:00

中欧冬时制

MEZ

+1:00

中欧时区

NOR

+1:00

挪威标准时间

SET

+1:00

Seychelles Time

SWT

+1:00

瑞典冬时制

WETDST

+1:00

西欧光照利用时间(夏时制)

GMT

0:00

格林威治标准时间

WET

0:00

西欧

WAT

-1:00

西非时间

NDT

-2:30

纽芬兰(新大陆)白昼时间

ADT

-03:00

大西洋白昼时间

NFT

-3:30

纽芬兰(新大陆)标准时间

NST

-3:30

纽芬兰(新大陆)标准时间

AST

-4:00

大西洋标准时间(加拿大)

EDT

-4:00

(美国)东部夏令时

CDT

-5:00

(美国)中部夏令时

EST

-5:00

(美国)东部标准时间

CST

-6:00

(美国)中部标准时间

MDT

-6:00

(美国)山地夏令时

MST

-7:00

(美国)山地标准时间

PDT

-7:00

(美国)太平洋夏令时

PST

-8:00

(美国)太平洋标准时间

YDT

-8:00

Yukon夏令时

HDT

-9:00

夏威仪/阿拉斯加白昼时间

YST

-9:00

Yukon标准时

AHST

-10:00

夏威仪-阿拉斯加标准时间

CAT

-10:00

中阿拉斯加时间

NT

-11:00

州时间(Nome Time)

IDLW

-12:00

国际日期变更线,西边

//如果目标时区是在东区,则是负的,否则是正的。 setenv("TZ", "CST-8", 1); //东八区 tzset();

获取时间

  1. // 获取系统时间戳
  2. time_t now = 0;
  3. time(&now);
  4. // 结合设置的时区,转换为tm结构体
  5. struct tm timeinfo = {0};
  6. localtime_r(&now, &timeinfo);
  7. // 转为字符串(方法随意,不一定要用strftime)
  8. char str[64];
  9. strftime(str, sizeof(str), "%c", &timeinfo);

2、场景二:使用回调

当sntp成功同步时间后,会有一个异步的回调通知应用做出相应更改,例如:在LVGL等UI框架上弹窗等。只需要下边的函数

  1. sntp_set_time_sync_notification_cb(/* 需要的函数指针 /);
  2. //需要的函数声明为形如:
  3. void 函数名(struct timeval tv);

例如

  1. static void initialize_sntp_cb(void)
  2. {
  3. ESP_LOGI(TAG, "Initializing SNTP");
  4. sntp_setoperatingmode(SNTP_OPMODE_POLL);
  5. sntp_setservername(0, "cn.ntp.org.cn"); // 设置访问服务器
  6. sntp_setservername(1, "pool.ntp.org");
  7. sntp_setservername(2, "210.72.145.44"); // 国家授时中心服务器 IP 地址
  8. //开启一个 SNTP server(节省资源考虑), 如果用户需开启多个 SNTP server, 请配置menuconfig
  9. sntp_set_time_sync_notification_cb(time_sync_notification_cb);
  10. //设置时间同步模式
  11. sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
  12. sntp_init();
  13. }
  14. void time_sync_notification_cb(struct timeval *tv)
  15. {
  16. time_t now = 0;
  17. struct tm timeinfo = {0};
  18. time(&now);
  19. localtime_r(&now, &timeinfo);
  20. char strftime_buf[64];
  21. setenv("TZ", "UTC-0", 1);
  22. tzset();
  23. localtime_r(&now, &timeinfo);
  24. strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
  25. ESP_LOGI(TAG, "The time in time_zone:%s\r\n", strftime_buf);
  26. SntpFinishState = true;
  27. printf("===============set sntp config successfully==================\r\n");
  28. }
  29. //应用层只需调用
  30. initialize_sntp_cb();

3、场景三:主动立刻触发时间同步

调用sntp_init()会立刻请求服务器同步一次时间。

因此,我们需要主动同步时:

先调用sntp_stop()、再调用sntp_init() 即可立刻同步一次时间。

经过测试:一定要先stop!不然不会发起同步

实例

  1. static void esp_initialize_sntp(void)
  2. {
  3. sntp_setoperatingmode(SNTP_OPMODE_POLL); // 设置单播模式
  4. sntp_setservername(0, "cn.ntp.org.cn"); // 设置访问服务器
  5. sntp_setservername(1, "ntp1.aliyun.com");
  6. sntp_setservername(1, "pool.ntp.org");
  7. sntp_setservername(2, "210.72.145.44"); // 国家授时中心服务器 IP 地址
  8. setenv("TZ", "CST-8", 1); //东八区
  9. tzset(); // 更新本地C库时间
  10. sntp_init(); //初始化
  11. }
  12. void sntp_task(void* args)
  13. {
  14. esp_initialize_sntp();
  15. // 延时等待SNTP初始化完成
  16. do {
  17. vTaskDelay(1000 / portTICK_PERIOD_MS);
  18. BLUFI_INFO("wait for wifi sntp sync time---------------------\n");
  19. } while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET);
  20. // 成功获取网络时间后停止NTP请求,不然设备重启后会造成获取网络时间失败的现象
  21. // 大概是服务器时根据心跳时间来删除客户端的,如果不是stop结束的客户端,下次连接服务器时就会出错
  22. sntp_stop();
  23. vTaskDelete(NULL);
  24. }
  25. void start_sntp(void)
  26. {
  27. BLUFI_INFO("Start for sync standard time");
  28. xTaskCreate(&sntp_task, "sntp_task", 2048, NULL, 5, NULL);
  29. }
  30. struct tm* get_time(void)
  31. {
  32. time_t now;
  33. time(&now); // 获取网络时间, 64bit的秒计数
  34. localtime_r(&now, &timeinfo); // 转换成具体的时间参数
  35. ESP_LOGI(TAG, "%4d-%02d-%02d %02d:%02d:%02d week:%d", timeinfo.tm_year + 1900, timeinfo.tm_mon + 1,
  36. timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, timeinfo.tm_wday);
  37. return &timeinfo;
  38. }

官网:pool.ntp.org: the internet cluster of ntp servers

pool.ntp.org 是一个以时间服务器的大虚拟集群为上百万的客户端提供可靠的 易用的 网络时间协议(NTP)服务的项目。

NTP池正在为世界各地成百上千万的系统提供服务。 它是绝大多数主流Linux发行版和许多网络设备的默认“时间服务器”

设置多个 SNTP server需要配置:国内可用的NTP 服务器地址 服务器介绍 NTP池的介绍

参考地址

//c标准库版本

  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #ifdef _WIN32
  4. #include <time.h>
  5. #include<windows.h>
  6. #else
  7. #include <sys/time.h>
  8. #include <unistd.h>
  9. #endif
  10. uint64_t GetCurrentTimerMS(char* szTimer=NULL)
  11. {
  12. uint64_t nTimer = 0;
  13. #ifdef _WIN32
  14. SYSTEMTIME currentTime;
  15. GetLocalTime(&currentTime);
  16. tm temptm = { currentTime.wSecond,
  17. currentTime.wMinute,
  18. currentTime.wHour,
  19. currentTime.wDay,
  20. currentTime.wMonth - 1,
  21. currentTime.wYear - 1900
  22. };
  23. nTimer = mktime(&temptm) * 1000 + currentTime.wMilliseconds;
  24. #else
  25. struct timeval tv;
  26. gettimeofday(&tv,NULL);
  27. // printf("second:%ld\n",tv.tv_sec); //秒
  28. nTimer = tv.tv_sec*1000 + tv.tv_usec/1000;
  29. #endif
  30. if(szTimer != NULL)
  31. sprintf(szTimer, "%llu", nTimer);
  32. return nTimer;
  33. }
  34. int main()
  35. {
  36. char szTimer[64];
  37. uint64_t nTimer=-1;
  38. GetCurrentTimerMS(szTimer); //带参数
  39. nTimer = GetCurrentTimerMS(); //不带参数
  40. printf("millisecond:%s,\t%llu\n\n",szTimer,nTimer ); //毫秒
  41. return 0;
  42. }

通过HTTP获取时间并更新

  1. uint32_t get_net_time(void)
  2. {
  3. esp_err_t ret = ESP_FAIL;
  4. int i = 0;
  5. net_time = 0;
  6. //获取网络时间并打印 配置网页域名和对应的参数
  7. esp_http_client_config_t config = {
  8. .url = "http://worldtimeapi.org/api/ip",
  9. .event_handler = http_event_handle,
  10. .buffer_size = NET_TIME_BUFF_LEN,
  11. };
  12. esp_http_client_handle_t time_client = esp_http_client_init(&config);//初始化http
  13. for(i=0;i<3;i++)
  14. {
  15. ret = esp_http_client_perform(time_client);//请求获取数据
  16. if (ret == ESP_OK)
  17. {
  18. BLUFI_INFO("HTTP GET Status = %d, content_length = %lld",
  19. esp_http_client_get_status_code(time_client),
  20. esp_http_client_get_content_length(time_client));
  21. if (get_net_time_flag == 1) // 得到了平台下发
  22. {
  23. if (ESP_OK == wifi_analyse_time()) // 解析平台时间并存到对应变量中
  24. {
  25. break;
  26. }
  27. }
  28. }
  29. else
  30. {
  31. BLUFI_ERROR("HTTP GET request failed: %s", esp_err_to_name(ret));
  32. }
  33. vTaskDelay(500 / portTICK_PERIOD_MS); // 延时约1000ms
  34. }
  35. esp_http_client_cleanup(time_client);
  36. BLUFI_ERROR("time: %lu", net_time);
  37. return net_time;
  38. }
  39. // 功能:http处理中断
  40. static esp_err_t http_event_handle(esp_http_client_event_t *evt)
  41. {
  42. switch (evt->event_id) {
  43. case HTTP_EVENT_ERROR:
  44. BLUFI_ERROR("HTTP_EVENT_ERROR");
  45. break;
  46. case HTTP_EVENT_ON_CONNECTED:
  47. BLUFI_INFO("HTTP_EVENT_ON_CONNECTED");
  48. break;
  49. case HTTP_EVENT_HEADER_SENT:
  50. BLUFI_INFO("HTTP_EVENT_HEADER_SENT");
  51. break;
  52. case HTTP_EVENT_ON_HEADER:
  53. // BLUFI_INFO(TAG, "HTTP_EVENT_ON_HEADER");
  54. break;
  55. case HTTP_EVENT_ON_DATA: //收到网址下发的时间数据将数据存放到buffer之后处理
  56. BLUFI_INFO("HTTP_EVENT_ON_DATA");
  57. get_net_time_flag = 1;
  58. memset(net_time_buf, 0, NET_TIME_BUFF_LEN);
  59. memcpy(net_time_buf, evt->data, evt->data_len);
  60. // BLUFI_INFO("len=(%d),data=(%s)",evt->data_len,evt->data);
  61. break;
  62. case HTTP_EVENT_ON_FINISH:
  63. BLUFI_INFO("HTTP_EVENT_ON_FINISH");
  64. break;
  65. case HTTP_EVENT_DISCONNECTED:
  66. BLUFI_INFO("HTTP_EVENT_DISCONNECTED");
  67. break;
  68. case HTTP_EVENT_REDIRECT:
  69. break;
  70. default:
  71. break;
  72. }
  73. return ESP_OK;
  74. }
  75. void update_net_time(const uint32_t time)
  76. {
  77. net_time = time;
  78. }
  79. // 功能:解析网络时间
  80. static esp_err_t wifi_analyse_time(void)
  81. {
  82. cJSON *json_buff;
  83. cJSON *unixtime;
  84. cJSON *raw_offset;//东时区
  85. cJSON *dst_offset;//西时区
  86. // clr_link_create_certs();
  87. get_net_time_flag = 0;
  88. json_buff = cJSON_Parse(net_time_buf);//转化为json体
  89. if(json_buff == NULL)
  90. {
  91. BLUFI_INFO("time buffer not find\n");
  92. cJSON_Delete(json_buff);//释放json体
  93. return ESP_FAIL;
  94. }
  95. else
  96. {
  97. unixtime = cJSON_GetObjectItem(json_buff, "unixtime");//查找国际网络时间
  98. raw_offset = cJSON_GetObjectItem(json_buff, "raw_offset");//获取时区偏移量 可以采用电脑访问上述网址看网址得到的格式 postman模拟
  99. dst_offset = cJSON_GetObjectItem(json_buff, "dst_offset");//获取时区偏移量
  100. if((unixtime == NULL)||(raw_offset == NULL)||(dst_offset == NULL)) //没有对应字段
  101. {
  102. cJSON_Delete(json_buff);//释放json体
  103. BLUFI_INFO("unixtime not find\n");
  104. return ESP_FAIL;
  105. }
  106. else
  107. {
  108. update_net_time(unixtime->valueint); //将网络时间更新到本地存放网络时间变量里
  109. cJSON_Delete(json_buff);//释放json体
  110. return ESP_OK;
  111. }
  112. }
  113. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/472000
推荐阅读
相关标签
  

闽ICP备14008679号