MQTT 說明練習 EX1 (PC MQTTX Client , online mqttgo.io , 手機 Iot MQTT Panel)
設定 MQTT 連線時,最核心的四個基本參數為:Broker(伺服器網址)、Port(連接埠)、Topic(主題)以及 Client ID(客戶端識別碼)。
無論您是在設定手機 App(如 IoT MQTT Panel)、微控制器(如 ESP32、Arduino),或是智慧家庭系統(如 Home Assistant),都需要依照以下指南填入對應的資訊:
核心欄位設定指南
- Broker / Host / Server:輸入您的 MQTT 伺服器 IP 位址或網址。如果是自建伺服器填入該電腦的區網 IP;如果是使用雲端測試平台,可填入免費的公共伺服器(例如 HiveMQ 公共測試伺服器 的網址 mqtt:// broker.emqx.io , mqtt:// mqttgo.io , broker.hivemq.com )。
- Port(連接埠):
- Client ID:每個裝置在伺服器上的唯一識別碼,通常可以隨意設定(例如
my_esp32_01),但同一個伺服器下不可有兩個相同的 Client ID,否則會互相斷線擠下線。 - Username / Password:如果您的伺服器有開啟安全驗證,請在此輸入帳號與密碼;若使用匿名連線的公共測試伺服器,則保持空白即可。
Topic(主題)命名與溝通規則
MQTT 是透過「發布(Publish)」與「訂閱(Subscribe)」主題來傳遞資訊。
- 命名格式:建議使用英文、數字命名,並使用斜線
/來區分層級(例如:alex9ufo/temperature , alex9ufo/humidity , alex9ufo/ledstatus , alex9ufo/ledcontrol)。 - 連線邏輯:
- 負責傳送資料的裝置(如溫度感測器),必須對該主題進行發布 (Publish)。
- 負責接收資料的裝置(如手機 App 或螢幕),必須訂閱 (Subscribe) 相同名稱的主題才能收到資料。
高級進階參數(依需求調整)
- Keep Alive(心跳時間):預設通常為
60秒。這是裝置用來定時向伺服器報平安的時間間隔,避免因網路短暫閒置而被判定斷線。 - QoS(服務質量):
0:最多傳送一次(最快、最不佔頻寬,漏一兩筆沒關係的資料適用)。1:最少傳送一次(確保對方一定會收到,但可能重複接收)。2:剛好傳送一次(最嚴謹,通常用在扣款或不能重複的指令)。
- Retain(訊息保留):若勾選或設為 True,伺服器會永久保留這個主題的最後一筆訊息。當有新裝置新訂閱這個主題時,會立刻收到最新的歷史狀態,不需等待下一次資料更新。
// --- 設定區 ---
const char* mqtt_server = "mqttgo.io"; // 請替換成你的 MQTT 伺服器網址 (例如 io.adafruit.com)
const int mqtt_port = 1883;
// --- MQTT 主題定義 ---
const char* topic_temp = "alex9ufo/temperature";
const char* topic_humi = "alex9ufo/humidity";
const char* topic_ctrl = "alex9ufo/ledcontrol";
const char* topic_status = "alex9ufo/ledstatus";
IoT MQTT Panel (手機)
https://www.emqx.com/en/downloads/MQTTX
🛠️ Wokwi 元件接線指南
在 Wokwi 中,請將元件依照以下引腳(Pin)連接:
DHT22: VCC -> 3V3, GND -> GND, SDA (Data) -> GPIO 15
I2C LCD 16x2: VCC -> 5V/3V3, GND -> GND, SDA -> GPIO 21, SCL -> GPIO 22
LED1 (紅): 陽極 (Anode) -> GPIO 12(記得串聯 220Ω 電阻到 GND)
LED2 (綠): 陽極 (Anode) -> GPIO 14(記得串聯 220Ω 電阻到 GND)
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// --- 設定區 ---
const char* ssid = "Wokwi-GUEST"; // Wokwi 專用模擬 WiFi
const char* password = "";
const char* mqtt_server = "mqttgo.io"; // 請替換成你的 MQTT 伺服器網址 (例如 io.adafruit.com)
const int mqtt_port = 1883;
const char* mqtt_user = ""; // 如果需要認證,請填寫
const char* mqtt_pass = ""; // 如果需要認證,請填寫
// --- 引腳定義 ---
#define DHTPIN 15
#define DHTTYPE DHT22
#define LED1_PIN 12
#define LED2_PIN 14
// --- MQTT 主題定義 ---
const char* topic_temp = "alex9ufo/temperature";
const char* topic_humi = "alex9ufo/humidity";
const char* topic_ctrl = "alex9ufo/ledcontrol";
const char* topic_status = "alex9ufo/ledstatus";
// --- 初始化物件 ---
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2); // 模擬器中 I2C 位址通常為 0x27
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
const long interval = 5000; // 每 5 秒發行一次溫濕度
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connecting WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WiFi Connected");
delay(1000);
}
// 接收到訂閱訊息的回呼函式 (Callback)
void callback(char* topic, byte* payload, unsigned int length) {
String messageTemp;
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
messageTemp += (char)payload[i];
}
Serial.println();
// 顯示接收到的控制指令到 LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("MQTT Recv:");
lcd.setCursor(0, 1);
lcd.print(messageTemp);
// 判斷指令並控制 LED
if (String(topic) == topic_ctrl) {
if (messageTemp == "on1") {
digitalWrite(LED1_PIN, HIGH);
client.publish(topic_status, "ON1");
Serial.println("LED1 turned ON");
} else if (messageTemp == "off1") {
digitalWrite(LED1_PIN, LOW);
client.publish(topic_status, "OFF1");
Serial.println("LED1 turned OFF");
} else if (messageTemp == "on2") {
digitalWrite(LED2_PIN, HIGH);
client.publish(topic_status, "ON2");
Serial.println("LED2 turned ON");
} else if (messageTemp == "off2") {
digitalWrite(LED2_PIN, LOW);
client.publish(topic_status, "OFF2");
Serial.println("LED2 turned OFF");
}
}
delay(1500); // 讓使用者看清 LCD 上的控制訊息,隨後會被溫濕度刷掉
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connect MQTT...");
// 嘗試連接 (使用隨機 Client ID 避免衝突)
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
// 如果不需要帳密,請改為 client.connect(clientId.c_str())
if (client.connect(clientId.c_str(), mqtt_user, mqtt_pass)) {
Serial.println("connected");
lcd.setCursor(0, 1);
lcd.print("MQTT Connected!");
// 訂閱控制主題
client.subscribe(topic_ctrl);
delay(1000);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
lcd.setCursor(0, 1);
lcd.print("Failed! Retry...");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(LED1_PIN, OUTPUT);
pinMode(LED2_PIN, OUTPUT);
digitalWrite(LED1_PIN, LOW);
digitalWrite(LED2_PIN, LOW);
// 初始化 LCD
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Initializing...");
// 初始化 DHT22
dht.begin();
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
if (now - lastMsg > interval) {
lastMsg = now;
// 讀取溫濕度
float h = dht.readHumidity();
float t = dht.readTemperature();
// 檢查讀取是否失敗
if (isnan(h) || isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("DHT Read Error");
return;
}
// 顯示於 Serial Monitor
Serial.print("Humidity: ");
Serial.print(h);
Serial.print("% Temperature: ");
Serial.print(t);
Serial.println("°C");
// 顯示於 16x2 LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(t, 1);
lcd.print((char)223); // 顯示 ° 符號
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("Humi: ");
lcd.print(h, 1);
lcd.print("%");
// 發行到 MQTT
client.publish(topic_temp, String(t).c_str());
client.publish(topic_humi, String(h).c_str());
Serial.println("Data published to MQTT.");
}
}
MQTTX 設定畫面
https://mqttgo.io/ 設定畫面




























沒有留言:
張貼留言