2026年8月20日 星期四

JQ6500 STOP 爆音除錯實錄

JQ6500 STOP 爆音除錯實錄

從「按 STOP 後無法續播」到 V1.8.8 Reset Only+Deferred Re-init

水井三寶智慧互動展覽系統|ESP32 × JQ6500 × Web Control × Debugging

在「水井三寶智慧互動展覽系統」中,JQ6500 負責播放白馬、烏龜、姻緣花等故事。系統原本在故事自然播放完畢後,可以正常切換到下一個故事;但只要使用手機 Web 按下 STOP,中途停止播放,再選另一個故事,就會出現「無法再次播放」的問題。更麻煩的是,後續雖然成功解決續播問題,STOP 時卻又出現明顯的「啵、啵」兩聲爆音。這篇文章完整記錄這次除錯過程,以及最後得到的工程經驗。

一、最初的問題:自然播完正常,STOP 後卻無法續播

最早觀察到的現象非常明確:

情況 A 白馬播放 ↓ 自然播放完畢 ↓ 再按烏龜 ↓ 正常播放 情況 B 白馬播放 ↓ 手機按 STOP ↓ 故事停止 ↓ 再按烏龜 ↓ 沒有正常播放 ↓ 必須斷電重開

這表示問題不在一般播放流程,而是在「人工中止」之後,JQ6500 的內部狀態沒有回到可重新播放的狀態。

二、第一個錯誤認知:把 0x0E 當成 STOP

早期程式使用:

0x7E, 0x02, 0x0E, 0xEF

原本把它命名為:

jqStop();

後來重新檢查指令語意後發現,0x0E 實際上是 PAUSE,不是真正的 STOP。這正好解釋為什麼人工停止後,播放器可能停留在 PAUSED 狀態,下一次使用 Play-by-index 指令時不一定能正常重新起播。

第一個重要經驗:
裝置通訊最怕「指令名稱寫得像真的」。如果函式叫 jqStop(),開發者很容易直接相信它就是 Stop,而忽略真正協定中的語意。

三、V1.8.5:改用 RESET 解決無法續播

後來改用 JQ6500 的 RESET 指令:

0x7E, 0x02, 0x0C, 0xEF

流程改成:

PAUSE ↓ RESET ↓ Select Flash ↓ Restore Volume ↓ READY

這一版最大的成果是:STOP 後終於可以正常再播放下一個故事。

但新的問題出現了:

按下 STOP 時,喇叭會明顯聽到「啵、啵」兩聲。

四、V1.8.6:先把音量設成 0,仍然沒有解決

第一個直覺是:會不會是 JQ6500 音量太大,所以 RESET 的瞬態被放大?

因此嘗試:

Volume → 0 ↓ Pause ↓ Reset ↓ Select Flash ↓ Restore Volume

程式另外設計了 Raw Volume Control,讓 STOP 過程中的暫時音量 0 不會改動手機設定,也不會寫入 NVS。

void jqSendVolumeRaw(uint8_t volume)
{
  // 只送命令
  // 不修改 currentVolume
  // 不寫入 NVS
}

但實測結果仍然是:

「啵、啵」兩聲依舊明顯。

這個結果非常重要,因為它告訴我們:問題不是數位音量參數本身。

五、V1.8.7:拿掉 PAUSE,只保留 RESET

接下來進一步做變因隔離。

如果兩聲分別是:

PAUSE → 啵 RESET → 啵

那拿掉 PAUSE 後,理論上應該只剩一聲。

因此 STOP 改成:

RESET ↓ Select Flash ↓ Volume = 0 ↓ Restore Volume

結果卻仍然是:

「啵、啵」兩聲。

這表示「第一聲=Pause、第二聲=Reset」這個推論並不成立。

六、V1.8.8:STOP 時真的只做 RESET

為了徹底排除後續初始化造成的影響,V1.8.8 採用最乾淨的實驗方式:

STOP 階段: RESET 0x0C ↓ jqNeedsRearm = true ↓ READY ★ 不 Select Flash ★ 不送 Volume=0 ★ 不 Restore Volume

真正的初始化全部延後到下一次使用者按 PLAY 時:

下一次 PLAY: 偵測 jqNeedsRearm ↓ Select Flash ↓ Restore Volume ↓ PLAY

這個版本有兩個重要結果:

測試項目結果
STOP 後再選下一個故事✅ 正常播放
STOP 當下爆音⚠️ 仍然是「啵、啵」兩聲

七、最後可以得到什麼結論?

經過 V1.8.5 → V1.8.8 的逐步排除,可以相當有把握地判斷:

這兩聲爆音不是 Web 控制、狀態機、NVS 音量、Select Flash 或 Restore Volume 造成,而是 JQ6500 在 RESET 過程中,內建 DAC/功放輸出級工作點改變所產生的硬體瞬態。

目前系統是 JQ6500 直接推喇叭,沒有使用外部功放:

JQ6500 │ SPK+ / SPK- │ ▼ Speaker

因此 RESET 時內部音訊級的關閉與重新建立偏壓,都直接反映到 Speaker 上。

八、為什麼會出現兩聲?

雖然 STOP 程式只有送一次 RESET,但 JQ6500 內部在 Reset 過程可能經歷:

內部功放 / DAC 關閉 ↓ 輸出工作點改變 ↓ 第一聲「啵」 ↓ 內部模組重新啟動 ↓ 偏壓重新建立 ↓ 第二聲「啵」

也就是說,兩聲未必需要兩個外部命令;一個 RESET 本身就可能包含兩個類比輸出瞬態。

九、這次除錯最重要的方法:一次只改一個變因

這次能真正找到原因,不是因為一次改很多程式,而是把可能因素逐步拆開:

版本STOP策略結果
V1.8.5Pause → Reset → Init可續播,但啵、啵
V1.8.6Volume 0 → Pause → Reset仍啵、啵
V1.8.7Reset → Init仍啵、啵
V1.8.8STOP 只 Reset;Init 延後到 PLAY仍啵、啵
第二個重要經驗:
除錯不是一直「加功能」,而是要有意識地做變因隔離。每一版只改一個關鍵行為,才能知道真正是哪一個因素造成結果。

十、什麼問題已經解決?什麼問題還沒解決?

項目目前狀態
自然播放完畢後再播下一首✅ 正常
手機中途 STOP✅ 正常停止
STOP 後再播下一首✅ V1.8.8 已正常
手機 Realtime Status✅ 正常
手機音量控制✅ 正常
音量寫入 NVS✅ 關機重開可保留
姻緣花 24 顆柔和彩虹旋轉✅ 正常
STOP 爆音⚠️ 還有「啵、啵」兩聲

十一、目前最合理的工程判斷

在功能已穩定的前提下,繼續修改 delay 或音量命令,效益已經很低。

目前最合理的判斷是:

V1.8.8 可視為目前穩定軟體版。

STOP 爆音屬於 JQ6500 直接驅動 Speaker 時,RESET 造成的類比輸出瞬態。若要完全消除,下一步應從硬體音訊架構處理,而不是持續修改 Web 或狀態機。

十二、未來真正要消除爆音,應該怎麼做?

如果正式展覽版要完全消除爆音,可以把音訊路徑改成:

JQ6500 DAC / Line Out ↓ 具有 MUTE / SHDN 的外部功放 ↓ Speaker

STOP 時先:

AMP MUTE ↓ JQ6500 RESET ↓ 等待穩定 ↓ AMP UNMUTE

這樣 JQ6500 即使仍然產生 RESET transient,也不會直接送到 Speaker。

目前尚未接外部功放,因此現階段不要誤以為「再加一個 delay」就能根治爆音。真正的解法應該是建立硬體 MUTE 點。

十三、這個案例對《網際網路應用》課程有什麼價值?

表面上看,這只是「STOP 後有爆音」的硬體問題;但實際上,它很適合讓學生理解完整系統除錯。

層級這次檢查的內容
Web手機是否真的送出 STOP Request
ESP32 ApplicationhandleStop() 與 State Machine 是否正確
UARTJQ6500 收到的是 Pause 還是 Reset
Device StateReset 後是否可以重新播放
Audio Hardware爆音是否來自 DAC/功放輸出瞬態

也就是說,一個看似簡單的 STOP 按鈕,其實橫跨:

Browser ↓ HTTP ↓ ESP32 Web Handler ↓ State Machine ↓ UART Command ↓ JQ6500 ↓ Audio Output ↓ Speaker

十四、從這次經驗學到的五件事

1. 指令語意一定要回到協定本身。
函式名稱叫 Stop,不代表實際送出的命令真的是 Stop。
2. 自然結束和人工中止,是兩條不同狀態路徑。
不能因為自然播放正常,就假設 STOP 後也會進入相同狀態。
3. 音量 0 不等於類比輸出真正靜音。
RESET 時 DAC/功放的工作點仍可能產生 transient。
4. 除錯要一次只改一個變因。
Pause、Reset、Volume、Select Flash、Restore Volume 必須逐項隔離。
5. 軟體問題解到最後,可能會證明其實是硬體特性。
這時應該停止一直改程式,改從系統架構處理。

十五、結語:失敗的版本也是教材

從 V1.8.5 到 V1.8.8,表面上像是在「反覆修改 STOP」,但真正累積的是一套非常有價值的工程判斷過程。

我們先解決「STOP 後不能再播放」,再逐步確認爆音不是音量、不是 Pause、不是 Select Flash、也不是重新初始化造成,最後把問題定位到 JQ6500 本身 RESET 時的音訊輸出瞬態。

真正有價值的不是某一版程式,而是知道:為什麼要改、改了什麼、結果如何、下一步該往哪裡查。

這也是「水井三寶智慧互動展覽系統」作為大學《網際網路應用》與 IoT 實作教材的重要價值:學生看到的不只是一個成功作品,而是一個真實系統如何一步一步從問題、測試、假設、修正走向穩定。

JQ6500 ESP32 STOP RESET UART Pop Noise Debugging Realtime Web IoT 水井三寶 USR

2026年8月18日 星期二

從接線施工到手機控制: 水井三寶 ESP32 擴充底板 × GPIO19 WS2812B × Web 音量控制實作

從接線施工到手機控制:
水井三寶 ESP32 擴充底板 × GPIO19 WS2812B × Web 音量控制實作

水井三寶智慧互動展覽系統|Layer 2~Layer 3 實作紀錄

ESP32 × WS2812B × JQ6500 × Edge Web × Realtime Status × Mobile Volume Control

「水井三寶智慧互動展覽系統」在實作過程中,除了要考慮程式能不能執行,更重要的是: 設備真正裝進展覽箱之後,好不好接線?好不好維修?現場人員能不能不用重新燒錄程式,就完成基本設定?

因此,本次系統在原有功能穩定之後,又進行兩項很重要的實務調整: 第一項是為了配合 ESP32 擴充底板與 WS2812B 三線式插頭,重新調整 LED DATA GPIO; 第二項則是在 V1.8 Realtime Web Status 基礎上加入手機音量控制,形成 Layer 4 V1.8.1「Realtime Status+Mobile Volume Control」

一、為什麼已經可以動了,還要修改GPIO?

早期測試 WS2812B 時,DATA 使用 GPIO13。從程式的角度來看完全沒有問題, 但當系統開始由麵包板實驗走向正式展覽箱施工時,問題就不再只是「GPIO能不能輸出」。

真正的問題變成:哪一支GPIO最適合施工?

  • 能不能直接配合擴充底板的三針插座?
  • 能不能使用現有 WS2812B 三線插頭?
  • 是否會和三顆實體按鈕衝突?
  • 是否會影響 JQ6500 UART?
  • 日後拆裝與維修是否方便?

二、從 GPIO13 改成 GPIO19

經過重新檢查擴充底板可使用的腳位後, GPIO19 可以直接配合板上的插座,而且不需要搬動目前已經測試穩定的按鈕與 JQ6500 接腳, 因此最後決定:

WS2812B DATA:GPIO13 → GPIO19
功能 GPIO 說明
白馬按鈕 GPIO32 維持原接線
烏龜按鈕 GPIO33 維持原接線
姻緣花按鈕 GPIO25 維持原接線
JQ6500 UART GPIO26 / GPIO27 已完成穩定測試,不再更動
ToF VL53L0X GPIO21 / GPIO22 I2C SDA / SCL
WS2812B DATA GPIO19 配合擴充底板三針插座

三、程式其實只需要改一個地方

這正是軟硬體模組化的好處。 LED控制邏輯沒有改變,只是將資料輸出的GPIO重新指定。

原來版本

#define LED_PIN 13

新版

#define LED_PIN 19

Adafruit NeoPixel 的初始化方式仍然相同:

#define LED_PIN    19
#define LED_COUNT  61

Adafruit_NeoPixel strip(
  LED_COUNT,
  LED_PIN,
  NEO_GRB + NEO_KHZ800
);
這次修改的重要經驗:
GPIO選擇不能只從「程式能不能跑」來思考。 當作品進入正式施工階段,還要把接頭、底板、線材、維修方式與模組位置一起納入設計。

四、WS2812B 如何接到 ESP32 擴充底板?

WS2812B 基本上需要三條線:

ESP32 擴充底板 GPIO19 / Signal │ ├────────────→ WS2812B DIN │ 5V / VCC ├────────────→ WS2812B +5V │ GND └────────────→ WS2812B GND

如果 LED 數量較多,正式展覽系統建議讓 WS2812B 使用獨立 5V 電源, ESP32只提供 DATA,但兩邊的 GND 必須共地。

ESP32 GPIO19 ─────────→ WS2812B DIN 外接 5V + ───────────→ WS2812B +5V 外接 5V GND ─────┬───→ WS2812B GND │ ESP32 GND ────────┘ 必須共地
施工注意: 三針插頭的線色不能直接當成腳位依據, 一定要確認擴充板的 Signal / VCC / GND, 以及 WS2812B 的 DIN / 5V / GND 順序。

五、61顆WS2812B不是只拿來「發亮」

目前系統將 61 顆 WS2812B 分成不同區域:

#define BASE_START       0
#define BASE_COUNT       9

#define HORSE_START      9
#define HORSE_COUNT     16

#define TURTLE_START    25
#define TURTLE_COUNT    12

#define FLOWER_START    37
#define FLOWER_COUNT    24
區域 LED數量 燈光意義
底座 9 系統基礎氛圍
白馬 16 行動、力量、向前
烏龜 12 水、生態、守護
姻緣花 24 祝福、緣分、生命與地方情感

尤其姻緣花已由原本的固定色彩改成 HSV 彩虹色, 讓不同 LED 呈現五顏六色的效果,再搭配逐漸綻放與收縮的動畫。

uint16_t hue =
  colorOffset +
  (65535UL * i / FLOWER_COUNT);

strip.setPixelColor(
  FLOWER_START + i,
  strip.gamma32(
    strip.ColorHSV(
      hue,
      255,
      100
    )
  )
);

因此燈光不只是裝飾,而是成為展覽系統的一種 視覺回饋介面

六、第二個問題:展場音量不能每次都重新燒錄

JQ6500 原本的音量是在 Arduino 程式中設定:

uint8_t currentVolume = 20;

JQ6500 的控制範圍設定為:

0 ~ 30

如果要從 20 改成 25 或 30,最簡單的方法當然是修改程式再重新燒錄。 但是到了真正的展覽現場,這種方式非常不方便。

不同場域需要不同音量:
  • 安靜教室可能只需要 15~20。
  • 兒童館可能需要 20~25。
  • 大型展覽空間可能需要更高音量。
  • 閉館測試時可能希望立即靜音。

因此 V1.8.1 的設計目標很直接:

讓手機成為水井三寶的音量遙控器。

七、V1.8.1:手機直接控制 JQ6500 音量

手機連上 ESP32 的:

Wi-Fi SSID: Shuijing-Treasures ↓ 瀏覽器 ↓ http://192.168.4.1

就可以在 Edge Web 控制頁看到:

🔊 音量控制

0 ─────────── ● ─────────── 30

目前音量:20 / 30

【靜音】 【15】 【20】 【25】 【最大30】

八、HTML使用 Range Slider

Web介面使用 HTML 的 range 元件:

<input
  type="range"
  id="volumeSlider"
  min="0"
  max="30"
  value="20"
>

這讓手機可以直接拖曳調整:

0 ↓ 5 ↓ 10 ↓ 15 ↓ 20 ↓ 25 ↓ 30

九、手機不是直接控制JQ6500

這一點非常適合拿來作為《網際網路應用》課程教材。

手機調整音量時,真正的資料流程是:

手機瀏覽器 │ │ HTTP Request ▼ ESP32 Edge Web │ │ /volume?v=25 ▼ Web Handler │ ▼ jqSetVolume(25) │ │ UART Command ▼ JQ6500 │ ▼ 喇叭音量改變

也就是:

Web介面 → HTTP → ESP32 → UART → JQ6500 → 喇叭

十、Web端如何送出音量設定?

JavaScript 可以使用 fetch()

async function setVolume(v)
{
  const r = await fetch(
    '/volume?v=' + encodeURIComponent(v),
    {
      cache:'no-store'
    }
  );

  const d = await r.json();

  document.getElementById(
    'volumeValue'
  ).textContent = d.volume;
}

例如使用者選擇 25,瀏覽器送出:

GET /volume?v=25

十一、ESP32如何接收?

ESP32 Web Server 收到 /volume Request 後, 讀取參數並限制在 0~30:

int volume =
  server.arg("v").toInt();

if (volume < 0)
{
  volume = 0;
}

if (volume > 30)
{
  volume = 30;
}

jqSetVolume(
  (uint8_t)volume
);

完成後再回傳 JSON:

{
  "ok": true,
  "volume": 25
}

十二、為什麼回傳JSON,而不是重新整理網頁?

早期 Web 控制很容易採用:

按按鈕 ↓ ESP32執行 ↓ Redirect ↓ 整個網頁重新載入

V1.8.1 則改成:

拖曳音量 ↓ fetch() ↓ /volume?v=25 ↓ ESP32設定JQ6500 ↓ 回傳JSON ↓ 只更新音量數字

因此操作更接近現代 Web App, 也不會因為每次調整音量就讓整個手機畫面閃動。

十三、V1.8的重要改進:Realtime Web Status

在早期版本中曾經出現一個很有意思的問題:

故事已經播放完畢,ESP32 Serial Monitor 也顯示 PLAY COMPLETE, 但是手機網頁仍然顯示:

PLAYING

原因不是 JQ6500,也不是 ESP32 狀態機, 而是瀏覽器看到的是載入網頁那一刻的狀態。

因此 V1.8 新增:

/api/status

手機每秒讀取一次最新狀態:

setInterval(
  updateStatus,
  1000
);

十四、Realtime Status與音量控制整合

V1.8.1 再把音量加入 Status JSON。 概念上可以得到:

{
  "state":"PLAYING",
  "story":"白馬故事",
  "jq_busy":true,
  "volume":25,
  "cloud_ok":18,
  "cloud_fail":0
}

因此手機控制頁可以同時知道:

  • 現在是不是正在播放。
  • 目前播放哪一個故事。
  • JQ6500 BUSY 是否有效。
  • 目前音量是多少。
  • ESP32目前的即時狀態。

十五、播放完成後,手機會自己變化

現在操作流程變成:

手機按下「白馬」 ↓ PLAYING 白馬故事 JQ BUSY:ACTIVE ↓ 語音播放完成 ↓ COOLDOWN 白馬故事 JQ BUSY:IDLE ↓ 約2秒 ↓ READY / IDLE 待機

使用者不再需要手動按「重新整理」。

十六、為什麼Status Polling不能算成「使用者操作」?

這是 V1.8 開發過程中另一個很重要的系統設計問題。

水井三寶採用:

Local First, Cloud Later
現場互動優先,雲端同步延後。

如果瀏覽器每秒查詢 /api/status, ESP32每次都把它當成「使用者正在操作」, Cloud Sync 就可能永遠等不到真正的 Idle 時間。

因此:

void handleStatus()
{
  // 不呼叫 markLocalActivity()

  ...
}

也就是把:

「查詢狀態」 和 「真正操作設備」 分開處理。

十七、V1.8.1的完整控制關係

手機 │ │ Wi-Fi ▼ ESP32 Edge Web 192.168.4.1 │ ┌─────────┼─────────┐ │ │ │ ▼ ▼ ▼ 故事控制 音量控制 即時狀態 /play /volume /api/status │ │ ▲ ▼ ▼ │ ESP32 ────────────────┘ │ ├──── UART ───→ JQ6500 ───→ 喇叭 │ ├──── GPIO19 ─→ WS2812B │ ├──── I2C ────→ VL53L0X │ └──── Wi-Fi STA │ ▼ Internet │ ▼ Django / Cloud

十八、從「接腳修改」看工程設計

GPIO13改成GPIO19,看起來只修改了一行程式:

#define LED_PIN 19

但背後其實代表系統已經從:

「麵包板能動」 進入 「正式作品能施工」 再進入 「現場人員能維護」

這也是 IoT 專題很重要的一課: 好的系統不只是功能正確,也要考慮安裝、操作與維護。

十九、從「音量控制」看Edge Web的價值

同樣地,音量原本只是 Arduino 裡的一個變數:

uint8_t currentVolume = 20;

但是加入 Edge Web 之後, 這個變數就成為使用者可以透過手機操作的系統參數。

Arduino Variable currentVolume ↓ ESP32 Web API /volume?v=25 ↓ HTML / JavaScript Volume Slider ↓ 手機操作介面

這就是 Edge Web 很重要的價值:

把嵌入式系統內部的控制功能, 轉換成一般使用者也能操作的 Web 服務。

二十、從水井三寶學「網際網路應用」

這次修改雖然從「換一支GPIO」和「增加音量滑桿」開始, 但其實可以串起很多《網際網路應用》的重要概念。

實作 可以學到的概念
GPIO19控制WS2812B Embedded I/O、硬體介面、模組化設計
手機連ESP32 SoftAP、Wi-Fi、IP、Client / Server
192.168.4.1 Private IP、Edge Web Server
/volume?v=25 URL、Path、Query Parameter、HTTP GET
fetch() 非同步Web Request
JSON Response Web資料交換格式
/api/status API、Realtime Status、Polling
JQ6500 UART、裝置控制
WS2812B 數位燈光與視覺回饋
Django同步 Edge → Internet → Cloud

二十一、版本演進

版本 主要功能
早期版本 ESP32+JQ6500基本故事播放
Layer 3 ESP32 Edge Web手機控制
Layer 4 V1.7 AP+STA+Django+Queue+Cloud Sync
Layer 4 V1.8 Realtime Web Status
Layer 4 V1.8.1 Realtime Status+Mobile Volume Control+GPIO19 WS2812B施工配置

二十二、結語:真正的IoT,是讓實體作品、網路與使用者連在一起

水井三寶智慧互動展覽系統的開發不是一次完成, 而是在實際接線、播放、展示、手機操作與雲端同步的過程中不斷修正。

從 GPIO13 改成 GPIO19, 是為了讓硬體更適合正式施工; 從固定音量改成手機控制, 是為了讓系統更適合真實展覽環境; 從靜態網頁改成 Realtime Status, 則是讓使用者真正看見設備當下的狀態。

文化作品是起點,ESP32負責互動,Edge Web負責控制, Internet負責連結,Django負責資料,而未來的AI/RAG則負責讓地方知識持續被理解與使用。

這也正是「水井三寶智慧互動展覽系統」作為 大學《網際網路應用》與USR實作教材最重要的價值: 不是只教學生把程式寫出來,而是讓學生從一個真實地方文化作品出發, 一路理解硬體、網路、Web、資料與使用者之間如何形成一個完整系統。

水井三寶 ESP32 GPIO19 WS2812B JQ6500 Edge Web Realtime Status Mobile Volume Control HTTP JSON IoT Django USR

2026年8月16日 星期日

以「水井三寶智慧互動展覽系統」為場域型專題教材

網際網路應用|課程大綱

以「水井三寶智慧互動展覽系統」為場域型專題教材

ESP32 → Edge Web → Internet → Django → Data → Knowledge → AI/RAG

模組名稱智慧生活與物聯網
課程名稱網際網路應用
計畫名稱水井村智慧減碳節水三生一體實踐計畫

一、課程簡介

本課程以「水井三寶智慧互動展覽系統」作為《網際網路應用》的場域型專題教材,將抽象的網路協定、位址、Client/Server、Web API與雲端資料概念,轉化為學生可以看見、操作、量測與除錯的真實系統。學生從白馬、烏龜、姻緣花三項地方文化作品出發,理解按鈕、感測器、JQ6500語音與WS2812B燈光如何由ESP32控制;再以手機連入ESP32 Edge Web,實際觀察AP、STA、IP、MAC、DNS、Domain、Port及HTTP Request的作用;進一步將匿名互動事件以JSON及REST API送往Django,建立Digital Twin、資料庫與雲端儀表板。課程不以「會做網頁」為終點,而是追問「一個按鈕按下後,資料去了哪裡?」讓學生沿著實體互動、區域網路、Internet、Web Server、API、Database一路追蹤資料生命週期。最後再由Data走向Knowledge與AI/RAG,思考地方故事如何被整理為可搜尋、可引用、可延伸的文化知識。藉由水井村USR真實場域,學生不只學習網際網路技術,也理解科技如何服務文化保存、地方教育與大學社會責任,培養需求分析、系統整合、網路診斷與知識應用能力。

二、課程核心問題

一個按鈕按下後,資料去了哪裡? ↓ ESP32 → Edge Web → Wi-Fi → IP / DNS → HTTP / JSON / REST API ↓ Django → Database → Digital Twin ↓ Data → Knowledge → AI/RAG

三、學習目標

  • 理解ESP32與周邊裝置通訊,以及實體事件如何轉為數位資料。
  • 理解AP、STA、LAN、IP、MAC、DNS、Domain、Port等網路概念。
  • 理解Browser、Client、Server、Edge Web及HTTP資料流程。
  • 理解GET/POST、Header、Body、JSON與REST API。
  • 將ESP32匿名事件送至Django,理解Database與Dashboard。
  • 能以分層方法診斷Wi-Fi、DNS、HTTPS、API與Cloud問題。
  • 理解Data、Knowledge與AI/RAG的關係。
  • 從USR場域需求思考網際網路技術的社會實踐價值。

四、五層架構與課程主軸

層級系統角色課程重點
Layer 1|文化作品層白馬、烏龜、姻緣花需求、情境、實體與數位系統邊界
Layer 2|智慧互動層ESP32+ToF+按鈕+JQ6500+RGBGPIO、UART、事件、裝置控制
Layer 3|Edge Web層ESP32內嵌網站AP/STA、IP、Web Server、HTTP
Layer 4|Digital Twin / Data層Django+Database+DashboardDNS、HTTPS、JSON、REST API、資料庫
Layer 5|文化知識層文化網站+AI/RAGData → Knowledge、RAG、知識服務

五、系列教材文章

#教材主題核心概念文章連結
1ESP32 × JQ6500 UART 通訊UART序列通訊、語音模組、封包命令閱讀教材
2Layer 2|智慧互動層GPIO、按鈕事件、JQ6500故事播放、互動狀態閱讀教材
3Layer 3|ESP32 Edge WebWeb Server、HTTP、手機控制、192.168.4.1、Edge Computing閱讀教材
4Layer 4|ESP32 × DjangoClient/Server、HTTP、Django、事件資料、Digital Twin閱讀教材
5ESP32 AP+STA 共存SoftAP、Station、LAN與Internet、本地控制與雲端連線閱讀教材
6Layer 4 V1.7|AP+STA+Django整合實測Wi-Fi診斷、DNS、HTTPS、Queue、Local First / Cloud Later閱讀教材
7水井三寶智慧互動展覽系統|五層架構文化作品、智慧互動、Edge Web、Digital Twin/Data、文化知識閱讀教材
8WS2812B × ESP32 燈光控制RGB LED、單線數位控制、色彩編碼、故事狀態回饋閱讀教材
9一個按鈕按下後,資料去了哪裡?Browser → Edge → HTTP → JSON → Django → Database → Dashboard閱讀教材
10IP、MAC、DNS、Domain與PortMAC、IP、Gateway、DNS、Domain、Port、網路診斷閱讀教材
11Data → Knowledge → AI/RAG事件資料、文化知識庫、Chunk、Metadata、Embedding、Vector Search、RAG閱讀教材
12HTTP+JSON+REST APIGET/POST、Header、Body、JSON、REST Endpoint、HTTP Status、Django API閱讀教材

六、建議學習路徑

裝置通訊:ESP32 × JQ6500 × WS2812B ↓ 智慧互動:按鈕 / 感測 → 故事 → 狀態 ↓ Edge Web:手機 → AP → 192.168.4.1 → HTTP ↓ 網路基礎:AP / STA → MAC → IP → Gateway → DNS → Domain → Port ↓ Internet應用:HTTP → JSON → REST API → HTTPS ↓ Cloud / Data:Django → Database → Dashboard → Digital Twin ↓ Knowledge / AI:Data → Knowledge Base → Retrieval → AI/RAG

七、從「做作品」轉向「理解系統」

本課程不把Arduino程式、ESP32接線或Django網站視為彼此獨立的單元,而是要求學生追蹤一筆資料的完整旅程。學生不只要知道「程式可以跑」,還要能回答:手機為什麼找到192.168.4.1?ESP32為什麼同時需要AP與STA?Domain如何透過DNS找到Server?JSON如何進入HTTP Body?Django為什麼回201?當Cloud HTTP=-1時,問題究竟發生在Wi-Fi、DNS、TLS還是API?

核心教學觀念:會使用網路工具只是起點;能畫出資料流、說明協定角色、判斷故障所在層級,才是真正理解「網際網路應用」。

八、USR × 網際網路應用

水井三寶讓網際網路課程不再只是虛擬案例。學生面對的是地方文化作品、展覽觀眾、現場網路、設備可靠度與文化知識保存等真實需求。技術因此不只是完成作業,而是成為連結地方故事、智慧互動、教育推廣與資料累積的工具。透過場域實作,學生可以理解大學社會責任不只是「到社區服務」,而是運用專業知識與地方共同解決問題,並留下可以持續運作、持續學習與持續擴充的系統。

九、關鍵字

ESP32IoTEdge WebAP / STAIP / MAC / DNSHTTPJSONREST APIDjangoDigital TwinAI/RAGUSR

[水井村USR] HTTP+JSON+REST API

HTTP+JSON+REST API

從「水井三寶智慧互動展覽系統」看懂ESP32如何把資料送到Django

HTTP Request × Header × JSON Body × REST Endpoint × Django API × Response

當ESP32已經能連上Internet,下一個問題就是:它到底如何把「烏龜故事被播放」這件事送到Django?答案不是單靠Wi-Fi,而是透過HTTP、JSON與REST API三個重要概念協同工作。這篇文章就用水井三寶Layer 4的資料流,帶學生看懂一筆匿名事件如何從ESP32送到雲端。

一、先從一筆事件開始

{
  "event_uuid":"SHUIJING-001-0000000062",
  "event_type":"STORY_START",
  "story":"002",
  "source":"web",
  "duration_ms":0,
  "completed":null,
  "network_status":"online",
  "metadata":{
    "firmware":"Layer4-V1.7",
    "jq_confirmed":true
  }
}

這段資料本身還沒有「送上網」。它只是ESP32中的一個JSON字串。接下來才輪到HTTP與REST API登場。

二、HTTP是什麼?

HTTP可以理解成Client與Server之間溝通的規則。水井三寶同時用到GET與POST:

Method水井三寶例子用途
GET/play?track=2手機要求ESP32播放烏龜故事
POST/api/exhibition/events/ESP32把匿名事件送到Django
一句話記:GET常用來取得資源或提出查詢;POST常用來把資料送給Server處理。

三、一個HTTP Request有哪三個部分?

Request Line POST /api/exhibition/events/ HTTP/1.1 Headers Content-Type: application/json X-Device-ID: SHUIJING-001 X-Device-Key: ******** Body { "event_type":"STORY_START", "story":"002" }
部分作用
Request Line使用什麼Method、要去哪一個Path
Headers提供內容格式、裝置識別、驗證資訊
Body真正要送給Server的資料

四、JSON是什麼?

JSON是一種文字格式,適合不同系統之間交換結構化資料。

{
  "story":"002",
  "source":"web",
  "completed":true
}
KeyValue意義
story"002"烏龜故事
source"web"由Edge Web啟動
completedtrue故事完整播放
JSON的價值:ESP32、JavaScript、Python、Django等平台都可以很容易解析,因此非常適合IoT與Web API。

五、為什麼要寫 Content-Type?

Content-Type: application/json

這一行是在告訴Django:「這次HTTP Body裡裝的是JSON。」如果Server不知道資料格式,就無法正確解析內容。

六、REST API是什麼?

REST API是一種設計Web服務的方式:把系統功能整理成清楚的URL Endpoint,再搭配HTTP Method進行操作。

https://shuijingtreasures.pythonanywhere.com/api/exhibition/events/
https:// 安全的HTTP通訊 shuijingtreasures.pythonanywhere.com Domain / Server /api/exhibition/events/ REST API Endpoint
Endpoint可以理解成「API的入口地址」。

七、為什麼ESP32不能直接呼叫Django函式?

ESP32和Django位於不同設備、不同執行環境,因此ESP32不能直接執行Server上的Python函式,只能透過網路把Request送到URL,再由Django URL Router找到對應View。

ESP32 ↓ HTTP POST /api/exhibition/events/ ↓ Django URL Router ↓ api_event() ↓ Database

八、Device ID與API Key放在哪裡?

X-Device-ID: SHUIJING-001
X-Device-Key: ********

它們放在HTTP Header,讓Django知道是哪一台設備,以及這台設備是否有權限傳送資料。

正式API Key不應公開放在部落格、簡報或公開GitHub倉庫。教材只示範格式即可。

九、ESP32端的HTTP POST概念

WiFiClientSecure client;
HTTPClient https;

https.begin(
  client,
  "https://shuijingtreasures.pythonanywhere.com/api/exhibition/events/"
);

https.addHeader(
  "Content-Type",
  "application/json"
);

https.addHeader(
  "X-Device-ID",
  DEVICE_ID
);

https.addHeader(
  "X-Device-Key",
  DEVICE_KEY
);

int code = https.POST(jsonBody);
建立HTTPS Client ↓ 指定REST API URL ↓ 加入Headers ↓ 放入JSON Body ↓ POST ↓ 等待HTTP Response

十、Server如何告訴ESP32成功或失敗?

Status Code常見意義
200Request成功
201資料建立成功
400Request內容有問題
401驗證失敗
404API路徑不存在
500Server內部錯誤

水井三寶Cloud Test成功時,可看到:

Cloud HTTP = 201
Response = {"ok":true,...}
CLOUD POST OK

這代表DNS、HTTPS、API URL、裝置驗證與Django資料接收都已經成功。

十一、為什麼 Cloud HTTP = -1 不是Django回的狀態碼?

實作過程中曾出現:

Cloud HTTP = -1

後來追查發現問題發生在DNS解析階段,也就是HTTP Request根本還沒到Django。

DNS失敗 ↓ 找不到Server IP ↓ 無法建立TCP/TLS連線 ↓ HTTP Request沒有到Django ↓ 自然也不會有401 / 404 / 500
除錯原則:Cloud失敗時,不要第一時間就修改Django;先確認Wi-Fi、DNS、TLS與HTTP是否真的走到Server。

十二、為什麼採用 Local First, Cloud Later?

如果每次故事一開始就同步做HTTPS POST,可能讓JQ6500播放、Edge Web與網路傳輸互相干擾。因此系統採取:

故事播放 ↓ 建立JSON Event ↓ 先存LittleFS Queue ↓ 播放完成 ↓ 系統空閒 ↓ HTTP POST ↓ Django
設計原則:現場互動優先;雲端同步延後。

十三、HTTP、JSON、REST API怎麼分工?

技術主要工作水井三寶角色
HTTP規定Client與Server怎麼請求與回應ESP32 POST事件到Django
JSON描述資料格式故事、來源、完成狀態等事件內容
REST API定義Server提供的URL服務入口/api/exhibition/events/
一句話記:HTTP是「怎麼送」,JSON是「送什麼」,REST API是「送到哪個功能入口」。

十四、一筆「烏龜故事」事件的完整旅程

使用者按「002 烏龜故事」 ↓ ESP32 Edge Web ↓ JQ6500開始播放 ↓ 建立 JSON ↓ LittleFS Queue ↓ ESP32 STA ↓ DNS找到PythonAnywhere ↓ HTTPS ↓ POST /api/exhibition/events/ ↓ Headers:Device ID / API Key ↓ JSON Body ↓ Django View ↓ Database ↓ HTTP 201 Response ↓ Dashboard

十五、和水井三寶五層架構的關係

層級HTTP / JSON / REST API的角色
Layer 2 智慧互動層產生故事與感測事件
Layer 3 Edge Web層本地HTTP GET控制ESP32
Layer 4 Digital Twin / Data層HTTP POST+JSON+REST API送到Django
Layer 5 文化知識層未來可透過API提供文化內容與AI/RAG服務

十六、真正理解API,要能回答七個問題

Client是誰? ESP32 Server是誰? Django Protocol? HTTPS Endpoint? /api/exhibition/events/ Method? POST 資料格式? JSON 成功如何判斷? HTTP Status + Response Body

十七、課堂思考題

問題一:如果JSON格式正確,但API URL打錯,可能得到哪一類HTTP狀態?
問題二:為什麼Device ID與API Key適合放Header,而故事內容放Body?
問題三:GET與POST都能帶資料,為什麼事件上傳通常選POST?
問題四:如果Django已回201,但Dashboard沒有資料,問題可能已經移到哪一層?

十八、結語:REST API是Edge與Cloud之間的橋

水井三寶的ESP32負責感測、故事播放與現場控制,Django負責跨場次資料、Dashboard與後續分析。兩邊位於不同設備、使用不同語言,卻能透過HTTP+JSON+REST API協同工作。

因此,REST API真正重要的地方,不只是讓ESP32「可以傳資料」,而是建立清楚的系統邊界:Edge負責即時互動,Cloud負責資料服務。HTTP定義溝通方式,JSON定義資料語言,而REST API定義雙方合作的入口。

HTTP GET POST JSON REST API Endpoint Header HTTPS ESP32 Django

[水井村USR] Data → Knowledge → AI/RAG

Data → Knowledge → AI/RAG

從「水井三寶智慧互動展覽系統」第五層看懂資料如何成為文化知識

Event Data × Database × Cultural Knowledge × Retrieval × LLM × RAG

前面的水井三寶教材已經讓一筆「烏龜故事被播放」的事件,從ESP32經過HTTP、JSON與REST API送到Django。但資料送到Database並不是終點。真正值得思考的是:「烏龜今天播放37次」和「烏龜為什麼代表守水?」是同一種資料嗎?答案是否定的。這正是水井三寶五層架構從Layer 4走向Layer 5,以及未來導入AI/RAG最重要的分界。

一、先分清楚:Data不等於Knowledge

假設Django儀表板顯示:

白馬故事:52次
烏龜故事:37次
姻緣花故事:46次
總故事:21次
今日互動人次:156

這些是非常有價值的Data(資料),它告訴我們系統發生了什麼。

但如果觀眾問:

「為什麼水井村會有白馬與烏龜?」
「姻緣花和地方記憶有什麼關係?」
「水井三寶是哪三件作品?」
「這些作品和生產、生態、生活三生一體有什麼關係?」

這些問題就不能只靠播放次數回答。它需要地方故事、創作者資料、作品說明、影音、教材與USR實踐內容,這些才逐步形成Knowledge(知識)

一句話記:Data告訴我們「發生了什麼」;Knowledge幫助我們理解「這代表什麼、為什麼」。

二、Layer 4和Layer 5到底差在哪裡?

比較Layer 4:Digital Twin / DataLayer 5:文化知識
核心事件、狀態、統計故事、脈絡、意義、教材
典型內容故事播放次數、時間、來源、完成率白馬、烏龜、姻緣花的文化故事
資料型態結構化資料文字、圖片、影音、文件等多元內容
主要工具Django Model、Database、Dashboard文化網站、知識庫、未來RAG
回答問題今天有多少互動?這個故事的文化意義是什麼?
第五層不是「再做一個網站」。網站只是呈現知識的介面;第五層真正的核心是把地方文化整理成可保存、可搜尋、可教學、可被AI檢索的知識資源。

三、從Data到Information,再到Knowledge

可以把轉換過程理解成:

Data 「002故事被播放」 「20:22:39」 「source = web」 ↓ Information 「今天烏龜故事共播放37次」 「手機操作占60%」 ↓ Knowledge 「觀眾為什麼對烏龜故事有興趣?」 「烏龜在水井三寶文化中的意義是什麼?」 ↓ AI / RAG 讓觀眾用自然語言詢問文化知識

從原始事件到統計,是「整理資料」;從統計到文化脈絡,則需要另外建立知識內容,不能只靠數字自動產生。

四、水井三寶的Knowledge從哪裡來?

第五層可以逐步整理以下知識來源:

知識類型內容例子
地方故事白馬、烏龜、姻緣花、水井村與地方記憶
作品資料作品名稱、創作者、材料、設計理念、創作歷程
工藝知識玉米籜、蓪草、姻緣花燈、地方工藝製作
教育教材繪本、教案、親子活動、科技教育教材
影音內容故事語音、影片、訪談、活動紀錄
USR實踐生產、生態、生活三生一體與大學社會責任歷程
互動資料Layer 4匿名事件與展覽統計

五、傳統搜尋和AI問答有什麼不同?

傳統網站通常要求使用者先知道要點哪一頁:

首頁 ↓ 水井三寶 ↓ 烏龜 ↓ 故事介紹 ↓ 閱讀內容

AI問答則可以讓使用者直接問:

「為什麼烏龜代表珍惜水資源?」
「請用小學生聽得懂的方式介紹水井三寶。」
「姻緣花和地方工藝有什麼關係?」

但這裡出現一個新問題:大型語言模型不一定知道水井村的地方知識,即使回答得很流暢,也可能產生錯誤內容。

六、這就是為什麼需要RAG

RAG是 Retrieval-Augmented Generation,中文常譯為「檢索增強生成」。

核心概念不是讓AI憑記憶回答,而是:

使用者問題 「姻緣花代表什麼?」 ↓ Retrieval 檢索 從水井三寶知識庫找相關資料 ↓ 找到: 作品介紹 創作者資料 地方故事 USR教材 ↓ 把相關內容交給LLM ↓ Generation 生成 ↓ 根據水井三寶資料回答
一句話理解RAG:先「查資料」,再「請AI根據查到的資料回答」。

七、為什麼不直接問Chatbot就好?

一般LLM可能具備廣泛知識,但「水井三寶」屬於高度地方化、專案化的內容。這類知識可能不在模型訓練資料中,也可能在作品持續發展後改變。

直接LLMRAG
主要依賴模型既有知識先查水井三寶自己的知識庫
地方內容可能不足可以納入地方採集與USR資料
更新通常不容易立即反映更新知識庫即可提供新內容
回答來源較難控制可要求依檢索內容回答並提供來源

八、RAG不是把整個網站一次丟給AI

真正的RAG通常會先對文化內容做前處理:

文化文章 / 教材 / 訪談 / 作品資料 ↓ 清理與整理 ↓ 切成較小的 Chunk ↓ 建立 Metadata ↓ Embedding ↓ Vector Database ↓ 等待使用者查詢

例如一篇長文章可以切成:

Chunk 001:白馬的故事
Chunk 002:烏龜與水文化
Chunk 003:姻緣花的文化意義
Chunk 004:創作者與作品歷程
Chunk 005:水井三寶與三生一體

九、Embedding是在做什麼?

Embedding可以簡化理解成:把文字轉換成一組數值向量,讓系統可以比較「語意上像不像」。

例如使用者問:

「哪一個角色和珍惜水資源有關?」

即使文章中沒有完全相同的句子,向量檢索仍可能找到:

「烏龜慢慢觀察土地與水,
提醒我們珍惜自然。」

這和傳統只比對關鍵字的搜尋方式不同。

十、Metadata為什麼很重要?

每個知識Chunk除了文字,也應保存來源資訊:

{
  "title":"水井三寶作品介紹",
  "category":"地方文化",
  "character":"turtle",
  "source":"official",
  "language":"zh-Hant",
  "updated_at":"2026-08"
}

這讓未來RAG可以限制:

只找「官方作品資料」
只找「烏龜」相關內容
只找「教育教材」
只找最新版本內容

十一、一個完整RAG問答會怎麼走?

① 使用者 「請告訴我烏龜和水井村的關係」 ↓ ② Web / Django 接收問題 ↓ ③ Embedding 把問題轉成向量 ↓ ④ Vector Search 找最相關的文化資料 ↓ ⑤ Retrieve 取回Top-K相關Chunk ↓ ⑥ Prompt 問題 + 檢索資料 + 回答規則 ↓ ⑦ LLM 根據資料生成回答 ↓ ⑧ Response 回答 + 來源

十二、Django在第五層還可以扮演什麼角色?

Django在Layer 4主要接收事件;到了Layer 5,可以進一步成為文化知識與AI服務的入口:

/api/exhibition/events/     → Layer 4事件
/api/knowledge/search/      → 搜尋文化知識
/api/ai/ask/                → AI/RAG問答
/api/treasures/white-horse/ → 白馬知識
/api/treasures/turtle/      → 烏龜知識
/api/treasures/flower/      → 姻緣花知識

這樣就形成:

ESP32 / Browser ↓ Django ↙ ↘ Data Knowledge 事件庫 文化知識庫 \ / \ / AI/RAG

十三、Layer 4資料能不能直接拿來做RAG?

可以使用,但用途不同。

例如Layer 4告訴我們:

今天:
白馬 52次
烏龜 37次
姻緣花 46次

AI可以根據這些結構化資料回答:

「今天哪個故事最多人選?」
「三個故事的播放比例是多少?」

文化知識庫則回答:

「白馬象徵什麼?」
「誰參與水井三寶作品創作?」
「水井三寶如何連結三生一體?」
因此未來更完整的AI,不只是RAG查文章,而可能同時查詢結構化Data+非結構化Knowledge

十四、未來可以形成兩種AI工具

AI角色資料來源問題例子
展覽數據助理Django事件資料庫今天哪個故事最熱門?
文化導覽助理RAG文化知識庫請介紹姻緣花的故事

再進一步,也可以讓兩者合作:

「今天白馬故事最多人選,請結合白馬的文化意義,產生一段展覽觀察摘要。」

十五、AI回答文化故事時,最重要的是「有根據」

文化AI不能只追求回答流暢,還必須重視:

原則說明
Grounding回答必須根據知識庫資料
Source能指出資料來源
Version知道資料更新時間
Authority區分官方、訪談、學生整理等來源
Uncertainty資料不足時應說不知道,而不是自行編故事
文化數位化最怕「AI把地方故事講得很好聽,卻不是地方真正的故事」。因此RAG的價值不只是提升回答能力,更重要的是讓AI回到地方資料與文化脈絡。

十六、五層架構到這裡終於完整串起來

Layer 1
文化作品層
白馬、烏龜、姻緣花實體作品,是文化的起點。
Layer 2
智慧互動層
ESP32、ToF、按鈕、JQ6500、WS2812B讓作品能感測、發聲與發光。
Layer 3
Edge Web層
手機透過ESP32內嵌網站控制作品、查看設備狀態。
Layer 4
Digital Twin / Data層
匿名事件經HTTP+JSON+REST API進入Django,形成Database與Dashboard。
Layer 5
文化知識層
地方故事、作品、工藝、影音、教育與USR內容形成Knowledge Base,未來再透過AI/RAG提供智慧文化導覽。

十七、從五層架構看資料價值如何增加

實體文化 Layer 1 ↓ 互動訊號 Layer 2 ↓ Web控制 Layer 3 ↓ Data Layer 4 ↓ Knowledge Layer 5 ↓ AI / RAG ↓ 新的文化學習與導覽體驗

這條路徑也說明了為什麼水井三寶不是單純的ESP32作品:硬體只是入口,真正長期累積的資產是資料、文化內容與知識。

十八、課堂實作可以怎麼做?

可以把學生分成四個階段:

階段任務
1. Data讀取Django事件資料,統計三個故事播放次數
2. Knowledge把白馬、烏龜、姻緣花文章整理成知識文件
3. Retrieval把文件切Chunk、加入Metadata並進行檢索
4. AI/RAG讓LLM只根據檢索內容回答文化問題

十九、課堂思考題

問題一:「烏龜故事今天播放37次」屬於Data、Information還是Knowledge?為什麼?
問題二:為什麼Layer 5不能只把Layer 4的Database直接改名叫「知識庫」?
問題三:如果LLM已經很強,為什麼地方文化仍然需要RAG?
問題四:RAG回答水井三寶故事時,為什麼來源與Metadata特別重要?
問題五:未來要如何讓AI同時回答「今天誰最熱門」和「這個角色代表什麼」?

二十、結語:真正的第五層,是把地方記憶變成可以延續的知識

從ESP32送出一筆事件,到Django形成Dashboard,我們完成的是Data;把作品故事、創作者、工藝、教育與USR歷程整理起來,我們開始建立Knowledge;當這些知識能被檢索、被引用,再交給LLM產生符合不同觀眾需求的回答,就進一步形成AI/RAG服務。

因此,水井三寶五層架構的最後一層並不是為了「加上AI」而加AI。真正的目標是先把地方知識整理好,再讓AI成為連結人與知識的新介面。

Data告訴我們發生了什麼;Knowledge保存地方為什麼重要;AI/RAG則讓更多人能用自己的問題,走進這些知識。

Data Knowledge AI RAG Embedding Vector Search Django LLM 文化數位化 USR

[水井村USR] IP、MAC、DNS、Domain與Port

IP、MAC、DNS、Domain與Port

從「水井三寶智慧互動展覽系統」看懂網際網路位址與服務

MAC → IP → DNS → Domain → Port → HTTP/HTTPS

當手機可以打開 192.168.4.1,ESP32也顯示 STA=ONLINE,為什麼Django有時還是收不到資料?這個問題正好可以帶學生理解網際網路中幾個最重要、也最容易混淆的概念:MAC、IP、DNS、Domain與Port。它們不是同一件事,而是在不同階段回答不同問題:你是誰?你在哪裡?我要找誰?服務開在哪裡?

一、先看水井三寶的真實網路環境

目前水井三寶智慧互動展覽系統同時有兩條重要網路路徑:

【本地控制】 手機 ↓ Wi-Fi ESP32 SoftAP ↓ http://192.168.4.1 【雲端同步】 ESP32 STA ↓ Wi-Fi Router ↓ Gateway ↓ DNS ↓ Internet ↓ shuijingtreasures.pythonanywhere.com ↓ Django API

這兩條路徑雖然都使用Wi-Fi,但目的完全不同。第一條是LAN內的本地控制;第二條才真正需要Internet與DNS。

二、MAC Address:你是哪一張網路卡?

MAC Address可以理解成網路介面的「硬體識別碼」。ESP32的Wi-Fi介面有自己的MAC,手機也有自己的MAC。

MAC主要回答:
「區域網路裡,這個網路介面是誰?」

在同一個LAN內,資料傳遞最後仍需要靠資料鏈結層識別實際設備。IP可以改變,但MAC通常是網路介面的基礎識別資訊。

ESP32 MAC:
AA:BB:CC:DD:EE:FF

手機 MAC:
11:22:33:44:55:66

對學生來說,最簡單的理解方式是:

MAC像「網路卡的身分證號」;IP像「目前所在位置的地址」。

三、IP Address:資料要送到哪一台設備?

在水井三寶系統中,最常看到兩個IP:

ESP32 AP IP:
192.168.4.1

ESP32 STA IP:
192.168.1.119

這兩個IP屬於同一顆ESP32,但代表不同網路介面角色。

IP用途誰會使用
192.168.4.1ESP32 SoftAP本地控制頁連到Shuijing-Treasures AP的手機
192.168.1.119ESP32連到外部Wi-Fi後取得的STA IP路由器與區域網路

所以同一台ESP32可以同時:

AP角色: 我提供一個Wi-Fi給別人連 IP = 192.168.4.1 STA角色: 我自己去連另一台Wi-Fi IP = 192.168.1.119
這就是AP+STA共存的核心:一邊當本地Server,一邊當Internet Client。

四、Private IP與Public IP有什麼差別?

192.168.x.x這類位址是Private IP,只在區域網路內使用,不能直接在Internet上被全球路由。

例如:

ESP32:192.168.1.119
Router:192.168.1.1

ESP32如果要存取Internet,通常必須經過Router,再由Router以Public IP代表內部設備與外界通訊。

ESP32 192.168.1.119 ↓ Router / NAT 192.168.1.1 ↓ Public IP ↓ Internet

五、Default Gateway:離開這個LAN,要先找誰?

當ESP32要連PythonAnywhere時,目標已經不在自己的區域網路內,因此資料必須先交給Default Gateway。

水井三寶實測曾顯示:

STA IP = 192.168.1.119
Gateway = 192.168.1.1
Gateway回答:
「如果目的地不在我這個LAN,我下一站要把封包交給誰?」

六、Domain Name:人類比較容易記住的名稱

與其讓程式直接記一串Server IP,我們通常使用Domain Name:

shuijingtreasures.pythonanywhere.com

這比IP好記,也方便Server未來搬移。

因此Domain可以理解成:

給人看的服務名稱。

但電腦不能只靠名稱送封包,它仍需要把Domain轉成IP,這就是DNS的工作。

七、DNS:把Domain翻譯成IP

DNS可以想成「Internet電話簿」。

shuijingtreasures.pythonanywhere.com ↓ DNS ↓ Server IP Address

水井三寶V1.7最重要的一次除錯,就是發現:

WiFi status = 3
STA IP = 192.168.1.119
Gateway = 192.168.1.1
DNS = 192.168.1.1
RSSI = -20

Resolving:
shuijingtreasures.pythonanywhere.com

DNS result = -54
ERROR: DNS FAILED

這個案例非常適合用來提醒學生:

Wi-Fi連線成功,不代表Internet服務一定可用。
當DNS失敗,即使STA已取得IP,仍然找不到Domain對應的Server。

最後系統改用Public DNS:

DNS1 = 8.8.8.8
DNS2 = 1.1.1.1

DNS正常後,Cloud Test才真正成功。

八、Domain與DNS不要混在一起

概念例子作用
Domainshuijingtreasures.pythonanywhere.com人類容易記住的Server名稱
DNS8.8.8.8把Domain查成IP的服務

一句話記:

Domain是「名字」,DNS是「查名字的服務」。

九、Port:同一台Server上,要找哪一個服務?

IP只能找到「哪一台主機」,但同一台主機上可能同時運行很多不同服務。

例如:

Web Server
SSH
Database
Email
API
...

Port就是用來區分服務。

服務常見Port
HTTP80
HTTPS443
SSH22

水井三寶ESP32本地Edge Web使用:

http://192.168.4.1

沒有寫Port時,HTTP預設使用80。

而Django雲端API使用:

https://shuijingtreasures.pythonanywhere.com/...

HTTPS預設使用443。

IP回答「哪台電腦」;Port回答「那台電腦上的哪個服務」。

十、URL其實把很多資訊組在一起

例如水井三寶Edge Web:

http://192.168.4.1/play?track=2

可以拆成:

部分內容意義
Protocolhttp使用HTTP
Host192.168.4.1ESP32本地IP
Port80省略時使用HTTP預設Port
Path/play播放功能
Querytrack=2播放第2個故事

再看Django API:

https://shuijingtreasures.pythonanywhere.com/api/exhibition/events/

可拆成:

https
  ↓
Domain
shuijingtreasures.pythonanywhere.com
  ↓
Port 443
  ↓
Path
/api/exhibition/events/

十一、把MAC、IP、DNS、Domain與Port放在同一條資料流

手機按「002 烏龜故事」 ↓ Wi-Fi區域網路 ↓ MAC 找到LAN中的實際網路介面 ↓ IP 找到ESP32:192.168.4.1 ↓ Port 80 找到ESP32 Web Server ↓ HTTP GET /play?track=2 ↓ 故事播放 之後雲端同步: ESP32 STA 192.168.1.119 ↓ Gateway 192.168.1.1 ↓ DNS 8.8.8.8 ↓ Domain shuijingtreasures.pythonanywhere.com ↓ Server IP ↓ Port 443 ↓ HTTPS ↓ Django API

十二、五個名詞,用一句話一起記

名稱一句話記憶
MAC這張網路卡是誰?
IP設備目前在哪裡?
Domain人類想找的服務叫什麼名字?
DNS這個名字對應哪個IP?
Port主機上的哪個服務?

十三、最容易搞錯的幾件事

1
有IP,不代表DNS一定正常。
ESP32可以取得192.168.1.119,但仍可能解析不了Domain。
2
能開192.168.4.1,不代表Internet正常。
因為這只是ESP32 SoftAP內的本地LAN通訊。
3
Domain不是IP。
Domain必須先透過DNS解析成IP。
4
IP相同,Port不同,可以是完全不同的服務。

十四、遇到「雲端連不上」應該怎麼查?

不要一開始就修改Django。應該由下往上逐層檢查:

① Wi-Fi connected? ↓ ② 有沒有取得 IP? ↓ ③ Gateway 正常? ↓ ④ DNS 可以解析 Domain? ↓ ⑤ TCP / Port 443 可連? ↓ ⑥ HTTPS 成功? ↓ ⑦ Django API URL 正確? ↓ ⑧ Device ID / API Key 正確? ↓ ⑨ JSON格式正確? ↓ ⑩ Database / Dashboard 有資料?
這就是分層除錯的價值:不是看到「Cloud失敗」就全部一起查,而是先判斷問題究竟在哪一層。

十五、這和OSI七層模型有什麼關係?

本篇出現的概念可以粗略放進OSI / TCP/IP架構中:

概念大致所在層級
Wi-Fi、MACData Link
IP、Router、GatewayNetwork
TCP、PortTransport
DNS、HTTP、HTTPSApplication

這也是下一步理解OSI七層模型的重要基礎。

十六、課堂思考題

問題一:
如果手機可以打開192.168.4.1,但是Django沒有收到資料,MAC、IP、DNS、Domain、Port中,哪些已經可以確定正常?哪些還不能?
問題二:
ESP32的STA IP從192.168.1.119變成192.168.1.125,為什麼Django網址不需要跟著改?
問題三:
為什麼 https://... 沒有寫 :443,瀏覽器仍知道要連443?
問題四:
如果DNS失敗,直接把Server IP寫進程式可以暫時解決嗎?這樣做又會產生什麼維護問題?

十七、結語:網際網路不是一條線,而是一連串「找到正確對象」的過程

從水井三寶實作可以看見,網際網路通訊不是單純「ESP32有Wi-Fi,所以就能上雲端」。資料必須先找到正確的網路介面、正確的IP、正確的Gateway、正確的Server名稱,再經由DNS取得Server IP,最後還要找到正確的Port與應用服務。

因此,MAC、IP、DNS、Domain與Port並不是五個孤立的名詞,而是一條完整通訊鏈上的不同角色。當學生能用一筆「烏龜故事事件」解釋這五個概念,就代表他已經開始真正理解網際網路是如何運作的。

MAC IP Gateway DNS Domain Port HTTP HTTPS ESP32 Django

[水井村USR] 一個按鈕按下後,資料去了哪裡?

一個按鈕按下後,資料去了哪裡?

從「水井三寶智慧互動展覽系統」看懂網際網路資料流

Browser × Edge Web × Wi‑Fi × IP × HTTP × JSON × Django × Database

對初學者來說,「按下一個按鈕,故事就播放了」好像只是ESP32的一個控制功能;但從網際網路角度來看,這個動作其實會經過一連串不同層次的資料處理。這篇文章用「按下烏龜故事」作為例子,追蹤一筆事件如何從使用者手指,經過ESP32、Wi‑Fi、HTTP、JSON、Django與資料庫,最後出現在雲端儀表板上。

一、按下的是什麼?

水井三寶有兩種啟動方式:實體按鈕與手機Edge Web。實體按鈕由ESP32直接讀GPIO;手機則先連上ESP32的AP,再開啟 http://192.168.4.1

手機操作時真正發生的第一件事:瀏覽器送出一個HTTP Request,而不是直接播放MP3。

二、一個Web按鈕,其實是一個URL

例如「002 烏龜故事」可對應:

http://192.168.4.1/play?track=2

瀏覽器會送出類似:

GET /play?track=2 HTTP/1.1
Host: 192.168.4.1
概念水井三寶例子作用
IP Address192.168.4.1找到ESP32
HTTPGETBrowser與Web Server溝通
URL Path/play告訴Server要做什麼
Query Stringtrack=2指定播放第2個故事
重點:網頁不是網際網路。網頁只是應用層的一部分,背後還有Wi‑Fi、IP、TCP與HTTP。

三、資料先到ESP32 Edge Web

Browser ↓ HTTP GET ESP32 Edge Web ↓ 解析 track=2 ↓ 啟動 STORY_TURTLE ├─ JQ6500:播放002 ├─ WS2812B:烏龜藍色呼吸 └─ System State:PLAYING

四、到這裡為止,其實還沒有上Internet

手機連的是ESP32自己的AP,因此這是區域網路內的本地通訊。即使展場Internet完全中斷,192.168.4.1仍然可以工作。

能開啟192.168.4.1,不代表Internet一定正常;Internet斷線,也不代表Edge Web一定不能用。

五、故事播放後,ESP32建立事件資料

{
  "event_uuid":"SHUIJING-001-0000000062",
  "event_type":"STORY_START",
  "story":"002",
  "source":"web",
  "duration_ms":0,
  "completed":null,
  "network_status":"online",
  "metadata":{
    "firmware":"Layer4-V1.7",
    "jq_confirmed":true
  }
}

這是一個JSON物件,用來把系統狀態整理成適合網路傳輸的文字格式。

六、為什麼不直接送雲端?

Local First 先完成:JQ6500播放、燈光、按鈕與Web回應 ↓ 事件先寫入 LittleFS Queue ↓ Cloud Later 空閒後再送 Django

這樣即使Wi‑Fi暫時斷線,事件也不會立即遺失。

七、真正上Internet時,資料經過哪些地方?

ESP32 STA ↓ Wi‑Fi Router ↓ Default Gateway ↓ DNS ↓ Internet ↓ shuijingtreasures.pythonanywhere.com ↓ HTTPS / Django API

八、DNS的工作:把名稱變成IP

ESP32知道的是網域名稱,但Internet路由需要IP,因此必須先做DNS解析。

shuijingtreasures.pythonanywhere.com ↓ DNS IP Address
診斷觀念:Wi‑Fi → Gateway → DNS → TCP/TLS → HTTP → API,每一層都可能失敗。

九、ESP32如何把JSON送到Django?

POST /api/exhibition/events/ HTTP/1.1
Host: shuijingtreasures.pythonanywhere.com
Content-Type: application/json
X-Device-ID: SHUIJING-001
X-Device-Key: ********

{
  "event_type":"STORY_START",
  "story":"002",
  "source":"web"
}
項目作用
HTTP POST送資料給Server
Header放Content-Type、Device ID、API Key
JSON Body真正的事件內容

十、Django收到後做什麼?

Django URL Router ↓ api_event() ↓ 檢查 Device ID / API Key ↓ 解析 JSON ↓ 寫入 ExhibitionEvent ↓ Database ↓ Dashboard

十一、一筆「烏龜故事」事件的完整旅程

1. 使用者點選「002 烏龜故事」 2. Browser送出 HTTP GET 3. ESP32收到 /play?track=2 4. JQ6500播放002 5. WS2812B切換烏龜燈效 6. 建立 STORY_START JSON 7. 寫入 LittleFS Queue 8. ESP32 STA連Router 9. DNS解析網域 10. HTTPS POST送到Django 11. Django驗證裝置 12. JSON寫入Database 13. Dashboard統計「002 烏龜故事 +1」

十二、這和水井三寶五層架構有什麼關係?

層級角色
第一層|文化作品白馬、烏龜、姻緣花實體作品
第二層|智慧互動ESP32、按鈕、ToF、JQ6500、RGB
第三層|Edge Web192.168.4.1、HTTP、本地控制與診斷
第四層|Digital Twin / DataJSON、HTTPS、Django、Database、Dashboard
第五層|文化知識品牌故事、影音、教育、工藝、USR與未來AI/RAG

十三、這個案例可以學到哪些《網際網路》概念?

Browser / ServerLANWi‑Fi AP / STAIP AddressGatewayDNSHTTP GETHTTP POSTJSONREST APIHTTPSDatabaseEdge Computing

十四、課堂思考題

問題一:手機能開192.168.4.1,但Django收不到資料,可能是哪一段有問題?
問題二:ESP32顯示STA ONLINE,是否代表Internet一定正常?為什麼?
問題三:為什麼事件要先進LittleFS Queue,而不是每次按下按鈕就立即POST到Django?

十五、結語:真正的網際網路,不是一張網頁

水井三寶案例讓我們看見,網際網路真正有趣的地方,不在於「做出一個網頁」,而是理解一筆資料如何從實體世界產生,再經過本地網路、IP、DNS、HTTP、JSON、API與Database,最後轉化成可被理解的資訊。

當學生按下「002 烏龜故事」時,他不只是啟動一段音檔;他其實啟動了一條從文化作品 → Edge → Internet → Cloud → Data的完整資料鏈。這正是把《網際網路》從課本名詞變成真實系統最有價值的地方。