Series
Lập Trình ESP32 Cơ Bản
  1. Series Lập Trình ESP32 Cơ Bản – Giới Thiệu: Lộ Trình 19 Bài Từ Số 0
  2. 1Lập trình ESP32 – Bài 1: ESP32 là gì? Hướng dẫn bắt đầu với ESP32 cho người mới
  3. 2Lập trình ESP32 – Bài 2: Kết nối WiFi và kiểm tra Internet với ESP32
  4. 3Lập trình ESP32 – Bài 3: Đọc nút nhấn và điều khiển LED với ESP32
  5. 4Lập trình ESP32 – Bài 4: Đọc nhiệt độ & độ ẩm với cảm biến DHT11
  6. 5Lập trình ESP32 – Bài 5: ESP32 Web Server – Điều khiển LED qua trình duyệt
  7. 6Lập trình ESP32 – Bài 6: Điều khiển LED RGB
  8. 7Lập trình ESP32 – Bài 7: Điều khiển Relay qua Web Server
  9. 8Lập trình ESP32 – Bài 8: WebSocket – Điều khiển LED realtime từ trình duyệt
  10. 9Lập trình ESP32 – Bài 9: Đọc cảm biến ánh sáng (LDR) và hiển thị realtime qua WebSocket
  11. 10Lập trình ESP32 – Bài 10: Điều khiển Servo SG90 qua Web Server
  12. 11Lập trình ESP32 – Bài 11: Đọc các loại biến trở (Potentiometer / Analog Sensor)
  13. 12Lập trình ESP32 – Bài 12: Đọc cảm biến khoảng cách HC-SR04
  14. 13Lập trình ESP32 – Bài 13: ESP32 – Đọc cảm biến nhiệt độ, độ ẩm DHT11 và hiển thị dữ liệu realtime qua WebSocket
  15. 14Lập trình ESP32 – Bài 14: Hiển thị màn hình TFT (SPI)
  16. 15Lập trình ESP32 – Bài 15: Màn hình OLED SSD1306 (I2C)
  17. 16Lập trình ESP32 – Bài 16: Module SIM 4G A7680C – Gọi điện thoại, in thông tin SIM/Module, trạng thái 4G
  18. 17Lập trình ESP32 – Bài 17: Phát nhạc MP3 với module DFPlayer Mini
  19. 18Lập trình ESP32 – Bài 18: Đọc cảm biến khí gas MQ-2 và hiển thị lên màn hình OLED
  20. 19Lập trình ESP32 – Bài 19: Kết nối MQTT, Publish dữ liệu cảm biến & Subscribe điều khiển thiết bị
Kiến thức

Lập trình ESP32 – Bài 19: Kết nối MQTT, Publish dữ liệu cảm biến & Subscribe điều khiển thiết bị

Th10 2025
Lập trình ESP32 – Bài 19: Kết nối MQTT, Publish dữ liệu cảm biến & Subscribe điều khiển thiết bị

Hướng dẫn dùng MQTT với ESP32: publish dữ liệu cảm biến (DHT11) lên topic và subscribe lệnh điều khiển LED từ server. Có ví dụ mã đầy đủ, cấu trúc topic, JSON payload, và cách tự reconnect.

Mục lục

  1. Giới thiệu
  2. MQTT hoạt động thế nào?
  3. Phần cứng cần chuẩn bị
  4. Sơ đồ kết nối
  5. Cài thư viện & cấu hình
  6. Mã nguồn ví dụ hoàn chỉnh
  7. Giải thích mã
  8. Test nhanh bằng MQTT client
  9. Lỗi thường gặp & cách khắc phục
  10. Gợi ý mở rộng

1) Giới thiệu

MQTT là giao thức nhẹ cho IoT, tối ưu băng thông và độ trễ thấp. Với ESP32, bạn có thể:

  • Publish dữ liệu cảm biến lên topic (telemetry).
  • Subscribe lệnh từ server để điều khiển LED/relay.
  • Tự reconnect khi WiFi/MQTT bị gián đoạn.

2) MQTT hoạt động thế nào?

  • Broker (ví dụ: Mosquitto, EMQX, HiveMQ) làm “trung tâm”.
  • Thiết bị publish vào một topic (vd: iot/orgA/dev01/telemetry).
  • Ứng dụng khác subscribe topic đó để nhận dữ liệu.
  • Có QoS 0/1/2, retained message, Last Will để báo mất kết nối.

Cấu trúc topic khuyến nghị:

iot/<org>/<deviceId>/telemetry

iot/<org>/<deviceId>/cmd/led

Payload JSON mẫu (telemetry):

{"ts": 1731148800000, "temp": 29.5, "hum": 62.1, "device": "dev01"}

3) Phần cứng cần chuẩn bị

Linh kiệnSố lượngGhi chú
ESP32 DevKit V11
Cảm biến DHT111DATA → GPIO4 (từ Bài 4)
LED + điện trở 220Ω1LED trạng thái, GPIO2
Dây nối, breadboardVài sợi

4) Sơ đồ kết nối (Connection Diagram)

Tóm tắt dây:

  • DHT11: VCC → 3V3, GND → GND, DATA → GPIO4 (+ 10kΩ kéo lên 3V3 nếu cảm biến rời).
  • LED: Anode → GPIO2 qua 220Ω, Cathode → GND.

5) Cài thư viện & cấu hình

  • PubSubClient (by Nick O’Leary) – Tools → Manage Libraries…
  • DHT sensor library + Adafruit Unified Sensor (nếu chưa cài từ Bài 4)

Khai báo broker:

  • Nếu có broker riêng: mqtt_host = “mqtt.yourdomain.com” (TLS khuyến nghị).
  • Nếu test nhanh: dùng broker public (không bảo mật – chỉ dùng thử), ví dụ broker.hivemq.com.

6) Mã nguồn ví dụ hoàn chỉnh

#include <WiFi.h>

#include <PubSubClient.h>

#include <DHT.h>

// ==== WiFi & MQTT ====

const char* ssid       = "YourWiFiName";

const char* password   = "YourPassword";

// Dùng broker riêng nếu có (khuyến nghị). Public chỉ để demo.

const char* mqtt_host  = "broker.hivemq.com";

const uint16_t mqtt_port = 1883; // TLS thường 8883 (cần thêm WiFiClientSecure)

const char* org       = "orgA";

const char* deviceId  = "dev01";

String topicTelemetry = String("iot/") + org + "/" + deviceId + "/telemetry";

String topicCmdLed    = String("iot/") + org + "/" + deviceId + "/cmd/led";

String lastWillTopic  = String("iot/") + org + "/" + deviceId + "/status";

// ==== DHT & LED ====

#define DHTPIN 4

#define DHTTYPE DHT11

#define LED_PIN 2

DHT dht(DHTPIN, DHTTYPE);

WiFiClient espClient;

PubSubClient mqtt(espClient);

// Forward declare

void ensureMqtt();

void onMqttMessage(char* topic, byte* payload, unsigned int length);

void setup() {

  Serial.begin(115200);

  delay(500);

  pinMode(LED_PIN, OUTPUT);

  digitalWrite(LED_PIN, LOW);

  // WiFi

  Serial.print("Connecting WiFi");

  WiFi.begin(ssid, password);

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

  Serial.println("\n✅ WiFi connected: " + WiFi.localIP().toString());

  // MQTT

  mqtt.setServer(mqtt_host, mqtt_port);

  mqtt.setCallback(onMqttMessage);

  dht.begin();

}

unsigned long lastPub = 0;

void loop() {

  if (WiFi.status() != WL_CONNECTED) {

    Serial.println("⚠️ WiFi lost. Reconnecting...");

    WiFi.reconnect();

    delay(1000);

  }

  ensureMqtt();

  mqtt.loop();

  // Publish telemetry mỗi 5 giây

  unsigned long now = millis();

  if (now - lastPub > 5000) {

    lastPub = now;

    float h = dht.readHumidity();

    float t = dht.readTemperature();

    if (isnan(h) || isnan(t)) {

      Serial.println("❌ DHT read failed");

      return;

    }

    // JSON đơn giản (có thể dùng ArduinoJson cho payload lớn)

    String payload = String("{\"ts\":") + String((unsigned long)(millis())) +

                     ",\"temp\":" + String(t, 2) +

                     ",\"hum\":"  + String(h, 2) +

                     ",\"device\":\"" + deviceId + "\"}";

    boolean ok = mqtt.publish(topicTelemetry.c_str(), payload.c_str(), true); // retained

    Serial.print(ok ? "✅ Published: " : "❌ Publish failed: ");

    Serial.println(payload);

  }

}

// Đảm bảo MQTT luôn kết nối, có Last Will & subscribe lệnh

void ensureMqtt() {

  while (!mqtt.connected()) {

    Serial.print("Connecting MQTT...");

    String clientId = "esp32-" + String(deviceId) + "-" + String(random(0xffff), HEX);

    // Last Will: báo "offline" khi mất kết nối đột ngột

    if (mqtt.connect(clientId.c_str(), NULL, NULL,

                     lastWillTopic.c_str(), 0, true, "offline")) {

      Serial.println(" connected.");

      // Đánh dấu online

      mqtt.publish(lastWillTopic.c_str(), "online", true);

      // Nhận lệnh LED

      mqtt.subscribe(topicCmdLed.c_str());

      Serial.print("Subscribed: "); Serial.println(topicCmdLed);

    } else {

      Serial.print(" failed, rc="); Serial.print(mqtt.state());

      Serial.println(" | retry in 2s");

      delay(2000);

    }

  }

}

// Xử lý lệnh: iot/<org>/<deviceId>/cmd/led  -> payload: "ON" / "OFF" / "TOGGLE"

void onMqttMessage(char* topic, byte* payload, unsigned int length) {

  String msg; msg.reserve(length);

  for (unsigned int i = 0; i < length; i++) msg += (char)payload[i];

  Serial.print("? ["); Serial.print(topic); Serial.print("] "); Serial.println(msg);

  if (String(topic) == topicCmdLed) {

    if (msg == "ON")       digitalWrite(LED_PIN, HIGH);

    else if (msg == "OFF") digitalWrite(LED_PIN, LOW);

    else if (msg == "TOGGLE") digitalWrite(LED_PIN, !digitalRead(LED_PIN));

  }

}

7) Giải thích mã

  • PubSubClient xử lý MQTT; setServer() chỉ định broker; setCallback() nhận tin.
  • Last Will: lastWillTopic mang trạng thái “offline” khi thiết bị rớt kết nối đột ngột.
  • Retained: publish retained giúp client mới subscribe sẽ nhận trạng thái mới nhất.
  • ensureMqtt(): tự kết nối lại & subscribe topic lệnh.
  • onMqttMessage(): nhận lệnh “ON” | “OFF” | “TOGGLE” để điều khiển LED.

8) Test nhanh bằng MQTT client

Bạn có thể dùng:

  • MQTTX (GUI)
  • MQTT Explorer
  • Hoặc mosquitto_pub/sub (CLI)

Ví dụ (CLI):

# Subscribe telemetry

mosquitto_sub -h broker.hivemq.com -t "iot/orgA/dev01/telemetry" -v

# Gửi lệnh bật LED

mosquitto_pub -h broker.hivemq.com -t "iot/orgA/dev01/cmd/led" -m "ON" -q 1

9) Lỗi thường gặp & cách khắc phục

  • Không kết nối được broker → Kiểm tra host/port, tường lửa router, hoặc đổi mạng.
  • Mất kết nối liên tục → Tăng keepAlive, kiểm tra nguồn ESP32, bắt WiFi yếu.
  • DHT đọc lỗi → Tăng delay giữa các lần đọc; kiểm tra điện trở kéo lên cho DATA.
  • Topic sai chính tả → Dùng biến topicTelemetry, topicCmdLed thống nhất.

10) Gợi ý mở rộng

  • Dùng TLS (8883) với WiFiClientSecure + chứng chỉ CA.
  • Thêm QoS 1 cho gói lệnh quan trọng.
  • Lưu local buffer (SPIFFS/LittleFS) để retry khi mất mạng.
  • Gửi batched JSON (nhiều mẫu/gói) để tối ưu băng thông.
  • Tạo dashboard bằng Node-RED / Grafana / Home Assistant.