ESP32-WIFI配网优化
前言
之前文章中有介绍过两种 WIFI 配网的方式,如果需要详细了解相关内容可以参考之前的文章: [[ESP32-两种有趣的wifi连接方式]],这里主要对于强制门户认证过程再进行优化和升级。
在强制门户认证中,在生成的网页中,WiFi 名称总是要自己输入,这里总感觉有一点麻烦,前段时间看到一篇博客介绍了,在建立网页前 WIFI 扫描当前环境下的 WIFI 然后根据扫描到的 WiFi 进行连接,有点类似于手机连 WiFi 的方式,这种方式又快捷且方便,于是乎我准备将其加入到我目前的配网工程当中。
由于强制门户认证之前详细介绍过这里就不过赘述了,直接进入正题。
配网页面
由于我并不会前端的相关知识,也不会制作网页,这里直接网上白嫖大佬的网页代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>登录页面</title>
<style>
#content,.login,.login-card a,.login-card h1,.login-help{text-align:center}body,html{margin:0;padding:0;width:100%;height:100%;display:table}#content{font-family:'Source Sans Pro',sans-serif;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover;display:table-cell;vertical-align:middle}.login-card{padding:40px;width:274px;background-color:#F7F7F7;margin:0 auto 10px;border-radius:20px;box-shadow:8px 8px 15px rgba(0,0,0,.3);overflow:hidden}.login-card h1{font-weight:400;font-size:2.3em;color:#1383c6}.login-card h1 span{color:#f26721}.login-card img{width:70%;height:70%}.login-card input[type=submit]{width:100%;display:block;margin-bottom:10px;position:relative}.login-card input[type=text],input[type=password]{height:44px;font-size:16px;width:100%;margin-bottom:10px;-webkit-appearance:none;background:#fff;border:1px solid #d9d9d9;border-top:1px solid silver;padding:0 8px;box-sizing:border-box;-moz-box-sizing:border-box}.login-card input[type=text]:hover,input[type=password]:hover{border:1px solid #b9b9b9;border-top:1px solid #a0a0a0;-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.login{font-size:14px;font-family:Arial,sans-serif;font-weight:700;height:36px;padding:0 8px}.login-submit{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;color:#fff;text-shadow:0 1px rgba(0,0,0,.1);background-color:#4d90fe}.login-submit:disabled{opacity:.6}.login-submit:hover{border:0;text-shadow:0 1px rgba(0,0,0,.3);background-color:#357ae8}.login-card a{text-decoration:none;color:#666;font-weight:400;display:inline-block;opacity:.6;transition:opacity ease .5s}.login-card a:hover{opacity:1}.login-help{width:100%;font-size:12px}.list{list-style-type:none;padding:0}.list__item{margin:0 0 .7rem;padding:0}label{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;text-align:left;font-size:14px;}input[type=checkbox]{-webkit-box-flex:0;-webkit-flex:none;-ms-flex:none;flex:none;margin-right:10px;float:left}.error{font-size:14px;font-family:Arial,sans-serif;font-weight:700;height:25px;padding:0 8px;padding-top: 10px; -webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;color:#fff;text-shadow:0 1px rgba(0,0,0,.1);background-color:#ff1215}@media screen and (max-width:450px){.login-card{width:70%!important}.login-card img{width:30%;height:30%}}
</style>
</head>
<body style="background-color: #e5e9f2">
<div id="content">
<form name='input' action='/wifi_data' method='POST'>
<div class="login-card">
<h1>WiFi登录</h1>
<form name="login_form" method="post" action="$PORTAL_ACTION$">
<input type="text" name="ssid" placeholder="请输入 WiFi 名称" id="auth_user" list = "data-list"; style="border-radius: 10px">
<datalist id = "data-list">
<option> WIFI名称1</option>
<option> WIFI名称2</option>
<option> WIFI名称3</option>
<option> WIFI名称4</option>
<option> WIFI名称5</option>
<option> WIFI名称6</option>
</datalist>
<!--上下分界-->
<input type="password" name="password" placeholder="请输入 WiFi 密码" id="auth_pass"; style="border-radius: 10px">
<div class="login-help">
<ul class="list">
<li class="list__item">
</li>
</ul>
</div>
<input type="submit" class="login login-submit" value="确 定 连 接" id="login"; disabled; style="border-radius: 15px" >
</form>
</body>
</html>
网页显示效果:
由于这是个静态的网页,而 WiFi 扫描需要将新的 WiFi 信息填入 datalist
当中,所以网页内容会动态变更,所以我需要将网页内容分段,将扫描到的 WiFi 逐个添加进去。
这里我使用 C++ 来处理这段字符串内容,用 C++ 相关函数接口能够更方便的实现功能。
std::string Web = "";
extern "C" const char *get_web_page(void)
{
std::string Web1 = "<!DOCTYPE html><html><head> <meta charset=\"UTF-8\"> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"> <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" /> <title>登录页面</title> <style> #content,.login,.login-card a,.login-card h1,.login-help{text-align:center}body,html{margin:0;padding:0;width:100%;height:100%;display:table}#content{font-family:\'Source Sans Pro\',sans-serif;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover;display:table-cell;vertical-align:middle}.login-card{padding:40px;width:274px;background-color:#F7F7F7;margin:0 auto 10px;border-radius:20px;box-shadow:8px 8px 15px rgba(0,0,0,.3);overflow:hidden}.login-card h1{font-weight:400;font-size:2.3em;color:#1383c6}.login-card h1 span{color:#f26721}.login-card img{width:70%;height:70%}.login-card input[type=submit]{width:100%;display:block;margin-bottom:10px;position:relative}.login-card input[type=text],input[type=password]{height:44px;font-size:16px;width:100%;margin-bottom:10px;-webkit-appearance:none;background:#fff;border:1px solid #d9d9d9;border-top:1px solid silver;padding:0 8px;box-sizing:border-box;-moz-box-sizing:border-box}.login-card input[type=text]:hover,input[type=password]:hover{border:1px solid #b9b9b9;border-top:1px solid #a0a0a0;-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.login{font-size:14px;font-family:Arial,sans-serif;font-weight:700;height:36px;padding:0 8px}.login-submit{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;color:#fff;text-shadow:0 1px rgba(0,0,0,.1);background-color:#4d90fe}.login-submit:disabled{opacity:.6}.login-submit:hover{border:0;text-shadow:0 1px rgba(0,0,0,.3);background-color:#357ae8}.login-card a{text-decoration:none;color:#666;font-weight:400;display:inline-block;opacity:.6;transition:opacity ease .5s}.login-card a:hover{opacity:1}.login-help{width:100%;font-size:12px}.list{list-style-type:none;padding:0}.list__item{margin:0 0 .7rem;padding:0}label{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;text-align:left;font-size:14px;}input[type=checkbox]{-webkit-box-flex:0;-webkit-flex:none;-ms-flex:none;flex:none;margin-right:10px;float:left}.error{font-size:14px;font-family:Arial,sans-serif;font-weight:700;height:25px;padding:0 8px;padding-top: 10px; -webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;color:#fff;text-shadow:0 1px rgba(0,0,0,.1);background-color:#ff1215}@media screen and (max-width:450px){.login-card{width:70%!important}.login-card img{width:30%;height:30%}}</style></head><body style=\"background-color: #e5e9f2\"><div id=\"content\"><form name=\'input\' action=\'/wifi_data\' method=\'POST\'><div class=\"login-card\"><h1>WiFi登录</h1><form name=\"login_form\" method=\"post\" action=\"$PORTAL_ACTION$\"><input type=\"text\" name=\"ssid\" placeholder=\"请输入 WiFi 名称\" id=\"auth_user\" list = \"data-list\"; style=\"border-radius: 10px\"> <datalist id = \"data-list\">";
std::string Web2 = "<input type=\"password\" name=\"password\" placeholder=\"请输入 WiFi 密码\" id=\"auth_pass\"; style=\"border-radius: 10px\"><div class=\"login-help\"><ul class=\"list\"><li class=\"list__item\"></li></ul></div><input type=\"submit\" class=\"login login-submit\" value=\"确 定 连 接\" id=\"login\"; disabled; style=\"border-radius: 15px\" ></form></body></html>";
std::string scan_id = "";
if (scan_len == 0)
{
ESP_LOGI(TAG, "scan_len is 0");
scan_id += "<option>no networks found</option>";
}
else
{
for (int i = 0; i < scan_len; i++)
{
std::string ssid(scan_ssid[i]);
scan_id += "<option>" + ssid + "</option>";
}
}
scan_id += "</datalist>";
Web = Web1 + scan_id + Web2;
return Web.c_str();
}
extern "C" uint32_t get_web_length(void)
{
return Web.length();
}
[!NOTE] Title
在 html 代码导入字符串中"
符号需要在前方加入\
符号。才能正确识别
在网页回调函数接口中获取刷新好的网页字符串,并发送到服务器上。
static esp_err_t root_get_handler(httpd_req_t *req)
{
// const uint32_t root_len = index_root_end - index_root_start;
const char *index_root_web = get_web_page();
ESP_LOGI(TAG, "Serve html");
httpd_resp_set_type(req, "text/html");
httpd_resp_send(req, index_root_web, get_web_length());
return ESP_OK;
}
static const httpd_uri_t root = {
.uri = "/", //根地址默认 192.168.4.1
.method = HTTP_GET,
.handler = root_get_handler,
.user_ctx = NULL
};
在此代码中 scan_ssid
为扫描到的 WiFi,接下来介绍一下 WiFi 扫描相关实现方式。
WiFi 扫描
WiFi 扫描的需要将 WiFi 配置为 STA 模式,跟强制门户认证的 AP 模式不同,所以在最开始 WiFi 扫描完成后,需要将 WiFi 资源注销回收。
// 用来存储扫描到的WiFi信息
char scan_ssid[SCAN_LIST_SIZE][33] = {0};
uint16_t scan_len = 0;
void wifi_scan(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
uint16_t number = SCAN_LIST_SIZE;
wifi_ap_record_t ap_info[SCAN_LIST_SIZE];
uint16_t ap_count = 0;
memset(ap_info, 0, sizeof(ap_info));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
//在所有信道中扫描全部 AP(前端)
wifi_country_t country_config = {
.cc = "CN",
.schan = 1,
.nchan = 13,
};
esp_wifi_set_country(&country_config); // 4.1 扫描配置国家代码
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 < ap_count); i++) {
ESP_LOGI(TAG, "NUM \t\t%d", i);
ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid);
ESP_LOGI(TAG, "RSSI \t\t%d", ap_info[i].rssi);
ESP_LOGI(TAG, "MAC \t\t%02X-%02X-%02X-%02X-%02X-%02X\n", ap_info[i].bssid[0], ap_info[i].bssid[1], ap_info[i].bssid[2], ap_info[i].bssid[3], ap_info[i].bssid[4], ap_info[i].bssid[5]);
strncpy((char *)scan_ssid[i], (char *)ap_info[i].ssid, 33);
}
ESP_LOGI(TAG, "Scan done");
scan_len = (number > ap_count)? ap_count : number;
// 注销资源回收
ESP_ERROR_CHECK(esp_wifi_stop());
esp_netif_destroy_default_wifi(sta_netif);
ESP_ERROR_CHECK(esp_event_loop_delete_default());
ESP_ERROR_CHECK(esp_wifi_deinit());
esp_netif_deinit();
}
优化配网流程
目前配网流程设计成如下,但个人感觉部分细节还是可以优化的,如有相关建议欢迎联系我讨论。
参考链接
本文来自博客园,作者:一月一星辰,转载请注明原文链接:https://www.cnblogs.com/tangwc/p/18603752