2025年6月3日 星期二

MQTT 解說範例 使用MQTTX Clinet程式

 MQTT 解說範例使用MQTTX Clinet程式














WOKWI程式

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <AsyncMQTT_ESP32.h>
#include <Ticker.h>

// WiFi 設定
const char* ssid = "Wokwi-GUEST";   // "你的WiFi名稱" <<--- 請修改成你的 WiFi 名稱
const char* password = "" ;         // "你的WiFi密碼" <<--- 請修改成你的 WiFi 密碼


// MQTT 設定
const char* mqtt_broker = "broker.mqttgo.io";
const int mqtt_port = 1883;
const char* mqtt_client_id = "ESP32_DHT22_LED_Client"; // 請為你的裝置設定一個獨特的 ID

// 發布主題
const char* mqtt_publish_topic_temphumi = "alex9ufo/esp32/dht/temphumi";
// 訂閱主題
const char* mqtt_subscribe_topic_led_control = "alex9ufo/esp32/led/control";
// 回覆主題
const char* mqtt_publish_topic_led_status = "alex9ufo/esp32/led/status";

// DHT22 設定
#define DHTPIN 4          // DHT22 連接到 ESP32 的 GPIO Pin 4
#define DHTTYPE DHT22     // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);

// LED 設定
const int ledPins[] = {16, 17, 18, 19}; // 假設 LED 連接到 GPIO 16, 17, 18, 19
const int numLeds = sizeof(ledPins) / sizeof(ledPins[0]);
bool ledStatus[numLeds]; // 儲存 LED 的狀態 (on/off)

WiFiClient espClient;
PubSubClient client(espClient);

// Function Prototypes
void setup_wifi();
void reconnect_mqtt();
void callback(char* topic, byte* payload, unsigned int length);
void readAndPublishDHT();
void sendLedStatus(int ledNum, bool status); // 函式簽名,ledNum在此表示第幾個LED,1-4

void setup() {
  Serial.begin(115200);
  dht.begin();

  // 初始化 LED 腳位為輸出模式,並關閉所有 LED
  for (int i = 0; i < numLeds; i++) {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], LOW);
    ledStatus[i] = false; // 初始狀態為關閉
  }

  setup_wifi();
  client.setServer(mqtt_broker, mqtt_port);
  client.setCallback(callback);

  // 在 Core 0 上運行 readAndPublishDHT 函數
  xTaskCreatePinnedToCore(
    [](void * pvParameters) {
      while (true) {
        readAndPublishDHT();
        vTaskDelay(pdMS_TO_TICKS(5000)); // 每 5 秒讀取並發布一次
      }
    },
    "DHTTask",
    4096, // 堆疊大小
    NULL,
    1, // 優先級
    NULL,
    0 // 運行在 Core 0
  );
}

void loop() {
  if (!client.connected()) {
    reconnect_mqtt();
  }
  client.loop(); // 保持 MQTT 連線活躍
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

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

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void reconnect_mqtt() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect(mqtt_client_id)) {
      Serial.println("connected");
      // 訂閱 LED 控制主題
      client.subscribe(mqtt_subscribe_topic_led_control);
      Serial.print("Subscribed to topic: ");
      Serial.println(mqtt_subscribe_topic_led_control);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String message = "";
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
  }
  Serial.println(message);

  // 檢查是否是 LED 控制主題
  if (String(topic) == mqtt_subscribe_topic_led_control) {
    int ledIndex = -1; // LED 陣列的索引 (0-3)
    bool turnOn = false;

    // 將收到的訊息與預期的 payload 進行比較
    if (message == "1on") {
      ledIndex = 0;
      turnOn = true;
    } else if (message == "1off") {
      ledIndex = 0;
      turnOn = false;
    } else if (message == "2on") {
      ledIndex = 1;
      turnOn = true;
    } else if (message == "2off") {
      ledIndex = 1;
      turnOn = false;
    } else if (message == "3on") {
      ledIndex = 2;
      turnOn = true;
    } else if (message == "3off") {
      ledIndex = 2;
      turnOn = false;
    } else if (message == "4on") {
      ledIndex = 3;
      turnOn = true;
    } else if (message == "4off") {
      ledIndex = 3;
      turnOn = false;
    }

    if (ledIndex != -1) {
      if (turnOn) {
        digitalWrite(ledPins[ledIndex], HIGH);
        ledStatus[ledIndex] = true;
        Serial.print("LED ");
        Serial.print(ledIndex + 1); // 顯示第幾個 LED (1-4)
        Serial.println(" ON");
      } else {
        digitalWrite(ledPins[ledIndex], LOW);
        ledStatus[ledIndex] = false;
        Serial.print("LED ");
        Serial.print(ledIndex + 1); // 顯示第幾個 LED (1-4)
        Serial.println(" OFF");
      }
      // 回覆 LED 狀態,ledNum在這裡傳遞的是 1-4
      sendLedStatus(ledIndex + 1, ledStatus[ledIndex]);
    } else {
      Serial.println("Invalid LED control payload.");
    }
  }
}

void readAndPublishDHT() {
  // 讀取濕度
  float h = dht.readHumidity();
  // 讀取溫度 (攝氏)
  float t = dht.readTemperature();

  // 檢查讀取是否失敗,如果是則跳過
  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  // 格式化溫濕度字串
  String temperatureString = String(t, 1); // 顯示一位小數
  String humidityString = String(h, 1);   // 顯示一位小數
  String payload = "{\"temperature\": " + temperatureString + ", \"humidity\": " + humidityString + "}";

  // 發布到 MQTT 主題
  if (client.connected()) {
    client.publish(mqtt_publish_topic_temphumi, payload.c_str());
    Serial.print("Published temphumi: ");
    Serial.println(payload);
  }
}

void sendLedStatus(int ledNum, bool status) {
  String statusPayload = "";
  for (int i = 0; i < numLeds; i++) {
    if (i > 0) {
      statusPayload += ",";
    }
    statusPayload += String(i + 1);
    statusPayload += (ledStatus[i] ? "on" : "off");
  }

  if (client.connected()) {
    client.publish(mqtt_publish_topic_led_status, statusPayload.c_str());
    Serial.print("Published LED status: ");
    Serial.println(statusPayload);
  }
}


程式 2




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

// WiFi 設定
// WiFi 設定
const char* ssid = "Wokwi-GUEST";   // "你的WiFi名稱" <<--- 請修改成你的 WiFi 名稱
const char* password = "" ;         // "你的WiFi密碼" <<--- 請修改成你的 WiFi 密碼

// MQTT Broker 設定
const char* mqtt_server = "broker.mqttgo.io";

// DHT 設定
#define DHTPIN 4         // DHT22 資料腳位
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// LED 腳位設定
const int ledPins[4] = {16, 17, 18, 19};  // 對應 LED 1~4

WiFiClient espClient;
PubSubClient client(espClient);

// 記錄上次發布時間
unsigned long lastMsg = 0;
const long interval = 3000;  // 每 3 秒上傳一次資料

// Core 0 任務句柄
TaskHandle_t TempTaskHandle;

void setup_wifi() {
  delay(10);
  Serial.println("Connecting to WiFi...");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
}

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

  Serial.printf("Received message: %s on topic: %s\n", msg.c_str(), topic);

  // 控制 LED
  for (int i = 1; i <= 4; i++) {
    if (msg == String(i) + "on") {
      digitalWrite(ledPins[i - 1], HIGH);
      client.publish("alex9ufo/esp32/led/status", (String(i) + "on").c_str());
    } else if (msg == String(i) + "off") {
      digitalWrite(ledPins[i - 1], LOW);
      client.publish("alex9ufo/esp32/led/status", (String(i) + "off").c_str());
    }
  }
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP32Client")) {
      Serial.println("connected");
      client.subscribe("alex9ufo/esp32/led/control");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      delay(2000);
    }
  }
}

// Core 0 任務函式
void DHTTask(void* pvParameters) {
  for (;;) {
    if (!client.connected()) {
      reconnect();
    }
    client.loop();

    unsigned long now = millis();
    if (now - lastMsg > interval) {
      lastMsg = now;
      float h = dht.readHumidity();
      float t = dht.readTemperature();
      if (isnan(h) || isnan(t)) {
        Serial.println("Failed to read from DHT sensor!");
        continue;
      }
      String payload = "{\"temperature\":" + String(t) + ",\"humidity\":" + String(h) + "}";
      client.publish("alex9ufo/esp32/dht/temphumi", payload.c_str());
      Serial.println("Published DHT data: " + payload);
    }
    delay(10); // 避免 watchdog timeout
  }
}

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

  for (int i = 0; i < 4; i++) {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], LOW);
  }

  dht.begin();
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  // 啟用 Core 0 任務
  xTaskCreatePinnedToCore(
    DHTTask,        // 任務函數
    "DHT Task",     // 名稱
    4096,           // 堆疊大小
    NULL,           // 傳入參數
    1,              // 優先權
    &TempTaskHandle,// 任務句柄
    0               // 指定 Core 0
  );
}

void loop() {
  // 主迴圈保留空白,DHT 與 MQTT 操作皆由 core 0 執行
}

沒有留言:

張貼留言

ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite

 ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite  ESP32 VS Code 程式 ; PlatformIO Project Configuration File ; ;   Build op...