從 MQTT 基本觀念、Broker 架設、Topic 規劃,到 Raspberry Pi Pico W、ESP32 發佈資料,並使用 Python 撰寫 Subscriber 進行接收。
適合 IoT、嵌入式系統、網路通訊與智慧裝置課程。
| 角色 | 說明 |
|---|---|
| Publisher | 發送訊息的裝置,例如感測器、ESP32、Pico W |
| Subscriber | 接收訊息的裝置或程式,例如 Python 應用程式 |
| Broker | 負責轉送訊息的中心伺服器,例如 Mosquitto |
MQTT 用 topic 來分類訊息,例如:
iot/classroom/temp
iot/classroom/humidity
iot/pico/led
iot/esp32/status
| 功能 | 說明 |
|---|---|
| QoS 0 | 最多傳一次,最快,但不保證一定收到 |
| QoS 1 | 至少傳一次,可能重複收到 |
| QoS 2 | 只傳一次,最可靠但開銷較大 |
| Retain | Broker 保留最後一筆訊息,新訂閱者一連上就能收到 |
sudo apt update
sudo apt install -y mosquitto mosquitto-clients
sudo systemctl enable mosquitto
sudo systemctl start mosquitto
sudo systemctl status mosquitto
先開兩個終端機。
終端機 A,訂閱:
mosquitto_sub -h localhost -t test/topic
終端機 B,發送:
mosquitto_pub -h localhost -t test/topic -m "Hello MQTT"
iot/班級/裝置/資料類型
例如:
iot/ece2026/picow/temp
iot/ece2026/picow/humidity
iot/ece2026/esp32/light
iot/ece2026/esp32/status
group1、group2python3 -m pip install paho-mqtt
import paho.mqtt.client as mqtt
BROKER_IP = "192.168.1.120"
TOPIC = "iot/ece2026/#"
def on_connect(client, userdata, flags, rc):
print("Connected with result code", rc)
client.subscribe(TOPIC)
def on_message(client, userdata, msg):
print(f"Topic: {msg.topic}")
print(f"Message: {msg.payload.decode()}")
print("-" * 40)
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER_IP, 1883, 60)
client.loop_forever()
python3 subscriber.py
iot/ece2026/ 底下的所有子 topic,非常適合課堂展示。本節採用 MicroPython。請先使用 Thonny 或 mpremote 將 MicroPython 韌體燒錄到 Pico W。
boot.py,可選main.py,主程式umqtt.simple 模組import network
import time
from umqtt.simple import MQTTClient
SSID = '你的WiFi名稱'
PASSWORD = '你的WiFi密碼'
BROKER = '192.168.1.120'
CLIENT_ID = 'pico_w_01'
TOPIC = b'iot/ece2026/picow/temp'
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)
while not wlan.isconnected():
print('WiFi connecting...')
time.sleep(1)
print('WiFi connected:', wlan.ifconfig())
client = MQTTClient(CLIENT_ID, BROKER)
client.connect()
print('MQTT connected')
count = 0
while True:
message = 'Pico W temperature=' + str(25 + count % 5)
client.publish(TOPIC, message)
print('Published:', message)
count += 1
time.sleep(5)
import network
import time
from umqtt.simple import MQTTClient
SSID = '你的WiFi名稱'
PASSWORD = '你的WiFi密碼'
BROKER = '192.168.1.120'
CLIENT_ID = 'pico_w_sub_01'
TOPIC = b'iot/ece2026/picow/led'
def sub_cb(topic, msg):
print('Received:', topic, msg)
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)
while not wlan.isconnected():
time.sleep(1)
client = MQTTClient(CLIENT_ID, BROKER)
client.set_callback(sub_cb)
client.connect()
client.subscribe(TOPIC)
print('Subscribed to', TOPIC)
while True:
client.check_msg()
time.sleep(1)
若 ESP32 安裝的是 MicroPython,可直接使用與 Pico W 類似的方式。
import network
import time
from umqtt.simple import MQTTClient
SSID = '你的WiFi名稱'
PASSWORD = '你的WiFi密碼'
BROKER = '192.168.1.120'
CLIENT_ID = 'esp32_01'
TOPIC = b'iot/ece2026/esp32/status'
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)
while not wlan.isconnected():
print('Connecting WiFi...')
time.sleep(1)
print('WiFi OK:', wlan.ifconfig())
client = MQTTClient(CLIENT_ID, BROKER)
client.connect()
print('MQTT connected')
counter = 0
while True:
payload = 'ESP32 alive ' + str(counter)
client.publish(TOPIC, payload)
print('Published:', payload)
counter += 1
time.sleep(3)
如果課程使用 Arduino IDE,這個版本通常更常見。
#include <WiFi.h>
#include <PubSubClient.h>
const char* ssid = "你的WiFi名稱";
const char* password = "你的WiFi密碼";
const char* mqtt_server = "192.168.1.120";
WiFiClient espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(10);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void reconnect() {
while (!client.connected()) {
if (client.connect("ESP32Client")) {
client.publish("iot/ece2026/esp32/status", "ESP32 connected");
} else {
delay(1000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
client.publish("iot/ece2026/esp32/status", "Hello from ESP32");
delay(5000);
}
import paho.mqtt.client as mqtt
import json
from datetime import datetime
BROKER_IP = "192.168.1.120"
TOPICS = [
("iot/ece2026/picow/temp", 0),
("iot/ece2026/esp32/status", 0),
("iot/ece2026/#", 0)
]
def on_connect(client, userdata, flags, rc):
print("Connected:", rc)
for topic, qos in TOPICS:
client.subscribe(topic, qos)
print("Subscribed:", topic)
def on_message(client, userdata, msg):
payload = msg.payload.decode()
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{now}] {msg.topic} -> {payload}")
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER_IP, 1883, 60)
client.loop_forever()
import paho.mqtt.client as mqtt
import time
BROKER_IP = "192.168.1.120"
TOPIC = "iot/ece2026/rpi/message"
client = mqtt.Client()
client.connect(BROKER_IP, 1883, 60)
count = 0
while True:
msg = f"Hello from Raspberry Pi {count}"
client.publish(TOPIC, msg)
print(msg)
count += 1
time.sleep(5)
mosquitto_pub 與 mosquitto_sub 做第一個測試| 問題 | 可能原因 | 解法 |
|---|---|---|
| 連不到 Broker | IP 填錯、Broker 未啟動、防火牆阻擋 | 檢查 systemctl status mosquitto 與 IP 位址 |
| Python 收不到訊息 | topic 不一致 | 確認 topic 字串完全一致 |
| Pico W 無法連 Wi-Fi | SSID/密碼錯誤、頻段不支援 | 確認 2.4GHz Wi-Fi 與帳密 |
| ESP32 斷線 | Wi-Fi 不穩、未做重連 | 加入 reconnect 邏輯 |
| 訊息中文亂碼 | 編碼問題 | 統一使用 UTF-8 |
MQTT 是 IoT 世界中非常重要的通訊協定,觀念清楚之後,學生很快就能把感測器、微控制器、樹莓派、資料庫與網頁儀表板串接起來。
這份教材的重點不是只會執行範例,而是讓學生理解資料如何從裝置經過 Broker,再傳到應用程式端。