Appearance
wifi
基础知识
在多个主机之间进行交流的时候, 主机之间直接连接会导致网络十分复杂, 在实际的使用时候会使用一个转发器进行连接(Access Point AP可接入点), 其他的主机为station(STA)站
基础配置AP
c
#include <stdio.h>
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "string.h"
#define EXAMPLE_ESP_WIFI_SSID "ESP32-C3"
void app_main(void)
{
nvs_flash_init(); //esp32的nvs分区 #include "nvs_flash.h"
esp_event_loop_create_default(); //建立一个事件循环 #include "esp_event.h"
//配置AP esp_netif(可以理解为软件模拟网卡 为了方便使用TCPIP协议族) Wifi外设
//初始化网卡的底层配置
ESP_ERROR_CHECK(esp_netif_init());
//默认的方式建立一个AP类型的网卡
esp_netif_t * pnetif = esp_netif_create_default_wifi_ap();
/* wifi */
//初始化Wifi底层配置
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
//设置Wifi的模式
esp_wifi_set_mode(WIFI_MODE_AP);
//配置AP模式特有的属性
wifi_config_t cfg2 = {
.ap = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
.channel = 1,
.password = "1234567890",
.max_connection = 4,
.authmode = WIFI_AUTH_WPA2_PSK
}
};
esp_wifi_set_config(WIFI_IF_AP, &cfg2);
//启动Wifi
esp_wifi_start();
}
c
// 建立一个AP类型的网卡
esp_netif_t* esp_netif_create_default_wifi_ap(void)
{
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_WIFI_AP(); //一个默认的配置
esp_netif_t *netif = esp_netif_new(&cfg); //建立一个网络接口
assert(netif);
ESP_ERROR_CHECK(esp_netif_attach_wifi_ap(netif)); //举行关联
ESP_ERROR_CHECK(esp_wifi_set_default_wifi_ap_handlers()); //注册事件
return netif;
}
c
/** @brief Soft-AP configuration settings for the device */
typedef struct {
uint8_t ssid[32]; /**< SSID of soft-AP. If ssid_len field is 0, this must be a Null terminated string. Otherwise, length is set according to ssid_len. wifi的名称*/
uint8_t password[64]; /**< Password of soft-AP. 密码*/
uint8_t ssid_len; /**< Optional length of SSID field. 长度*/
uint8_t channel; /**< Channel of soft-AP 信道在实际使用的Wifi的频段有13个, 其中1, 6, 13完全没有重叠,一般使用1*/
wifi_auth_mode_t authmode; /**< Auth mode of soft-AP. Do not support AUTH_WEP, AUTH_WAPI_PSK and AUTH_OWE in soft-AP mode. When the auth mode is set to WPA2_PSK, WPA2_WPA3_PSK or WPA3_PSK, the pairwise cipher will be overwritten with WIFI_CIPHER_TYPE_CCMP. 认证模式 设置为WIFI_AUTH_OPEN开放式WIFI, WIFI_AUTH_WPA_WPA2_PSK一般使用这一个 */
uint8_t ssid_hidden; /**< Broadcast SSID or not, default 0, broadcast the SSID 是否广播SSID 默认为0(进行广播)*/
uint8_t max_connection; /**< Max number of stations allowed to connect in 可以连接的个数*/
uint16_t beacon_interval; /**< Beacon interval which should be multiples of 100. Unit: TU(time unit, 1 TU = 1024 us). Range: 100 ~ 60000. Default value: 100 广播频率, 0默认值*/
wifi_cipher_type_t pairwise_cipher; /**< Pairwise cipher of SoftAP, group cipher will be derived using this. Cipher values are valid starting from WIFI_CIPHER_TYPE_TKIP, enum values before that will be considered as invalid and default cipher suites(TKIP+CCMP) will be used. Valid cipher suites in softAP mode are WIFI_CIPHER_TYPE_TKIP, WIFI_CIPHER_TYPE_CCMP and WIFI_CIPHER_TYPE_TKIP_CCMP. 加密方式0即可*/
bool ftm_responder; /**< Enable FTM Responder mode wifi测距, 不需要false*/
wifi_pmf_config_t pmf_cfg; /**< Configuration for Protected Management Frame */
wifi_sae_pwe_method_t sae_pwe_h2e; /**< Configuration for SAE PWE derivation method */
} wifi_ap_config_t;
事件组
c
void Wifi_callback(void* event_handler_arg,esp_event_base_t event_base,
int32_t event_id,void* event_data){
if(event_base == IP_EVENT){
if(event_id == IP_EVENT_AP_STAIPASSIGNED){
ip_event_ap_staipassigned_t *info = (ip_event_ap_staipassigned_t *)event_data;
//打印一下实际的ip
printf("\nSTA IP: "IPSTR"\n", IP2STR(&info->ip));
printf("STA Mac is "MACSTR"\n", MAC2STR(info->mac)); //#include "esp_mac.h"
}
}
}
//在发生事件IP_EVENT基底的IP_EVENT_AP_STAIPASSIGNED的时候, 调用Wifi_callback, 传入参数NULL
esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_AP_STAIPASSIGNED,
Wifi_callback,
NULL, NULL);
c
/** Event structure for IP_EVENT_AP_STAIPASSIGNED event */
typedef struct {
esp_netif_t *esp_netif; /*!< Pointer to the associated netif handle */
esp_ip4_addr_t ip; /*!< IP address which was assigned to the station */
uint8_t mac[6]; /*!< MAC address of the connected client */
} ip_event_ap_staipassigned_t;
处理连接事件
c
if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED){
wifi_event_ap_stadisconnected_t *info = (wifi_event_ap_stadisconnected_t *)event_data;
printf("\n disconnected STA Mac is "MACSTR"\n", MAC2STR(info->mac));
}
esp_event_handler_instance_register(WIFI_EVENT,
WIFI_EVENT_AP_STADISCONNECTED,
Wifi_callback,
NULL, NULL);
处理断开连接
基础配置STA
c
void app_main(void)
{
nvs_flash_init();
esp_event_loop_create_default();
//初始化网络接口
esp_netif_init();
//建立sta接口
esp_netif_create_default_wifi_sta();
//初始化Wifi底层配置
wifi_init_config_t wifi_cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&wifi_cfg);
//设置wifi
esp_wifi_set_mode(WIFI_MODE_STA);
//配置STA的相关参数, 这两个是必须设置的
wifi_config_t sta_cfg = {
.sta = {
.ssid = "jiao",
.password = "1234567890"
}
};
esp_wifi_set_config(WIFI_IF_STA, &sta_cfg);
esp_wifi_start();
esp_wifi_connect();
}
可使用的事件
c
uint8_t connect = 0;
void wifi_cb(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START){
//wifi启动成功
esp_wifi_connect();
}
if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED){
//wifi连接失败
connect ++;
if(connect <= 5){
esp_wifi_connect();
}else{
ESP_LOGE("main", "connected failed");
}
}
if(event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP){
ESP_LOGI("main", "connected successed");
ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data;
printf("get sta ip "IPSTR"\n", IP2STR(&info->ip_info.ip));
}
}
esp_event_loop_create_default();
esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_START, wifi_cb, NULL);
//连接失败的回调
esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, wifi_cb, NULL);
//连接成功的事件
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_cb, NULL);
//初始化网络接口
esp_netif_init();
这时候出现时间比较长的现象, 是省电模式的原因
省电模式
这一个模式是在STA发送信息给AP, AP转发信息给STA的时候
AP设备每一段时间会进行一次广播, 发送一个信号帧, 这一个信号帧可以用于告诉其他的设备自己的存在, 还有一个TIM告诉已经接入的STA设备, 他这里有没有要发送给你的数据(这是一个单播, 是一对一的)
还有一个DTIM, 这一个是特殊的TIM, 不是每一个信号帧里面都有, 他有TIM的功能还有一个组播
含有TIM的信标帧是可以不及时接收的(可以之后重复发送), 但是DTIM是必须接受的, 是不会重复发送的
省电模式的实现实际是让esp32平时的时候是一个省电模式, 只有在有AP发送DTIM的时候唤醒
c
/**
* @brief Set current WiFi power save type
*
* @attention Default power save type is WIFI_PS_MIN_MODEM.
*
* @param type power save type
*
* @return ESP_OK: succeed
*/
esp_err_t esp_wifi_set_ps(wifi_ps_type_t type);
typedef enum {
WIFI_PS_NONE, /**< No power save */
WIFI_PS_MIN_MODEM, /**< Minimum modem power saving. In this mode, station wakes up to receive beacon every DTIM period 这一个模式是默认的*/
WIFI_PS_MAX_MODEM, /**< Maximum modem power saving. In this mode, interval to receive beacons is determined by the listen_interval parameter in wifi_sta_config_t */
} wifi_ps_type_t;
使用最大省电模式的时候, 需要设置wifi_config_t 里面的参数 .listen_interval 这一个参数, 会在收到这么多信标帧以后才进行一次接收
cesp_wifi_set_ps(WIFI_PS_MAX_MODEM); esp_pm_config_t pm_config = { .max_freq_mhz = 160, .min_freq_mhz = 40, .light_sleep_enable = true }; ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
静态ip
- 停止这一个网卡的DHCP
esp_netif_dhcpc_stop()
在创建sta网卡以后就可以立即使用
DHCP(Dynamic Host Configuration Protocol)是一种网络协议,用于在局域网中动态分配IP地址
- 设置ip
c
esp_err_t esp_netif_set_ip_info(esp_netif_t *esp_netif, const esp_netif_ip_info_t *ip_info);
c
/**
* @brief IPv4 address
*
*/
struct esp_ip4_addr {
uint32_t addr; /*!< IPv4 address */
};
typedef struct esp_ip4_addr esp_ip4_addr_t;
typedef struct {
esp_ip4_addr_t ip; /**< Interface IPV4 address */
esp_ip4_addr_t netmask; /**< Interface IPV4 netmask */
esp_ip4_addr_t gw; /**< Interface IPV4 gateway address */
} esp_netif_ip_info_t;
c
esp_netif_ip_info_t ip_info = {
.gw.addr = inet_addr("192.168.97.183"),
.ip.addr = inet_addr("192.168.97.190"),
.netmask.addr = inet_addr("255.255.255.0")
};
esp_netif_set_ip_info(netif, &ip_info);
扫描
在wifi目录下面有一个scan例程
bash
I (2988) scan: Max AP number ap_info can hold = 10
I (2988) scan: Total APs scanned = 10, actual AP number ap_info holds = 10
I (2988) scan: SSID jiao
I (2988) scan: RSSI -45
I (2988) scan: Authmode WIFI_AUTH_WPA2_PSK
I (2998) scan: Pairwise Cipher WIFI_CIPHER_TYPE_CCMP
I (2998) scan: Group Cipher WIFI_CIPHER_TYPE_CCMP
I (3008) scan: Channel 11
c
void app_main(void)
{
// Initialize NVS
esp_err_t ret = nvs_flash_init(); //初始化分区表
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
wifi_scan();
}
分区表
分区表 - ESP32-C3 - — ESP-IDF 编程指南 v5.1.3 文档 (espressif.com)\
esp32-c3的 flash 可以包含多个应用程序,以及多种不同类型的数据(例如校准数据、文件系统数据、参数存储数据等)。因此,我们在 flash 的 默认偏移地址 0x8000 处烧写一张分区表。
分区表的长度为 0xC00 字节,最多可以保存 95 条分区表条目。MD5 校验和附加在分区表之后,用于在运行时验证分区表的完整性。分区表占据了整个 flash 扇区,大小为 0x1000 (4 KB)。因此,它后面的任何分区至少需要位于 (默认偏移地址) + 0x1000 处。
- flash 的 0x10000 (64 KB) 偏移地址处存放一个标记为 "factory" 的二进制应用程序,且启动加载器将默认加载这个应用程序。
- 分区表中还定义了两个数据区域,分别用于存储 NVS 库专用分区和 PHY 初始化数据。
nvs分区就是用来配置wifi数据的,凡是涉及到需要使用wifi外设的应用程序,必须先初始化nvs分区。
这一个分区里面实际存储的是一些键值对, 之后连接Wifi的时候会自动的吧Wifi的信息写入这一个分区里面
wifi扫描
Wi-Fi 驱动程序 - ESP32-C3 - — ESP-IDF 编程指南 v5.1.3 文档 (espressif.com)
c
/* Initialize Wi-Fi as sta and set scan method */
static void wifi_scan(void)
{
//WIFI初始化
ESP_ERROR_CHECK(esp_netif_init()); //创建一个LwIP核心任务
ESP_ERROR_CHECK(esp_event_loop_create_default()); //创建一个系统事任务
//创建一个有TCP/IP堆栈的默认网络接口
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
//创建Wi-Fi驱动程序任务,并初始化Wi-Fi驱动程序。
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
uint16_t number = DEFAULT_SCAN_LIST_SIZE;
wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
uint16_t ap_count = 0;
memset(ap_info, 0, sizeof(ap_info));
//将Wi-Fi模式配置为station模式。
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());//启动WI-FI驱动程序。
esp_wifi_scan_start(NULL, true);
ESP_LOGI(TAG, "Max AP number ap_info can hold = %u", number);
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
ESP_LOGI(TAG, "Total APs scanned = %u, actual AP number ap_info holds = %u", ap_count, number);
for (int i = 0; i < number; i++) {
ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid);
ESP_LOGI(TAG, "RSSI \t\t%d", ap_info[i].rssi);
print_auth_mode(ap_info[i].authmode);
if (ap_info[i].authmode != WIFI_AUTH_WEP) {
print_cipher_type(ap_info[i].pairwise_cipher, ap_info[i].group_cipher);
}
ESP_LOGI(TAG, "Channel \t\t%d\n", ap_info[i].primary);
}
}
以上代码,按照顺序,分为wifi的初始化阶段、配置阶段、启动阶段。因为只扫描名称,没有连接,所以没有执行后面的几个wifi阶段。关于wifi的所有阶段介绍,可以通过下面链接查看。
WIFI连接
一般来说, WIFI有两种模式, STA和AP, STA是站点, AP是热点
这个使用官方的station工程
c
I (6401) esp_netif_handlers: sta ip: 192.168.97.190, mask: 255.255.255.0, gw: 192.168.97.183
I (6401) wifi station: got ip:192.168.97.190
I (6401) wifi station: connected to ap SSID:jiao password:1234567890
I (6411) main_task: Returned from app_main()
c
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); //设置事件组的位
}
ESP_LOGI(TAG,"connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
void wifi_init_sta(void)
{
//创建一个事件组
s_wifi_event_group = xEventGroupCreate();
//初始化Wifi
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
//注册两个事件
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.password = EXAMPLE_ESP_WIFI_PASS,
/* Setting a password implies station will connect to all security modes including WEP/WPA.
* However these modes are deprecated and not advisable to be used. Incase your Access point
* doesn't support WPA2, these mode can be enabled by commenting below line */
.threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
.sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
/* The event will not be processed after unregister */
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
vEventGroupDelete(s_wifi_event_group);
}
sntp
SNTP的全称是Simple Network Time Protocol,意思是简单网络时间协议,用来从网络中获取当前的时间,也可以称为网络授时。
c
void app_main(void)
{
++boot_count;
ESP_LOGI(TAG, "Boot count: %d", boot_count);
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 < (2016 - 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];
// Set timezone to Eastern Standard Time and print local time
setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1);
tzset(); //设置时区
localtime_r(&now, &timeinfo); //进行转换
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);//把时间转换为字符串
ESP_LOGI(TAG, "The current date/time in New York is: %s", strftime_buf);
// 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);
if (sntp_get_sync_mode() == SNTP_SYNC_MODE_SMOOTH) {
...
}
//深度睡眠
const int deep_sleep_sec = 10;
ESP_LOGI(TAG, "Entering deep sleep for %d seconds", deep_sleep_sec);
esp_deep_sleep(1000000LL * deep_sleep_sec);
}
c
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());
#if LWIP_DHCP_GET_NTP_SRV
/**
* NTP server address could be acquired via DHCP,
* see following menuconfig options:
* 'LWIP_DHCP_GET_NTP_SRV' - enable STNP over DHCP
* 'LWIP_SNTP_DEBUG' - enable debugging messages
*
* NOTE: This call should be made BEFORE esp acquires IP address from DHCP,
* otherwise NTP option would be rejected by default.
*/
ESP_LOGI(TAG, "Initializing SNTP");
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_SNTP_TIME_SERVER);
config.start = false; // start SNTP service explicitly (after connecting)
config.server_from_dhcp = true; // accept NTP offers from DHCP server, if any (need to enable *before* connecting)
config.renew_servers_after_new_IP = true; // let esp-netif update configured SNTP server(s) after receiving DHCP lease
config.index_of_first_server = 1; // updates from server num 1, leaving server 0 (from DHCP) intact
// configure the event on which we renew servers
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
config.ip_event_to_renew = IP_EVENT_STA_GOT_IP;
#else
config.ip_event_to_renew = IP_EVENT_ETH_GOT_IP;
#endif
config.sync_cb = time_sync_notification_cb; // only if we need the notification function
esp_netif_sntp_init(&config);
#endif /* LWIP_DHCP_GET_NTP_SRV */
/* 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()); //Wifi连接
#if LWIP_DHCP_GET_NTP_SRV
ESP_LOGI(TAG, "Starting SNTP");
esp_netif_sntp_start();
#if LWIP_IPV6 && SNTP_MAX_SERVERS > 2
/* This demonstrates using IPv6 address as an additional SNTP server
* (statically assigned IPv6 address is also possible)
*/
ip_addr_t ip6;
if (ipaddr_aton("2a01:3f7::1", &ip6)) { // ipv6 ntp source "ntp.netnod.se"
esp_sntp_setserver(2, &ip6);
}
#endif /* LWIP_IPV6 */
#else
ESP_LOGI(TAG, "Initializing and starting SNTP");
#if CONFIG_LWIP_SNTP_MAX_SERVERS > 1
/* This demonstrates configuring more than one server
*/
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2,
ESP_SNTP_SERVER_LIST(CONFIG_SNTP_TIME_SERVER, "pool.ntp.org" ) );
#else
/*
* This is the basic default config with one server and starting the service
*/
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_SNTP_TIME_SERVER);
#endif
config.sync_cb = time_sync_notification_cb; // Note: This is only needed if we want
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
config.smooth_sync = true;
#endif
esp_netif_sntp_init(&config);
#endif
print_servers();
// wait for time to be set
time_t now = 0;
struct tm timeinfo = { 0 };
int retry = 0;
//实际的连接, 尝试15次
const int retry_count = 15;
while (esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS) == ESP_ERR_TIMEOUT && ++retry < retry_count) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
}
time(&now);
localtime_r(&now, &timeinfo);
ESP_ERROR_CHECK( example_disconnect() );
esp_netif_sntp_deinit();
}