ESP32学习笔记(23)——NVS(非易失性存储)接口使用
目录
前言
使用WEB配网可以使ESP32连接到WIFI更加的便捷,灵活性更高
一、工程创建
1.获取源代码
先拿到博主大大的代码代码在 13_captive_portal
2.新建一个ESP32的工程
3.移植代码到工程下
把博主其中的两份代码复制到新建的工程下
因为配网要连接WIFI,所以给连接WIFI单独写在一文件(自己新建)中,实现WIFI的STA和AP模式(移植自IDF的其他示例工程)
文件目录如下:
4.修改工程的配置信息
修改main下的CMakeLists.txt
修改如下内容
idf_component_register(SRCS "main.c" "./WIFI/ConnectWIFI.c" "./dns_server/my_dns_server.c" "./web_server/webserver.c" "./tcp_client/tcp_client.c"
INCLUDE_DIRS "." "./WIFI" "./dns_server" "./web_server" "./tcp_client"
EMBED_FILES "./web_server/index.html"
)
因为嵌入html,所以 EMBED_FILES "./web_server/index.html" 就是对html的处理
二、修改工程代码
1.main.c
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "nvs_flash.h"
#include "esp_vfs_fat.h"
#include <netdb.h>
#include <sys/socket.h>
#include "WIFI/ConnectWIFI.h"
#include "my_dns_server.h"
#include "webserver.h"
void app_main(void)
{
ESP_ERROR_CHECK( nvs_flash_init() );
//NvsWriteDataToFlash("","","");
char WIFI_Name[50] = { 0 };
char WIFI_PassWord[50] = { 0 }; /*读取保存的WIFI信息*/
if(NvsReadDataFromFlash("WIFI Config Is OK!",WIFI_Name,WIFI_PassWord) == 0x00)
{
printf("WIFI SSID :%s\r\n",WIFI_Name );
printf("WIFI PASSWORD :%s\r\n",WIFI_PassWord);
printf("开始初始化WIFI Station 模式\r\n");
wifi_init_sta(WIFI_Name,WIFI_PassWord); /*按照读取的信息初始化WIFI Station模式*/
}
else
{
printf("未读取到WIFI配置信息\r\n");
printf("开始初始化WIFI AP 模式\r\n");
WIFI_AP_Init(); /*上电后配置WIFI为AP模式*/
//vTaskDelay(1000 / portTICK_PERIOD_MS);
dns_server_start(); //开启DNS服务
web_server_start(); //开启http服务
}
}
2.ConnectWIFI.c
别忘了修改一下STA模式下的WIFI的名字密码
#include <stdio.h>
#include "WIFI/ConnectWIFI.h"
/* The examples use WiFi configuration that you can set via project configuration menu.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID "设置WIFI STA模式的名字"
#define EXAMPLE_ESP_WIFI_PASS "设置WIFI STA模式的密码"
#define EXAMPLE_ESP_WIFI_CHANNEL (10)
#define EXAMPLE_MAX_STA_CONN (1)
// #define EXAMPLE_ESP_WIFI_SSID "espConnect"
// #define EXAMPLE_ESP_WIFI_PASS "12345678"
#define EXAMPLE_ESP_MAXIMUM_RETRY 10
#define CONFIG_ESP_WIFI_AUTH_OPEN 1
#if CONFIG_ESP_WIFI_AUTH_OPEN
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN
#elif CONFIG_ESP_WIFI_AUTH_WEP
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP
#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK
#endif
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
ESP_LOGI("ESP32", "station "MACSTR" join, AID=%d",
MAC2STR(event->mac), event->aid);
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
ESP_LOGI("ESP32", "station "MACSTR" leave, AID=%d",
MAC2STR(event->mac), event->aid);
}
}
void WIFI_AP_Init(void)
{
ESP_LOGI("ESP32", "WIFI Start Init");
ESP_ERROR_CHECK(esp_netif_init()); /*初始化底层TCP/IP堆栈*/
ESP_ERROR_CHECK(esp_event_loop_create_default()); /*创建默认事件循环*/
esp_netif_create_default_wifi_ap(); /*创建默认WIFI AP,如果出现任何初始化错误,此API将中止*/
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); /*初始化WiFi为WiFi驱动程序分配资源,如WiFi控制结构、RX/TX缓冲区、WiFi NVS结构等。此WiFi还启动WiFi任务。*/
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&wifi_event_handler,
NULL,
NULL));
wifi_config_t wifi_config = {
.ap = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
.channel = EXAMPLE_ESP_WIFI_CHANNEL,
.password = EXAMPLE_ESP_WIFI_PASS,
.max_connection = EXAMPLE_MAX_STA_CONN,
.authmode = WIFI_AUTH_WPA_WPA2_PSK
},
};
if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI("ESP32", "wifi_init_softap finished. SSID:%s password:%s channel:%d",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static const char *TAG = "wifi station";
static int s_retry_num = 0;
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(char *WIFI_Name,char *WIFI_PassWord)
{
s_wifi_event_group = xEventGroupCreate();
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 = {
/* 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,
},
};
strcpy((char *)&wifi_config.sta.ssid,WIFI_Name);
strcpy((char *)&wifi_config.sta.password,WIFI_PassWord);
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",
WIFI_Name, WIFI_PassWord);
//xTaskCreate(tcp_client_task, "tcp_client", 1024 * 10, NULL, 5, NULL);/*TCP_client 连接TCP*/
}
else if (bits & WIFI_FAIL_BIT)
{
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
WIFI_Name, WIFI_PassWord);
NvsWriteDataToFlash("","","");/*超出最大重连次数后,退出连接,清楚保存的连接信息,重启*/
esp_restart();
}
else
{
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
}
void NvsWriteDataToFlash(char *ConfirmString,char *WIFI_Name,char *WIFI_PassWord)
{
nvs_handle handle;
// 写入一个整形数据,一个字符串,WIFI信息以及版本信息
static const char *NVS_CUSTOMER = "customer data";
static const char *DATA2 = "String";
static const char *DATA3 = "blob_wifi";
// static const char *DATA4 = "blob_version";
// // 要写入的字符串
// char str_for_store[50] = "WIFI Config Is OK!";
// 要写入的WIFI信息
wifi_config_t wifi_config_to_store;
// wifi_config_t wifi_config_to_store = {
// .sta = {
// .ssid = "store_ssid:hello_kitty",
// .password = "store_password:1234567890",
// },
// };
strcpy((char *)&wifi_config_to_store.sta.ssid,WIFI_Name);
strcpy((char *)&wifi_config_to_store.sta.password,WIFI_PassWord);
// // 要写入的版本号
// uint8_t version_for_store[4] = {0x01, 0x01, 0x01, 0x00};
printf("set size:%u\r\n", sizeof(wifi_config_to_store));
ESP_ERROR_CHECK( nvs_open( NVS_CUSTOMER, NVS_READWRITE, &handle) );
ESP_ERROR_CHECK( nvs_set_str( handle, DATA2, ConfirmString) );
ESP_ERROR_CHECK( nvs_set_blob( handle, DATA3, &wifi_config_to_store, sizeof(wifi_config_to_store)) );
// ESP_ERROR_CHECK( nvs_set_blob( handle, DATA4, version_for_store, 4) );
ESP_ERROR_CHECK( nvs_commit(handle) );
nvs_close(handle);
}
unsigned char NvsReadDataFromFlash(char *ConfirmString,char *WIFI_Name,char *WIFI_PassWord)
{
nvs_handle handle;
static const char *NVS_CUSTOMER = "customer data";
static const char *DATA2 = "String";
static const char *DATA3 = "blob_wifi";
// static const char *DATA4 = "blob_version";
uint32_t str_length = 50;
char str_data[50] = {0};
wifi_config_t wifi_config_stored;
// uint8_t version[4] = {0};
// uint32_t version_len = 4;
memset(&wifi_config_stored, 0x0, sizeof(wifi_config_stored));
uint32_t wifi_len = sizeof(wifi_config_stored);
ESP_ERROR_CHECK( nvs_open(NVS_CUSTOMER, NVS_READWRITE, &handle) );
ESP_ERROR_CHECK ( nvs_get_str(handle, DATA2, str_data, &str_length) );
ESP_ERROR_CHECK ( nvs_get_blob(handle, DATA3, &wifi_config_stored, &wifi_len) );
// ESP_ERROR_CHECK ( nvs_get_blob(handle, DATA4, version, &version_len) );
printf("[data1]: %s len:%u\r\n", str_data, str_length);
printf("[data3]: ssid:%s passwd:%s\r\n", wifi_config_stored.sta.ssid, wifi_config_stored.sta.password);
strcpy(WIFI_Name,(char *)&wifi_config_stored.sta.ssid);
strcpy(WIFI_PassWord,(char *)&wifi_config_stored.sta.password);
nvs_close(handle);
if(strcmp(ConfirmString,str_data) == 0)
{
return 0x00;
}
else
{
return 0xFF;
}
}
ConnectWIFI.h
#ifndef _CONNECT_WIFI_H
#define _CONNECT_WIFI_H
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "lwip/err.h"
#include "lwip/sys.h"
void WIFI_AP_Init(void);
void wifi_init_sta(char *WIFI_Name,char *WIFI_PassWord);
void NvsWriteDataToFlash(char *ConfirmString,char *WIFI_Name,char *WIFI_PassWord);
unsigned char NvsReadDataFromFlash(char *ConfirmString,char *WIFI_Name,char *WIFI_PassWord);
#endif
3.webserver.c
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "esp_http_server.h"
#include "webserver.h"
#include "WIFI/ConnectWIFI.h"
extern const uint8_t index_html_start[] asm("_binary_index_html_start");
extern const uint8_t index_html_end[] asm("_binary_index_html_end");
static const char *TAG = "WEB_SERVER";
#define MIN( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) )
/* Send HTTP response with a run-time generated html consisting of
* a list of all files and folders under the requested path.
* In case of SPIFFS this returns empty list when path is any
* string other than '/', since SPIFFS doesn't support directories */
static esp_err_t http_SendText_html(httpd_req_t *req)
{
/* Get handle to embedded file upload script */
const size_t upload_script_size = (index_html_end - index_html_start);
const char TxBuffer[] = "<h1> SSID1 other WIFI</h1>";
/* Add file upload form and script which on execution sends a POST request to /upload */
httpd_resp_send_chunk(req, (const char *)index_html_start, upload_script_size);
httpd_resp_send_chunk(req,(const char *)TxBuffer,sizeof(TxBuffer));
return ESP_OK;
}
unsigned char CharToNum(unsigned char Data)
{
if(Data >= '0' && Data <= '9')
{
return Data - '0';
}
else if(Data >= 'a' && Data <= 'f')
{
switch (Data)
{
case 'a':return 10;
case 'b':return 11;
case 'c':return 12;
case 'd':return 13;
case 'e':return 14;
case 'f':return 15;
default:
break;
}
}
else if(Data >= 'A' && Data <= 'F')
{
switch (Data)
{
case 'A':return 10;
case 'B':return 11;
case 'C':return 12;
case 'D':return 13;
case 'E':return 14;
case 'F':return 15;
default:
break;
}
}
return 0;
}
/* 强制门户访问时连接wifi后的第一次任意GET请求 */
static esp_err_t HTTP_FirstGet_handler(httpd_req_t *req)
{
http_SendText_html(req);
return ESP_OK;
}
/* 门户页面发回的,带有要连接的WIFI的名字和密码 */
static esp_err_t WIFI_Config_POST_handler(httpd_req_t *req)
{
char buf[100];
int ret, remaining = req->content_len;
while (remaining > 0) {
/* Read the data for the request */
if ((ret = httpd_req_recv(req, buf,
MIN(remaining, sizeof(buf)))) <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
/* Retry receiving if timeout occurred */
continue;
}
return ESP_FAIL;
}
/* Send back the same data */
char WIFI_ConfigBackInformation[100] = "The WIFI To Connect :";
strcat(WIFI_ConfigBackInformation,buf);
httpd_resp_send_chunk(req, WIFI_ConfigBackInformation, sizeof(WIFI_ConfigBackInformation));
remaining -= ret;
char wifi_name[50];
char wifi_password[50];
char wifi_passwordTransformation[50] = {0};
esp_err_t e = httpd_query_key_value(buf,"ssid",wifi_name,sizeof(wifi_name));
if(e == ESP_OK) {
printf("SSID = %s\r\n",wifi_name);
}
else {
printf("error = %d\r\n",e);
}
e = httpd_query_key_value(buf,"passWord",wifi_password,sizeof(wifi_password));
if(e == ESP_OK) {
/*对传回来的数据进行处理*/
unsigned char Len = strlen(wifi_password);
char tempBuffer[2];
char *temp;
unsigned char Cnt = 0;
temp = wifi_password;
for(int i=0;i<Len;)
{
if(*temp == '%')
{
tempBuffer[0] = CharToNum(temp[1]);
tempBuffer[1] = CharToNum(temp[2]);
*temp = tempBuffer[0] * 16 + tempBuffer[1];
wifi_passwordTransformation[Cnt] = *temp;
temp+=3;
i+=3;
Cnt++;
}
else
{
wifi_passwordTransformation[Cnt] = *temp;
temp++;
i++;
Cnt++;
}
}
temp -= Len;
printf("Len = %d\r\n",Len);
printf("wifi_password = %s\r\n",wifi_password);
printf("pswd = %s\r\n",wifi_passwordTransformation);
}
else {
printf("error = %d\r\n",e);
}
/* Log data received */
ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
ESP_LOGI(TAG, "%.*s", ret, buf);
ESP_LOGI(TAG, "====================================");
NvsWriteDataToFlash("WIFI Config Is OK!",wifi_name,wifi_passwordTransformation);
esp_restart();
// esp_wifi_stop();
// esp_event_handler_unregister(WIFI_EVENT,
// ESP_EVENT_ANY_ID,
// &wifi_event_handler
// );
// esp_netif_destroy_default_wifi(ap_netif);
// esp_event_loop_delete_default();
// esp_wifi_deinit();
// esp_netif_deinit();
// httpd_stop(server);
// printf("hello \r\n");
// ESP_LOGI(TAG,"led on");
// wifi_init_sta(wifi_name,wifi_passwordTransformation);
}
return ESP_OK;
}
void web_server_start(void)
{
// xTaskCreate(&webserver, "webserver_task", 2048, NULL, 5, NULL);
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
/* Use the URI wildcard matching function in order to
* allow the same handler to respond to multiple different
* target URIs which match the wildcard scheme */
config.uri_match_fn = httpd_uri_match_wildcard;
ESP_LOGI(TAG, "Starting HTTP Server on port: '%d'", config.server_port);
if (httpd_start(&server, &config) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start file server!");
return ;
}
/* URI handler for getting uploaded files */
httpd_uri_t file_download = {
.uri = "/*", // Match all URIs of type /path/to/file
.method = HTTP_GET,
.handler = HTTP_FirstGet_handler,
.user_ctx = NULL,
};
httpd_register_uri_handler(server, &file_download);
/* URI handler for uploading files to server */
httpd_uri_t file_upload = {
.uri = "/configwifi", // Match all URIs of type /upload/path/to/file
.method = HTTP_POST,
.handler = WIFI_Config_POST_handler,
.user_ctx = NULL,
};
httpd_register_uri_handler(server, &file_upload);
}
webserver.h
#ifndef WEB_SERVER_h
#define WEB_SERVER_h
#ifdef __cplusplus
extern "C"
{
#endif
void web_server_start(void);
#endif
index.html
<!DOCTYPE html>
<html>
<head>
<title>WIFI
</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<style type="text/css">
.input{display: block; margin-top: 10px;}
.input span{width: 100px; float: left; float: left; height: 36px; line-height: 36px;}
.input input{height: 30px;width: 200px;}
.btn{width: 120px; height: 35px; background-color: #000000; border:0px; color:#ffffff; margin-top:15px; margin-left:100px;}
</style>
<body>
<form method="POST" action="configwifi">
<label class="input">
<span>
WiFi SSID
</span>
<input type="text" name="SSID">
</label>
<label class="input">
<span>
WiFi PASS
</span>
<input type="text" name="passWord">
</label>
<input class="btn" type="submit" name="submit" value="Submie">
<p>
<span> Nearby wifi:
</P>
</form>
</body>
</html>
4.my_dns_server.c
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "cJSON.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#include "mbedtls/md5.h"
#include "webserver.h"
static const char *TAG = "DNS_SERVER";
static int create_udp_socket(int port)
{
struct sockaddr_in saddr = { 0 };
int sock = -1;
int err = 0;
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock < 0) {
ESP_LOGE(TAG,"Failed to create socket. Error %d", errno);
return -1;
}
// Bind the socket to any address
saddr.sin_family = PF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
if (err < 0) {
ESP_LOGE(TAG,"Failed to bind socket. Error %d", errno);
goto err;
}
// All set, socket is configured for sending and receiving
return sock;
err:
close(sock);
return -1;
}
static void my_dns_server(void *pvParameters)
{
/* Wait for all the IPs we care about to be set
*/
uint8_t data[128];
int len = 0;
struct sockaddr_in client = { 0 };
socklen_t client_len=sizeof(struct sockaddr_in);
uint32_t i = 0;
ESP_LOGI(TAG,"DNS server start ...");
int sock = create_udp_socket(53);
if (sock < 0) {
ESP_LOGE(TAG,"Failed to create IPv4 multicast socket");
}
while(1)
{
len=recvfrom(sock,data,100,0,(struct sockaddr *)&client,&client_len); //阻塞式
if((len < 0) || ( len > 100))
{
ESP_LOGE(TAG,"recvfrom error\n");
continue;
}
printf("DNS request:");
for(i = 0x4; i< len;i++)
{
if((data[i] >= 'a' && data[i] <= 'z') || (data[i] >= 'A' && data[i] <= 'Z') ||(data[i] >= '0' && data[i] <= '9'))
printf("%c",data[i]);
else
printf("_");
}
printf("\r\n");
//printf("%d\r\n",esp_get_free_heap_size()); //打印系统可用内存
//过滤掉一些乱糟糟的域名
if( strstr((const char *)data+0xc,"taobao")||
strstr((const char *)data+0xc,"qq") ||
strstr((const char *)data+0xc,"sogou") ||
strstr((const char *)data+0xc,"amap") ||
strstr((const char *)data+0xc,"alipay")||
strstr((const char *)data+0xc,"youku") ||
strstr((const char *)data+0xc,"iqiyi") ||
strstr((const char *)data+0xc,"baidu"))
{
continue;
}
data[2] |= 0x80;
data[3] |= 0x80;
data[7] =1;
data[len++] =0xc0;
data[len++] =0x0c;
data[len++] =0x00;
data[len++] =0x01;
data[len++] =0x00;
data[len++] =0x01;
data[len++] =0x00;
data[len++] =0x00;
data[len++] =0x00;
data[len++] =0x0A;
data[len++] =0x00;
data[len++] =0x04;
data[len++] =192;
data[len++] =168;
data[len++] =4;
data[len++] =1;
/*打印客户端地址和端口号*/
// inet_ntop(AF_INET,&client.sin_addr,(char *)data,sizeof(data));
// printf("client IP is %s, port is %d\n",data,ntohs(client.sin_port));
sendto(sock,data,len,0,(struct sockaddr*)&client,client_len);
vTaskDelay(10);
}
ESP_LOGE(TAG,"DNS server stop ...");
shutdown(sock, 0);
close(sock);
vTaskDelete(NULL);
}
void dns_server_start()
{
xTaskCreate(&my_dns_server, "dns_task", 2048, NULL, 5, NULL);
}
my_dns_server.h
#ifndef MY_DNS_SERVER_h
#define MY_DNS_SERVER_h
#ifdef __cplusplus
extern "C"
{
#endif
void dns_server_start();
#ifdef __cplusplus
}
#endif
#endif
三、测试
首次编译下载后:
连接ESP32发出的热点
连接后会弹出浏览器,没有弹出可以手动输入192.168.4.1也可以进入WEB配网界面
输入要连接的WIFI后,ESP32会重启自动连接
四、说明
由于代码基本是拼凑起来的,稳定性不能保证,正式使用还需要多次测试
其实还可以添加搜索附近WIFI的功能(官方例程自带)这样就可以避免输入WIFI名字