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 執行
}













沒有留言:
張貼留言