延續第一篇貼文的程式碼,本單元將說明結合WiFi管理員的ESP網站伺服器程式的注意事項。由於ESP8266和ESP32的HTTP伺服器程式庫名稱不同,所以引用時必須透過巨集條件式,判斷編譯的目標開發板類型:
#include <WiFiManager.h> // 引用WiFi管理員程式庫 #ifdef ESP8266 // 若晶片類型是ESP8266 #include <ESP8266mDNS.h> #include <ESP8266WebServer.h> // ESP8266網站伺服器程式庫 ESP8266WebServer server(80); // 建立網站伺服器物件 #elif defined(ESP32) // 若晶片類型是ESP32 #include <ESPmDNS.h> #include <WebServer.h> // ESP32網站伺服器程式庫 WebServer server(80); // 建立網站伺服器物件 #endif
附加網站伺服器物件的路由處理函式,寫在setup()裡面,像這樣:
void setup() {
WiFi.mode(WIFI_STA); // Wi-Fi設置成STA模式
: 略
// 設定我們自訂的網站伺服器
server.on("/", []() { // 處理”/”路徑的路由
server.send(200, "text/html; charset=utf-8", "人生最大的風險,<br>就是不願意冒險。");
});
server.onNotFound([]() { // 處理「找不到指定資源」的路由
server.send(404, "text/plain", "File NOT found!");
});
server.begin(); // 啟動網站伺服器
}
包含自訂的網站伺服器程式的完整但有問題的程式碼如下,這個程式也設定了啟動AP模式的回呼函式“APCallback”:
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
#ifdef ESP8266 // 若晶片類型是ESP8266
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h> // ESP8266網站伺服器程式庫
ESP8266WebServer server(80); // 建立網站伺服器物件
#elif defined(ESP32) // 若晶片類型是ESP32
#include <ESPmDNS.h>
#include <WebServer.h> // ESP32網站伺服器程式庫
WebServer server(80); // 建立網站伺服器物件
#endif
#define AP_SSID "JarvisAP" // 自訂的ESP裝置AP名稱
#define AP_PWD "12345678" // 自訂的AP密碼
#define TRIGGER_PIN 0 // 啟用「Wi-Fi設置入口」的按鍵接腳
WiFiManager wm; // 建立WiFi管理員物件
unsigned int timeout = 120; // Wi-Fi管理員的運作秒數
unsigned int startTime = millis();
bool portalRunning = false;
bool startAP = true; // 僅啟動網站伺服器,設成true則啟動AP和網站伺服器。
void APCallback (WiFiManager *ptWM) {
Serial.print("啟動AP模式,AP的SSID:");
Serial.println(ptWM->getConfigPortalSSID());
Serial.print("IP位址:");
Serial.println(WiFi.softAPIP());
}
void doWiFiManager() {
if (portalRunning) {
wm.process();
if ((millis() - startTime) > (timeout * 1000)) {
Serial.println("「Wi-Fi設置入口」操作逾時…");
portalRunning = false;
if (startAP) {
wm.stopConfigPortal();
} else {
wm.stopWebPortal();
}
}
}
// 若啟用「Wi-Fi設置入口」的接腳被按一下…
if (digitalRead(TRIGGER_PIN) == LOW && (!portalRunning)) {
if (startAP) {
Serial.println("按鈕被按下了,啟動設置入口。");
wm.setConfigPortalBlocking(false);
wm.startConfigPortal(AP_SSID, AP_PWD);
} else {
Serial.println("按鈕被按下了,啟動Web入口。");
wm.startWebPortal();
}
portalRunning = true;
startTime = millis();
}
}
void setup() {
WiFi.mode(WIFI_STA); // Wi-Fi設置成STA模式;預設模式為STA+AP
Serial.begin(115200);
Serial.setDebugOutput(true);
delay(1000);
pinMode(TRIGGER_PIN, INPUT_PULLUP);
wm.setHostname("jarvis"); // 設置ESP的主機名稱
// wm.setDebugOutput(false); // 關閉除錯訊息
wm.setAPCallback(APCallback);
wm.autoConnect(AP_SSID, AP_PWD);
// 設定我們自訂的網站伺服器
server.on("/", []() { // 處理”/”路徑的路由
server.send(200, "text/html; charset=utf-8", "人生最大的風險,<br>就是不願意冒險。");
});
server.onNotFound([]() { // 處理「找不到指定資源」的路由
server.send(404, "text/plain", "File NOT found!");
});
server.begin(); // 啟動網站伺服器
}
void loop() {
#ifdef ESP8266
MDNS.update();
#endif
doWiFiManager(); // 確認是否啟動Wi-Fi設置介面
server.handleClient(); // 處理用戶端連線
}
上面的程式編譯沒問題,但是切換到AP模式,開啟Wi-Fi連線設置入口時,瀏覽器將呈現我們自訂網站伺服器的首頁,而非設置入口的頁面。

這是因為我們自訂的server物件仍在偵聽、處理用戶端的連線請求。解決這個問題的辦法有兩種:
- 啟動連線設置入口(或啟動AP模式)時,停止自訂的server伺服器,並於Wi-Fi設置完畢後,重新啟動server伺服器。
- 把設置入口的伺服器設在80以外的埠號,例如:3333。如此,兩個HTTP伺服器就能同時運作。
停止與重新啟動自訂的server伺服器
停止與再次啟動server物件的程式敘述都放在doWiFiManager()函式裡面:
void doWiFiManager() {
if (portalRunning) { // 如果「設置入口」運行中…
: 略
server.begin(); // 再次啟動自訂的網站伺服器
}
}
// 若啟用「Wi-Fi設置入口」的接腳被按一下…
if (digitalRead(TRIGGER_PIN) == LOW && (!portalRunning)) {
server.stop(); // 停止自訂的網站伺服器
: 略
}
}
完整的程式碼請參閱第一篇貼文。
設定「設置入口」網站的埠號
設置入口網站的埠號預設是80,可透過setHttpPort()方法設定其他埠號(指令說明請參閱第二篇貼文),底下程式將把AP模式的位址改成10.0.1.2(這不是必要條件),入口網站伺服器的埠號設成3333。如此,設置或修改Wi-Fi網路期間,不必停止自訂的server伺服器。
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
// include MDNS
#ifdef ESP8266 // 若晶片類型是ESP8266
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h> // ESP8266網站伺服器程式庫
ESP8266WebServer server(80); // 建立網站伺服器物件
#elif defined(ESP32) // 若晶片類型是ESP32
#include <ESPmDNS.h>
#include <WebServer.h> // ESP32網站伺服器程式庫
WebServer server(80); // 建立網站伺服器物件
#endif
#define AP_SSID "JarvisAP" // 自訂的ESP裝置AP名稱
#define AP_PWD "12345678" // 自訂的AP密碼
#define TRIGGER_PIN 0 // 啟用「Wi-Fi設置入口」的按鍵接腳
WiFiManager wm; // 建立WiFi管理員物件
unsigned int timeout = 120; // Wi-Fi管理員的運作秒數
unsigned int startTime = millis();
bool portalRunning = false;
bool startAP = true; // 僅啟動網站伺服器,設成true則啟動AP和網站伺服器。
void APCallback (WiFiManager *ptWM) {
Serial.print("啟動AP模式,AP的SSID:");
Serial.println(ptWM->getConfigPortalSSID());
Serial.print("IP位址:");
Serial.println(WiFi.softAPIP());
}
void doWiFiManager() {
if (portalRunning) {
wm.process();
if ((millis() - startTime) > (timeout * 1000)) {
Serial.println("「Wi-Fi設置入口」操作逾時…");
portalRunning = false;
if (startAP) {
wm.stopConfigPortal();
} else {
wm.stopWebPortal();
}
}
}
// 若啟用「Wi-Fi設置入口」的接腳被按一下…
if (digitalRead(TRIGGER_PIN) == LOW && (!portalRunning)) {
if (startAP) {
Serial.println("按鈕被按下了,啟動設置入口。");
wm.setConfigPortalBlocking(false);
wm.startConfigPortal(AP_SSID, AP_PWD);
} else {
Serial.println("按鈕被按下了,啟動Web入口。");
wm.startWebPortal();
}
portalRunning = true;
startTime = millis();
}
}
void setup() {
WiFi.mode(WIFI_STA); // Wi-Fi設置成STA模式;預設模式為STA+AP
Serial.begin(115200);
Serial.setDebugOutput(true);
delay(1000);
pinMode(TRIGGER_PIN, INPUT_PULLUP);
wm.setHostname("jarvis"); // 設置ESP的主機名稱
wm.setAPStaticIPConfig(IPAddress(10,0,1,2), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
// wm.setDebugOutput(false); // 關閉除錯訊息
wm.setHttpPort(3333);
// 設置入口頁面的背景色改成Tiffany藍
wm.setCustomHeadElement("<style>body {background-color: #E3FFFF;}</style>");
wm.setAPCallback(APCallback);
wm.autoConnect(AP_SSID, AP_PWD);
// 確認晶片是否存有Wi-Fi連線資料
if (WiFi.status() == WL_CONNECTED && wm.getWiFiIsSaved()) {
Serial.println("\n晶片存有Wi-Fi連線資料!");
} else {
Serial.println("\n晶片沒有Wi-Fi連線資料…");
}
// 設定自訂的網站伺服器
server.on("/", []() { // 處理”/”路徑的路由
server.send(200, "text/html; charset=utf-8", "人生最大的風險,<br>就是不願意冒險。");
});
server.onNotFound([]() { // 處理「找不到指定資源」的路由
server.send(404, "text/plain", "File NOT found!");
});
server.begin(); // 啟動網站伺服器
}
void loop() {
#ifdef ESP8266
MDNS.update();
#endif
doWiFiManager(); // 確認是否啟動Wi-Fi設置介面
server.handleClient(); // 處理用戶端連線
}
編譯並上傳程式碼到ESP8266或ESP32開發板,按一下腳0的開關,即可啟動AP模式連線,也能順利連接「設置入口」頁面。
