顯示具有 網際網路 標籤的文章。 顯示所有文章
顯示具有 網際網路 標籤的文章。 顯示所有文章

2026年9月3日 星期四

網際網路應用:我的搖桿,只開我的小車!

網際網路應用:我的搖桿,只開我的小車!

今天我們用搖桿控制 Q霸小車,也用它認識網路。網路的工作就是:送訊息、收訊息、確認是不是傳給對的人。

今天完成後,你可以做到:
① 用搖桿開車 ② 讓小車不會撞到東西 ③ 讓你的搖桿不會開到別人的車

一、網路像傳話遊戲

生活中的角色小車系統裡是誰?
說話的人搖桿
傳話的路無線電波
聽話的人Q霸小車
回覆「收到」嗶一聲、震一下、顯示勾勾

二、開車四步驟

  1. 看同色號:搖桿和小車要有一樣的顏色與號碼。
  2. 等一下:看到勾勾、聽到嗶聲、感覺震動,表示配對成功。
  3. 推搖桿:往前推前進;往左、右推就轉彎。
  4. 遇到危險:按紅色 F,立刻停!

三、四個按鍵

C慢慢開
D正常開
E快快開
F立刻停

四、小車的三個安全規則

  1. 太久沒聽到搖桿:小車會自己停下來。
  2. 前面太近:小車會先慢慢走;再靠近就停下來。
  3. 按 F:小車一定先停,按 C、D 或 E 才能再開。

五、我們也會看懂一點程式

下面這段意思是:「如果太久沒收到訊息,小車停止。」

if control.millis() - lastControlTime > 500:
    cuteBot.motors(0, 0)

下面這段意思是:「第 2 組只聽第 2 組的搖桿。」

pairId = 2
radio.set_group(100 + pairId)

六、闖關任務

  1. 和同學同時開兩組小車,看看會不會互相影響。
  2. 讓小車靠近障礙物,觀察它什麼時候會慢下來、什麼時候會停。
  3. 行駛中按 F,確認小車能不能立刻停止。
  4. 用自己的話說出:為什麼搖桿和小車要同色同號?
記住:網路不是只有手機和電腦。搖桿、小車、感測器也可以互相傳訊息,這就是物聯網!

延伸閱讀:V1V2V3V4V5

網際網路應用:一支搖桿如何可靠地控制一台 Q霸小車?

網際網路應用:一支搖桿如何可靠地控制一台 Q霸小車?

「遙控車」看似只是硬體活動,其實是一個縮小版的網際網路系統:裝置收集輸入、封裝成訊息、透過無線網路傳送、接收端解讀資料並做出行動。本教材從 Joystick:bit × Q霸小車 V1~V5,認識網際網路應用最重要的可靠性、安全性與多人協作問題。

一、學習目標

  • 說明感測端、傳輸端、服務端與致動端的角色。
  • 理解廣播群組、鍵值訊息、回覆確認與逾時處理。
  • 以「安全優先」思維分析物聯網應用。
  • 設計多人共用場域的一對一裝置配對方案。

二、一台遙控車就是一個網路應用

系統角色本案例網路概念
輸入端Joystick:bit x、y 軸與四鍵資料產生者
傳輸端micro:bit Radio無線通道與群組
處理端小車端 Python 程式訊息解析、狀態機、規則
輸出端馬達、燈號、蜂鳴器服務回應與人機介面

三、V1~V5 對應的網路議題

  1. V1|訊息傳遞:搖桿將 x、y 值以鍵值訊息送出,小車依名稱接收。
  2. V2|可靠性:死區避免雜訊;超過 0.5 秒未收到訊息便停車,這就是逾時偵測。
  3. V3|邊緣運算:小車本地讀取超音波距離,快速做出降速或停止決策。
  4. V4|事件驅動:C、D、E、F 鍵不是持續輪詢,而是在按下事件發生時更新系統狀態。
  5. V5|識別與回覆:pairId 選擇專屬群組,並用 pair / ack 做握手確認。

四、資料封包設計:不要只傳數字

有意義的訊息必須包含「名稱」與「值」。例如 ("x", 35) 表示向右 35,("stop", 1) 表示緊急停止。這種設計比只傳一串數字更容易除錯與擴充。

# 搖桿端
radio.send_value("x", x)
radio.send_value("y", y)
radio.send_value("stop", 1)

# 小車端
if name == "x":
    xValue = value
elif name == "stop":
    emergencyStop = value == 1

討論:如果未來要加入「車燈」、「任務開始」與「低電量」,應如何命名訊息?請提出一份小組通訊協定表。

五、可靠性與安全性:先判斷不能做什麼

真正的網路應用不能假設每個封包都會到達。小車端的決策順序應為:

未配對/緊急停止 → 斷線停車 → 避障 → 一般控制
if emergencyStop:
    cuteBot.motors(0, 0)
elif control.millis() - lastControlTime > 500:
    cuteBot.motors(0, 0)
elif yValue > 0 and distance <= 15:
    cuteBot.motors(0, 0)
else:
    cuteBot.motors(leftSpeed, rightSpeed)

六、多人同時使用:廣播群組就像班級頻道

若所有設備都使用群組 51,一位學生的搖桿可能控制全班的小車。V5 將每一組設備設為專屬頻道:

pairId = 3
radio.set_group(100 + pairId)  # 第 3 組使用群組 103

radio.send_value("pair", pairId)
# 小車確認後:radio.send_value("ack", pairId)

這相當於網路上的「位址+連線確認」。雖然不是完整的 TCP/IP,卻已經具備辨識對象、建立關係與回覆確認的核心精神。

七、3 小時課堂任務

  1. 30 分鐘:畫出 V5 的資料流,標記每一種訊息與方向。
  2. 50 分鐘:完成兩組小車同時運作,驗證不互控。
  3. 40 分鐘:刻意關閉搖桿或遮住超音波,記錄安全機制的反應。
  4. 40 分鐘:設計一項新服務,例如車位預約、任務通知或低電量警示。
  5. 20 分鐘:用「問題、資料、規則、結果」分享設計。

八、延伸閱讀

V1 基礎遙控V2 可靠控制V3 安全避障V4 事件互動V5 配對與回饋

2026年8月22日 星期六

MQTT不只是能傳: QoS、Retain、LWT與斷線重連

封包旅行記 EP04|可靠的 IoT 訊息設計

MQTT不只是能傳:
QoS、Retain、LWT與斷線重連

感測值送得出去,只代表展示成功;真正能進入水井村智慧養殖、樹藝故事機或場域儀表板的 MQTT,還必須回答:訊息可否重複?新訂閱者需不需要立刻看到狀態?裝置突然離線時誰來通知?斷線後如何安全恢復?

一、MQTT為什麼適合IoT?

ESP32 PublisherMQTT BrokerDjango/Node-RED/儀表板 Subscriber

MQTT採用發布/訂閱模式。ESP32不必知道Django在哪裡,只要把訊息發布到Topic;Broker負責把訊息分送給訂閱者。這種解耦讓裝置、雲端與儀表板可以分別擴充。

Topicsite/pond01/water/temp
訊息分類與路由名稱
Payload{"value":28.4}
真正傳送的資料內容
BrokerMosquitto等訊息中介站,接收並轉送訊息
ClientESP32、Django服務、手機或儀表板

重點:Broker收到訊息,不等於資料一定寫入資料庫;Publisher成功送出,也不等於每個Subscriber都已完成業務處理。

二、QoS:不是越高越好,而是語意要正確

QoS 0|最多一次

送出後不等待MQTT層確認;可能遺失,但額外負擔最低。

適合高頻、下一筆可取代上一筆的即時感測值。

QoS 1|至少一次

未收到確認會重送,因此比較不易遺失,卻可能收到重複訊息。

適合警報、控制事件、播放紀錄等重要事件。

QoS 2|恰好一次

用更完整的交換流程降低重複交付,成本與延遲最高;裝置、Broker與函式庫均須支援。

適合極少數不能遺失也不能重複的交換。

資料情境建議起點為什麼
每5秒水溫QoS 0少一筆通常可由下一筆補足;仍可在裝置端另做離線保存
溶氧過低警報QoS 1不希望輕易遺失,但接收端必須能處理重複
故事播放開始事件QoS 1+事件UUID重送時以UUID去重,避免播放次數被重複計算
燈光即時亮度滑桿QoS 0最新狀態通常比每次變化都抵達更重要
QoS的保證範圍有限:它處理的是MQTT傳遞,不會替你保證Django已寫入資料庫。重要事件仍應加入event_uuid、時間戳與應用層確認。

三、Retain:讓新訂閱者立刻取得「最後狀態」

Publisher把訊息以Retain方式發布後,Broker會為該Topic保留最後一筆Retained Message。新的Subscriber一訂閱,就會立即收到它,不必等ESP32下一次發布。

適合Retain

裝置目前在線狀態、最後水溫、目前模式、韌體版本、開關的目標狀態。

不適合Retain

「餵魚一次」、「播放故事一次」、「重新啟動」等一次性命令。新裝置訂閱時若重播舊命令,可能造成危險。

TopicRetain理由
site/pond01/status/online儀表板訂閱後立即知道裝置狀態
site/pond01/telemetry/water_temp視需求可顯示最後讀值,但介面必須同時呈現時間,避免把舊值誤認成即時值
site/pond01/cmd/feed_once避免斷線重連後再次執行舊命令

清除Retained Message:依MQTT慣例,對同一Topic發布空Payload並設定Retain,可要求Broker刪除該Retained Message;實際操作仍需依使用的Client函式庫確認。

四、LWT:裝置來不及說再見時,由Broker代為通知

LWT(Last Will and Testament,遺囑訊息)是在Client連線時,預先交給Broker的一則訊息。如果ESP32因斷電、訊號中斷或程式崩潰而非正常離線,Broker會代替它發布LWT。

連線時登記:若我異常消失請發布 offline儀表板收到並告警
  1. ESP32連線Broker時設定LWT:Topic為site/pond01/status/online,Payload為offline,並設為Retain。
  2. 連線成功後,ESP32主動在同一Topic發布Retained online
  3. 若正常關機,可先發布offline再主動Disconnect;若異常消失,由Broker發布LWT。

LWT不是即時斷線感測器:Broker通常要等到Keep Alive逾時或網路連線被判定中止後才發布,因此告警時間會受Keep Alive與網路狀況影響。

五、斷線重連:不要用while把整台ESP32卡死

初學範例常用無限while (!client.connected())反覆連線。場域系統若Broker故障,主迴圈就可能被卡住,感測、按鍵、JQ6500播放與離線保存全部停擺。

正確思路

採非阻塞重連、限制頻率、逐步增加等待時間;即使MQTT離線,裝置本地功能仍要運作。

恢復後要做

重新訂閱Topic、發布online、補送離線佇列、同步目標狀態,並防止重複事件。

重連次數等待例目的
第1次1秒+隨機抖動快速恢復短暫斷線
連續失敗2、4、8、16…秒指數退避,減少對Broker與網路的壓力
到達上限例如60秒避免等待時間無限增長
為何要加Jitter(隨機抖動)?停電復電後,數十台ESP32若同時重連,可能形成「驚群效應」;稍微錯開時間可降低Broker瞬間負荷。

六、ESP32範例:LWT、Retain與非阻塞重連

#include <WiFi.h>
#include <PubSubClient.h>

WiFiClient net;
PubSubClient mqtt(net);

const char* broker = "192.168.1.10";
const char* statusTopic = "site/pond01/status/online";
const char* commandTopic = "site/pond01/cmd/#";

unsigned long nextRetryAt = 0;
unsigned long retryDelayMs = 1000;
const unsigned long maxRetryMs = 60000;

void onMessage(char* topic, byte* payload, unsigned int length) {
  // 驗證Topic、Payload、長度與權限後再執行控制
}

bool connectMqtt() {
  String clientId = "pond01-" + String((uint32_t)ESP.getEfuseMac(), HEX);

  // clientId, user, password, willTopic, willQoS, willRetain, willMessage
  bool ok = mqtt.connect(clientId.c_str(), "device_user", "device_password",
                         statusTopic, 1, true, "offline");
  if (ok) {
    mqtt.publish(statusTopic, "online", true); // Retained online
    mqtt.subscribe(commandTopic, 1);           // 重連後重新訂閱
    retryDelayMs = 1000;
  }
  return ok;
}

void maintainMqtt() {
  if (WiFi.status() != WL_CONNECTED) return;

  if (mqtt.connected()) {
    mqtt.loop();
    return;
  }

  unsigned long now = millis();
  if ((long)(now - nextRetryAt) < 0) return;

  if (!connectMqtt()) {
    unsigned long jitter = random(0, 500);
    nextRetryAt = now + retryDelayMs + jitter;
    retryDelayMs = min(retryDelayMs * 2, maxRetryMs);
  }
}

void setup() {
  Serial.begin(115200);
  mqtt.setServer(broker, 1883);
  mqtt.setCallback(onMessage);
  mqtt.setKeepAlive(30);
}

void loop() {
  maintainMqtt();
  // 感測、按鍵、播放與離線佇列仍持續執行
}

此程式著重架構,帳密與Broker位址僅為示意。不同版本的MQTT函式庫支援的QoS與API可能不同,正式使用前應查閱所採用函式庫文件;外網連線應使用TLS、憑證驗證與安全保存的憑證。

七、四個功能不能互相取代

機制解決的問題不能保證
QoSClient與Broker間的MQTT傳遞品質Django一定成功處理或寫入資料庫
Retain新訂閱者立即取得某Topic最後保留值訊息是最新現場狀態;必須搭配時間戳
LWTClient異常離線時由Broker發布預設訊息零延遲偵測,也不代表設備硬體一定故障
重連網路恢復後重新建立Session與訂閱斷線期間資料自動存在;仍需離線佇列

八、常見錯誤與診斷線索

現象可能原因先檢查
連上Broker卻收不到命令重連後忘記重新Subscribe、ACL拒絕、Topic拼錯CONNACK、訂閱結果、完整Topic與權限
儀表板一直顯示online未設LWT、LWT未Retain、狀態Topic不同斷電測試與Broker日誌
一重連就再次啟動設備一次性Command被設為Retain清除舊Retained Message並重整Topic設計
資料庫出現重複紀錄QoS 1重送或應用程式重試event_uuid、唯一約束、冪等寫入
Broker恢復後大量設備仍離線阻塞重連、重試太頻繁、驚群效應指數退避、Jitter、資源使用量
顯示最後水溫但其實是昨天Retained值缺少時間Payload加入ts,UI顯示資料年齡

九、場域Topic設計範例

site/{site_id}/{device_id}/telemetry/water_temp
site/{site_id}/{device_id}/telemetry/dissolved_oxygen
site/{site_id}/{device_id}/event/story_start
site/{site_id}/{device_id}/status/online
site/{site_id}/{device_id}/status/firmware
site/{site_id}/{device_id}/cmd/set_mode
site/{site_id}/{device_id}/ack/{command_id}
  • Telemetry:週期性量測,可依資料價值選QoS 0或1。
  • Event:一次性事實,使用QoS 1、事件UUID及伺服器去重。
  • Status:目前狀態,適合Retain並附時間戳。
  • Command:控制要求,通常不Retain;加入command_id、期限與授權。
  • Ack:設備實際接受或完成命令的應用層回覆,不能只看MQTT QoS。

十、學生實作:從「能傳」走向「可靠」

No-AI|觀察封包行為

用兩個MQTT Client測試QoS 0與1;比較Retain開關前後,新Subscriber第一次收到的內容,並記錄時間。

AI Pair|設計決策辯論

請AI分別扮演裝置工程師、Broker管理者與資料工程師,評論水溫、警報、控制命令應採用的QoS與Retain;學生查證後完成決策表。

Challenge AI|斷線演練

拔除網路、重啟Broker、讓ESP32斷電;驗證LWT、非阻塞重連、重新訂閱、離線補送、UUID去重與儀表板狀態是否正確。

十一、驗收清單

檢核項目通過證據
QoS符合資料語意說得出可遺失、可重複與不可重複的差異
Retain沒有誤用於一次性命令新Client訂閱不會觸發舊動作
LWT可辨識異常離線直接斷電後,Broker會發布Retained offline
斷線不阻塞本地功能Broker關閉時,感測與按鍵仍正常
恢復後不漏不重完成重新訂閱、佇列補送與UUID去重
安全配置完成獨立帳號、最小Topic ACL、TLS與憑證管理
封包旅行記 EP04|可靠的MQTT,不是每筆都用最高QoS,而是讓每一種訊息都有正確的生命週期、失敗策略與驗證證據。

Wi-Fi連上了, 為何資料還是送不到?

封包旅行記 EP03|分層找故障

Wi-Fi連上了,
為何資料還是送不到?

ESP32 顯示 WL_CONNECTED,只代表它已經加入無線基地台,不代表資料已抵達 Django。真正的連線,要連續通過「Wi-Fi → IP → Gateway → DNS → TCP/TLS → HTTP → 應用程式」七道關卡。

一、先破解最常見的誤會

Wi-Fi connected ≠ Internet available ≠ Server reachable ≠ Data accepted
「連上 Wi-Fi」是第一關成功;只要後面任何一層失敗,Django 儀表板仍然看不到資料。
1Wi-Fi連上 AP
2IP取得位址
3Gateway走出區網
4DNS找到伺服器
5TCP/TLS建立通道
6HTTP/App接受資料

診斷原則:不要一看到「資料沒上傳」就立刻改程式。由下往上逐層驗證,先找到第一個失敗點。

二、Wi-Fi連線只證明了什麼?

已經證明

SSID、密碼與無線訊號大致可用;ESP32 已與基地台完成關聯。

還沒證明

是否取得正確 IP、Subnet、Gateway、DNS,網路是否能通往外部。

更沒證明

Django 網址、Port、憑證、API 路徑、權杖、JSON 格式與資料庫都正確。

先把 ESP32 的網路身分印出來

#include <WiFi.h>

void printNetworkInfo() {
  Serial.println("=== NETWORK INFO ===");
  Serial.print("SSID: ");    Serial.println(WiFi.SSID());
  Serial.print("IP: ");      Serial.println(WiFi.localIP());
  Serial.print("Subnet: ");  Serial.println(WiFi.subnetMask());
  Serial.print("Gateway: "); Serial.println(WiFi.gatewayIP());
  Serial.print("DNS: ");     Serial.println(WiFi.dnsIP());
  Serial.print("RSSI: ");    Serial.println(WiFi.RSSI());
}

若 IP 是 0.0.0.0,表示尚未完成網路配置;若是 169.254.x.x,通常代表 DHCP 沒有成功提供位址。RSSI 約 -30 dBm 很強、-67 dBm 尚可,低於 -75 dBm 時傳輸容易不穩。

三、從區域網路到 Django:封包實際走哪裡?

ESP32Wi-Fi AP/RouterNAT/InternetWeb ServerDjango URLView/Database
關卡封包需要知道常見失敗
Wi-FiSSID、密碼、訊號密碼錯、2.4/5 GHz 不相容、訊號弱
IP/Subnet本機 IP 與同網段判斷DHCP 失敗、固定 IP 衝突、Subnet 設錯
Gateway/NAT跨網段的下一跳Gateway 錯、訪客網路隔離、路由器無外網
DNS網域名稱對應的 IPDNS 未配置、解析失敗、網址拼錯
TCP/TLS目標 Port 與安全連線Port 關閉、防火牆阻擋、時間或憑證錯誤
HTTPMethod、URL、Header、BodyPOST/GET 用錯、路徑錯、JSON 或 Content-Type 錯
Django路由、驗證、資料模型404、403、CSRF、500、欄位驗證失敗

四、七層診斷法:先找第一個失敗點

① 無線層

狀態WiFi.status() == WL_CONNECTED
訊號觀察 RSSI 是否持續過低或大幅波動。

② IP 配置層

確認 IP、Subnet、Gateway、DNS 不是空值;檢查固定 IP 是否與其他設備重複。

③ 本地網路層

用同一 Wi-Fi 的電腦或手機測試 Router 與區網伺服器。若訪客 Wi-Fi 開啟 Client Isolation,設備彼此可能不能連線。

④ DNS 層

先用 IP 測,再用網域測。IP 可通、網域不通,問題多半在 DNS;不要把 https:// 一起當作主機名稱解析。

⑤ TCP/TLS 層

確認 Port:HTTP 常用 80,HTTPS 常用 443。HTTPS 還要檢查 ESP32 時間、CA 憑證與 TLS 相容性。

⑥ HTTP 層

序列埠必須印出完整 URL、HTTP 回應碼與回應內容。只有「send failed」不足以定位問題。

⑦ Django 應用層

同步查看伺服器 log。請求有進來但回 4xx/5xx,代表網路大致已通,問題已經移到 API 或程式端。

⑧ 儀表板與資料庫

API 回 200/201 仍未顯示時,檢查資料是否真正寫入、查詢條件、時區、快取與前端刷新。

五、HTTP回應碼就是伺服器留下的線索

回應代表意義優先檢查
200 OK201 Created請求成功或資料已建立若畫面仍沒資料,檢查資料庫與前端查詢
301/302網址被重新導向HTTP→HTTPS、尾端斜線、網域設定
400 Bad Request請求內容無法解析JSON、必填欄位、資料型別
401/403身分驗證或權限失敗API Key、Token、CSRF、權限
404 Not Found找不到 API 路徑Django urls.py、版本路徑、尾斜線
405 Method Not AllowedHTTP 方法不被接受伺服器要 POST,裝置卻送 GET
415 Unsupported Media Type資料格式宣告不符Content-Type: application/json
500502503應用程式或伺服器端異常Django log、反向代理、服務狀態
-1 或連線逾時常是 HTTP 之前就失敗DNS、TCP、TLS、Port、防火牆

六、ESP32上傳時,至少留下這些診斷資訊

#include <HTTPClient.h>

void postEvent(const String& json) {
  const char* url = "https://example.org/api/events/";
  HTTPClient http;

  Serial.print("POST URL: "); Serial.println(url);
  Serial.print("WiFi RSSI: "); Serial.println(WiFi.RSSI());

  if (!http.begin(url)) {
    Serial.println("HTTP begin failed");
    return;
  }

  http.addHeader("Content-Type", "application/json");
  int code = http.POST(json);
  Serial.print("HTTP code: "); Serial.println(code);

  if (code > 0) {
    Serial.print("Response: "); Serial.println(http.getString());
  } else {
    Serial.print("Transport error: ");
    Serial.println(http.errorToString(code));
  }
  http.end();
}

上例用 example.org 作教材占位網址。實際部署 HTTPS 時,應依函式庫版本正確設定 CA 憑證與系統時間;不要為了省事而長期停用憑證驗證。

離線佇列很重要:IoT 裝置不應假設網路永遠在線。每筆事件加入唯一 event_uuid,失敗時先保存,恢復連線後再重送;伺服器依 UUID 去除重複資料。

七、最有效率的交叉測試

測試結果可推論的範圍
手機使用同一 Wi-Fi 也打不開 API先查 Router、DNS、伺服器或 API,不急著改 ESP32
手機可用,ESP32 不行查 ESP32 的 DNS、TLS、時間、憑證、記憶體與程式
用 IP 可連,用網域不行DNS 解析問題
HTTP 可用,HTTPS 不行TLS、CA 憑證、系統時間或 SNI
API 收得到,但回 400/403/404網路已走到應用層,查 Header、Token、路徑與資料格式
API 回 201,但儀表板沒顯示查資料庫、查詢條件、時區與前端刷新

八、場域版故障排除順序

  1. 記錄現象:時間、裝置 ID、IP、RSSI、目標網址、HTTP code。
  2. 確認影響範圍:一台裝置、同一基地台,還是所有場域都失敗?
  3. 由下往上測:Wi-Fi → DHCP → Gateway → DNS → TCP/TLS → HTTP → Django。
  4. 做單一變因測試:不要同時換 Wi-Fi、改網址又重寫程式。
  5. 恢復後驗證:即時資料與離線佇列是否都完成補送,是否產生重複事件。

好系統不只是「正常時會動」:還要在斷網時保留資料、恢復時自動重送、出錯時留下足以診斷的證據。

九、學生實作:同一問題,三種學習層次

No-AI|人工診斷

抄錄 ESP32 的 IP、Subnet、Gateway、DNS、RSSI與 HTTP code;依七層表判斷第一個失敗點,畫出封包停在哪裡。

AI Pair|協作除錯

把「去識別化後」的序列埠紀錄與 Django log 交給 AI,要求它提出三個假設、每個假設的驗證方法,以及不可直接下結論的原因。

Challenge AI|場域韌性

設計斷網佇列、指數退避重試、event_uuid 去重與狀態儀表板;實測關閉 Wi-Fi 5 分鐘後能否完整補送。

十、學習檢核

我能做到完成證據
說明 Wi-Fi connected 與資料送達的差異能指出封包必須通過的七個關卡
讀懂 ESP32 的網路配置能解釋 IP、Subnet、Gateway、DNS與RSSI
利用 HTTP code 定位問題能區分傳輸錯誤、用戶端錯誤與伺服器錯誤
完成可重現的故障報告包含時間、環境、步驟、log、假設、測試與結果
設計斷線不漏資料的 IoT 裝置具備佇列、重試、去重與恢復驗證
封包旅行記 EP03|「連上」只是狀態;能逐層驗證、找到第一個失敗點,才是真正的網路能力。

192.168.x.x是什麼? DHCP、Subnet、Gateway與NAT

封包旅行記 EP02|區域網路配置

192.168.x.x是什麼?
DHCP、Subnet、Gateway與NAT

ESP32顯示「Wi-Fi connected,IP=192.168.1.119」之後,這串數字代表什麼?它如何知道誰在同一個網路、誰必須交給Gateway,又如何透過NAT走向Internet?

Private IPDHCPSubnetGatewayARPNAT/PAT

192.168.1.119不是Internet上的地址嗎?

當ESP32、手機或電腦連上家中、學校或展場Wi-Fi後,常會得到192.168.x.x。它是區域網路中的「私有IPv4位址」,可以在內部重複使用,但不會直接在全球Internet上被路由。

最重要的觀念:192.168.1.119只說明ESP32在目前LAN中的位置;要前往Django網站,仍需知道Subnet、Gateway、DNS,並由Router執行NAT。

學習目標

看懂位址

區分私有IP、公網IP、Network Address、Host Address與Broadcast。

判斷路徑

使用Subnet Mask判斷目的地在同一LAN,還是必須交給Gateway。

解釋出網

說明DHCP給了什麼,以及NAT/PAT如何讓多台裝置共用一個公網IP。

先看一個智慧場域網路

ESP32-A192.168.1.119
ESP32-B192.168.1.120
手機192.168.1.50
RouterLAN:192.168.1.1
InternetDjango Cloud

在這個例子中,三台終端裝置都位於192.168.1.0/24。它們彼此通訊時留在LAN內;要連Django、DNS或其他外部服務時,則把封包交給192.168.1.1

一、192.168.x.x是私有IPv4位址

IPv4位址由32個bit組成,通常用四個0~255的十進位數字表示。IANA保留三段IPv4範圍供私有網路使用:

私有範圍CIDR常見場景
10.0.0.0 ~ 10.255.255.25510.0.0.0/8大型組織、雲端VPC、校園網路
172.16.0.0 ~ 172.31.255.255172.16.0.0/12企業、容器與內部服務
192.168.0.0 ~ 192.168.255.255192.168.0.0/16家庭、教室、小型場域與IoT

私有IP

只在內部網路使用,可由不同家庭或場域重複使用。例如很多人的Router都可能是192.168.1.1

公網IP

在Internet上具有全球可路由性,通常由ISP提供給Router或雲端伺服器。

私有IP不等於安全。即使裝置不能直接從Internet被路由,區域網路內仍可能有未授權存取;Router設定、Wi-Fi密碼、服務驗證、防火牆與更新仍然必要。

二、DHCP:自動發放網路設定

ESP32加入Wi-Fi後,通常不必手動輸入IP。DHCP Server(多半位於Router)透過DORA流程協助裝置取得租約。

Discover有人可以給我IP嗎?
Offer可以使用這組設定
Request我要接受這個租約
Acknowledge租約成立

DHCP不只給IP

DHCP提供範例功能
IP Address192.168.1.119ESP32在目前LAN中的位址
Subnet Mask255.255.255.0分辨Network與Host部分
Default Gateway192.168.1.1通往其他網路的預設出口
DNS Server192.168.1.1或外部DNS把Domain解析成IP
Lease Time例如24小時這組設定可使用多久
ESP32輸出網路設定
#include <WiFi.h>

void printNetworkInfo() {
  Serial.println("===== NETWORK INFO =====");
  Serial.print("IP      : "); Serial.println(WiFi.localIP());
  Serial.print("MASK    : "); Serial.println(WiFi.subnetMask());
  Serial.print("GATEWAY : "); Serial.println(WiFi.gatewayIP());
  Serial.print("DNS     : "); Serial.println(WiFi.dnsIP());
  Serial.print("RSSI    : "); Serial.println(WiFi.RSSI());
}
教學建議:每一篇ESP32連網文章都應固定輸出IP、Mask、Gateway、DNS與RSSI。這五項資訊是分層診斷的起點。

三、Subnet:誰和我在同一個網路?

IPv4位址同時包含「Network部分」與「Host部分」。Subnet Mask用1標示Network bit,用0標示Host bit。最常見的:

255.255.255.0 = /24 = 前24個bit是Network,後8個bit是Host
Network:192.168.1
Host:119
項目192.168.1.119/24的結果用途
Network Address192.168.1.0代表整個Subnet,不分配給一般Host
可用Host範圍192.168.1.1 ~ 192.168.1.254Router、ESP32、手機與電腦可使用
Broadcast Address192.168.1.255傳送給該Subnet內的所有Host
總位址數2562^(32-24)
一般可用Host數254扣除Network與Broadcast

用AND運算找Network Address

設備會把自己的IP或目的IP與Subnet Mask做bitwise AND:

IP:    192.168.1.119
Mask:  255.255.255.0
AND:   192.168.1.0   ← Network Address

若ESP32與目的設備計算出的Network Address相同,就在同一個Subnet;不同則交給Gateway。

ESP32目的位址/24判斷下一步
192.168.1.119192.168.1.50同為192.168.1.0留在LAN,先用ARP找目的MAC
192.168.1.119192.168.2.50Network不同交給Default Gateway
192.168.1.119Django公網IPNetwork不同交給Default Gateway

四、Gateway:通往其他網路的出口

取得目的IP套用Subnet Mask比較Network同Subnet:直接傳不同Subnet:交給Gateway

Default Gateway通常是Router的LAN位址,例如192.168.1.1。ESP32要連Django時,IP Packet的目的IP仍是Django Server;但目前這一跳的Wi-Fi/Ethernet Frame會先送到Gateway的MAC。

常見誤解:ESP32不是把「目的IP改成Gateway」。IP目的地仍是遠端伺服器;Gateway只是下一跳的設備。

ARP在這裡做什麼?

ESP32知道Gateway的IP,卻還不知道它在目前LAN中的MAC,因此發出ARP Request詢問:「誰是192.168.1.1?」Router回覆MAC後,ESP32才能建立這一跳的Frame。

五、NAT/PAT:讓私有IP走向Internet

私有IP不能直接在Internet上被路由。Router執行Source NAT,並常搭配Port Address Translation,讓多台內部裝置共用一個公網IP。

192.168.1.119:49152→ NAT/PAT →203.0.113.20:62001
192.168.1.120:49153→ NAT/PAT →203.0.113.20:62002
192.168.1.50:51000→ NAT/PAT →203.0.113.20:62003

上例的203.0.113.20是文件示意用公網IP。Router建立一張暫時對照表,讓Django回應到達後,可以交回正確的ESP32或手機。

位置來源目的
ESP32送往Router前192.168.1.119:49152Django-IP:443
Router送往Internet後Public-IP:62001Django-IP:443
Django回應Django-IP:443Public-IP:62001
Router交回LANDjango-IP:443192.168.1.119:49152

NAT不等於Port Forwarding

一般出站NAT讓內部設備主動連出去;Port Forwarding則把外部進站連線轉交給指定內部設備,風險與用途不同。

NAT不等於防火牆

NAT改寫位址;防火牆依規則允許或阻擋流量。兩者常在同一台Router上,但功能不同。

六、DHCP與固定IP如何選?

方式優點風險/注意適合情境
一般DHCP設定簡單、自動避免多數衝突租約更新後IP可能改變手機、筆電、一般ESP32 Client
DHCP Reservation由Router依MAC固定發同一IP需管理MAC與Router設定場域Gateway、Dashboard、Home Assistant
裝置手動Static IP不依賴DHCP租約容易設定錯Mask/Gateway/DNS或造成IP衝突封閉、受管理且有完整清冊的網路
場域建議:ESP32主動向Django送資料時,多半不需要固定IP;若其他設備要主動連回ESP32或本地Server,優先考慮DHCP Reservation,較方便集中管理。

七、常見錯誤與分層診斷

Wi-FiDHCPIPMaskGatewayDNSNAT/Internet
現象可能原因取得證據
IP顯示0.0.0.0尚未連線、DHCP失敗或狀態讀取太早WiFi.status、連線時間、DHCP Server
IP是169.254.x.x未取得正常DHCP租約,設備使用Link-localRouter DHCP服務、租約數量與網路阻擋
同LAN裝置無法互通Mask錯誤、AP Isolation、防火牆或IP衝突IP/Mask比較、ARP、Router無線隔離設定
能連Gateway,不能用DomainDNS設定或解析失敗DNS IP、Domain解析結果
能解析Domain但無法連DjangoInternet、Routing、Port、TLS或Server問題目的IP、TCP連線、TLS錯誤與HTTP狀態
偶爾換一個IP後系統失效程式依賴動態IP或租約改變DHCP Lease、Router紀錄、是否應用Reservation
兩台設備時好時壞IP衝突裝置清冊、ARP表、Router租約與MAC
不要只寫「網路不通」。診斷紀錄至少要包含:本機IP、Mask、Gateway、DNS、RSSI、目的Domain、解析IP、失敗時間與錯誤碼。

八、場域網路規劃範例

水井三寶展覽、智慧養殖或慢食平台若逐步增加設備,建議先建立網路與裝置清冊。

類型建議位址方式範例管理重點
Router/Gateway固定192.168.10.1管理密碼、韌體、防火牆、備份
本地Server/Home AssistantDHCP Reservation192.168.10.10服務Port、備份、健康檢查
ESP32感測節點DHCP192.168.10.101~150Device ID、MAC、場域位置、韌體版本
管理者手機/筆電DHCP192.168.10.51~100帳號、權限與訪客網路分離
訪客獨立Guest Network192.168.20.0/24禁止直接存取IoT與管理設備
網路規劃不是只分IP:還要處理SSID、頻段、訊號覆蓋、訪客隔離、裝置身分、更新、金鑰、資料回傳、離線機制與維運責任。

三項學生任務

No-AI|找出我的網路

記錄電腦或ESP32的IP、Mask、Gateway、DNS,計算Network、Broadcast與可用Host範圍。

AI Pair|比較三個目的IP

讓AI協助判斷哪些位於同Subnet,再由學生用AND運算驗證並修正AI解釋。

Challenge|網路故障闖關

教師設定錯誤Mask、錯誤Gateway、錯誤DNS或重複IP,學生依證據定位並完成修復報告。

學習檢核

問題應回答的核心
為什麼不同家庭都能使用192.168.1.1它是私有IP,只在各自LAN內有意義,可重複使用。
DHCP只負責分配IP嗎?還提供Mask、Gateway、DNS、Lease等設定。
192.168.1.119/24的Network與Broadcast是什麼?192.168.1.0192.168.1.255
為什麼連Django要交給Gateway?Django的目的IP不在本機Subnet。
NAT改變什麼?出站封包的私有來源IP/Port被轉成公網IP/Port,並建立回程對照。
NAT是否等於防火牆?不是;NAT做位址轉換,防火牆依安全規則管控流量。

192.168.x.x,是智慧場域走向Internet的起點

DHCP讓裝置取得設定;Subnet決定目的地是否在同一個LAN;Gateway提供通往其他網路的出口;NAT/PAT則把私有位址轉換成可在Internet上回應的連線。

看懂IP,不是記住四個數字,而是能判斷「我是誰、誰和我同網、下一跳要交給誰、如何走到雲端」。

系列定位:《封包旅行記》EP02。建議先閱讀EP01《一個封包如何從ESP32走到Django?》。本文適用於大學部網際網路應用、物聯網與智慧生活、ESP32聯網、Django雲端平台及USR場域專題。文中的公網IP 203.0.113.20屬文件示意用途,不代表實際服務位址。

一個封包如何從ESP32走到Django?

封包旅行記 EP01|大學部網際網路應用

一個封包如何從
ESP32走到Django?

按下按鈕、讀到水溫或播放一段故事之後,資料如何穿越Wi-Fi、路由器、DNS、Internet與HTTPS,最後被Django接收並寫進Database?

ESP32Wi-FiDNSTCP/TLSHTTP/JSONDjango

一個按鈕按下後,真正發生了什麼?

在智慧生活系統中,我們常看到ESP32序列監控視窗顯示「POST成功」,Django Dashboard也出現一筆新資料。看起來只是幾行程式,但在這短短幾秒內,資料其實經過多個設備、位址與協定。

本篇的重點不是再做一個能上傳資料的Demo,而是能清楚回答:資料從哪裡產生、每一層加了什麼資訊、封包如何找到伺服器,以及失敗時應該檢查哪一層。

學習目標

說得清架構

說明ESP32、AP、Router、DNS、Internet、Django與Database的責任。

看得懂封包

分辨MAC、IP、TCP、TLS、HTTP與JSON各自負責的工作。

找得到故障

使用分層診斷,不再把所有問題都歸因於「Wi-Fi不好」。

先看完整路線

感測器/按鈕
ESP32
Wi-Fi AP
Router/NAT
DNS
Internet
Django
Database

回應則沿著已建立的連線反方向返回:Database → Django → HTTPS Response → Internet → Router → ESP32。

五層看懂同一筆資料

應用層HTTP+JSON+REST API定義要送什麼資料、送到哪一個功能入口
安全/傳輸層TLS+TCP加密、建立可靠連線、排序、重送與確認
網路層IP+Routing決定封包從來源IP送往目的IP的路徑
資料連結層Wi-Fi+MAC在目前區域網路的一跳內傳送Frame
實體層2.4GHz無線電波把位元轉成無線訊號,在空氣中傳遞
重要:日常口語常把所有傳輸資料都叫「封包」,但精確來說,應用層是資料、TCP是Segment、IP是Packet、Wi-Fi/Ethernet是Frame。本篇在描述整體旅程時沿用「封包」作為易懂稱呼。

封包出發前:先定義這次事件

以水井三寶智慧互動展覽為例,使用者按下「烏龜故事」按鈕後,ESP32可以把事件整理成JSON。這份JSON是應用層要傳遞的內容,不包含MAC、IP或TCP資訊。

JSON Payload
{
  "event_uuid": "SHUIJING-001-0000000062",
  "event_type": "STORY_START",
  "story": "002",
  "source": "button",
  "network_status": "online",
  "metadata": {
    "firmware": "Layer4-V1.4",
    "jq_confirmed": true
  }
}

為什麼需要event_uuid?

網路逾時後ESP32可能重送同一事件。Django可用唯一識別碼判斷是否重複,避免同一筆資料寫入兩次。

為什麼要有metadata?

保留韌體版本、確認狀態及診斷資訊,方便日後比較不同設備與版本的行為。

八站完成一次封包旅行

01

ESP32加入Wi-Fi,取得網路身分

Association → Authentication → DHCP

ESP32先以STA模式加入無線基地台。連線成功後,通常透過DHCP取得四項重要資訊:

資訊範例用途
本機IP192.168.1.119ESP32在目前LAN中的位址
Subnet Mask255.255.255.0判斷目的地是否位於同一區域網路
Default Gateway192.168.1.1前往其他網路與Internet的出口
DNS Server192.168.1.1或ISP DNS將網域名稱解析成IP位址
檢查證據:序列監控應輸出SSID、本機IP、Gateway、DNS與RSSI。只有顯示 WiFi.status()==WL_CONNECTED,還不能證明Internet或Django已正常。
02

DNS把網域名稱翻譯成IP

Domain Name → DNS Query → Server IP

程式使用的網址可能是:

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

ESP32並不知道這個字串位於世界哪裡,因此會向DNS Server詢問:shuijingtreasures.pythonanywhere.com對應哪一個IP?DNS回覆後,ESP32才能建立後續連線。

診斷觀念:STA=ONLINE只代表取得區域網路連線。若DNS失敗,ESP32仍然無法用網域名稱連到Django。測試時可分別檢查「能否到Gateway」、「能否解析Domain」與「能否連上Server」。
03

ARP找到Gateway的MAC位址

下一跳不是遠端Django,而是本地Router

Django不在同一個Subnet,所以ESP32不會直接找Django的MAC。它先透過ARP找出Default Gateway的MAC位址,再把Wi-Fi Frame交給Router。

Wi-Fi來源MACESP32的MAC
Wi-Fi目的MACAP/Gateway在這一跳使用的MAC
IP來源位址192.168.1.119
IP目的位址DNS解析得到的Django主機IP

每經過一個路由節點,Frame的MAC資訊可能改變;但IP Packet的目的IP仍指向遠端伺服器。

04

Router執行NAT並選擇路徑

Private IP → Public IP → Internet

192.168.1.119是私有IP,不能直接在全球Internet上被路由。Router會執行NAT/PAT,把ESP32的私有IP與來源Port轉換成路由器的公網IP與暫時Port,並記錄對應關係。

位置來源目的
LAN內192.168.1.119:隨機來源PortServer-IP:443
Internet側Public-IP:轉換後PortServer-IP:443

伺服器回應抵達Router後,Router依NAT表把資料交回原本的ESP32。

05

TCP建立可靠連線

SYN → SYN-ACK → ACK

HTTPS一般建立在TCP之上。ESP32與伺服器先進行三向交握,確認雙方都能收發資料。TCP負責:

可靠性

透過Sequence Number、ACK、逾時與重送,降低資料遺失造成的錯誤。

有序傳輸

即使Segment經過不同路徑或抵達順序不同,也能重新排列成正確資料。

Timeout不一定是Django錯誤:TCP連線建立失敗,可能來自DNS錯誤、Port被阻擋、Server未回應、路由問題或訊號品質不穩。
06

TLS確認伺服器並加密資料

Certificate → Key Exchange → Encrypted Channel

因為網址使用HTTPS,TCP建立後還要進行TLS Handshake。ESP32檢查憑證是否可信、網域是否相符、憑證是否在有效期限內,再協商加密金鑰。

不要把正式系統設成「不驗證憑證」。使用不安全Client或略過憑證驗證,雖可能暫時連線成功,卻失去確認伺服器身分的能力。教學測試與正式部署應清楚區分。
07

HTTP把JSON送進Django API

POST+Header+Body

安全通道建立後,ESP32送出HTTP Request。概念上包含以下內容:

Request LinePOST /api/events/ HTTP/1.1
Hostshuijingtreasures.pythonanywhere.com
Content-Typeapplication/json
AuthorizationBearer DEVICE_TOKEN(範例,依系統設計)
Body{"event_uuid":"...","event_type":"STORY_START",...}

HTTP定義「怎麼送」,JSON定義「送什麼」,REST API定義「送到哪一個功能入口」。

08

Django驗證、處理並寫入Database

URL → View → Validation → Model → Response

Django收到Request後,通常依序進行:

  1. URL Router將 /api/events/交給對應View。
  2. 驗證Method、Content-Type、Token與JSON格式。
  3. 檢查必要欄位、資料型別及event_uuid是否重複。
  4. 使用Model寫入Database。
  5. 回傳JSON與適當HTTP Status Code。
Django View示意
import json
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from .models import DeviceEvent

@require_POST
def create_event(request):
    try:
        data = json.loads(request.body)
        event_uuid = data["event_uuid"]

        event, created = DeviceEvent.objects.get_or_create(
            event_uuid=event_uuid,
            defaults={
                "event_type": data["event_type"],
                "story": data.get("story", ""),
                "source": data.get("source", "unknown"),
                "metadata": data.get("metadata", {}),
            },
        )

        return JsonResponse(
            {"ok": True, "created": created, "id": event.id},
            status=201 if created else 200,
        )
    except (KeyError, json.JSONDecodeError) as exc:
        return JsonResponse(
            {"ok": False, "error": str(exc)}, status=400
        )
成功不只看200:新增資源通常可回傳201 Created;重複事件可回200並標示created:false;格式錯誤用400;未授權用401;伺服器錯誤用500

ESP32送出HTTPS POST的示意程式

以下程式聚焦資料旅程,憑證、Token、逾時、重送與離線Queue仍需依正式系統補齊。不得把真實密鑰直接寫進公開文章或GitHub。

Arduino/ESP32示意
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>

const char* WIFI_SSID = "YOUR_WIFI_SSID";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* API_URL =
  "https://shuijingtreasures.pythonanywhere.com/api/events/";

void postEvent(const String& payload) {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("NETWORK ERROR: Wi-Fi disconnected");
    return;  // 正式版應排入離線Queue
  }

  WiFiClientSecure client;
  // 正式版:設定並驗證正確CA憑證
  // client.setCACert(ROOT_CA);

  HTTPClient https;
  https.setTimeout(8000);

  if (!https.begin(client, API_URL)) {
    Serial.println("HTTPS BEGIN FAILED");
    return;
  }

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

  int statusCode = https.POST(payload);
  String response = https.getString();

  Serial.printf("HTTP STATUS: %d\n", statusCode);
  Serial.println("RESPONSE: " + response);

  https.end();
}

封包裡到底包了什麼?

「封裝」可以想像成一層一層加上信封。最裡面是JSON,外面依序包上HTTP、TLS、TCP、IP與Wi-Fi Frame。

由內到外主要資訊在哪裡被處理
JSON資料事件類型、故事編號、裝置資訊ESP32程式與Django View
HTTPMethod、Path、Header、Body、Status CodeHTTPClient、Web Server、Django
TLS憑證、加密參數、加密後內容ESP32安全Client與HTTPS伺服器
TCP來源/目的Port、Sequence、ACK兩端作業系統或網路堆疊
IP來源IP、目的IP、TTLESP32、Router及Internet路由器
Wi-Fi Frame本地一跳使用的MAC與錯誤檢查ESP32、AP與區域網路

出錯時,從哪裡開始查?

PowerDeviceWi-FiIPGatewayDNSTCP/TLSHTTPAPIDatabase
現象可能層級應取得的證據
無法取得IPWi-Fi/DHCPSSID、密碼、WiFi狀態、DHCP紀錄
有IP但Domain解析失敗DNSDNS Server、解析結果、其他Domain測試
連線逾時Routing/TCP/FirewallGateway、目的IP、Port 443、Timeout位置
TLS失敗憑證/時間/網域憑證錯誤、系統時間、CA與Host名稱
HTTP 400JSON/API驗證Request Body、Content-Type、Django錯誤回應
HTTP 401/403身分與權限Token、Header、裝置權限與ACL
HTTP 500Django/DatabaseServer Log、Exception、Migration與資料庫狀態
ESP32顯示成功但Dashboard沒資料API/Database/Dashboard QueryResponse、資料表紀錄、查詢條件與時間範圍
工程判斷要用證據:不要只說「網路不穩」或「伺服器壞了」。應記錄失敗在哪一層、看到什麼狀態碼、哪一個測試成功、哪一個測試失敗。

三項學生任務

No-AI|畫出封包旅行圖

標示ESP32、AP、Router、DNS、Internet、Django與Database,並為每段寫出主要協定。

AI Pair|解釋封裝

請AI協助比較Frame、Packet、Segment與HTTP資料,再以自己的話修正與重畫。

Challenge|故障闖關

教師設定錯誤DNS、錯誤API Path、無效Token或重複event_uuid,學生用證據定位與修復。

學習檢核

問題學生應能回答的重點
ESP32已取得IP,為何仍可能無法連到Django?Gateway、DNS、Routing、TCP、TLS、HTTP與API仍可能失敗。
為什麼目的MAC不是Django伺服器的MAC?MAC只負責本地一跳;跨網路時先交給Gateway。
NAT做了什麼?把私有IP與Port轉換為公網IP與Port,並保存回程對應。
HTTP、JSON與REST API如何分工?HTTP定義傳送方式,JSON定義資料格式,REST API定義資源入口與操作。
為何需要event_uuid?讓伺服器辨識重送與重複事件,支援冪等處理。
如何證明事件已成功?同時檢查ESP32 Log、HTTP Status、Django Response、Database與Dashboard。

一個封包的旅程,就是一套系統的縮影

ESP32負責把實體事件轉成資料;Wi-Fi與Router把資料送出場域;DNS找到服務;TCP與TLS提供可靠且安全的通道;HTTP與JSON定義溝通;Django與Database把事件保存成可分析的資訊。

真正學會網際網路,不是只讓資料送成功,而是能解釋每一站、驗證每一層、修復每一種失敗。

系列定位:《封包旅行記》EP01。適用於大學部網際網路應用、物聯網與智慧生活、ESP32聯網、Django雲端平台及USR場域型專題。範例中的網址、Token、IP與資料內容均為教學示意,正式系統應採安全憑證、環境變數、裝置身分、權限控管與完整異常處理。

2026年8月21日 星期五

聯網一下:從裝置、協定到智慧場域

大學部|網際網路系統整合與場域實作

聯網一下:
從裝置、協定到智慧場域

把ESP32、Wi-Fi、MQTT、HTTP、JSON、REST API、Django、Database與AI串成一個真正能運作、能診斷、能持續改善的智慧系統。

說得清架構寫得出協定找得到故障完成場域整合

會寫程式,還不等於會建構聯網系統

一段程式能在開發板上執行,只代表單一裝置可以工作。真正的智慧場域還需要考量裝置如何加入網路、訊息採用什麼格式、伺服器如何接收、資料如何保存,以及某一層失效時要從哪裡開始檢查。

大學部的網際網路課程,應從「使用網路」走向「設計網路服務」。學生不只要完成Demo,更要能解釋架構、驗證協定、診斷問題,並在真實場域中維持系統運作。

四項核心能力

① 說得清架構

說明Device、Edge、LAN、Internet、Cloud、Database與AI的責任邊界及資料流。

② 寫得出協定

能實作MQTT發布訂閱、HTTP Request、JSON Payload與REST API Endpoint。

③ 找得到故障

不把「不能用」當成單一問題,而是依Wi-Fi、DNS、TLS、API、Database逐層驗證。

④ 完成場域整合

把文化、養殖、農業或教育需求轉化為可操作、可監測、可維護的聯網服務。

智慧聯網五層架構

Layer 5|KnowledgeAI/RAG、決策服務把資料轉化成可理解、可檢索與可行動的知識
Layer 4|Cloud & DataDjango、API、Database、Dashboard接收、保存、查詢、視覺化與跨場次管理
Layer 3|NetworkWi-Fi、IP、DNS、HTTP/HTTPS、MQTT定義資料如何定址、傳輸及安全抵達
Layer 2|EdgeESP32 Edge Web、Gateway提供即時互動、離線能力與本地控制
Layer 1|Device感測器、按鈕、致動器、機器人把實體事件轉成數位資料,並把指令轉回動作

第一篇|說得清架構

從單一裝置走向端、邊、網、雲、智

學習重點:系統邊界、資料流、同步/非同步與服務責任。

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

總整架構從ESP32、Edge Web、Internet、Django到AI/RAG。

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

資料流追蹤一筆事件從實體世界進入雲端資料庫。

ESP32同時當基地台又能上網:AP+STA

EdgeNetwork理解本地控制與Internet通道如何共存。

Machine Learning with Raspberry Pi 4 and Coral USB

Edge AI比較邊緣推論與雲端AI的角色及限制。

第二篇|寫得出協定

MQTT發布/訂閱與Topic
HTTP(S)Request/Response
JSON跨系統資料格式
REST API服務資源與Endpoint

讓不同設備與程式說同一種語言

學習重點:Topic、Method、Header、Body、Status Code與Payload驗證。

Raspberry Pi安裝MQTT之IoT應用-Arduino示範

MQTT從發布者、Broker、Topic到訂閱者建立基本模型。

利用ChatGPT產生發布MQTT主題的Python程式

AI協作MQTT產生程式後進行錯誤檢查、修改與驗證。

HTTP+JSON+REST API

HTTPJSONAPI理解「怎麼送、送什麼、送到哪個入口」。

ESP32 × Django REST API:將感測資料上傳雲端

HTTPS POST從ESP32送出JSON到Django Database與Dashboard。

第三篇|找得到故障

分層診斷順序

PowerWi-FiIPGatewayDNSTLSHTTP/MQTTAPIDatabase

「STA=ONLINE」只代表裝置加入Wi-Fi並取得IP,並不代表DNS、憑證、HTTPS、API及資料庫都已正常。每一層都要有可觀測證據。

用證據取代猜測

學習重點:Log、Status Code、Timeout、Retry、Queue與可觀測性。

IP、MAC、DNS、Domain與Port

定址診斷分辨裝置、服務名稱與Port之間的責任。

ESP32 AP+STA到Django雲端

分層除錯逐層檢查Wi-Fi、Gateway、DNS、TLS、HTTPS與Django。

在Home Assistant添加MQTT Broker並測試MQTT

Broker測試驗證連線、Topic與訊息收發。

Django+AJAX+JavaScript整合MQTT

前後端整合觀察訊息從Broker到網頁呈現的每個交界。

第四篇|完成場域整合

場域專題不是把技術堆在一起

學生要先界定使用者、情境與真實問題,再決定哪些資料值得感測、哪些反應必須留在Edge、哪些資料需要上Cloud,以及AI能否產生真正有用的知識。

文化展覽
按鈕/ToF → 故事播放 → Edge Web → Django事件 → AI導覽
智慧養殖
水溫/pH/DO/EC → HTTPS API → Dashboard → 異常判讀
農漁產銷
開放資料 → Django平台 → 市場圖表 → 電商與決策服務

可作為期末專題的場域文章

學習重點:需求分析、架構設計、整合驗證、成果展示與永續維運。

從Atlas Aquaponics Kit到Django雲端監控平台

智慧養殖多感測器、HTTPS POST、API、Database與Dashboard。

尚虎雲產銷平台助水井村智慧減碳節水三生一體

USRPBL從地方需求走向跨系統整合與永續服務。

Python/Django/PythonAnywhere實作農漁業交易行情

雲端資料整合開放資料、網站服務與產銷應用。

網際網路×USR:從地方故事到數位共生平台

服務設計思考系統為誰而做,以及如何持續被使用。

大學部成果評量

能力學生應完成成果證據
架構表達說明每一層的角色、責任邊界與資料流架構圖、資料流程圖、口頭簡報
協定實作完成MQTT或REST API收發,定義Payload與錯誤回應程式碼、API規格、測試紀錄
故障診斷用分層方法定位至少三種人為設定的故障Log、狀態碼、診斷報告
場域整合把裝置、Edge、Network、Cloud及Dashboard整合運作展示影片、系統網址、現場驗收
社會實踐說明使用者價值、資料倫理、隱私及維運方式需求訪談、風險檢核、維運計畫

真正的聯網能力,是讓系統在場域中持續運作

學生能寫出一段程式,只是開始;能把不同設備與服務整合、找出問題、提出證據並持續改善,才是大學部網際網路教育要培養的系統能力。

說得清架構・寫得出協定・找得到故障・完成場域整合

教材來源:智慧生活科技專業社群。本文依大學部網際網路、物聯網與智慧生活課程需求重新整理,可搭配PBL、CDIO、USR場域實作與期末系統驗收。

網路一下: 看得懂、連得上、做得出來

專科部|網際網路概論自主學習指南

網路一下:
看得懂、連得上、做得出來

從每天使用的手機與Wi-Fi出發,沿著一筆資料的旅行,認識IP、DNS、網站、雲端、物聯網與生成式AI,最後親手完成一個能真正上線的智慧應用。

👀 看得懂📡 連得上🛠️ 做得出來

網際網路,不只是「會上網」

我們每天傳訊息、看影片、搜尋資料、使用生成式AI,也可能用手機控制燈光、機器人與感測器。但是,按下按鈕之後,資料究竟去了哪裡?手機如何找到網站?為什麼同一台ESP32既能讓手機直接連線,又能把資料送到雲端?

這門課真正要學的,不是背完所有名詞,而是能把「裝置、網路、網站、資料與使用者」連成一條看得懂、查得到問題,也能動手完成的路徑。

三個學習目標

👀

看得懂

理解LAN、Internet、IP、MAC、DNS、Domain、Port、Client、Server及Cloud的角色,不再只記名詞。

📡

連得上

能設定Wi-Fi、辨認AP與STA、讀懂IP資訊,並用分層方法找出連線、DNS、HTTPS或API問題。

🛠️

做得出來

從HTML頁面開始,逐步完成Django網站、MQTT控制、REST API與智慧生活小專題。

先看懂:一筆資料如何旅行

  1. 使用者在手機或裝置上按下按鈕,產生一筆事件。
  2. 裝置透過Wi-Fi加入區域網路,由路由器取得IP位址。
  3. DNS把容易記憶的網域名稱轉換成伺服器IP。
  4. 瀏覽器或ESP32透過HTTP/HTTPS送出Request。
  5. 伺服器接收JSON資料,由Django程式處理並寫入Database。
  6. Dashboard把資料整理成圖表,AI再從資料中產生知識與建議。

單元一|看得懂網路的角色

從位址、名稱與服務入口,建立網際網路基本地圖。

IP、MAC、DNS、Domain與Port

CH01CH03理解「哪一台裝置、哪一個名稱、哪一項服務」。

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

CH01CH08用完整資料旅程串起抽象名詞。

Raspberry Pi應用之Windows檔案伺服器

CH04CH06理解Client/Server與網路資源分享。

當個快樂的物聯網自造者

CH08認識感測器、雲端、大數據與AI之間的關係。

再連上:從手機、Wi-Fi到Internet

單元二|讓裝置真正連得上

不只看到「已連線」,還要知道資料能不能抵達服務。

Raspberry Pi藍牙4.0應用之iBeacon發射器

CH02比較BLE、Wi-Fi、NFC及室內定位。

ESP32 Edge Web × 手機

CH04CH05手機直接連到小型Web Server。

ESP32同時當基地台又能上網:AP+STA

CH02CH04理解本地控制通道與Internet通道。

在Home Assistant添加MQTT Broker並測試MQTT

CH08以圖形化平台理解Broker、Topic與訊息傳遞。

最後做出來:網站、雲端、IoT與AI

單元三|完成可以展示的智慧應用

從一頁網站逐步走向雲端服務與智慧生活專題。

在PythonAnywhere設計Django網站的功能表

CH05建立網站頁面、URL與導覽結構。

在PythonAnywhere設計Django網站的輪播功能

CH05CH12結合內容設計與網站行銷。

在Django網站中設計登入功能

CH11CH13認識會員、Session及帳號安全。

Django登入功能加上圖形驗證

CH13從CAPTCHA理解網站的自動化攻擊防護。

好用的物聯網APP工具-IoT MQTT Panel

CH06CH08用手機完成物聯網發布、訂閱與控制。

Ollama和ChatGPT有何不同?

CH07CH09比較本地AI、雲端AI、隱私與成本。

HTTP+JSON+REST API

CH05CH08進一步理解網頁與雲端服務如何交換資料。

網際網路×USR:從地方故事到數位共生平台

CH11CH12思考網站為誰而做、解決什麼問題。

四項學習任務

任務一|畫出我的上網地圖從手機、AP、路由器、DNS到網站伺服器,畫出開啟網頁時資料經過的節點。
任務二|成為網路小偵探使用IP資訊與瀏覽器訊息,判斷問題發生在Wi-Fi、Gateway、DNS還是網站服務。
任務三|完成一頁地方網站用HTML或Django製作地方人物、文化、食農或工藝主題頁面。
任務四|讓實體事件上雲端讓按鈕、感測器或機器人透過MQTT或REST API把資料送到Dashboard。

學完之後,我可以做到什麼?

能力我能做到成果證據
網路理解用自己的話解釋IP、DNS、Domain、Port及Client/Server資料旅程圖、概念說明
連線診斷依序檢查Wi-Fi、IP、Gateway、DNS、HTTPS與服務狀態連線檢查表、除錯紀錄
網站製作完成具有導覽、圖片、內容及基本互動的網站網站網址、QR Code
智慧聯網讓手機、ESP32或感測器與雲端交換資料MQTT訊息、API紀錄、Dashboard
數位素養辨識密碼、個資、AI內容與著作權的基本風險風險檢核與使用說明

網路學習的終點,不是背出答案

而是面對一個真實需求時,知道資料從哪裡來、要往哪裡去、如何安全抵達,並能把技術做成真正有人願意使用的服務。

看得懂,是理解;連得上,是能力;做得出來,才是實踐。

教材來源:智慧生活科技專業社群。文章依專科部《網際網路概論》學習需求重新整理,實際授課時可搭配操作示範、學習單與場域型專題。