顯示具有 EasyBuilderPro HMI 標籤的文章。 顯示所有文章
顯示具有 EasyBuilderPro HMI 標籤的文章。 顯示所有文章

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):

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

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

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

  • 切換至 TIMER:led4status 發行 {"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 / URL:broker.mqtt-dashboard.com

    • Port:1883

    • 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/led1status當 value == true 時點亮(綠燈),false 時熄滅
LB-12alex9ufo/led2status當 value == true 時點亮(紅燈),false 時熄滅
LB-13alex9ufo/led3status當 value == true 時點亮(黃燈),false 時熄滅
LB-14alex9ufo/led4status當 value == 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年8月17日 星期一

Cargo Transfer Process Simulation 「貨物轉移過程模擬」

Cargo Transfer Process Simulation「貨物轉移過程模擬」

https://www.youtube.com/watch?v=Ic9PpPG-_NU



 以下是操作步驟:

  1. 打開 EasyBuilder Pro,選擇「新建專案」(New Project),接著選擇「MT8102iE」機型。
這是威綸科技(Weintek)人機介面(HMI)的專案設定步驟。若您需要,我可以繼續為您:
  • 翻譯後續的 EasyBuilder Pro 操作步驟
  • 提供 MT8102iE 與 PLC 連線的通訊設定教學
  1. 彈出「系統屬性」(System Properties)視窗,點擊「確定」(OK)。
  2. 進入 HMI 畫面,請參照下表新增對應的元件:
  3. 夾爪、瓶子和紙箱的圖片,請至此連結下載:[HMI 圖片]
  4. HMI 畫面上的元件外觀,理應呈現如下圖所示:
  5. 為了讓這些元件能依據期望的流程運行,請新增巨集(Macro)。本次將建立 2 個巨集:第一個巨集用於設定所有元件的初始狀態,且僅在程式啟動時執行一次。第二個巨集用於持續循環執行程式,使期望的製程得以運作。欲建立第一個巨集,請開啟「專案」(Project)選單,點擊「巨集」(Macro)按鈕,並在巨集視窗中輸入以下程式碼:macro-0
  6. 將 macro-0 程式碼輸入至工作區(Work Space)後,勾選「HMI 啟動時執行一次」(Execute one time when HMI starts)選項。
  7. 點擊「儲存並編譯」(Save & Compile)按鈕,畫面應顯示 0 錯誤(0 error)訊息。接著點擊「離開」(Exit)按鈕關閉工作區視窗。
  8. 接下來建立第二個巨集,點擊「新建」(New)。在工作區中勾選「週期性執行」(Periodical execution),設定時間間隔(Time Interval) = 1 x 100ms,隨後輸入以下程式碼:macro-1。
  9. 點擊「儲存並編譯」(Save & Compile)按鈕,畫面應顯示 0 錯誤(0 error)訊息。
  10. 點擊「離線模擬」(Off-line Simulation)按鈕。
備註: 當沒有 PLC 或其他設備連接 HMI 時,請使用「離線模擬」。若有其他設備與 HMI 連接,則請使用「線上模擬」(On-line Simulation)。
這段教學完整說明了威綸 HMI 巨集的初始化與週期性控制設定。若您需要,我可以繼續為您:
  • 撰寫或解構 macro-0 的初始化程式碼(例如設定初始座標或變數)
  • 撰寫或優化 macro-1 的邏輯程式碼(實現瓶子移動、夾爪搬運等動畫邏輯)
  • 提供威綸巨集常用的 GetData / SetData 語法說明 與暫存器對照

  1. 按下 Start 按鈕以點亮指示燈,按下 Stop 按鈕則熄滅指示燈。 當指示燈熄滅時,所有後續製程皆無法執行。
  2. 按下 S1 按鈕以產生瓶子,並讓瓶子在 1 號輸送帶上運行。
  3. 按下 S2 按鈕將瓶子從 1 號輸送帶夾起,並放入 2 號輸送帶上的紙箱內。
  4. 按下 S3 按鈕讓夾爪(Gripper)返回初始位置。
  5. 若紙箱尚未裝滿,則無法按下 S4 按鈕。 為此,請重複按下 S1 至 S3 按鈕,直到紙箱內裝滿 3 個瓶子。裝滿 3 個瓶子後即可按下 S4 按鈕,使紙箱移動到 2 號輸送帶的最右端。
  6. 按下 S1 按鈕將會把(已裝滿的)紙箱運走,接著 2 號輸送帶的最左端會出現一個新紙箱,同時 1 號輸送帶上也會運行一個新瓶子,整個流程將重新循環。







macro-0

macro_command main()
short data_lw[10]
bool data_lb[11]
data_lb[7]=1
data_lb[8]=0
data_lb[9]=0
data_lb[10]=0
//lw[0] dan lw[1] dikosongkan untuk mqtt
data_lw[2]=0 	//kondisi gripper membuka
data_lw[3]=390	//posisi griper sumbu x
data_lw[4]=10	//posisi griper sumbu y
data_lw[5]=0 	//kondisi botol 
data_lw[6]=0	//posisi botol sumbu x
data_lw[7]=0	//posisi botol sumbu y
data_lw[8]=0 	//box kosong 
data_lw[9]=510	//posisi box di konveyor2
SetDataEx(data_lw[0], "Local HMI", LW, 0, 10)
SetDataEx(data_lb[0], "Local HMI", LB, 0, 11)
end macro_command

macro-1

macro_command main()
bool data_lb[11]
bool turun1
bool turun2
bool naik1
bool naik2
bool geser1
bool geser2
bool geser3
bool geser4
bool awal=1
short data_lw[10]
GetDataEx(data_lw[0], "Local HMI", LW, 0, 10)
GetDataEx(data_lb[0], "Local HMI", LB, 0, 11)
if data_lb[1]==1 then  //tombol Start ditekan
	data_lb[0]=1	   //indikator menyala
end if
if data_lb[2]==1 then  //tombol Stop ditekan
	data_lb[0]=0       //indikator padam
end if
if data_lb[3]==1  then //tombol S1 ditekan
	data_lw[5]=1
	data_lw[6]=98
	data_lw[7]=275
	data_lb[7]=0
	geser1=1
	if data_lw[9]>700 then
		data_lw[8]=0
		data_lw[9]=510
	end if
end if
if geser1==1 and data_lb[0]==1 then
	data_lw[6]=data_lw[6]+5
	if data_lw[6]>412 then 
		geser1=0
		data_lb[8]=1
	end if
end if	
if data_lb[4]==1 then //tombol S2 ditekan
	data_lb[8]=0
	turun1=1
end if
if turun1==1 and data_lb[0]==1 then
	data_lw[4]=data_lw[4]+5
	if data_lw[4]>136 then
		turun1=0
		naik1=1
	end if
end if
if naik1==1 and data_lb[0]==1 then
	data_lw[2]=1
	data_lw[4]=data_lw[4]-5
	data_lw[7]=data_lw[7]-5
	if data_lw[4]<15 then
		naik1=0
		geser2=1
	end if
end if
if geser2==1 and data_lb[0]==1 then
	data_lw[3]=data_lw[3]+5
	data_lw[6]=data_lw[6]+5
	if data_lw[6]>(530+data_lw[8]*56) then
		geser2=0
		turun2=1
	end if
end if
if turun2==1 and data_lb[0]==1 then
	data_lw[4]=data_lw[4]+5
	data_lw[7]=data_lw[7]+5
	if data_lw[4]>130 then
		turun2=0
		data_lb[9]=1
	end if
end if
if data_lb[5]==1 then //tombol S3 ditekan
	data_lw[5]=0
	data_lw[6]=0
	data_lw[7]=0
	data_lb[5]=0
	data_lb[9]=0
	data_lb[7]=1
	naik2=1
	data_lw[8]=data_lw[8]+1
	if data_lw[8]==3 then
		data_lb[10]=1
		data_lb[7]=0
	end if
	if data_lw[8]>3 then 
		data_lw[8]=0
	end if
end if
if naik2==1 and data_lb[0]==1 then
	data_lw[2]=0
	data_lw[4]=data_lw[4]-5
	if data_lw[4]<15 then
		naik2=0
		geser3=1
	end if
end if
if geser3==1 and data_lb[0]==1 then
	data_lw[3]=data_lw[3]-5
	if data_lw[3]<395 then
		geser3=0
	end if
end if
if data_lw[8]==3 and data_lb[6]==1 then //tombol S4 ditekan
	data_lb[10]=0
	geser4=1
end if
if geser4==1 and data_lb[0]==1 then
	data_lw[9]=data_lw[9]+5
	if data_lw[9]>700 then
		data_lb[7]=1
		geser4=0
	end if
end if
SetDataEx(data_lb[0], "Local HMI", LB, 0, 11)
SetDataEx(data_lw[0], "Local HMI", LW, 0, 10)
end macro_command

ESP32 門禁感應端 與 電腦管理中控端 透過 MQTT 通訊協定 所架構出的 遠端智慧門禁與 Telegram 雙向控制系統 (2)

ESP32 門禁感應端 與 電腦管理中控端 透過 MQTT 通訊協定 所架構出的 遠端智慧門禁與 Telegram 雙向控制系統 (2) 優化 Telegram 警報訊息,最直觀且便利的方式是利用 Telegram 的 Inline Code ( 單行程式碼塊 ) 語法。 ...