#include
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_err.h" //? 错误检查的头文件
#define CON_SSID "ling"
#define CON_PASSWORD "527628..."
#define TAG "wifi_sta"
// #define MY_CFG_ORDER
void event_handle(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
if(event_base == WIFI_EVENT)
{
switch (event_id)
{
case WIFI_EVENT_STA_START: //? STA工作模式已启动
esp_wifi_connect(); //? 连接WiFi
break;
case WIFI_EVENT_STA_CONNECTED: //? EPS32已经成功连接到路由器
ESP_LOGI(TAG, "esp32 connected to api!");
break;
case WIFI_EVENT_STA_DISCONNECTED: //? 断连
esp_wifi_connect();
default:
break;
}
}
else if(event_base == IP_EVENT)
{
switch (event_id)
{
case IP_EVENT_STA_GOT_IP: //? EPS32获取到无线路由器分配的IP,此时ESP32才真正的连接到路由器(如果路由器能连接到互联网,ESP32也能连接到互联网)
ESP_LOGI(TAG, "esp32 get ip address");
break;
default:
break;
}
}
}
void app_main(void)
{
#ifndef MY_CFG_ORDER
/* 1.初始化NVS
默认状态下,当我们使用一组SSID和密码连接WiFi成功后,ESP-IDF的底层会帮我们把这组SSID和密码保存到NVS中;
下次系统重启后,当进入STA模式并进行连接时,就会用这组SSID和密码进行连接;
*/
ESP_ERROR_CHECK(nvs_flash_init()); //? 宏ESP_ERROR_CHECK,用来检查NVS初始化是否有问题;
// 2.初始化TCP/IP协议栈(ESP-IDF中使用的时LWIP)
ESP_ERROR_CHECK(esp_netif_init()); //? netif--->net interface,网络接口的缩写;
/* 3.创建事件系统循环
WiFi连接过程中会产生各种的事件,这些事件都是通过回调函数来通知我们的
*/
ESP_ERROR_CHECK(esp_event_loop_create_default());
// 4.创建STA
esp_netif_create_default_wifi_sta(); //? 该函数会返回一个STA网卡对象,这里我们使用不到,可以忽略该返回值;
/* 5.初始化WiFi
定义一个WiFi初始化结构体,将其设置到WiFi初始化函数中;
该步骤会设置WiFi的缓冲区数量,加密功能等,我们按默认功能设置就可以;
*/
wifi_init_config_t wifi_init_cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_cfg));
// 6.注册事件响应
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handle, NULL); //? 注册WiFi事件回调
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handle, NULL); //? 注册IP事件回调(连接到路由器,获取到IP地址后就会触发该事件)
// 7.WiFi参数配置
wifi_config_t wifi_config = {
.sta = {
.ssid = CON_SSID, //? SSID,服务器集标识符,即WiFi名称;
.password = CON_PASSWORD, //? WiFi密码;
.threshold.authmode = WIFI_AUTH_WPA2_PSK, //? 配置加密模式,目前常用的时WPA2_PSK;
.pmf_cfg.capable = true, //? 是否启用保护管理帧,启用后可以增强安全性;
.pmf_cfg.required = false, //? 是否只和有保护管理帧功能的设备通信;
},
};
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
// 8.设置WiFi模式
esp_wifi_set_mode(WIFI_MODE_STA);
// 9.启动WiFi
esp_wifi_start();
#else
/* 1.初始化NVS
默认状态下,当我们使用一组SSID和密码连接WiFi成功后,ESP-IDF的底层会帮我们把这组SSID和密码保存到NVS中;
下次系统重启后,当进入STA模式并进行连接时,就会用这组SSID和密码进行连接;
*/
ESP_ERROR_CHECK(nvs_flash_init()); //? 宏ESP_ERROR_CHECK,用来检查NVS初始化是否有问题;
// 2.初始化TCP/IP协议栈(ESP-IDF中使用的时LWIP)
ESP_ERROR_CHECK(esp_netif_init()); //? netif--->net interface,网络接口的缩写;
/* 3.创建事件系统循环
WiFi连接过程中会产生各种的事件,这些事件都是通过回调函数来通知我们的
*/
ESP_ERROR_CHECK(esp_event_loop_create_default());
// 6.注册事件响应
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handle, NULL); //? 注册WiFi事件回调
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handle, NULL); //? 注册IP事件回调(连接到路由器,获取到IP地址后就会触发该事件)
// 4.创建STA
esp_netif_create_default_wifi_sta(); //? 该函数会返回一个STA网卡对象,这里我们使用不到,可以忽略该返回值;
// 8.设置WiFi模式为STA
esp_wifi_set_mode(WIFI_MODE_STA);
/* 5.初始化WiFi
定义一个WiFi初始化结构体,将其设置到WiFi初始化函数中;
该步骤会设置WiFi的缓冲区数量,加密功能等,我们按默认功能设置就可以;
*/
wifi_init_config_t wifi_init_cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_cfg));
// 7.WiFi参数配置
wifi_config_t wifi_config = {
.sta = {
.ssid = CON_SSID, //? SSID,服务器集标识符,即WiFi名称;
.password = CON_PASSWORD, //? WiFi密码;
.threshold.authmode = WIFI_AUTH_WPA2_PSK, //? 配置加密模式,目前常用的时WPA2_PSK;
.pmf_cfg.capable = true, //? 是否启用保护管理帧,启用后可以增强安全性;
.pmf_cfg.required = false, //? 是否只和有保护管理帧功能的设备通信;
},
};
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
// 9.启动WiFi
esp_wifi_start();
#endif
}
传输数据的特点——加密
在802.11无线协议中,MAC帧的数据是加密的,没有连上热点的设备是无法读取数据帧的具体内容,具体帧格式如下图所示
数据内容如何表示?——长度
如果手机发送的是UDP广播博文,则这部分加密报文就是IP报文------>虽然我们无法知道报文的确切内容,但我们可以知道报文的长度;------>SmartConfig就是根据UDP报文的长度传输SSID和Password的;
如何区分进行SmartConfig配网的数据——前导码
当设备在混杂模式时,会在所处环境中快速切换各条信道来抓取每个信道中的数据包------>当遇到正在发送前导码的的信道时,设备锁定该信道并继续接受UDP广播包,直到收到足够的数据来解码出WiFi的SSID和Password;------>为了方便和其他UDP广播包区分,前导码由几个特殊的字节组成------>在发送时,APP先发送3个前导码(3个UDP广播包),之后发送用于SmartConfig的UDP广播包,最后发送3个终止码;
SmartConfig的流程:
2.设备部分
3.注意:上述是传输的基本原理,但每家厂商的算法常量、前导码、终止码、传输内容格式会不太一样,因此不同厂家的SmartConfig一般是没有办法通用的;
#include
#include
#include "esp_log.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_smartconfig.h"
#define TAG "wifi_smartconfig"
void event_handle(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
if(event_base == WIFI_EVENT)
{
switch (event_id)
{
case WIFI_EVENT_STA_START: //? STA工作模式已启动
esp_wifi_connect(); //? 连接WiFi
break;
case WIFI_EVENT_STA_CONNECTED: //? EPS32已经成功连接到路由器
ESP_LOGI(TAG, "esp32 connected to api!");
break;
case WIFI_EVENT_STA_DISCONNECTED: //? 断连
esp_wifi_connect();
default:
break;
}
}
else if(event_base == IP_EVENT)
{
switch (event_id)
{
case IP_EVENT_STA_GOT_IP: //? EPS32获取到无线路由器分配的IP,此时ESP32才真正的连接到路由器(如果路由器能连接到互联网,ESP32也能连接到互联网)
ESP_LOGI(TAG, "esp32 get ip address");
break;
default:
break;
}
}
else if(event_base == SC_EVENT)
{
switch (event_id)
{
case SC_EVENT_SCAN_DONE: //? 扫描完成
ESP_LOGI(TAG,"sc scan done!");
break;
case SC_EVENT_GOT_SSID_PSWD: //? 收到了APP发过来的SSID和密码
smartconfig_event_got_ssid_pswd_t *ev = (smartconfig_event_got_ssid_pswd_t *)event_data;
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config));
snprintf((char *) wifi_config.sta.ssid, sizeof(wifi_config.sta.ssid), (char *)ev->ssid);
snprintf((char *) wifi_config.sta.password, sizeof(wifi_config.sta.ssid), (char *)ev->password);
wifi_config.sta.bssid_set = ev->bssid_set;
if(wifi_config.sta.bssid_set) //? 是否设置接入点的MAC地址,共48位,6字节;
memcpy(wifi_config.sta.bssid, ev->bssid, 6);
esp_wifi_disconnect(); //? 如果有WiFi连接,先断开连接
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
esp_wifi_connect();
break;
case SC_EVENT_SEND_ACK_DONE: //? 通知手机APP,Smartconfig结束
esp_smartconfig_stop(); //? 停止Smartconfig
break;
default:
break;
}
}
}
void app_main(void)
{
/* 1.初始化NVS
默认状态下,当我们使用一组SSID和密码连接WiFi成功后,ESP-IDF的底层会帮我们把这组SSID和密码保存到NVS中;
下次系统重启后,当进入STA模式并进行连接时,就会用这组SSID和密码进行连接;
*/
ESP_ERROR_CHECK(nvs_flash_init()); //? 宏ESP_ERROR_CHECK,用来检查NVS初始化是否有问题;
// 2.初始化TCP/IP协议栈(ESP-IDF中使用的时LWIP)
ESP_ERROR_CHECK(esp_netif_init()); //? netif--->net interface,网络接口的缩写;
/* 3.创建事件系统循环
WiFi连接过程中会产生各种的事件,这些事件都是通过回调函数来通知我们的
*/
ESP_ERROR_CHECK(esp_event_loop_create_default());
// 4.创建STA
esp_netif_create_default_wifi_sta(); //? 该函数会返回一个STA网卡对象,这里我们使用不到,可以忽略该返回值;
/* 5.初始化WiFi
定义一个WiFi初始化结构体,将其设置到WiFi初始化函数中;
该步骤会设置WiFi的缓冲区数量,加密功能等,我们按默认功能设置就可以;
*/
wifi_init_config_t wifi_init_cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_cfg));
// 6.注册事件响应
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handle, NULL); //? 注册WiFi事件回调
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handle, NULL); //? 注册IP事件回调(连接到路由器,获取到IP地址后就会触发该事件)
esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, event_handle, NULL);
// 8.设置WiFi模式
esp_wifi_set_mode(WIFI_MODE_STA);
// 9.启动WiFi
esp_wifi_start();
// 10.开启SmartConfig
esp_smartconfig_set_type(SC_TYPE_ESPTOUCH); //? 设置SmartConfig类型
smartconfig_start_config_t sc_cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
esp_smartconfig_start(&sc_cfg);
return;
}