sntp_example_main.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /* LwIP SNTP example
  2. This example code is in the Public Domain (or CC0 licensed, at your option.)
  3. Unless required by applicable law or agreed to in writing, this
  4. software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied.
  6. */
  7. #include <string.h>
  8. #include <time.h>
  9. #include <sys/time.h>
  10. #include "esp_system.h"
  11. #include "esp_event.h"
  12. #include "esp_log.h"
  13. #include "esp_attr.h"
  14. #include "esp_sleep.h"
  15. #include "nvs_flash.h"
  16. #include "protocol_examples_common.h"
  17. #include "esp_netif_sntp.h"
  18. #include "lwip/ip_addr.h"
  19. #include "esp_sntp.h"
  20. static const char *TAG = "example";
  21. #ifndef INET6_ADDRSTRLEN
  22. #define INET6_ADDRSTRLEN 48
  23. #endif
  24. /* Variable holding number of times ESP32 restarted since first boot.
  25. * It is placed into RTC memory using RTC_DATA_ATTR and
  26. * maintains its value when ESP32 wakes from deep sleep.
  27. */
  28. RTC_DATA_ATTR static int boot_count = 0;
  29. static void obtain_time(void);
  30. #ifdef CONFIG_SNTP_TIME_SYNC_METHOD_CUSTOM
  31. void sntp_sync_time(struct timeval *tv)
  32. {
  33. settimeofday(tv, NULL);
  34. ESP_LOGI(TAG, "Time is synchronized from custom code");
  35. sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED);
  36. }
  37. #endif
  38. void time_sync_notification_cb(struct timeval *tv)
  39. {
  40. ESP_LOGI(TAG, "Notification of a time synchronization event");
  41. }
  42. void app_main(void)
  43. {
  44. ++boot_count;
  45. ESP_LOGI(TAG, "Boot count: %d", boot_count);
  46. time_t now;
  47. struct tm timeinfo;
  48. time(&now);
  49. localtime_r(&now, &timeinfo);
  50. // Is time set? If not, tm_year will be (1970 - 1900).
  51. if (timeinfo.tm_year < (2016 - 1900)) {
  52. ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
  53. obtain_time();
  54. // update 'now' variable with current time
  55. time(&now);
  56. }
  57. #ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
  58. else {
  59. // add 500 ms error to the current system time.
  60. // Only to demonstrate a work of adjusting method!
  61. {
  62. ESP_LOGI(TAG, "Add a error for test adjtime");
  63. struct timeval tv_now;
  64. gettimeofday(&tv_now, NULL);
  65. int64_t cpu_time = (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec;
  66. int64_t error_time = cpu_time + 500 * 1000L;
  67. struct timeval tv_error = { .tv_sec = error_time / 1000000L, .tv_usec = error_time % 1000000L };
  68. settimeofday(&tv_error, NULL);
  69. }
  70. ESP_LOGI(TAG, "Time was set, now just adjusting it. Use SMOOTH SYNC method.");
  71. obtain_time();
  72. // update 'now' variable with current time
  73. time(&now);
  74. }
  75. #endif
  76. char strftime_buf[64];
  77. // Set timezone to Eastern Standard Time and print local time
  78. setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1);
  79. tzset();
  80. localtime_r(&now, &timeinfo);
  81. strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
  82. ESP_LOGI(TAG, "The current date/time in New York is: %s", strftime_buf);
  83. // Set timezone to China Standard Time
  84. setenv("TZ", "CST-8", 1);
  85. tzset();
  86. localtime_r(&now, &timeinfo);
  87. strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
  88. ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf);
  89. if (sntp_get_sync_mode() == SNTP_SYNC_MODE_SMOOTH) {
  90. struct timeval outdelta;
  91. while (sntp_get_sync_status() == SNTP_SYNC_STATUS_IN_PROGRESS) {
  92. adjtime(NULL, &outdelta);
  93. ESP_LOGI(TAG, "Waiting for adjusting time ... outdelta = %jd sec: %li ms: %li us",
  94. (intmax_t)outdelta.tv_sec,
  95. outdelta.tv_usec/1000,
  96. outdelta.tv_usec%1000);
  97. vTaskDelay(2000 / portTICK_PERIOD_MS);
  98. }
  99. }
  100. const int deep_sleep_sec = 10;
  101. ESP_LOGI(TAG, "Entering deep sleep for %d seconds", deep_sleep_sec);
  102. esp_deep_sleep(1000000LL * deep_sleep_sec);
  103. }
  104. static void print_servers(void)
  105. {
  106. ESP_LOGI(TAG, "List of configured NTP servers:");
  107. for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i){
  108. if (esp_sntp_getservername(i)){
  109. ESP_LOGI(TAG, "server %d: %s", i, esp_sntp_getservername(i));
  110. } else {
  111. // we have either IPv4 or IPv6 address, let's print it
  112. char buff[INET6_ADDRSTRLEN];
  113. ip_addr_t const *ip = esp_sntp_getserver(i);
  114. if (ipaddr_ntoa_r(ip, buff, INET6_ADDRSTRLEN) != NULL)
  115. ESP_LOGI(TAG, "server %d: %s", i, buff);
  116. }
  117. }
  118. }
  119. static void obtain_time(void)
  120. {
  121. ESP_ERROR_CHECK( nvs_flash_init() );
  122. ESP_ERROR_CHECK(esp_netif_init());
  123. ESP_ERROR_CHECK( esp_event_loop_create_default() );
  124. #if LWIP_DHCP_GET_NTP_SRV
  125. /**
  126. * NTP server address could be acquired via DHCP,
  127. * see following menuconfig options:
  128. * 'LWIP_DHCP_GET_NTP_SRV' - enable STNP over DHCP
  129. * 'LWIP_SNTP_DEBUG' - enable debugging messages
  130. *
  131. * NOTE: This call should be made BEFORE esp acquires IP address from DHCP,
  132. * otherwise NTP option would be rejected by default.
  133. */
  134. ESP_LOGI(TAG, "Initializing SNTP");
  135. esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_SNTP_TIME_SERVER);
  136. config.start = false; // start SNTP service explicitly (after connecting)
  137. config.server_from_dhcp = true; // accept NTP offers from DHCP server, if any (need to enable *before* connecting)
  138. config.renew_servers_after_new_IP = true; // let esp-netif update configured SNTP server(s) after receiving DHCP lease
  139. config.index_of_first_server = 1; // updates from server num 1, leaving server 0 (from DHCP) intact
  140. // configure the event on which we renew servers
  141. #ifdef CONFIG_EXAMPLE_CONNECT_WIFI
  142. config.ip_event_to_renew = IP_EVENT_STA_GOT_IP;
  143. #else
  144. config.ip_event_to_renew = IP_EVENT_ETH_GOT_IP;
  145. #endif
  146. config.sync_cb = time_sync_notification_cb; // only if we need the notification function
  147. esp_netif_sntp_init(&config);
  148. #endif /* LWIP_DHCP_GET_NTP_SRV */
  149. /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
  150. * Read "Establishing Wi-Fi or Ethernet Connection" section in
  151. * examples/protocols/README.md for more information about this function.
  152. */
  153. ESP_ERROR_CHECK(example_connect());
  154. #if LWIP_DHCP_GET_NTP_SRV
  155. ESP_LOGI(TAG, "Starting SNTP");
  156. esp_netif_sntp_start();
  157. #if LWIP_IPV6 && SNTP_MAX_SERVERS > 2
  158. /* This demonstrates using IPv6 address as an additional SNTP server
  159. * (statically assigned IPv6 address is also possible)
  160. */
  161. ip_addr_t ip6;
  162. if (ipaddr_aton("2a01:3f7::1", &ip6)) { // ipv6 ntp source "ntp.netnod.se"
  163. esp_sntp_setserver(2, &ip6);
  164. }
  165. #endif /* LWIP_IPV6 */
  166. #else
  167. ESP_LOGI(TAG, "Initializing and starting SNTP");
  168. #if CONFIG_LWIP_SNTP_MAX_SERVERS > 1
  169. /* This demonstrates configuring more than one server
  170. */
  171. esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2,
  172. ESP_SNTP_SERVER_LIST(CONFIG_SNTP_TIME_SERVER, "pool.ntp.org" ) );
  173. #else
  174. /*
  175. * This is the basic default config with one server and starting the service
  176. */
  177. esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_SNTP_TIME_SERVER);
  178. #endif
  179. config.sync_cb = time_sync_notification_cb; // Note: This is only needed if we want
  180. #ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
  181. config.smooth_sync = true;
  182. #endif
  183. esp_netif_sntp_init(&config);
  184. #endif
  185. print_servers();
  186. // wait for time to be set
  187. time_t now = 0;
  188. struct tm timeinfo = { 0 };
  189. int retry = 0;
  190. const int retry_count = 15;
  191. while (esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS) == ESP_ERR_TIMEOUT && ++retry < retry_count) {
  192. ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
  193. }
  194. time(&now);
  195. localtime_r(&now, &timeinfo);
  196. ESP_ERROR_CHECK( example_disconnect() );
  197. esp_netif_sntp_deinit();
  198. }