2026年9月20日 星期日

Easybuilder pro + WOKWI esp32 LED (4Mode on off flash timer)

 Easybuilder pro + WOKWI esp32 LED (4Mode on off flash timer)






本專案實現使用 EasyBuilder Pro (HMI 人機介面) 透過 MQTT 通訊協定 (broker.mqtt-dashboard.com) 遠端控制 Wokwi ESP32 的 Pin 2 LED(包含 ON 常亮、OFF 關閉、FLASH 閃爍、TIMER 5秒計時 四種模式),並實時回傳狀態以點亮 HMI 上對應的指示燈。

系統架構與 JSON 資料格式定義

1. 控制命令 (HMI $\rightarrow$ ESP32)

當點擊 HMI 按鈕時,會發送 JSON 格式訊息:

  • alex9ufo/led1 $\rightarrow$ {"value": true} (開啟 LED / ON)

  • alex9ufo/led2 $\rightarrow$ {"value": true} (關閉 LED / OFF)

  • alex9ufo/led3 $\rightarrow$ {"value": true} (閃爍 LED / FLASH)

  • alex9ufo/led4 $\rightarrow$ {"value": true} (計時 5 秒亮 / TIMER)

2. 狀態回傳 (ESP32 $\rightarrow$ HMI)

當模式切換時,ESP32 會一次性更新 4 個狀態主題,採取互斥原則(當前模式為 true,其餘 3 個為 false):

  • 切換至 ONled1status 發行 {"value": true}led2~4status 發行 {"value": false} $\rightarrow$ LB-11 亮

  • 切換至 OFFled2status 發行 {"value": true}led1,3,4status 發行 {"value": false} $\rightarrow$ LB-12 亮

  • 切換至 FLASHled3status 發行 {"value": true}led1,2,4status 發行 {"value": false} $\rightarrow$ LB-13 亮

  • 切換至 TIMERled4status 發行 {"value": true}led1~3status 發行 {"value": false} $\rightarrow$ LB-14 亮(5 秒後自動切回 OFF 並更新狀態)

第一部分:EasyBuilder Pro 設定與規劃步驟

步驟 1:建立 MQTT 連線設定

  1. 開啟 EasyBuilder Pro,點選上方功能列 【常用】 $\rightarrow$ 【系統參數設定】

  2. 【裝置列表】 頁籤點選 【新增裝置...】

  3. 參數設定:

    • 裝置類型:選擇 MQTT (Client)MQTT Server/Client

    • IP / URLbroker.mqtt-dashboard.com

    • Port1883

    • Client ID:設為不重複字串(例如 HMI_Master_Client

步驟 2:規劃控制按鈕 (LB-1 ~ LB-4)

在 HMI 畫面上拖入 【MQTT 按鈕】【位元按鈕】

按鈕元件發送 MQTT Topic觸發動作 / 發送內容說明
LB-1alex9ufo/led1按下時發送 JSON:{"value": true}ON 按鈕
LB-2alex9ufo/led2按下時發送 JSON:{"value": true}OFF 按鈕
LB-3alex9ufo/led3按下時發送 JSON:{"value": true}FLASH 按鈕
LB-4alex9ufo/led4按下時發送 JSON:{"value": true}TIMER 按鈕

步驟 3:規劃狀態指示燈 (LB-11 ~ LB-14)

拖入 4 個 【位元燈 (Bit Lamp)】 元件:

  1. 雙擊位元燈進入設定,將讀取位址指定為 MQTT 訂閱

  2. 設定 JSON 解析路徑,綁定 value 欄位(當 value == true 時,位元燈顯示為狀態 1/亮起)。

指示燈元件訂閱 MQTT Topic顯示狀態
LB-11alex9ufo/led1statusvalue == true 時點亮(綠燈),false 時熄滅
LB-12alex9ufo/led2statusvalue == true 時點亮(紅燈),false 時熄滅
LB-13alex9ufo/led3statusvalue == true 時點亮(黃燈),false 時熄滅
LB-14alex9ufo/led4statusvalue == true 時點亮(藍燈),false 時熄滅

第二部分:Wokwi ESP32 Arduino 完整程式碼說明

此程式具備以下特點:

  1. 非阻塞式架構 (millis()):閃爍與 5 秒倒數不會卡住 loop(),可隨時接收新指令。

  2. JSON 格式解析:過濾與判斷 {"value": true},若收到 false 則自動忽略。

  3. 狀態互斥發行:每次狀態切換,一次性輸出 4 個 Topic 的 true/false 狀態。

  4. Serial Monitor 日誌:將 WiFi 連線、MQTT 收發主題與內文即時顯示於序列埠監控器。

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

// WiFi 與 MQTT 設定
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "broker.mqtt-dashboard.com";

WiFiClient espClient;
PubSubClient client(espClient);

// 引腳定義
const int ledPin = 2;

// 運行模式列舉
enum LedMode { MODE_OFF, MODE_ON, MODE_FLASH, MODE_TIMER };
LedMode currentMode = MODE_OFF;

// 時間控制變數
unsigned long previousMillis = 0;
const long flashInterval = 300; // 閃爍間隔 300ms
unsigned long timerStartMillis = 0;
const long timerDuration = 5000; // 5秒定時
bool flashState = LOW;

// 發送 MQTT JSON 狀態訊息:指定的 activeMode 發行 true,其餘 3 個發行 false
void updateAllStatusTopics(LedMode activeMode) {
  currentMode = activeMode;

  const char* topics[4] = {
    "alex9ufo/led1status", // ON 狀態 (MODE_ON = 1)
    "alex9ufo/led2status", // OFF 狀態 (MODE_OFF = 0)
    "alex9ufo/led3status", // FLASH 狀態 (MODE_FLASH = 2)
    "alex9ufo/led4status"  // TIMER 狀態 (MODE_TIMER = 3)
  };

  LedMode modes[4] = { MODE_ON, MODE_OFF, MODE_FLASH, MODE_TIMER };

  Serial.println("----------------------------------------");
  Serial.print("[狀態更新] 當前啟用模式: ");
  switch(activeMode) {
    case MODE_ON:    Serial.println("ON (常亮)"); break;
    case MODE_OFF:   Serial.println("OFF (關閉)"); break;
    case MODE_FLASH: Serial.println("FLASH (閃爍)"); break;
    case MODE_TIMER: Serial.println("TIMER (5秒計時)"); break;
  }

  // 循環發行 4 個主題的狀態
  for (int i = 0; i < 4; i++) {
    if (modes[i] == activeMode) {
      client.publish(topics[i], "{\"value\":true}");
      Serial.print("[PUB 發行] ");
      Serial.print(topics[i]);
      Serial.println(" -> {\"value\":true}");
    } else {
      client.publish(topics[i], "{\"value\":false}");
      Serial.print("[PUB 發行] ");
      Serial.print(topics[i]);
      Serial.println(" -> {\"value\":false}");
    }
  }
  Serial.println("----------------------------------------");
}

// 解析 JSON 字串是否包含 "value": true 或 "value":true
bool parseJsonValueIsTrue(String msg) {
  msg.replace(" ", "");
  msg.replace("\n", "");
  msg.replace("\r", "");
  msg.toLowerCase();
 
  return (msg.indexOf("\"value\":true") != -1);
}

// MQTT 訊息接收回調函數
void callback(char* topic, byte* payload, unsigned int length) {
  String message = "";
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
  }
 
  String strTopic = String(topic);
 
  Serial.println();
  Serial.print("[SUB 收到訂閱訊息] Topic: ");
  Serial.print(strTopic);
  Serial.print(" | Payload: ");
  Serial.println(message);

  // 判斷 value 是否為 true,若為 false 或解析失敗則忽略不處理
  if (!parseJsonValueIsTrue(message)) {
    Serial.println(">> value 為 false 或格式無效,忽略不發行。");
    return;
  }

  // 接收到 true 命令時先重置 LED 引腳
  digitalWrite(ledPin, LOW);

  // 切換模式並一次發行 1 個 true 與 3 個 false
  if (strTopic == "alex9ufo/led1") {
    digitalWrite(ledPin, HIGH);
    updateAllStatusTopics(MODE_ON);
  }
  else if (strTopic == "alex9ufo/led2") {
    digitalWrite(ledPin, LOW);
    updateAllStatusTopics(MODE_OFF);
  }
  else if (strTopic == "alex9ufo/led3") {
    updateAllStatusTopics(MODE_FLASH);
  }
  else if (strTopic == "alex9ufo/led4") {
    digitalWrite(ledPin, HIGH);
    timerStartMillis = millis();
    updateAllStatusTopics(MODE_TIMER);
  }
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("正在嘗試連接 MQTT Broker: ");
    Serial.println(mqtt_server);
   
    String clientId = "ESP32Client-" + String(random(0xffff), HEX);
    if (client.connect(clientId.c_str())) {
      Serial.println(">> MQTT 連線成功!");
     
      client.subscribe("alex9ufo/led1");
      client.subscribe("alex9ufo/led2");
      client.subscribe("alex9ufo/led3");
      client.subscribe("alex9ufo/led4");
     
      Serial.println(">> 已成功訂閱主題: alex9ufo/led1 ~ led4");
     
      // 連線成功時預設進入 OFF 狀態,發行 led2status=true,其餘=false
      digitalWrite(ledPin, LOW);
      updateAllStatusTopics(MODE_OFF);
    } else {
      Serial.print(">> 連線失敗, rc=");
      Serial.print(client.state());
      Serial.println(" 5 秒後重試...");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  delay(500);
 
  Serial.println("\n=== ESP32 MQTT LED 控制系統 (互斥狀態發行模式) ===");

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  Serial.print("正在連接 WiFi: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("\n>> WiFi 連線成功!");
  Serial.print(">> ESP32 IP 位址: ");
  Serial.println(WiFi.localIP());

  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

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

  unsigned long currentMillis = millis();

  // 1. FLASH 閃爍模式處理
  if (currentMode == MODE_FLASH) {
    if (currentMillis - previousMillis >= flashInterval) {
      previousMillis = currentMillis;
      flashState = !flashState;
      digitalWrite(ledPin, flashState);
    }
  }

  // 2. TIMER 定時 5 秒模式處理
  if (currentMode == MODE_TIMER) {
    if (currentMillis - timerStartMillis >= timerDuration) {
      Serial.println("\n[TIMER 倒數結束] 5 秒時間到,自動關閉並切換為 OFF 狀態");
      digitalWrite(ledPin, LOW);
      updateAllStatusTopics(MODE_OFF); // 時間到後自動切換為 OFF,更新狀態
    }
  }
}









2026年9月17日 星期四

2026-09 mqtt 實驗3

 2026-09 mqtt 實驗3


node-red參考網址

Node-RED入門課程

Node-Red - 1: 安裝 Node-RED

Node-Red - 2: Node-RED 啟動、關閉、開機自動執行、移除

Node-Red - 3: 程式初體驗 Hello World、什麼是 payload、物件

Node-Red - 4: 函數及樂透號碼計算

Node-Red - 5: dashboard模版,視覺化輸出的起點

Node-Red - 6: 序列控制LED

Node_Red - 7: 透過序列傳送,在dashboard顯示溫度

Node-Red - 8: 透過序列同時顯示溫、溼度 (如何拆分複合資料)

Node-Red - 9: MQTT簡介

Node-Red - 10: MQTTX軟體操作

Node-Red - 11: 訂閱MQTT訊息輸出至dashboard

Node-Red - 12: 在 iOS 的 EasyMQTT 訂閱資料

Node-Red - 13: 在手機上安裝 NodeRed








這套系統將 ESP32(硬體感知端)Node-RED(軟體控制端) 結合,打造了一個具備即時雙向通訊、閉環確認(ACK)與圖形化遠端監控的完整物聯網 (IoT) 架構。

系統整體運作流程與互動架構

  • 環境數據監測與雙向握手(下到上 + ACK 確認)

    1. ESP32 每 2 秒從 DHT22 採集溫濕度數據,經由 MQTT 發行至 temphumi 主題。

    2. Node-RED 接收數據後,即時更新網頁 Dashboard 上的溫度(深紅)與濕度(深綠)數值。

    3. Node-RED 收到數據時,會主動發送確認訊號至 tempOKhumiOK 主題。

    4. ESP32 收到 ACK 訊號後,在 Serial Monitor 印出 temp_Rx_OKhumi_Rx_OK,確保資料成功送達。

  • 遠端 LED 命令控制與狀態反饋(上到下 + 狀態回傳)

    1. 使用者在 Node-RED Dashboard 點擊按鈕(ONOFFFLASHTimer),將控制指令發行至 led 主題。

    2. ESP32 接收指令後切換 GPIO 2 電位或計時模式,並同步回傳當前狀態至 ledstatus 主題(如 on_ledflash_led)。

    3. Node-RED 收到狀態反饋後,同步更新 Dashboard 上的 LED 狀態文字(藍色)。

    4. 若觸發 5 秒定時(Timer),時間到達時 ESP32 會自動關燈並發送 off_led,Node-RED 介面也會同步變更為關閉狀態。

兩者整體功能對比表

功能維度Node-RED 程式(軟體控制層)Wokwi ESP32 程式(硬體感知層)
主要角色系統指揮中心、圖形化人機介面 (GUI)硬體執行器、數據採集節點
通訊協定MQTT (Pub/Sub)MQTT (Pub/Sub)
數據處理接收溫濕度並發行 OK ACK;接收 LED 狀態讀取 DHT22 並發行數據;接收 OK ACK 並印出紀錄
控制邏輯提供按鈕觸發控制指令發行解析控制指令,驅動 GPIO 2(點亮/關閉/閃爍/5秒定時)
使用者互動網頁化 Dashboard (/ui) 提供視覺化監控Serial Monitor 輸出除錯日誌與硬體 LED 實體反應

Node-RED 程式功能說明

Node-RED 程式取代了原本 Python + Tkinter 的角色,扮演系統圖形化介面 (Dashboard) 與控制邏輯中樞,主要功能包含:

  • MQTT 網路連線與主題訂閱:自動連接至 broker.hivemq.com:1883,並即時訂閱 ESP32 發佈的三個主題:

    • alex9ufo/2026/ledstatus:接收 LED 當前狀態。

    • alex9ufo/2026/temp:接收實時溫度數據。

    • alex9ufo/2026/humi:接收實時濕度數據。

  • Dashboard 圖形化 UI 介面:透過 node-red-dashboard 在網頁端 (/ui) 提供與原本 Python 介面相同的顯示與控制按鈕:

    • 文字顯示區:以不同顏色呈現 LED 狀態(藍色)、環境溫度(深紅)與環境濕度(深綠)。

    • 命令按鈕區:提供 ONOFFFLASHTimer (定時5秒) 四個按鈕,點擊時將指令發行至 alex9ufo/2026/led 主題。

  • 自動握手確認 (Handshake ACK)

    • 當接收到溫度資料時,觸發 Function 節點自動發送 "OK" 訊息至 alex9ufo/2026/tempOK 主題。

    • 當接收到濕度資料時,觸發 Function 節點自動發送 "OK" 訊息至 alex9ufo/2026/humiOK 主題。

Wokwi ESP32 程式功能說明

ESP32 程式為硬體感知與致動核心,負責實體(或模擬)硬體的控制與數據採集,主要功能包含:

  • Wi-Fi 與 MQTT 自動連線:開機後連接至 Wokwi-GUEST 熱點,並連接至 broker.hivemq.com。連線成功後訂閱控制主題 alex9ufo/2026/led 以及兩個握手主題 tempOKhumiOK

  • LED 狀態控制與回報:收到控制命令時切換模式,並向 alex9ufo/2026/ledstatus 回報狀態(on_ledoff_ledflash_ledtimer(5Sec)_led)。

  • 溫濕度感測與定期發行:在 loop() 中使用 millis() 計時,每 2 秒透過 DHT22 讀取溫濕度,並分別發行至 alex9ufo/2026/tempalex9ufo/2026/humi 主題。

  • 接收確認訊息 (ACK 驗證):當收到來自 Node-RED 的 tempOKhumiOK 訊息時,於 Serial Monitor 印出 temp_Rx_OKhumi_Rx_OK,用以驗證訊息已成功傳遞至 Node-RED。

  • 非阻塞式模式運作

    • FLASH 模式:每 500 毫秒翻轉一次 GPIO 2 電位。

    • TIMER 模式:計時 5 秒後自動熄滅 LED,切回 OFF 模式並發布 off_led 狀態給 Node-RED。

ESP32程式
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

#define DHTPIN 4
#define DHTTYPE DHT22

const char* ssid = "Wokwi-GUEST";
const char* password = "";

const char* mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;

const char* sub_topic = "alex9ufo/2026/led";
const char* pub_topic = "alex9ufo/2026/ledstatus";
const char* temp_topic = "alex9ufo/2026/temp";
const char* humi_topic = "alex9ufo/2026/humi";
const char* temp_ok_topic = "alex9ufo/2026/tempOK";
const char* humi_ok_topic = "alex9ufo/2026/humiOK";

const int ledPin = 2;

WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(DHTPIN, DHTTYPE);

enum Mode { OFF, ON, FLASH, TIMER };
Mode currentMode = OFF;

unsigned long lastFlashTime = 0;
unsigned long timerStartTime = 0;
unsigned long lastDHTTime = 0;
bool ledState = LOW;

void setup_wifi() {
  delay(10);
  Serial.print("[Wi-Fi] 正在連線至 ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\n[Wi-Fi] 已成功連線!");
}

void publishStatus(const char* payload) {
  client.publish(pub_topic, payload);
  Serial.print("[MQTT 發行] LED 狀態: ");
  Serial.println(payload);
}

void callback(char* topic, byte* payload, unsigned int length) {
  String message;
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
  }

  Serial.print("[MQTT 接收] 主題: ");
  Serial.print(topic);
  Serial.print(" | Payload: ");
  Serial.println(message);

  // 接收 tempOK 主題
  if (String(topic) == temp_ok_topic) {
    Serial.println("temp_Rx_OK");
    return;
  }
 
  // 接收 humiOK 主題
  if (String(topic) == humi_ok_topic) {
    Serial.println("humi_Rx_OK");
    return;
  }

  if (message == "on") {
    currentMode = ON;
    digitalWrite(ledPin, HIGH);
    publishStatus("on_led");
  } else if (message == "off") {
    currentMode = OFF;
    digitalWrite(ledPin, LOW);
    publishStatus("off_led");
  } else if (message == "flash") {
    currentMode = FLASH;
    publishStatus("flash_led");
  } else if (message == "timer(5Sec)") {
    currentMode = TIMER;
    timerStartTime = millis();
    digitalWrite(ledPin, HIGH);
    publishStatus("timer(5Sec)_led");
  }
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("[MQTT] 正在嘗試連線至 Broker: ");
    Serial.println(mqtt_server);
    String clientId = "ESP32Client-" + String(random(0xffff), HEX);
    if (client.connect(clientId.c_str())) {
      Serial.println("[MQTT] 連線成功!");
      client.subscribe(sub_topic);
      client.subscribe(temp_ok_topic); // 訂閱 tempOK
      client.subscribe(humi_ok_topic); // 訂閱 humiOK
    } else {
      Serial.print("[MQTT] 連線失敗, rc=");
      Serial.print(client.state());
      Serial.println(" 5 秒後重試...");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  dht.begin();
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
}

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

  unsigned long currentMillis = millis();

  // 每 2 秒讀取並發行溫濕度
  if (currentMillis - lastDHTTime >= 5000) {
    lastDHTTime = currentMillis;
    float h = dht.readHumidity();
    float t = dht.readTemperature();

    if (!isnan(h) && !isnan(t)) {
      client.publish(temp_topic, String(t, 1).c_str());
      client.publish(humi_topic, String(h, 1).c_str());
      Serial.printf("[DHT22] 溫度: %.1f °C | 濕度: %.1f %%\n", t, h);
    }
  }

  if (currentMode == FLASH) {
    if (currentMillis - lastFlashTime >= 500) {
      lastFlashTime = currentMillis;
      ledState = !ledState;
      digitalWrite(ledPin, ledState);
    }
  } else if (currentMode == TIMER) {
    if (currentMillis - timerStartTime >= 5000) {
      digitalWrite(ledPin, LOW);
      currentMode = OFF;
      publishStatus("off_led");
    }
  }
}

Node-Red程式

[{"id":"e98647487e9c1821","type":"mqtt in","z":"191b6456391ed604","name":"Sub LED Status","topic":"alex9ufo/2026/ledstatus","qos":"0","datatype":"auto-detect","broker":"hivemq_broker","nl":false,"rap":true,"rh":0,"inputs":0,"x":100,"y":80,"wires":[["0c7b0f3d1068f7c4"]]},{"id":"0c7b0f3d1068f7c4","type":"function","z":"191b6456391ed604","name":"格式化 LED 狀態","func":"msg.payload = \"LED 狀態: \" + msg.payload;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":80,"wires":[["33cbcbe74dbe1b6b"]]},{"id":"33cbcbe74dbe1b6b","type":"ui_text","z":"191b6456391ed604","group":"esp32_group","order":1,"width":4,"height":1,"name":"LED 狀態顯示","label":"","format":"<div style='color:blue; font-weight:bold; font-size:18px; text-align:center;'>{{msg.payload}}</div>","layout":"col-center","x":540,"y":80,"wires":[]},{"id":"53a8cbf4a4c56341","type":"mqtt in","z":"191b6456391ed604","name":"Sub Temp","topic":"alex9ufo/2026/temp","qos":"0","datatype":"auto-detect","broker":"hivemq_broker","nl":false,"rap":true,"rh":0,"inputs":0,"x":90,"y":160,"wires":[["3fe49a7cc8e45de4","14fd1a1b7f5cbe31","a75de3836fdff505"]]},{"id":"3fe49a7cc8e45de4","type":"function","z":"191b6456391ed604","name":"格式化溫度","func":"msg.payload = \"環境溫度: \" + msg.payload + \" °C\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":140,"wires":[["dcba01ce9b17d90f"]]},{"id":"14fd1a1b7f5cbe31","type":"function","z":"191b6456391ed604","name":"組裝 TempOK","func":"msg.payload = \"OK\";\nmsg.topic = \"alex9ufo/2026/tempOK\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":220,"wires":[["56a3f7a8fd77616c"]]},{"id":"dcba01ce9b17d90f","type":"ui_text","z":"191b6456391ed604","group":"esp32_group","order":3,"width":4,"height":1,"name":"溫度顯示","label":"","format":"<div style='color:darkred; font-weight:bold; font-size:18px; text-align:center;'>{{msg.payload}}</div>","layout":"col-center","x":520,"y":140,"wires":[]},{"id":"ef09c2f981a95de5","type":"mqtt in","z":"191b6456391ed604","name":"Sub Humi","topic":"alex9ufo/2026/humi","qos":"0","datatype":"auto-detect","broker":"hivemq_broker","nl":false,"rap":true,"rh":0,"inputs":0,"x":90,"y":260,"wires":[["4f1df0d2769d467c","4bb11901439c7593","e0fdb83f522c47ce"]]},{"id":"4f1df0d2769d467c","type":"function","z":"191b6456391ed604","name":"格式化濕度","func":"msg.payload = \"環境濕度: \" + msg.payload + \" %\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":260,"wires":[["bca3c946b461e603"]]},{"id":"4bb11901439c7593","type":"function","z":"191b6456391ed604","name":"組裝 HumiOK","func":"msg.payload = \"OK\";\nmsg.topic = \"alex9ufo/2026/humiOK\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":340,"wires":[["56a3f7a8fd77616c"]]},{"id":"bca3c946b461e603","type":"ui_text","z":"191b6456391ed604","group":"esp32_group","order":4,"width":4,"height":1,"name":"濕度顯示","label":"","format":"<div style='color:darkgreen; font-weight:bold; font-size:18px; text-align:center;'>{{msg.payload}}</div>","layout":"col-center","x":520,"y":260,"wires":[]},{"id":"7e56b6a33e7f720c","type":"ui_button","z":"191b6456391ed604","name":"ON 按鈕","group":"esp32_group","order":6,"width":4,"height":1,"passthru":false,"label":"ON (開啟)","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"on","payloadType":"str","topic":"alex9ufo/2026/led","topicType":"str","x":260,"y":420,"wires":[["56a3f7a8fd77616c"]]},{"id":"8975ee23cc5c1257","type":"ui_button","z":"191b6456391ed604","name":"OFF 按鈕","group":"esp32_group","order":8,"width":4,"height":1,"passthru":false,"label":"OFF (關閉)","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"off","payloadType":"str","topic":"alex9ufo/2026/led","topicType":"str","x":260,"y":460,"wires":[["56a3f7a8fd77616c"]]},{"id":"a4d8b92c7d3bdbd9","type":"ui_button","z":"191b6456391ed604","name":"FLASH 按鈕","group":"esp32_group","order":9,"width":4,"height":1,"passthru":false,"label":"FLASH (閃爍)","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"flash","payloadType":"str","topic":"alex9ufo/2026/led","topicType":"str","x":270,"y":500,"wires":[["56a3f7a8fd77616c"]]},{"id":"e59cef064b02ae83","type":"ui_button","z":"191b6456391ed604","name":"Timer 按鈕","group":"esp32_group","order":10,"width":4,"height":1,"passthru":false,"label":"Timer (定時5秒)","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"timer(5Sec)","payloadType":"str","topic":"alex9ufo/2026/led","topicType":"str","x":270,"y":540,"wires":[["56a3f7a8fd77616c"]]},{"id":"56a3f7a8fd77616c","type":"mqtt out","z":"191b6456391ed604","name":"MQTT 發行節點","topic":"","qos":"0","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"hivemq_broker","x":580,"y":480,"wires":[]},{"id":"a75de3836fdff505","type":"ui_gauge","z":"191b6456391ed604","name":"","group":"esp32_group","order":2,"width":6,"height":4,"gtype":"gage","title":"環境溫度","label":"°C","format":"{{value}}","min":"-40","max":"80","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","diff":false,"className":"","x":520,"y":200,"wires":[]},{"id":"e0fdb83f522c47ce","type":"ui_gauge","z":"191b6456391ed604","name":"","group":"esp32_group","order":7,"width":6,"height":4,"gtype":"gage","title":"環境濕度","label":"%","format":"{{value}}","min":"0","max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"50","seg2":"75","diff":false,"className":"","x":520,"y":320,"wires":[]},{"id":"hivemq_broker","type":"mqtt-broker","name":"HiveMQ Broker","broker":"broker.hivemq.com","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true},{"id":"esp32_group","type":"ui_group","name":"ESP32 LED & DHT22 控制器","tab":"esp32_dashboard_tab","order":1,"disp":true,"width":10,"collapse":false},{"id":"esp32_dashboard_tab","type":"ui_tab","name":"ESP32 控制面板","icon":"dashboard","disabled":false,"hidden":false},{"id":"86c9ae5506a16be4","type":"global-config","env":[],"modules":{"node-red-dashboard":"3.6.6"}}]

Easybuilder pro + WOKWI esp32 LED (4Mode on off flash timer)

 Easybuilder pro + WOKWI esp32 LED (4Mode on off flash timer) 本專案實現使用 EasyBuilder Pro (HMI 人機介面) 透過 MQTT 通訊協定 (broker.mqtt-dashboard.com) ...