2026年9月12日 星期六

Easybuilder pro + WOKWI esp32 LED控制 (MQTT)

Easybuilder pro + WOKWI esp32 LED控制  (MQTT)







EasyBuilder Pro 搭配 MQTT 與 ESP32 進行雙向控制時,MQTT 物件按鈕/燈號元件的具體設定步驟如下:

一、 建立 MQTT 物件設定 (MQTT Server)

  1. 開啟 EasyBuilder Pro,點選上方選單 [物件] $\rightarrow$ [MQTT]

  2. [屬性] 頁籤設定連線參數:

    • IP / 主機名稱: broker.hivemq.com (即 mqtt-dashboard.com 預設的 Broker)

    • 通訊埠 (Port): 1883

    • Client ID: 可使用預設或自訂(例如 EBPro_HMI_Client)。

  3. 切換至 [位址映射 (Address Mapping)] 頁籤,新增 4 組控制(Publish)與 4 組接收(Subscribe)主題:

1. 控制主題設定 (發行 Publish - 控制 ESP32)

  • 主題名稱: alex9ufo/ebpro_wokwi/led1(LED 2~4 依此類推)

  • 對應 HMI 位址: 設定為 LB-0(LED 2~4 分別對應 LB-1, LB-2, LB-3)

  • 資料格式: JSON 格式(內含 value 陣列)

2. 狀態主題設定 (訂閱 Subscribe - 接收 ESP32 狀態)

  • 主題名稱: alex9ufo/ebpro_wokwi/ledstatus1(LED 2~4 依此類推)

  • 對應 HMI 位址: 設定為 LB-10(LED 2~4 分別對應 LB-11, LB-12, LB-13)

  • 資料格式: JSON 格式(內含 value 陣列)

二、 畫面元件對應設定 (HMI 物件)

1. 控制開關 (LB-0 ~ LB-3)

  • 點選上方 [位元切換開關 (Bit Switch)] 並放至畫面上。

  • 讀寫位址設定:

    • 寫入位址 (Write Address): 設定為 LB-0 (對應 alex9ufo/ebpro_wokwi/led1)

  • 開關型態: 切換 (Toggle) 或 交替 (Alternate)。

  • 動作機制: 按下 ON 時,HMI 會經由 MQTT 自動送出 {"value":[true]};按下 OFF 時送出 {"value":[false]}

2. 狀態指示燈 (LB-10 ~ LB-13)

  • 點選上方 [位元指示燈 (Bit Lamp)] 並放至畫面上。

  • 讀取位址設定:

    • 讀取位址 (Read Address): 設定為 LB-10 (對應 alex9ufo/ebpro_wokwi/ledstatus1)

  • 動作機制: 當 ESP32 改變 GPIO 狀態並回傳 {"value":[true]} 時,HMI 接收到訊息會自動將 LB-10 暫存器設為 1(指示燈點亮)。

三、 點位對應總表

功能描述HMI 暫存器MQTT 發行 / 訂閱主題ESP32 GPIO
LED 1 控制按鈕LB-0alex9ufo/ebpro_wokwi/led1 (HMI 發行)GPIO 23
LED 2 控制按鈕LB-1alex9ufo/ebpro_wokwi/led2 (HMI 發行)GPIO 22
LED 3 控制按鈕LB-2alex9ufo/ebpro_wokwi/led3 (HMI 發行)GPIO 21
LED 4 控制按鈕LB-3alex9ufo/ebpro_wokwi/led4 (HMI 發行)GPIO 19
LED 1 狀態燈LB-10alex9ufo/ebpro_wokwi/ledstatus1 (HMI 訂閱)GPIO 23 (回傳)
LED 2 狀態燈LB-11alex9ufo/ebpro_wokwi/ledstatus2 (HMI 訂閱)GPIO 22 (回傳)
LED 3 狀態燈LB-12alex9ufo/ebpro_wokwi/ledstatus3 (HMI 訂閱)GPIO 21 (回傳)
LED 4 狀態燈LB-13alex9ufo/ebpro_wokwi/ledstatus4 (HMI 訂閱)GPIO 19 (回傳)


這份程式碼是專為 ESP32 微控制器 設計的 MQTT 遠端控制與狀態回報程式,主要用於配合 EasyBuilder Pro 人機介面 (HMI)Wokwi 線上模擬器 進行 4 路繼電器/LED 的控制。

系統架構說明

  • 通訊協定: MQTT Protocol (MQTT Broker: broker.hivemq.com / 1883 Port)

  • 硬體控制腳位: GPIO 23, 22, 21, 19(分別對應 4 顆 LED / Relay)

  • 控制流程: EasyBuilder Pro 發送指令 $\rightarrow$ ESP32 接收並控制 GPIO $\rightarrow$ ESP32 回傳最新狀態給 EasyBuilder Pro 顯示

核心功能區塊解析

1. 網路與 MQTT 連線建立 (setup_wifi / reconnect)

  • setup_wifi() 嘗試連接至 Wokwi 模擬器的虛擬 WiFi (Wokwi-GUEST),成功後會在 Serial Monitor 印出 ESP32 取得的 IP 位址。

  • reconnect() 當 MQTT 斷線時,會自動嘗試重新連線至 Broker。連線成功後,會一次性訂閱 (Subscribe) 4 個控制主題 (subTopics):

    • alex9ufo/ebpro_wokwi/led1 ~ led4

2. MQTT 訊息接收與解析 (callback)

當 HMI 按下按鈕發送控制指令時,ESP32 會觸發此回傳函式:

  1. 印出接收日誌: 在 Serial Monitor 印出收到的 Topic 與原始 Payload 訊息。

  2. 格式與狀態判斷:

    • 將接收到的字串轉為小寫並去除空白。

    • 支援多種格式: 無論 HMI 發送的是純字串 ("true", "1", "on") 或是 EasyBuilder Pro 預設的 JSON 格式 ({"value":[true]}),程式皆能正確識別並將硬體開關狀態設為 HIGH(亮)或 LOW(滅)。

  3. 執行硬體動作: 透過 digitalWrite(ledPins[i], state) 直接切換對應 GPIO 腳位的電位。

3. 狀態即時回報 (callback 後半段)

為確保 EasyBuilder Pro 的指示燈 (LB-10 ~ LB-13) 能同步顯示正確狀態,ESP32 在改變 GPIO 後會立即執行狀態發行 (Publish)

  • 發送格式: 打包為 JSON 格式字串 {"value":[true]}{"value":[false]}

  • 發行主題 (pubTopics):

    • alex9ufo/ebpro_wokwi/ledstatus1 ~ ledstatus4

  • 偵錯回報: 發送成功或失敗均會在 Serial Monitor 輸出結果,方便即時觀察通訊狀態。

4. 主程式循環 (setup / loop)

  • setup() 初始化 Serial 通訊埠(波特率 115200),將 4 個 GPIO 設定為輸出模式 (OUTPUT) 並預設輸出低電位 (LOW 關閉),最後啟動 WiFi 與 MQTT 設定。

  • loop() 持續檢查 MQTT 連線狀態,若斷線則呼叫 reconnect(),並透過 client.loop() 維持 MQTT 訊息封包的收發與心跳包(Keep-Alive)。

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

// WiFi 與 MQTT Broker 設定
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "mqtt-dashboard.com";   // 即 mqtt-dashboard.com 使用的 Broker
const int mqtt_port = 1883;

// GPIO 引腳配置 (依照圖中 D23, D22, D21, D19)
const int ledPins[4] = {23, 22, 21, 19};

// MQTT 主題配置
const char* subTopics[4] = {
  "alex9ufo/ebpro_wokwi/led1",
  "alex9ufo/ebpro_wokwi/led2",
  "alex9ufo/ebpro_wokwi/led3",
  "alex9ufo/ebpro_wokwi/led4"
};

const char* pubTopics[4] = {
  "alex9ufo/ebpro_wokwi/ledstatus1",
  "alex9ufo/ebpro_wokwi/ledstatus2",
  "alex9ufo/ebpro_wokwi/ledstatus3",
  "alex9ufo/ebpro_wokwi/ledstatus4"
};

WiFiClient espClient;
PubSubClient client(espClient);

// 1) 連上 WiFi 顯示於 Serial Monitor
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("[WiFi] Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("[WiFi] Connected successfully!");
  Serial.print("[WiFi] IP Address: ");
  Serial.println(WiFi.localIP());
}

// 2) 收到 MQTT 訊息時解析 JSON 並處理 GPIO
void callback(char* topic, byte* payload, unsigned int length) {
  String message = "";
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
  }

  Serial.println("----------------------------------------");
  Serial.print("[MQTT RX] Message arrived on topic: ");
  Serial.println(topic);
  Serial.print("[MQTT RX] Payload: ");
  Serial.println(message);

  // 整理字串以利比對
  message.trim();
  message.toLowerCase();

  for (int i = 0; i < 4; i++) {
    if (String(topic) == subTopics[i]) {
      int state = LOW;

      // 支援 JSON 中的 true 與純文字格式 ("true", "1", "on")
      if (message.indexOf("true") != -1 || message == "1" || message == "on") {
        state = HIGH;
      } else if (message.indexOf("false") != -1 || message == "0" || message == "off") {
        state = LOW;
      }

      digitalWrite(ledPins[i], state);
      Serial.print("[Hardware] LED ");
      Serial.print(i + 1);
      Serial.print(" (GPIO ");
      Serial.print(ledPins[i]);
      Serial.print(") set to: ");
      Serial.println(state == HIGH ? "ON" : "OFF");

      // 3) 發行 JSON 格式訊息給 EasyBuilder Pro 讀取 (LB-10 ~ LB-13)
      String pubPayload = (state == HIGH) ? "{\"value\":[true]}" : "{\"value\":[false]}";
      bool published = client.publish(pubTopics[i], pubPayload.c_str());

      if (published) {
        Serial.print("[MQTT TX] Published status to topic: ");
        Serial.println(pubTopics[i]);
        Serial.print("[MQTT TX] Payload: ");
        Serial.println(pubPayload);
      } else {
        Serial.print("[MQTT TX ERROR] Failed to publish to topic: ");
        Serial.println(pubTopics[i]);
      }
      Serial.println("----------------------------------------");
      break;
    }
  }
}

// MQTT 斷線重連機制
void reconnect() {
  while (!client.connected()) {
    Serial.print("[MQTT] Attempting MQTT connection to ");
    Serial.print(mqtt_server);
    Serial.print("...");
   
    String clientId = "ESP32Client-" + String(random(0xffff), HEX);
    if (client.connect(clientId.c_str())) {
      Serial.println(" connected!");
     
      // 重新訂閱主題
      for (int i = 0; i < 4; i++) {
        client.subscribe(subTopics[i]);
        Serial.print("[MQTT] Subscribed to: ");
        Serial.println(subTopics[i]);
      }
    } else {
      Serial.print(" failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.println("\n========================================");
  Serial.println("  ESP32 EasyBuilder Pro MQTT Controller ");
  Serial.println("========================================");

  // 初始化 GPIO 引腳
  for (int i = 0; i < 4; i++) {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], LOW);
  }

  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

沒有留言:

張貼留言

Easybuilder pro + WOKWI esp32 DHT22 控制 (MQTT)

Easybuilder pro + WOKWI esp32 DHT22 控制  (MQTT) EasyBuilder Pro 點位與暫存器對應說明 要在 HMI 畫面上正確顯示數值(如您上圖中的「數值顯示欄」與「表盤」): MQTT 物件設定: 訂閱主題 1: alex9ufo...