延續第一篇貼文的程式碼,本單元將說明結合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模式連線,也能順利連接「設置入口」頁面。