NodeMCU-32S 網路連線:Wi-Fi(DHCP)+ OLED 顯示 IP + NTP 校時(延伸:RTC)

0. 本單元學習目標(給學生)

1. 情境與成果(你會做出什麼)

你將完成兩個可展示的小作品:
1. Wi-Fi 連線成功偵測器:連線後把 IP 位址 顯示在 OLED 上(同時也在序列埠顯示)
2. 網路校時電子鐘:透過 NTP 取得時間,顯示在 OLED 上;延伸討論「沒網路怎麼辦?」(RTC)


2. 必備材料與前置準備(教師/學生)

2.1 硬體

2.2 軟體(Arduino IDE)

2.3 接線(I2C)

多數 SSD1306 I2C 模組只有 4 腳:GND / VCC / SCL / SDA

OLED 腳位 NodeMCU-32S(ESP32)建議腳位 說明
GND GND
VCC 3V3 建議 3.3V(避免 5V 造成不穩)
SCL GPIO 22 I2C 時脈
SDA GPIO 21 I2C 資料

3. 無線網路連線方式(Wi-Fi)

3.1 為什麼要學 Wi-Fi?(Why)

IoT 裝置要「變聰明」,必須能把資料送到網路(或從網路取資料)。Wi-Fi 是最常見、最容易在教室實作的無線連線方式之一。

3.2 Wi-Fi 連線的關鍵名詞(What)

工程學習的重點:名詞不是背誦,而是理解「它在系統中負責什麼」與「如何驗證它有沒有正常工作」。

名詞 工程語意(它負責什麼) 你要怎麼驗證(可觀測訊號) 常見問題
SSID AP 對外廣播的網路識別(你要連到哪個系統) 手機/電腦掃描到的名稱 連到錯的 SSID、SSID 含空白/特殊字元
Password 加密連線授權(你是否被允許加入) WiFi.status() 是否為 WL_CONNECTED 密碼錯、路由器改密碼未更新
STA(Station) 裝置端角色:當用戶端連到 AP WiFi.mode(WIFI_STA) 忘了設 STA、或同時 AP+STA 造成混淆
AP(Access Point) 網路入口:提供無線連線與上網路徑 其他裝置能否上網 AP 本身沒上網、或限制 UDP/NTP
DHCP 自動配置:分配 IP/Gateway/DNS(租約制) WiFi.localIP() / WiFi.gatewayIP() / WiFi.dnsIP() 取得 IP 失敗、租約到期、IP 衝突
IP 你的位址:封包要找得到你 WiFi.localIP() 是否非 0.0.0.0 有 IP 但無法上網(多半是 DNS/GW)
Gateway 出入口:往外網的下一跳(通常是路由器) WiFi.gatewayIP() 是否合理 Gateway 錯會造成「有 IP 但出不去」
DNS 名稱解析:把網域名轉成 IP 測試能否解析/連網域 DNS 錯:能連 IP 但連不了網域
RSSI 無線鏈路品質指標(dBm,越接近 0 越強) WiFi.RSSI() 訊號弱導致斷線、封包重傳
MAC 網卡硬體位址(L2 身分) WiFi.macAddress() 校園網路可能做 MAC 管制

3.2.1 工程化視角:Wi-Fi 連線是「分層協作」

flowchart TB A[應用層:你的程式] --> B[網路層:IP / 路由 / DNS] B --> C[連線層:Wi-Fi STA / AP] C --> D[實體層:無線電訊號 RSSI]

你寫的程式只是在「應用層」下指令,但故障常發生在更底層,所以除錯要會往下追:程式 -> IP -> Wi-Fi -> 訊號

3.3 WEP / WPA / WPA2 差異(常見安全性比較)

原檔寫「WEP, WAP, 與 WAP2」,實際應為 WEP / WPA / WPA2(WAP 通常指 Wireless Application Protocol,與 Wi-Fi 安全性不同)

名稱 安全性 現況 教室建議
WEP 很弱(已可被快速破解) 幾乎淘汰 不建議使用
WPA 比 WEP 好,但已過時 逐步淘汰 不建議使用
WPA2 目前最常見且相對安全 主流 建議使用
WPA3 更新、更安全 逐步普及 若環境支援可使用(但教室常以 WPA2 為主)

3.4 連線流程(Mermaid)

graph LR A[ESP32 開機] --> B[設定為 WiFi STA 模式] B --> C[開始連線 WiFi: SSID + 密碼] C --> D{連線成功?} D -- 否 --> C D -- 是 --> E[向 DHCP 取得 IP] E --> F[顯示 IP / 開始網路功能]

3.5 螺旋漸進的工程學習路徑(由簡而繁)

本單元建議用「可驗證、可累加」的方式練習:先做出最小可行版本(MVP),再逐步加功能;每一圈都要保留可觀測的證據(Serial/OLED)。

graph LR A[圈 1: 只做 WiFi 連線] --> B[圈 2: 印出 IP 與基本狀態] B --> C[圈 3: 加 OLED 顯示 IP] C --> D[圈 4: 加 NTP 校時顯示時間] D --> E[圈 5: 斷線重連與穩定性] E --> F[圈 6: 離線 RTC 與資料紀錄]

每一圈都用同一套「AI 協作」方式:提出明確需求 -> 編譯/上傳 -> 觀測輸出 -> 用證據回饋 AI 修正


4. 實作一:Wi-Fi 連線 + 序列埠顯示 IP(最小可行版)

4.1 操作步驟(How)

  1. Arduino IDE 選擇板子:ESP32 Dev Module(或你實際的 ESP32 板型)
  2. 選擇正確序列埠(Port)
  3. 貼上程式、填入你的 SSIDPASSWORD
  4. 上傳後開序列監控視窗(Serial Monitor,115200)

4.2 AI 協作 Prompt 範例(圈 1 → 圈 2)

目標:先只要求「會連線、看得到狀態」;成功後再加限制(超時、重試、顯示更多資訊)。

Prompt 4-A(最小可行:只連線 + Serial 印狀態)

請為 ESP32(NodeMCU-32S / ESP32 Dev Module)寫 Arduino IDE 完整程式(setup/loop)。
需求(最小可行版本):
1) 以 WiFi STA 模式連線到 SSID=____,PASSWORD=____(使用 DHCP)
2) Serial 速率 115200,印出:Connecting...、Connected、Local IP
3) 程式要可編譯可上傳,不要使用額外函式庫
請輸出完整程式。

Prompt 4-B(加工程限制:10 秒超時 + 每 3 秒重試)

請在你剛剛的 ESP32 WiFi 程式上加入「工程化連線策略」並輸出完整程式。
新增需求:
1) 連線等待最多 10 秒,若失敗要印出 FAIL
2) 失敗後每 3 秒重試一次(不要卡死在 while 迴圈)
3) 連線成功後印出 Local IP、Gateway IP、DNS IP

4.3 範例程式(Sketch 01:Wi-Fi + IP)

#include <WiFi.h>

// TODO: 改成你的 Wi-Fi
const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";

void connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);

  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi connected!");
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());
}

void setup() {
  Serial.begin(115200);
  delay(500);
  connectWiFi();
}

void loop() {
  // 可延伸:定期顯示 RSSI、重連機制等
  delay(1000);
}

4.4 讀懂程式做了什麼(Read)

核心流程(偽代碼)

初始化序列埠
設定 Wi-Fi 模式為 STA
開始連線 (SSID, 密碼)
重複檢查狀態直到連線成功
印出 DHCP 分配的 IP 位址

5. 實作二:Wi-Fi 連線 + OLED 顯示 IP(SSD1306 I2C)

5.1 常見 OLED I2C 位址

如果你不確定位址,可先用 I2C Scanner 掃描(見 5.2)。

提醒:I2C Scanner 顯示的是「7-bit 位址」。使用 U8g2 時,setI2CAddress() 需要 8-bit 位址,通常要做 addr << 1

5.1.1 工程化理解:I2C 位址、SDA/SCL 在做什麼?

名詞 它在系統中做什麼 你要怎麼驗證 常見錯誤
I2C 兩線式匯流排:多個裝置共用同一組線 I2C Scanner 能掃到裝置 線太長/接觸不良導致通訊不穩
SDA 資料線(Data) Scanner 能回應 SDA/SCL 接反
SCL 時脈線(Clock) Scanner 掃描穩定 時脈太快/拉不動(通常線材問題)
Address 裝置的門牌號碼(同匯流排要唯一) 掃描到 0x3C/0x3D 程式用錯位址、或忘記 U8g2 左移
Pull-up I2C 使用開漏(open-drain),需要上拉電阻 多數模組自帶 罕見:上拉不足導致不穩(長線更明顯)

5.2 範例程式(可選:I2C Scanner)

#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22); // SDA, SCL
  Serial.println("I2C scan start...");

  for (uint8_t addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("Found I2C device at 0x");
      Serial.println(addr, HEX);
    }
  }
  Serial.println("I2C scan done.");
}

void loop() {}

5.2.1 AI 協作 Prompt 範例(圈 2 → 圈 3)

目標:把「已驗證的 WiFi 連線」加上「可觀測的 OLED 顯示」,避免一次把所有需求混在一起。

Prompt 5-A(在 WiFi 成功版本上加 OLED 顯示 IP,使用 U8g2)

請基於「已能成功連上 WiFi 並印出 IP 的 ESP32 程式」,加入 OLED 顯示功能並輸出完整程式。
硬體:SSD1306 I2C 128x64 OLED
接線:SDA=21,SCL=22,I2C 位址=0x3C
顯示需求:
1) OLED 第 1 行顯示 WiFi OK
2) OLED 第 2 行顯示 IP: x.x.x.x
限制:
- OLED 請使用 U8g2 by olikraus
- 請提醒並正確處理 U8g2 setI2CAddress 需要 addr 左移 1 位

Prompt 5-B(除錯導向:先給「只顯示 Hello」最小測試程式)

請給我一個最小 OLED 測試程式(Arduino IDE,ESP32)。
條件:
1) 使用 U8g2
2) I2C:SDA=21、SCL=22、位址=0x3C
3) OLED 顯示 Hello 並在 Serial 印出「OLED OK」
請輸出完整程式,用來排除接線或位址問題。

5.3 範例程式(Sketch 02:Wi-Fi + OLED 顯示 IP)

#include <WiFi.h>
#include <Wire.h>
#include <U8g2lib.h>

// TODO: 改成你的 Wi-Fi
const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";

// OLED(U8g2)
// - SSD1306 128x64 常見型號 NONAME
// - HW I2C:使用 Wire(ESP32 可先 Wire.begin(SDA,SCL))
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

// I2C Scanner 看到的是「7-bit 位址」(0x3C / 0x3D)
// 但 U8g2 的 setI2CAddress() 需要「8-bit 位址」:所以要左移 1 位
static const uint8_t OLED_ADDR_7BIT = 0x3C; // 若掃描到 0x3D,請改成 0x3D

void show2Lines(const String& line1, const String& line2) {
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_6x10_tf);
  u8g2.drawStr(0, 12, line1.c_str());
  u8g2.drawStr(0, 28, line2.c_str());
  u8g2.sendBuffer();
}

void connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);

  Serial.print("Connecting to WiFi");
  show2Lines("Connecting WiFi", "...");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.println("WiFi connected!");
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());

  show2Lines("WiFi OK", "IP: " + WiFi.localIP().toString());
}

void setup() {
  Serial.begin(115200);
  delay(500);

  Wire.begin(21, 22); // SDA, SCL(依你的板子可調整)
  u8g2.setI2CAddress(OLED_ADDR_7BIT << 1);
  u8g2.begin();

  show2Lines("OLED OK", "Booting...");
  connectWiFi();
}

void loop() {
  // 可延伸:顯示 RSSI、連線狀態、重新連線
  delay(1000);
}

5.4 讀懂程式做了什麼(Read)

5.5 工程學習補充:I2C / OLED 顯示的「最小除錯路徑」

  1. 先確認匯流排:用 I2C Scanner 掃到位址(0x3C 或 0x3D)
  2. 再確認顯示流程:能否顯示 Hello(只做 u8g2.begin() + drawStr
  3. 最後才整合 Wi-Fi:避免「連線問題」與「顯示問題」互相干擾

6. 測試連接網路取得資料:NTP 時間伺服器

6.1 NTP 是什麼?(What)

NTP (Network Time Protocol) 是透過網路同步時間的協定。對微控制器來說,NTP 能讓裝置取得「可靠的現在時間」,例如做資料紀錄(log)、排程(schedule)、或顯示電子鐘。

6.1.1 工程化理解:NTP 校時背後的關鍵名詞

名詞 它在系統中做什麼 你要怎麼驗證 常見錯誤
UTC 世界協調時間(基準時間) NTP 取得的是 UTC 把 UTC 當本地時間,顯示差 8 小時
Time zone 本地時間換算規則(例如台灣 UTC+8) GMT_OFFSET_SEC=8*3600 時區設定錯、或誤用日光節約
SNTP/NTP NTP 的簡化使用(裝置端常用) getLocalTime() 成功 路由器/校園網路阻擋 UDP
UDP NTP 常用的傳輸協定(延遲較低) 連網正常但 NTP 失敗要懷疑 UDP 以為「能連 Wi-Fi」就一定能 NTP
Stratum 時間來源層級(越小越接近原子鐘) 不必深究,但知道「來源品質」 使用不可靠伺服器導致時間飄移

工程提醒:不需要每秒跟 NTP 取時間,常見做法是「開機或每天校一次」,其餘時間由系統/RTC 維持。

6.2 NTP 校時流程(Mermaid)

sequenceDiagram participant ESP32 as ESP32 participant AP as Wi-Fi AP participant NTP as NTP Server ESP32->>AP: 連線並取得 IP via DHCP ESP32->>NTP: 發送時間請求 via UDP NTP NTP-->>ESP32: 回傳 UTC 時間 ESP32->>ESP32: 套用時區 UTC+8 並顯示

6.3 台灣常見 NTP 伺服器

6.3.1 AI 協作 Prompt 範例(圈 3 → 圈 4)

目標:把「已能連網、OLED 正常」的作品升級成「可校時的時鐘」。

Prompt 6-A(在 WiFi+OLED 基礎上加 NTP 校時)

請在「ESP32 已能連 WiFi 並用 U8g2 OLED 顯示資訊」的基礎上,加入 NTP 校時並輸出完整程式。
需求:
1) NTP 伺服器依序使用:tock.stdtime.gov.tw、watch.stdtime.gov.tw、time.stdtime.gov.tw
2) 時區:台灣 UTC+8,DAYLIGHT=0
3) OLED 三行顯示:
   - NTP Clock
   - YYYY-MM-DD
   - HH:MM:SS
4) 若 NTP 10 秒內失敗:OLED 顯示 NTP FAIL,並每 5 秒重試一次
限制:
- 使用 configTime() 與 getLocalTime()
- OLED 使用 U8g2(提醒:setI2CAddress 需 addr<<1)

Prompt 6-B(效能與穩定性:避免每秒 NTP)

請改寫你的 ESP32 NTP 時鐘程式,符合工程化需求並輸出完整程式:
1) NTP 只在開機成功連網時同步一次(或每 6 小時同步一次),不要每秒打 NTP
2) OLED 仍每秒更新顯示時間
3) Serial 印出:同步成功或失敗、下一次同步時間(用秒數或簡單計數即可)

6.4 範例程式(Sketch 03:Wi-Fi + NTP + OLED 顯示時間)

這個版本使用 ESP32 內建的 configTime() + getLocalTime(),較簡潔。

#include <WiFi.h>
#include <Wire.h>
#include <U8g2lib.h>

// TODO: 改成你的 Wi-Fi
const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";

// NTP 與時區(台灣 UTC+8)
static const long GMT_OFFSET_SEC = 8 * 3600;
static const int DAYLIGHT_OFFSET_SEC = 0;

// OLED(U8g2)
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
static const uint8_t OLED_ADDR_7BIT = 0x3C;

void drawClock(const String& title, const String& dateStr, const String& timeStr) {
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_6x10_tf);
  u8g2.drawStr(0, 12, title.c_str());
  u8g2.drawStr(0, 28, dateStr.c_str());
  u8g2.drawStr(0, 44, timeStr.c_str());
  u8g2.sendBuffer();
}

void connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  drawClock("Connecting WiFi", "...", "");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  drawClock("WiFi OK", WiFi.localIP().toString(), "");
}

bool syncTimeByNTP() {
  // 依序使用多台伺服器,提高成功率
  configTime(
    GMT_OFFSET_SEC,
    DAYLIGHT_OFFSET_SEC,
    "tock.stdtime.gov.tw",
    "watch.stdtime.gov.tw",
    "time.stdtime.gov.tw"
  );

  struct tm timeinfo;
  if (!getLocalTime(&timeinfo, 10000)) { // 最多等 10 秒
    return false;
  }
  return true;
}

String nowTimeString() {
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) return "Time N/A";

  char buf[32];
  // 格式:YYYY-MM-DD HH:MM:SS
  strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
  return String(buf);
}

void setup() {
  Wire.begin(21, 22);
  u8g2.setI2CAddress(OLED_ADDR_7BIT << 1);
  u8g2.begin();

  connectWiFi();
  if (!syncTimeByNTP()) {
    drawClock("NTP FAIL", "Check network", "");
    delay(2000);
  }
}

void loop() {
  String t = nowTimeString();
  String dateStr = (t.length() >= 10) ? t.substring(0, 10) : "---- -- --";
  String timeStr = (t.length() >= 19) ? t.substring(11, 19) : "--:--:--";
  drawClock("NTP Clock", dateStr, timeStr);
  delay(1000);
}

6.5 讀懂程式做了什麼(Read)


7. 延伸應用:沒網路怎麼辦?用 RTC 維持時間(DS3231 範例思路)

7.1 為什麼需要 RTC?

NTP 必須「能上網」才抓得到時間;但很多裝置要在離線環境仍能計時(例如校園角落感測器、停電後重啟)。RTC (Real-Time Clock) 模組(常見 DS3231)可用電池維持走時。

7.2 建議策略(NTP 與 RTC 的分工)

策略偽代碼

開機:
  嘗試連 Wi-Fi
  若 Wi-Fi 成功:
    用 NTP 同步時間
    把時間寫入 RTC
  否則:
    從 RTC 讀取時間
循環:
  顯示時間(RTC 或系統時間)

7.3 實作提醒(教學重點)


8. 利用 AI 協作:Prompt 設計模板(更容易一次成功)

目標:讓 AI 回答「可直接上傳」的完整程式,同時避免常見缺漏(腳位/函式庫/位址/序列埠速率)。

使用建議:前面實作階段(第 4~6 節)先用「Prompt 範例」帶學生跑完螺旋漸進;第 8 節模板則用於學生專題或變更需求時的快速套用。

8.1 Prompt 模板:Wi-Fi + DHCP + 顯示 IP(OLED SSD1306 I2C)

請用 Arduino IDE(C++)為 ESP32(NodeMCU-32S / ESP32 Dev Module)寫一個完整可編譯的範例。
需求:
1) 連線到 Wi-Fi:SSID=______,PASSWORD=______,使用 DHCP 取得 IP
2) OLED:SSD1306 I2C 128x64,使用 U8g2(U8g2 by olikraus),SDA=GPIO21、SCL=GPIO22、I2C 位址 0x3C
3) 連線成功後在 OLED 顯示 IP 位址,同時 Serial(115200) 也印出狀態
4) 若連線失敗請顯示「Connecting...」並每 500ms 更新一次點點
補充要求:請注意 U8g2 的 setI2CAddress() 使用 8-bit 位址(0x3C 需左移 1 位)。
請附上需要安裝的函式庫名稱(U8g2 by olikraus)。

8.2 Prompt 模板:Wi-Fi + NTP + 顯示時間(OLED)

請用 Arduino IDE(C++)為 ESP32(NodeMCU-32S)寫一個完整可編譯的範例。
需求:
1) 連線到 Wi-Fi:SSID=______,PASSWORD=______(DHCP)
2) NTP 校時:使用 tock.stdtime.gov.tw / watch.stdtime.gov.tw / time.stdtime.gov.tw
3) 時區:台灣 UTC+8(不使用日光節約)
4) OLED:SSD1306 I2C 128x64,使用 U8g2(U8g2 by olikraus),SDA=GPIO21、SCL=GPIO22、位址 0x3C
5) OLED 每秒顯示目前時間(YYYY-MM-DD HH:MM:SS)
6) Serial(115200) 顯示除錯訊息
補充要求:請注意 U8g2 的 setI2CAddress() 使用 8-bit 位址(0x3C 需左移 1 位)。
請使用 configTime() 與 getLocalTime(),並列出需要的函式庫。

8.3 AI 回答驗收清單(你要會看)

8.4 Prompt 使用參考範例(從「描述需求」到「可上傳程式」)

教學用:讓學生知道「怎麼問」才會得到「能跑」的答案,並學會用回饋讓 AI 修正。

範例 A:第一次就要到「可編譯、可上傳」的 Wi-Fi + OLED(顯示 IP)

你是 Arduino/ESP32 助教。請輸出一個「可直接貼到 Arduino IDE 就能編譯上傳」的完整範例(含 setup/loop)。
硬體:ESP32 NodeMCU-32S + OLED SSD1306 I2C 128x64
接線:SDA=GPIO21,SCL=GPIO22,OLED I2C 位址=0x3C,供電=3V3
需求:
1) Wi-Fi STA 連線:SSID=你的SSID,PASSWORD=你的密碼(DHCP)
2) Serial(115200) 印出連線進度與最後的 IP
3) OLED 顯示兩行:第一行顯示 WiFi OK,第二行顯示 IP: x.x.x.x
4) 若 10 秒內連不上,請在 OLED 顯示 FAIL 並每 3 秒重試一次
5) 請使用 U8g2(U8g2 by olikraus),並列出必需安裝的函式庫名稱
6) 請注意 U8g2 I2C 位址使用 8-bit(0x3C 需左移 1 位)
請避免使用括號或特殊符號放在 Mermaid 圖內(本題不需要圖)。

範例 B:Wi-Fi + NTP 校時 + OLED 顯示時間(台灣 UTC+8)

請為 ESP32(NodeMCU-32S)寫 Arduino IDE 完整範例。
需求:
1) 連 Wi-Fi(STA/DHCP):SSID=____,PASSWORD=____
2) NTP:依序使用 tock.stdtime.gov.tw、watch.stdtime.gov.tw、time.stdtime.gov.tw
3) 時區:台灣 UTC+8,DAYLIGHT=0
4) OLED SSD1306 I2C 128x64:使用 U8g2,SDA=21、SCL=22、位址=0x3C(提醒:U8g2 setI2CAddress 需 addr<<1)
5) OLED 每秒顯示:
   第 1 行:NTP Clock
   第 2 行:YYYY-MM-DD
   第 3 行:HH:MM:SS
6) 若 NTP 10 秒內失敗,OLED 顯示 NTP FAIL,並每 5 秒再試一次
請使用 configTime() 與 getLocalTime(),並加上必要的 Serial 除錯訊息。

範例 C:加上「斷線自動重連」與「狀態列」(更像產品)

請在你剛剛提供的 Wi-Fi + OLED 程式上做增強(保留原功能)。
新增需求:
1) 每 2 秒檢查 WiFi.status(),若斷線就自動重連
2) OLED 最底下一行顯示 RSSI(訊號強度,例如 RSSI:-55dBm)或顯示 DISCONNECTED
3) 請用函式分工:connectWiFi()、drawStatus(),避免把所有邏輯塞在 loop
請輸出完整程式(不要只給片段)。

範例 D:編譯失敗時,怎麼「把錯誤訊息餵給 AI」讓它修正

規則:把「完整錯誤訊息」貼上,並告訴 AI 你的板子與你做過的嘗試。

我在 Arduino IDE 編譯失敗,請你根據錯誤訊息修改程式,並告訴我還缺哪個函式庫要安裝。
板子:ESP32 Dev Module
我已安裝:U8g2 by olikraus
錯誤訊息(請看這段原文):
---
fatal error: WiFi.h: No such file or directory
 #include <WiFi.h>
          ^~~~~~~~
compilation terminated.
---
請給我:
1) 可能原因(用一句話)
2) 如何在 Arduino IDE 安裝/選到正確的 ESP32 Board package
3) 修正後的完整程式(若程式本身沒錯,也請確認相容的 include)

範例 E:硬體沒反應時,怎麼問 AI「判斷是接線/位址/程式」哪裡錯

我照你的程式上傳後,Serial 看到 WiFi OK 也有 IP,但 OLED 仍然黑屏。
已知資訊:
1) I2C Scanner 掃描結果:Found I2C device at 0x3D
2) OLED 供電接 3V3
3) SDA=21、SCL=22
4) 我使用的是 U8g2(提醒:U8g2 setI2CAddress 需要 8-bit 位址)
請你:
1) 說明最可能的原因
2) 指出程式碼中哪個設定要改(給出具體值,例如 0x3D 與 setI2CAddress 左移)
3) 給我一個最小測試程式:只初始化 OLED 並印出 Hello

8.5 AI 協作的「三段式迭代流程」(教學生怎麼跟 AI 合作)

  1. 一次把需求說清楚:板子型號、接線(SDA/SCL)、I2C 位址、輸出裝置(Serial/OLED)、成功條件(顯示什麼)
  2. 先跑最小可行版本(MVP):先 Wi-Fi 成功+印出 IP;再加 OLED;最後才加 NTP / 重連 / 額外功能
  3. 用證據回饋 AI 修正:貼上「錯誤訊息」或「Serial 輸出」,不要只說「不能用」

8.6 回饋 AI 的資訊模板(學生照抄填空)

我需要你幫我除錯/改進 ESP32 程式。
環境:
- IDE:Arduino IDE
- Board:__________(例如 ESP32 Dev Module / NodeMCU-32S)
- ESP32 core version:__________(若知道再填)
硬體:
- OLED:SSD1306 I2C 128x64
- SDA:GPIO__
- SCL:GPIO__
- I2C address:0x__(用 I2C Scanner 測到的)
我做了什麼:
1) 我使用的程式版本:WiFi + OLED / WiFi + NTP / 其他:____
2) 我期待看到的結果:____
實際發生:
- Serial 輸出(原文貼上):____
- 編譯錯誤(原文貼上):____
請你輸出:
1) 你判斷的原因
2) 你要我做的 2 個驗證步驟
3) 修正後的完整程式

9. 常見問題與排除(Q&A / Troubleshooting)

  1. 一直連不上 Wi-Fi
  2. 確認 SSID/密碼正確(注意大小寫、空白)
  3. 確認是 2.4GHz Wi-Fi(很多 IoT 不支援 5GHz)
  4. 手機分享網路時,確認有開啟「最大相容性」/ 2.4GHz 模式
  5. 序列埠顯示正常,但 OLED 沒畫面
  6. 檢查接線(SDA/SCL 是否接反、是否接到 3V3)
  7. 先跑 I2C Scanner 確認位址(0x3C 或 0x3D)
  8. 使用 U8g2 時,確認程式有設定 setI2CAddress(addr<<1),且 addr 與掃描到的位址一致
  9. OLED 有畫面,但顯示亂碼或閃爍
  10. 供電不足(換更穩的 USB、不要用 5V 給 3.3V 模組)
  11. I2C 線太長/接觸不良(縮短線材)
  12. NTP 同步失敗
  13. Wi-Fi 是否真的有上網(路由器可能阻擋 NTP/UDP)
  14. 改用其他 NTP(例如 pool.ntp.org)測試(若網路策略允許)
  15. 時間不對
  16. 檢查時區偏移(台灣 UTC+8
  17. 檢查是否誤用日光節約(台灣通常設 0

10. 練習任務(Practice)

  1. 在 OLED 顯示:SSIDIPRSSI(訊號強度)
  2. 連線成功後,改成每 5 秒更新一次畫面(降低閃爍與耗電)
  3. 讓裝置「斷線自動重連」(提示:定期檢查 WiFi.status()
  4. 延伸挑戰:用 RTC DS3231 做離線時間顯示,並在有網路時自動校時

11. 學習總結(Summary)