目錄
- 前言
- Web配網詳解
- 強制門戶詳解
- 完整代碼
- 實驗效果
前言
1.Web配網概述
在應用到esp8266的場景,往往與wifi是離不開的,但用戶的wifi賬號密碼又無從知曉,于是乎有了配網,
目前,市面上的配網方式多種多樣,但其中博主覺得成功率最高,最方便的方式其實還是Web配網(個人看法),因為Web配網從根本來說就是esp8266開啟一個web服務器,在此基礎上進行資訊互動(POST,GET),所以資訊的傳輸較為穩定,配網成功率高,
2.強制門戶概述
強制門戶:連接上wifi以后,手機會自動打開一個網頁,這就是強制門戶,
相信大家遇見過很多擁有免費wifi的地方,連接上wifi以后,就會自動彈出認證界面,在Web配網的基礎上,我們加上強制門戶,就可以實作連接wifi以后自動打開配網界面,方便用戶操作,
Web配網詳解
想要實作Web配網,就需要讓esp8266開啟一個WebServer服務器,需要用到以下函式
ESP8266WebServer();//創建WebServer
begin();//啟動WebServer
on();//請求回應回呼
onNotFound();//無法回應的請求的回呼函式
send();//發送回應資料
hasArg();//是否存在某個引數
args();//獲取引數個數
具體WebServer實作代碼
const char* AP_NAME = "配網WIFI";//wifi名字
//html網頁原始碼
const char* page_html = "\
<!DOCTYPE html>\r\n\
<html lang='en'>\r\n\
<head>\r\n\
<meta charset='UTF-8'>\r\n\
<meta name='viewport' content='width=device-width, initial-scale=1.0'>\r\n\
<title>Document</title>\r\n\
</head>\r\n\
<body>\r\n\
<form name='input' action='/' method='POST'>\r\n\
wifi名稱: <br>\r\n\
<input type='text' name='ssid'><br>\r\n\
wifi密碼:<br>\r\n\
<input type='text' name='password'><br>\r\n\
<input type='submit' value='保存'>\r\n\
</form>\r\n\
</body>\r\n\
</html>\r\n\
";
IPAddress apIP(192, 168, 4, 1);//esp8266-AP-IP地址
ESP8266WebServer server(80);//創建WebServer
void initBasic(void){//初始化基礎
Serial.begin(115200);
WiFi.hostname("Smart-ESP8266");//設定ESP8266設備名
}
void initSoftAP(void){//初始化AP模式
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
if(WiFi.softAP(AP_NAME)){
Serial.println("ESP8266 SoftAP is right");
}
}
void handleRoot() {//訪問主頁回呼函式
server.send(200, "text/html", page_html);
}
void handleRootPost() {//Post回呼函式
Serial.println("handleRootPost");
if (server.hasArg("ssid")) {//判斷是否有賬號引數
Serial.print("got ssid:");
strcpy(sta_ssid, server.arg("ssid").c_str());//將賬號引數拷貝到sta_ssid中
Serial.println(sta_ssid);
} else {//沒有引數
Serial.println("error, not found ssid");
server.send(200, "text/html", "<meta charset='UTF-8'>error, not found ssid");//回傳錯誤頁面
return;
}
//密碼與賬號同理
if (server.hasArg("password")) {
Serial.print("got password:");
strcpy(sta_password, server.arg("password").c_str());
Serial.println(sta_password);
} else {
Serial.println("error, not found password");
server.send(200, "text/html", "<meta charset='UTF-8'>error, not found password");
return;
}
server.send(200, "text/html", "<meta charset='UTF-8'>保存成功");//回傳保存成功頁面
delay(2000);
//連接wifi
connectNewWifi();
}
void initWebServer(void){//初始化WebServer
server.on("/", HTTP_GET, handleRoot);//設定主頁回呼函式
server.on("/", HTTP_POST, handleRootPost);//設定Post請求回呼函式
server.begin();//啟動WebServer
Serial.println("WebServer started!");
}
void connectNewWifi(void){
WiFi.mode(WIFI_STA);//切換為STA模式
WiFi.setAutoConnect(true);//設定自動連接
WiFi.begin();//連接上一次連接成功的wifi
Serial.println("");
Serial.print("Connect to wifi");
int count = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
if(WiFi.status() == WL_CONNECTED){//如果連接上 就輸出IP資訊 防止未連接上break后會誤輸出
Serial.println("");
Serial.println("WIFI Connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
server.stop();
}
}
void setup() {
initBasic();
initSoftAP();
initWebServer();
}
void loop() {
server.handleClient();
dnsServer.processNextRequest();
}
強制門戶詳解
要想實作強制門戶,就要在以上的普通Web配網的基礎上加上DNS服務,
具體實作思路:當手機連接上一個無需密碼的wifi后(看上面的initSoftAP就可以發現設定的是無需密碼的AP),會訪問一個手機內部的網址去查看是否可以上網,在訪問此網址的時候會先發起DNS請求,向服務器問域名的IP地址,然后再發起HTTP請求,請求想要的內容,

esp8266充當AP的角色,會收到手機發來的DNS請求,這時將請求的IP地址指向esp8266的地址就可以了,這時手機就會向esp8266發送http請求,esp8266不管收到什么http請求,都將html頁面回復過去,就可以實作強制門戶功能了,
將請求IP指向esp8266地址代碼:
DNSServer dnsServer;//創建dnsServer實體
IPAddress apIP(192, 168, 4, 1);//esp8266-AP-IP地址
const byte DNS_PORT = 53;//DNS埠號
dnsServer.start(DNS_PORT, "*", apIP)
不管收到什么http請求,都將html頁面回復過去
ESP8266WebServer server(80);//創建WebServer
//server.on("/",handleRoot);
//上面那行必須在第二個引數上添加上HTTP_GET才能不影響強制門戶,防止有些設備無法彈出強制門戶,要用域名訪問,如果不加第二個引數,就只能實作域名訪問而無法強制門戶
//在無法回應的http請求回應回呼設定為主頁的回呼函式,才可以強制門戶
server.on("/", HTTP_GET, handleRoot);//設定主頁回呼函式
server.onNotFound(handleRoot);//設定無法回應的http請求的回呼函式
server.on("/", HTTP_POST, handleRootPost);//設定Post請求回呼函式
server.begin();//啟動WebServer
完整代碼
#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
const char* AP_NAME = "配網WIFI";//wifi名字
//暫時存盤wifi賬號密碼
char sta_ssid[32] = {0};
char sta_password[64] = {0};
//配網頁面代碼
const char* page_html = "\
<!DOCTYPE html>\r\n\
<html lang='en'>\r\n\
<head>\r\n\
<meta charset='UTF-8'>\r\n\
<meta name='viewport' content='width=device-width, initial-scale=1.0'>\r\n\
<title>Document</title>\r\n\
</head>\r\n\
<body>\r\n\
<form name='input' action='/' method='POST'>\r\n\
wifi名稱: <br>\r\n\
<input type='text' name='ssid'><br>\r\n\
wifi密碼:<br>\r\n\
<input type='text' name='password'><br>\r\n\
<input type='submit' value='保存'>\r\n\
</form>\r\n\
</body>\r\n\
</html>\r\n\
";
const byte DNS_PORT = 53;//DNS埠號
IPAddress apIP(192, 168, 4, 1);//esp8266-AP-IP地址
DNSServer dnsServer;//創建dnsServer實體
ESP8266WebServer server(80);//創建WebServer
void handleRoot() {//訪問主頁回呼函式
server.send(200, "text/html", page_html);
}
void handleRootPost() {//Post回呼函式
Serial.println("handleRootPost");
if (server.hasArg("ssid")) {//判斷是否有賬號引數
Serial.print("got ssid:");
strcpy(sta_ssid, server.arg("ssid").c_str());//將賬號引數拷貝到sta_ssid中
Serial.println(sta_ssid);
} else {//沒有引數
Serial.println("error, not found ssid");
server.send(200, "text/html", "<meta charset='UTF-8'>error, not found ssid");//回傳錯誤頁面
return;
}
//密碼與賬號同理
if (server.hasArg("password")) {
Serial.print("got password:");
strcpy(sta_password, server.arg("password").c_str());
Serial.println(sta_password);
} else {
Serial.println("error, not found password");
server.send(200, "text/html", "<meta charset='UTF-8'>error, not found password");
return;
}
server.send(200, "text/html", "<meta charset='UTF-8'>保存成功");//回傳保存成功頁面
delay(2000);
//連接wifi
connectNewWifi();
}
void initBasic(void){//初始化基礎
Serial.begin(115200);
WiFi.hostname("Smart-ESP8266");//設定ESP8266設備名
}
void initSoftAP(void){//初始化AP模式
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
if(WiFi.softAP(AP_NAME)){
Serial.println("ESP8266 SoftAP is right");
}
}
void initWebServer(void){//初始化WebServer
//server.on("/",handleRoot);
//上面那行必須以下面這種格式去寫否則無法強制門戶
server.on("/", HTTP_GET, handleRoot);//設定主頁回呼函式
server.onNotFound(handleRoot);//設定無法回應的http請求的回呼函式
server.on("/", HTTP_POST, handleRootPost);//設定Post請求回呼函式
server.begin();//啟動WebServer
Serial.println("WebServer started!");
}
void initDNS(void){//初始化DNS服務器
if(dnsServer.start(DNS_PORT, "*", apIP)){//判斷將所有地址映射到esp8266的ip上是否成功
Serial.println("start dnsserver success.");
}
else Serial.println("start dnsserver failed.");
}
void connectNewWifi(void){
WiFi.mode(WIFI_STA);//切換為STA模式
WiFi.setAutoConnect(true);//設定自動連接
WiFi.begin();//連接上一次連接成功的wifi
Serial.println("");
Serial.print("Connect to wifi");
int count = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
count++;
if(count > 10){//如果5秒內沒有連上,就開啟Web配網 可適當調整這個時間
initSoftAP();
initWebServer();
initDNS();
break;//跳出 防止無限初始化
}
Serial.print(".");
}
Serial.println("");
if(WiFi.status() == WL_CONNECTED){//如果連接上 就輸出IP資訊 防止未連接上break后會誤輸出
Serial.println("WIFI Connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());//列印esp8266的IP地址
server.stop();
}
}
void setup() {
initBasic();
connectNewWifi();
}
void loop() {
server.handleClient();
dnsServer.processNextRequest();
}
實驗效果


如果有什么不懂的可以評論咨詢,看到會回復,歡迎討論!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/239117.html
標籤:其他
