2026年7月3日 星期五

MQTT 說明練習 EX1 (PC MQTTX Client , online mqttgo.io , 手機 Iot MQTT Panel)

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(連接埠)
    • 1883:一般的未加密 TCP 連線(最常用於測試)。
    • 8883:安全加密的 SSL/TLS 連線(生產環境建議使用)。
    • 8083 / 8084:網頁端 WebSocket 連線專用。 [1, 2]
  • 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 (手機)

MQTTX 下載點 (PC)

https://www.emqx.com/en/downloads/MQTTX


https://mqttgo.io/   (online)

WOKWI 程式 與 線路

🛠️ 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/   設定畫面




IoT MQTT Panel   設定畫面

2個 switch , 2個 LED , 1個 Gauge , 1個 Line Graph

最後的畫面
元件設定畫面


裡面的Panel name 需修改成 SW1 , LED1 , SW2 ,LED2,溫度 濕度





















沒有留言:

張貼留言

MQTT 說明練習 EX1 (PC MQTTX Client , online mqttgo.io , 手機 Iot MQTT Panel)

MQTT 說明練習 EX1 (PC MQTTX Client , online mqttgo.io , 手機 Iot MQTT Panel)  設定 MQTT 連線時,最核心的四個基本參數為:Broker(伺服器網址)、Port(連接埠)、Topic(主題)以及 Client I...