National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 14

MQTT 物聯網通訊

連線 broker、發布感測值、訂閱指令
Interaction 25 minute(s)

Learning Objectives

  • 說明 MQTT 的發布/訂閱模型:裝置不直接互相連線,而是透過 broker 依「主題」轉送訊息
  • 用 umqtt.simple 的 MQTTClient 連上 broker,把感測值發布到主題
  • 訂閱主題、設定回呼函式,用 check_msg 收到指令後控制 LED
  • 看懂主題萬用字元 + 與 #,以及 QoS、保留訊息的用途

感測節點需要什麼樣的通訊

上一課用 HTTP 向網站要資料:ESP32 問一次,伺服器答一次。可是物聯網裝置常常要做兩件事:

  1. 一直送資料出去:教室的溫度每隔幾秒就要回報一次,而且可能有很多人、很多程式想看。
  2. 隨時接收指令:手機上按一下「開燈」,教室裡的 ESP32 要馬上知道。

如果用 HTTP,ESP32 得一直問「有沒有我的指令?」(大部分時候答案是沒有),手機也得知道每一塊 ESP32 的 IP 位址。 MQTT 是為這種情況設計的通訊協定:訊息小、連線一直開著,裝置之間不必知道彼此在哪裡。

發布/訂閱:所有訊息都經過 broker

MQTT 裡有一台中間的伺服器,叫做 broker(代理伺服器)。每個裝置都只連到 broker:

  • 發布(publish):把一則訊息送給 broker,並標上一個主題(topic),例如 uedu/room101/temp。
  • 訂閱(subscribe):告訴 broker「這個主題有新訊息時轉給我」。
  ESP32(101 教室)                    broker                     手機 App、儀表板
  發布 uedu/room101/temp = 25.6  ──▶  依主題轉送  ──▶  訂閱了 uedu/room101/temp 的人都收到
  訂閱 uedu/room101/led          ◀──  依主題轉送  ◀──  發布 uedu/room101/led = on

發布的人不知道誰會收到,訂閱的人也不知道是誰發的;兩邊只約定好主題名稱。 新增一個儀表板,只要讓它訂閱同一個主題,ESP32 的程式一行都不用改。

MQTT 是公開的標準,目前由 OASIS 維護,常見的版本是 3.1.1 與 5.0。 MicroPython 的 umqtt.simple 是一個小巧的用戶端,這一課用它。

逐步看:把溫度發布到 broker

上方電路畫面的網路紀錄會列出每一個 MQTT 動作。注意:publish 的兩個參數都是字串, 所以溫度要先用 str() 轉成文字;MQTT 只負責送出一串位元組,內容是什麼格式由你決定。

主題怎麼命名、萬用字元與 QoS

主題是用 / 分層的字串,像檔案路徑。常見的命名方式是「專案/地點/裝置或量測項目」:

主題 內容
uedu/room101/temp 101 教室的溫度
uedu/room101/hum 101 教室的濕度
uedu/room101/led 給 101 教室的開關燈指令
uedu/room202/temp 202 教室的溫度

訂閱時可以用萬用字元,一次訂閱很多主題(發布時不能用):

訂閱 收得到 收不到
uedu/+/temp uedu/room101/temp、uedu/room202/temp uedu/room101/hum
uedu/room101/# uedu/room101/temp、uedu/room101/led、uedu/room101 uedu/room202/temp
  • + 代表剛好一層,任何名稱都可以。
  • # 代表這一層以下的全部,只能放在最後面。

QoS:訊息要保證送到幾次

發布與訂閱時可以指定服務品質(Quality of Service,QoS):

QoS 意思 適合
0 最多送一次:送出去就不管了,可能遺失 每幾秒一筆的感測值,掉一筆沒關係
1 至少送一次:收到確認才算數,可能重複 開關指令、警報
2 剛好一次:多一次來回確認 計費、不能重複的動作

umqtt.simple 的 publish 支援 QoS 0 與 1。QoS 越高,來回的封包越多、越耗電。

另外兩個常用功能

  • 保留訊息(retain):publish(主題, 內容, retain=True),broker 會記住這個主題的最後一則訊息, 之後才訂閱的人一連上就先收到它。適合「目前狀態」,例如裝置在線、燈現在是開還是關。
  • 遺囑訊息(last will):連線時先用 set_last_will() 交給 broker 一則訊息;如果裝置沒有正常斷線就消失 (斷電、當機),broker 會替它發布出去,例如 uedu/room101/status = offline。

逐步看:訂閱指令,遠端開關燈

這次 ESP32 是接收的一方。模擬的 broker 會在 1.8 秒送來 on、3.2 秒送來 off(電路規格裡的時間表)。 注意 on_message 不是程式自己呼叫的:是 check_msg() 發現有新訊息時才呼叫它。看第 27 行之後有沒有跳進第 15 行。

逐步看:一個訂閱收很多主題,內容用 JSON

走廊的 ESP32 控制兩間教室的燈,只訂閱一次 uedu/+/led。時間表裡有 4 則訊息, 其中一則是 uedu/room101/fan(風扇),看它有沒有被收到。訊息內容用 JSON,可以一次帶好幾個欄位。

互動練習:發布感測值、接收開關燈指令

起始程式已經連上 Wi-Fi 與 broker,每 2 秒發布一次溫度。模擬的 broker 會在第 2 秒送來 on、第 4 秒送來 off 到主題 uedu/room101/led。依序完成任務:

  1. 直接執行起始程式,看網路紀錄裡的發布。
  2. 每次也把濕度發布到 uedu/room101/hum(sensor.humidity())。
  3. 訂閱 uedu/room101/led,收到 on 開燈、off 關燈(記得 set_callback,迴圈裡呼叫 check_msg())。
  4. 回答一個問題。

小測驗:發布、訂閱與主題

1.

手機 App 發布 uedu/room101/led = on,教室的 ESP32 怎麼收到這則訊息?

2.

ESP32 訂閱了 uedu/+/temp,下面哪一個主題的訊息收不到?

3.

溫度每 5 秒發布一次,偶爾掉一筆沒關係,想讓封包最少、最省電,QoS 選哪一個?

第 1 次作答

小測驗:回呼函式收到的資料

1.

回呼函式收到的 msg 是位元組。下面的程式會印出什麼?

msg = b"on"
print(msg == "on", msg.decode() == "on")
2.

下面的程式會印出什麼?

import json
topic = b"uedu/room202/led"
msg = b'{"on": 1, "level": 80}'
room = topic.decode().split("/")[1]
cmd = json.loads(msg.decode())
print(room, cmd["level"])
3.

主迴圈裡改用 client.wait_msg() 取代 client.check_msg(),會有什麼不同?

第 1 次作答

上線前要注意的事

  • 公開的測試 broker 任何人都能訂閱,包括 #(全部主題)。練習時不要發布個人資料、位置或密碼,主題名稱也要取得不容易撞到別人。
  • 自己的 broker 要設定帳號密碼(MQTTClient(..., user=..., password=...)),可能的話使用加密連線(ssl=True,預設連接埠 8883;不加密是 1883)。
  • client_id 不要重複:兩個裝置用同一個 client_id,broker 會把先連上的那一個踢掉,兩塊板子會輪流斷線。
  • 斷線要重連:Wi-Fi 或 broker 斷線時,publish 會拋出 OSError;第 18 課的專題會把重連寫進程式。

重點整理

  • MQTT 用發布/訂閱:裝置只連 broker,依主題轉送訊息,發布者和訂閱者不必知道彼此。
  • MQTTClient(client_id, broker) → connect() → publish(主題, 內容);內容是文字或位元組,數字要先轉成文字,多個欄位用 JSON。
  • 接收:set_callback(函式)、subscribe(主題),迴圈裡呼叫 check_msg()(不等待)或 wait_msg()(等到有訊息)。回呼收到的主題與內容都是位元組。
  • 訂閱可用萬用字元:+ 剛好一層、# 以下全部。
  • QoS 0/1/2 決定送達保證;保留訊息讓後來的訂閱者拿到最新狀態;遺囑訊息在裝置意外離線時由 broker 代發。

下一課討論用電池供電時怎麼省電:Wi-Fi 很耗電,感測節點常常是「醒來、量測、發布、睡覺」。

這一課完成了!
Next lesson:深度睡眠與省電
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。