#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();
}