IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series MQTT & IoT – Bài 2: Tạo Device → Kết nối MQTT → Gửi telemetry đầu tiên

Series: Hiểu về MQTT và Ứng dụng thực tế trong IoT


1) Mục tiêu

Sau bài này bạn sẽ làm được end-to-end:

  1. Tạo Device trên IoTLabs Cloud
  2. Copy đúng MQTT Host / Port / Username / Password / Topic
  3. Chạy được code ESP32 gửi telemetry
  4. Xem dữ liệu hiển thị trên dashboard ngay

Bài này dùng mock sensor (random) để bạn test nhanh mà không cần cảm biến.

2) Chuẩn bị

Phần cứng

  • 1 board ESP32 (ESP32 DevKit / ESP32-C3 / ESP32-S3 đều được)
  • Wi-Fi 2.4GHz

Phần mềm

  • Arduino IDE
  • Cài thư viện:
    • PubSubClient (Library Manager → tìm “PubSubClient”)

3) Triển khai

Bước 1 — Tạo Device trên IoTLabs Cloud

  1. Vào IoTLabs Cloud → chọn Project
  2. Mở DevicesCreate Device
  3. Đặt tên ví dụ: ESP32 Demo 01 → Create

Trong trang Device Details, bạn cần lấy các thông tin sau

  • MQTT_HOST
  • MQTT_PORT (TLS thường là 8883)
  • MQTT_USER
  • MQTT_PASS
  • TOPIC_TELEMETRY (topic telemetry của device)

Chỉ cần copy đúng 5 giá trị trên là chạy được.

Bước 2 — Chốt payload telemetry “chuẩn hiển thị dashboard”

Để dashboard dễ hiểu và mở rộng tốt, payload tối giản nên theo dạng:

{
  "ts": 1768324653,
  "metrics": {
    "temperature": 28.6,
    "humidity": 66.2
  }
}
  • ts: Unix timestamp seconds (khuyến nghị)
  • metrics: các số đo bạn muốn hiển thị

Bước 3 — Test nhanh bằng PC (tuỳ chọn nhưng rất hữu ích)

Nếu bạn quen command line, có thể test publish trước khi đụng ESP32:

  • Dùng mosquitto_pub để gửi 1 gói telemetry lên topic của device.
  • Nếu dashboard nhận được, tức là topic/credential đúng.

Phần này tuỳ chọn. Nếu bạn chỉ muốn làm với ESP32, có thể bỏ qua.

Bước 4 — Code ESP32 hoàn chỉnh

Chỉ cần sửa phần CONFIG.

/*
  IoTLabs Cloud - ESP32 MQTT Telemetry Quickstart
  ----------------------------------------------
  - WiFi connect
  - MQTT connect (TLS)
  - Publish telemetry mỗi 30 giây (mock sensor)
  
  Libraries:
  - WiFi (built-in)
  - WiFiClientSecure (built-in)
  - PubSubClient
*/

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

// =====================
// CONFIG (SỬA Ở ĐÂY)
// =====================
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_PASS";

const char* MQTT_HOST = "mqtt.iotlabs.vn";   // lấy từ Device Details
const int   MQTT_PORT = 8883;                // TLS thường 8883

const char* MQTT_USER = "YOUR_MQTT_USER";    // lấy từ Device Details
const char* MQTT_PASS = "YOUR_MQTT_PASS";    // lấy từ Device Details

const char* TOPIC_TELEMETRY =
  "iotlabs/<project_id>/devices/<device_id>/telemetry"; // lấy từ Device Details

// Test nhanh: bỏ verify cert (không khuyến nghị production)
#define MQTT_TLS_INSECURE true

// =====================
// GLOBALS
// =====================
WiFiClientSecure net;
PubSubClient mqtt(net);

unsigned long lastSendMs = 0;
const unsigned long SEND_INTERVAL_MS = 30UL * 1000UL; // 30s

// =====================
// WIFI
// =====================
void connectWiFi() {
  if (WiFi.status() == WL_CONNECTED) return;

  Serial.print("[WiFi] Connecting to ");
  Serial.println(WIFI_SSID);

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);

  unsigned long start = millis();
  while (WiFi.status() != WL_CONNECTED) {
    delay(300);
    Serial.print(".");
    if (millis() - start > 15000) {
      Serial.println("\n[WiFi] Timeout, retry...");
      WiFi.disconnect(true);
      delay(500);
      WiFi.begin(WIFI_SSID, WIFI_PASS);
      start = millis();
    }
  }

  Serial.println("\n[WiFi] Connected!");
  Serial.print("[WiFi] IP: ");
  Serial.println(WiFi.localIP());
}

// =====================
// MQTT
// =====================
void connectMQTT() {
  if (mqtt.connected()) return;

  Serial.println("[MQTT] Connecting...");

  #if MQTT_TLS_INSECURE
    net.setInsecure();
  #endif

  mqtt.setServer(MQTT_HOST, MQTT_PORT);

  // Client ID nên unique
  String clientId = String("iotlabs-") + String((uint32_t)ESP.getEfuseMac(), HEX);

  bool ok = mqtt.connect(clientId.c_str(), MQTT_USER, MQTT_PASS);
  if (ok) {
    Serial.println("[MQTT] Connected!");
  } else {
    Serial.print("[MQTT] Failed, rc=");
    Serial.println(mqtt.state());
    delay(1500);
  }
}

// =====================
// MOCK SENSOR
// =====================
struct SensorData {
  float temp;
  float hum;
};

SensorData readSensors() {
  SensorData d;
  d.temp = 24.0 + (float)(esp_random() % 800) / 100.0;   // 24.00 -> 31.99
  d.hum  = 45.0 + (float)(esp_random() % 4000) / 100.0;  // 45.00 -> 84.99
  return d;
}

// Timestamp demo (millis -> seconds).
// Production: dùng NTP hoặc time service để có thời gian thực.
uint32_t nowUnixSecondsApprox() {
  return (uint32_t)(millis() / 1000UL);
}

void publishTelemetry() {
  SensorData d = readSensors();
  uint32_t ts = nowUnixSecondsApprox();

  char payload[256];
  snprintf(payload, sizeof(payload),
           "{\"ts\":%lu,\"metrics\":{\"temperature\":%.2f,\"humidity\":%.2f}}",
           (unsigned long)ts, d.temp, d.hum);

  Serial.print("[MQTT] Publish: ");
  Serial.println(payload);

  bool ok = mqtt.publish(TOPIC_TELEMETRY, payload);
  if (!ok) {
    Serial.println("[MQTT] Publish failed (will retry next loop)");
  }
}

// =====================
// ARDUINO
// =====================
void setup() {
  Serial.begin(115200);
  delay(300);

  connectWiFi();
  connectMQTT();
}

void loop() {
  connectWiFi();
  connectMQTT();

  mqtt.loop();

  if (mqtt.connected() && (millis() - lastSendMs >= SEND_INTERVAL_MS)) {
    lastSendMs = millis();
    publishTelemetry();
  }

  delay(20);
}

3 lưu ý quan trọng

  1. setInsecure() chỉ để bạn test nhanh. Khi production, nên cấu hình CA cert để TLS đúng chuẩn.
  2. ts demo đang lấy từ millis() nên không phải thời gian thực. Khi làm dự án thật, hãy đồng bộ thời gian (NTP/time service).
  3. Tần suất mặc định 30s. Bạn có thể chỉnh theo mục tiêu (xem Bài S1-02).

Bước 5 — Upload và kiểm tra Serial Monitor

  • Upload code
  • Mở Serial Monitor (115200)

Bạn sẽ thấy kiểu:

[WiFi] Connected!
[MQTT] Connected!
[MQTT] Publish: {"ts":1234,"metrics":{"temperature":28.60,"humidity":66.20}}

Bước 6 — Xem telemetry trên Dashboard

Vào IoTLabs Cloud:

  • Mở Device Details
  • Vào phần Telemetry / Live Data / Dashboard
  • Bạn sẽ thấy:
    • Latest values: temperature/humidity
    • Chart (nếu UI có biểu đồ)

4) Khắc phục các vấn đề

90% các lỗi thường xuyên gặp phải nằm ở đây:

Lỗi 1 — MQTT connect fail

  • Sai MQTT_USER / MQTT_PASS
  • Sai MQTT_PORT (TLS thường 8883)
  • Host sai / DNS lỗi / mạng chặn

Lỗi 2 — Publish ok nhưng dashboard không hiện

  • Sai TOPIC_TELEMETRY
  • Payload không đúng format (thiếu metrics, hoặc key khác với dashboard parse)

Lỗi 3 — TLS lỗi chứng chỉ

  • Test nhanh: setInsecure()
  • Chạy thật: cấu hình CA cert đúng để TLS an toàn

5) Bạn đã “xong bài 2” — Bước tiếp theo để dùng thật

Từ demo này, bạn nâng cấp lên dự án thật theo 3 bước:

  1. Thay readSensors() bằng cảm biến thật (DHT22/DS18B20/INA219/…)
  2. Thêm topic .../status để gửi heartbeat (pin, RSSI, uptime)
  3. Thêm event cho cảnh báo (cửa mở, khói/gas, vượt ngưỡng…)

-> Bài tiếp theo trong series

Bài 3: 3 loại dữ liệu IoT phổ biến: telemetry / status / event (và cách map lên dashboard)
→ giúp bạn thiết kế dữ liệu “đúng chuẩn” để dashboard đẹp và dễ mở rộng.