2026年1月22日 星期四

經由MQTT協定的2個WOKWI ESP32 雙向通訊 (ESP32 to ESP32 MQTT Communication )

 經由MQTT協定的2個WOKWI ESP32 雙向通訊 (ESP32  to ESP32 MQTT Communication )



使用兩個 ESP32 建立一個遠端控制系統。

MQTT Broker: mqtt-dashboard.com
Topic (主題): alex9ufo/switchPB

訊息內容: on, off, flash, timer

發送: 按鈕去彈跳並循環發送 on/off/flash/timeralex9ufo/switchPB
接收: 訂閱 alex9ufo/DHT22,解析 JSON 格式並顯示於 LCD。
執行: 訂閱 alex9ufo/switchPB 控制 LED 動作。
發送: 每 2 秒讀取 DHT22 數據並發行 JSON 到 alex9ufo/DHT22

引腳連接提醒:

  • Button: GPIO 34 (外部下拉電阻)。

  • LCD: SDA=21, SCL=22。

  • LED: GPIO 2。

  • DHT22: GPIO 15。




發送端:按鈕 + LCD (含序列埠監控)

#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ArduinoJson.h>

const int buttonPin = 34;
LiquidCrystal_I2C lcd(0x27, 16, 2);
const char* mqtt_server = "mqtt-dashboard.com";

WiFiClient espClient;
PubSubClient client(espClient);

volatile int stateCounter = 0;
volatile bool sendFlag = false;
float sharedTemp = 0, sharedHum = 0;
volatile bool dataUpdated = false;

TaskHandle_t Task0;

void Task0code(void * pvParameters) {
  for (;;) {
    if (WiFi.status() != WL_CONNECTED) {
      WiFi.begin("Wokwi-GUEST", "");
      while (WiFi.status() != WL_CONNECTED) delay(500);
      Serial.println("[Core 0] WiFi Reconnected");
    }
    if (!client.connected()) {
      if (client.connect("ESP32_Button_Core0")) {
        client.subscribe("alex9ufo/DHT22");
        Serial.println("[Core 0] MQTT Connected & Subscribed to DHT22");
      }
    }
    if (sendFlag) {
      const char* cmds[] = {"on", "off", "flash", "timer"};
      const char* msg = cmds[stateCounter - 1];
      client.publish("alex9ufo/switchPB", msg);
      // 新增:顯示發行的訊息
      Serial.printf("[Core 0] ---> Published to switchPB: %s\n", msg);
      sendFlag = false;
    }
    client.loop();
    delay(10);
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  StaticJsonDocument<200> doc;
  deserializeJson(doc, payload, length);
  sharedTemp = doc["temp"];
  sharedHum = doc["hum"];
  dataUpdated = true;
  // 新增:顯示收到的訂閱訊息
  Serial.printf("[Core 0] <--- Received DHT22: Temp=%.1f, Hum=%.1f\n", sharedTemp, sharedHum);
}

void setup() {
  Serial.begin(115200);
  pinMode(buttonPin, INPUT);
  lcd.init();
  lcd.backlight();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  xTaskCreatePinnedToCore(Task0code, "Task0", 10000, NULL, 1, &Task0, 0);
  Serial.println("System Initialized (Sender)");
}

void loop() {
  static int lastButtonState = LOW;
  int reading = digitalRead(buttonPin);
  if (reading == HIGH && lastButtonState == LOW) {
    delay(50);
    stateCounter = (stateCounter % 4) + 1;
    sendFlag = true;
    Serial.printf("[Core 1] Button Pressed. State: %d\n", stateCounter);
  }
  lastButtonState = reading;

  if (dataUpdated) {
    lcd.setCursor(0, 0);
    lcd.printf("Temp: %.1f C  ", sharedTemp);
    lcd.setCursor(0, 1);
    lcd.printf("Hum : %.1f %%  ", sharedHum);
    dataUpdated = false;
  }
  delay(10);
}




接收端:LED + DHT22 (含序列埠監控)

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

#define DHTPIN 15
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

const int ledPin = 2;
const char* mqtt_server = "mqtt-dashboard.com";

WiFiClient espClient;
PubSubClient client(espClient);

volatile int currentModeCode = 0;
unsigned long myTimerStart = 0;
float t_val = 0, h_val = 0;

TaskHandle_t Task0_Comm;

void Task0_CommCode(void * pvParameters) {
  for (;;) {
    if (!client.connected()) {
      if (client.connect("ESP32_LED_Core0")) {
        client.subscribe("alex9ufo/switchPB");
        Serial.println("[Core 0] MQTT Connected & Subscribed to switchPB");
      }
    }
    static unsigned long lastUpdate = 0;
    if (millis() - lastUpdate > 5000) { // 每5秒發行一次
      StaticJsonDocument<200> doc;
      doc["temp"] = t_val;
      doc["hum"] = h_val;
      char buffer[128];
      serializeJson(doc, buffer);
      client.publish("alex9ufo/DHT22", buffer);
      // 新增:顯示發行的訊息
      Serial.printf("[Core 0] ---> Published DHT Data: %s\n", buffer);
      lastUpdate = millis();
    }
    client.loop();
    delay(10);
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  String msg = "";
  for (int i = 0; i < length; i++) msg += (char)payload[i];
 
  // 新增:顯示收到的訂閱訊息
  Serial.printf("[Core 0] <--- Received switchPB: %s\n", msg.c_str());

  if (msg == "off") currentModeCode = 0;
  else if (msg == "on") currentModeCode = 1;
  else if (msg == "flash") currentModeCode = 2;
  else if (msg == "timer") {
    currentModeCode = 3;
    myTimerStart = millis();
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  dht.begin();
  WiFi.begin("Wokwi-GUEST", "");
  while (WiFi.status() != WL_CONNECTED) delay(500);
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  xTaskCreatePinnedToCore(Task0_CommCode, "CommTask", 10000, NULL, 1, &Task0_Comm, 0);
  Serial.println("System Initialized (Receiver)");
}

void loop() {
  t_val = dht.readTemperature();
  h_val = dht.readHumidity();

  // 根據 currentModeCode 執行 LED 動作
  if (currentModeCode == 1) digitalWrite(ledPin, HIGH);
  else if (currentModeCode == 0) digitalWrite(ledPin, LOW);
  else if (currentModeCode == 2) digitalWrite(ledPin, (millis() / 500) % 2);
  else if (currentModeCode == 3) {
    if (millis() - myTimerStart < 5000) digitalWrite(ledPin, HIGH);
    else {
      digitalWrite(ledPin, LOW);
      currentModeCode = 0;
      Serial.println("[Core 1] Timer Finished. LED Off.");
    }
  }
  delay(100);
}

沒有留言:

張貼留言

經由MQTT協定的2個WOKWI ESP32 雙向通訊 (ESP32 to ESP32 MQTT Communication )

 經由MQTT協定的2個WOKWI ESP32 雙向通訊  (ESP32  to ESP32 MQTT Communication ) 使用兩個 ESP32 建立一個遠端控制系統。 MQTT Broker: mqtt-dashboard.com Topic (主題): ale...