顯示具有 NVS 標籤的文章。 顯示所有文章
顯示具有 NVS 標籤的文章。 顯示所有文章

2026年8月3日 星期一

[水井村USR] EP04|ESP32 Wi-Fi AP 模式與 NVS 設定

智慧生活科技專業社群|IoT 入門系列|適合大一新生
在前面的文章中,我們已經完成 ESP32 與 Atlas Scientific 四種水質感測器的整合。接下來要解決的是實際部署時最常遇到的問題:每個場域的 Wi-Fi SSID 與密碼都不同,難道每次都要修改程式再重新燒錄嗎?本篇將介紹如何讓 ESP32 在無法連線時自動進入 AP 模式,讓使用者用手機輸入 SSID 與密碼,儲存到 NVS Flash,重新啟動後再自動連線。

請先將 EP04 主圖上傳 Blogger,再把 EP04_MAIN_IMAGE_URL 換成圖片網址。
圖:ESP32 從 AP 設定、NVS 儲存到重新連線的完整流程。

一、為什麼需要 Wi-Fi AP 模式?

一般 ESP32 範例通常直接把 Wi-Fi 帳密寫死在程式中:

固定帳密寫法
const char* ssid = "MyHome";
const char* password = "12345678";

這種寫法雖然簡單,但每換一個 Wi-Fi,就要重新修改程式並燒錄。對智慧養殖、智慧農業或社區 IoT 設備而言,現場維護並不方便。

更好的方法:ESP32 找不到已儲存的 Wi-Fi 設定時,就自動建立自己的 AP 熱點,讓手機進入設定頁。

二、完整流程

ESP32 開機 讀取 NVS 嘗試連線 失敗進入 AP 手機輸入 SSID/密碼 寫入 NVS 重新啟動 自動連線
第一次開機尚未儲存 Wi-Fi 設定。
AP 模式ESP32 建立設定熱點。
NVS 儲存SSID 與密碼寫入 Flash。
自動連線重新啟動後讀回設定。

三、ESP32 建立 AP 熱點

當 ESP32 找不到 Wi-Fi 設定,或連線逾時,就建立自己的 AP:

程式碼 1:啟動 Soft-AP
String apName = "Shuijing-Setup-A1B2C3";
WiFi.mode(WIFI_AP_STA);
WiFi.softAP(apName.c_str(), "shuijing123");

手機搜尋 Wi-Fi 時,就會看到:

手機看到的熱點
Shuijing-Setup-A1B2C3
熱點名稱後面的六碼可由 ESP32 的 MAC 位址產生,讓每台設備都有不同名稱,避免多台裝置同時部署時混淆。

四、建立手機設定頁

ESP32 可透過內建 WebServer 建立設定頁。手機連上 AP 後,在瀏覽器輸入:

設定頁網址
http://192.168.4.1

設定頁包含 Wi-Fi SSID、Wi-Fi 密碼與「儲存並重新連線」按鈕。

程式碼 2:建立首頁路由
WebServer configServer(80);
configServer.on("/", HTTP_GET, handleConfigRoot);
configServer.begin();

五、手機送出設定

實際測試時,部分手機的 Captive Portal 對 POST 相容性不佳,因此後來改用 GET,並指定完整網址:

表單送出方式
<form method="GET" action="http://192.168.4.1/save">

ESP32 端接受所有 HTTP 方法:

程式碼 3:接收設定
configServer.on("/save", HTTP_ANY, handleConfigSave);
實際除錯經驗:若手機按鈕沒有反應,先用完整的 Chrome 或 Safari 開啟 192.168.4.1,不要只依賴手機自動跳出的迷你 Captive Portal 視窗。

六、NVS 是什麼?

NVS 是 Non-Volatile Storage,中文可理解為「非揮發性儲存」。它使用 ESP32 內建 Flash,資料在斷電與重新啟動後仍會保留。

項目說明
函式庫Preferences
儲存位置ESP32 內建 Flash 的 NVS 分區
斷電後資料仍保留
適合資料SSID、密碼、裝置編號、API 參數

七、把 SSID 與密碼寫入 NVS

程式碼 4:儲存 Wi-Fi 設定
#include <Preferences.h>
Preferences preferences;

bool saveWiFiCredentials(const String& ssid, const String& password) {
  preferences.begin("wifi-config", false);
  size_t ssidResult = preferences.putString("ssid", ssid);
  size_t passwordResult = preferences.putString("password", password);
  preferences.end();
  return ssidResult > 0;
}

這段程式開啟名為 wifi-config 的 namespace,並以 ssidpassword 作為 Key。

八、寫入後立即回讀驗證

本次開發中曾遇到重新啟動後顯示「尚未儲存 SSID」。因此加入寫入後立即回讀驗證:

程式碼 5:回讀確認
String verifySsid = preferences.getString("ssid", "");
String verifyPassword = preferences.getString("password", "");
bool ssidOK = verifySsid == ssid;
bool passwordOK = verifyPassword == password;
只要回讀值與原始輸入相同,就表示資料確實已寫入 NVS Flash。

九、顯示設定完成並重新啟動

設定成功後,手機顯示完成頁;ESP32 再排程重新啟動:

程式碼 6:安排重新啟動
restartScheduled = true;
restartAt = millis() + 5000;

loop() 中檢查:

程式碼 7:執行重新啟動
if (restartScheduled && millis() - restartAt >= 0) {
  configServer.stop();
  dnsServer.stop();
  WiFi.softAPdisconnect(true);
  delay(500);
  ESP.restart();
}

十、重新開機後讀取 NVS

這一步非常重要。即使資料已經寫入 Flash,重新啟動後仍必須主動讀回:

程式碼 8:開機讀取 NVS
void loadWiFiCredentials() {
  preferences.begin("wifi-config", true);
  wifiSsid = preferences.getString("ssid", "");
  wifiPassword = preferences.getString("password", "");
  preferences.end();
}

正確的 setup 流程是:

setup() loadWiFiCredentials() connectWiFi() 失敗則 startConfigPortal()
這次真正的問題:資料其實已寫入 NVS,但重新啟動後沒有呼叫 loadWiFiCredentials(),所以 RAM 中的 wifiSsid 仍是空字串。

十一、自動連線 Wi-Fi

程式碼 9:使用 NVS 帳密連線
bool connectWiFi() {
  if (wifiSsid.length() == 0) return false;
  WiFi.mode(WIFI_STA);
  WiFi.begin(wifiSsid.c_str(), wifiPassword.c_str());
  unsigned long startedAt = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - startedAt < 20000) {
    delay(500);
  }
  return WiFi.status() == WL_CONNECTED;
}

十二、序列監控應看到什麼?

儲存時
========== NVS 寫入結果 ==========
[NVS] SSID 寫入 bytes:10
[NVS] 密碼寫入 bytes:9
[NVS] SSID 回讀:成功
[NVS] 密碼回讀:成功
=================================
[AP] 設定已寫入,5 秒後重新啟動
重新啟動後
========== NVS Wi-Fi 設定 ==========
[NVS] SSID key:存在
[NVS] Password key:存在
[WiFi] 已儲存 SSID:Home_WiFi
===================================
[WiFi] 嘗試連線:Home_WiFi
[WiFi] 連線成功
[WiFi] IP:192.168.1.120

十三、從 Wi-Fi 到 Django Dashboard

Atlas 水質感測器 ESP32 Wi-Fi JSON Django REST API Dashboard

完成 AP 模式與 NVS 設定後,ESP32 就不再綁定單一網路。設備移到新的魚塭或養殖戶,只要用手機重新設定 Wi-Fi,就能繼續上傳資料。

十四、本篇重點

  1. ESP32 無法連線時,可自動啟動 Soft-AP。
  2. 手機可透過 192.168.4.1 開啟設定頁。
  3. SSID 與密碼使用 Preferences 寫入 NVS Flash。
  4. 寫入後應立即回讀驗證。
  5. 重新啟動後必須再次讀取 NVS。
  6. 成功連線後即可恢復 Django REST API 上傳。

結語

將 Wi-Fi 帳密寫死在程式中,適合實驗室測試,但不適合實際場域部署。透過 AP 模式、WebServer、DNSServer 與 Preferences,ESP32 可以在沒有螢幕與鍵盤的情況下,由手機完成 Wi-Fi 設定,並在重新啟動後自動連線。這讓智慧養殖系統從開發板實驗,進一步成為真正可交付、可維護的 IoT 設備。

AI 協作聲明:本文由作者主導教學規劃、ESP32 Wi-Fi AP 模式實作、NVS 儲存測試、手機設定流程與 Django REST API 系統整合,並使用生成式 AI 協助文字整理、程式碼說明、版面設計與教學資訊圖生成;所有程式流程、測試結果與系統架構均依實際測試結果整理,並由作者審核修訂。