TEMPERATURE
-- °C

0% Since last hour

HUMIDITY
-- %

0% Since last hour

DEVICES
-- Online

All active System stable

POWER
-- kWh

0% Efficiency up

Kết nối ESP32 với SupperQNNN

Hướng dẫn toàn diện từ A-Z: Cài đặt phần mềm, cấu hình phần cứng, kết nối WiFi, đăng ký thiết bị qua API, gửi dữ liệu cảm biến và nhận lệnh điều khiển realtime qua WebSocket.

30 phút Trung cấp ESP32 + DHT22

Luồng hoạt động

Kết nối WiFi
Đăng ký thiết bị
Nhận JWT Token
Kết nối WebSocket
Gửi Sensor Data
Nhận Lệnh Real-time
1

Chuẩn bị công cụ & phần cứng

Trước khi bắt đầu, hãy đảm bảo bạn đã chuẩn bị đầy đủ các thiết bị và phần mềm sau đây:

Linh kiện bắt buộc

  • Mạch ESP32 (WROOM-32, S3, v.v.)
  • Cảm biến DHT22 (Nhiệt độ/Độ ẩm)
  • LED & Điện trở 220Ω (Tuỳ chọn test lệnh)
  • Dây Jumper & Breadboard

Phần mềm & Môi trường

  • Arduino IDE hoặc PlatformIO
  • ESP32 Board Package
  • Mạng WiFi ổn định
  • SupperQNNN Server đang hoạt động

Sơ đồ đấu dây tham khảo

Wiring Diagram
┌─────────────┐ ┌──────────┐ ┌──────┐ │ ESP32 │ │ DHT22 │ │ LED │ │ │ │ │ │ │ │ 3.3V ──────────── VCC │ + │ │ GND ──────────── GND │ - │ │ GPIO4 ──────────── DATA │ │ │ │ │ │ │ [10KΩ] │ │ GND ────── GND │ GPIO2 ────────────────────── + │ │ │ └──────────┘ └──────┘ └─────────────┘ Lưu ý: Chân GPIO4 (DHT22 Data) cần điện trở kéo lên (Pull-up) 10KΩ nối lên 3.3V
2

Cài đặt Môi trường Arduino

2.1. Cài đặt ESP32 Board

Preferences
// 1. Mở Arduino IDE → File → Preferences // 2. Thêm URL sau vào "Additional Board Manager URLs": https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json // 3. Vào Tools → Board → Boards Manager → Tìm "esp32" → Cài đặt

2.2. Cài đặt Thư viện cần thiết

Library Manager
Mở Sketch → Include Library → Manage Libraries và cài các thư viện sau: 1. DHT sensor library (bởi Adafruit) 2. Adafruit Unified Sensor 3. ArduinoJson (bởi Benoit Blanchon) - Bản 7.x 4. WebSockets (bởi Markus Sattler) - Dùng cho kết nối Real-time
3

Khởi động Server SupperQNNN

Trước khi nạp code cho ESP32, đảm bảo server của bạn đã chạy và có thể truy cập qua mạng LAN.

Terminal
# Di chuyển vào thư mục dự án cd SupperQNNN # Chạy server với host 0.0.0.0 để cho phép truy cập từ mạng LAN dotnet run --urls "http://0.0.0.0:5175" # Log kết quả mong đợi: # info: Microsoft.Hosting.Lifetime[14] # Now listening on: http://0.0.0.0:5175
Lưu ý IP Address: Bạn cần tìm địa chỉ IP LAN của máy tính đang chạy server (VD: 192.168.1.100) để cấu hình cho ESP32.
- Windows: Mở CMD gõ ipconfig (Tìm dòng IPv4 Address)
- Mac/Linux: Mở Terminal gõ ifconfig
4

Code Điều khiển (Sketch)

Tạo file mới trong Arduino IDE, copy toàn bộ đoạn code dưới đây và nhớ thay đổi phần CẤU HÌNH cho phù hợp với mạng của bạn.

SupperQNNN_ESP32.ino
// ============================================================ // SupperQNNN IoT API - ESP32 Sketch // ============================================================ #include <WiFi.h> #include <HTTPClient.h> #include <ArduinoJson.h> #include <DHT.h> #include <EEPROM.h> #include <WebSocketsClient.h> // ===== CẤU HÌNH (THAY ĐỔI THÔNG TIN NÀY) ===== const char* WIFI_SSID = "YOUR_WIFI_SSID"; const char* WIFI_PASS = "YOUR_WIFI_PASSWORD"; const char* SERVER_HOST = "192.168.1.100"; // IP LAN của Server const int SERVER_PORT = 5175; const char* DEVICE_NAME = "ESP32-Smart-Home"; const char* DEVICE_SECRET = "my_secret_key_123"; #define DHT_PIN 4 #define DHT_TYPE DHT22 #define LED_PIN 2 #define SEND_INTERVAL 10000 // Gửi dữ liệu mỗi 10 giây #define PING_INTERVAL 30000 // Ping giữ kết nối mỗi 30 giây // ===== BIẾN TOÀN CỤC ===== DHT dht(DHT_PIN, DHT_TYPE); WebSocketsClient webSocket; int deviceId = 0; String deviceToken = ""; bool isRegistered = false; unsigned long lastSendTime = 0; unsigned long lastPingTime = 0; // ===== WEBSOCKET EVENT ===== void webSocketEvent(WStype_t type, uint8_t* payload, size_t length) { switch (type) { case WStype_CONNECTED: Serial.println("✓ WebSocket connected!"); // Join device group để nhận lệnh { StaticJsonDocument<128> msg; msg["type"] = 1; msg["target"] = "JoinDeviceGroup"; msg["arguments"].add(deviceId); String msgStr; serializeJson(msg, msgStr); webSocket.sendTXT(msgStr); } break; case WStype_TEXT: { StaticJsonDocument<512> doc; if (!deserializeJson(doc, payload)) { String method = doc["target"] | ""; JsonArray args = doc["arguments"]; // Xử lý lệnh từ Server if (method == "ReceiveCommand") { JsonObject cmd = args[0]; String command = cmd["command"]; if (command == "set_pin") { int pin = cmd["params"]["pin"]; String val = cmd["params"]["value"]; if (pin == 2) { digitalWrite(LED_PIN, val == "1" ? HIGH : LOW); Serial.println(val == "1" ? "> LỆNH: LED BẬT" : "> LỆNH: LED TẮT"); } } } } break; } case WStype_DISCONNECTED: Serial.println("✗ WebSocket disconnected!"); break; } } void connectWiFi() { WiFi.begin(WIFI_SSID, WIFI_PASS); Serial.print("Connecting WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.printf("\n✓ WiFi Connected: %s\n", WiFi.localIP().toString().c_str()); } bool registerDevice() { HTTPClient http; http.begin(String("http://") + SERVER_HOST + ":5175/api/auth/register-device"); http.addHeader("Content-Type", "application/json"); StaticJsonDocument<256> doc; doc["macAddress"] = WiFi.macAddress(); doc["name"] = DEVICE_NAME; doc["secret"] = DEVICE_SECRET; String body; serializeJson(doc, body); int code = http.POST(body); if (code == 200) { StaticJsonDocument<512> res; deserializeJson(res, http.getString()); deviceId = res["data"]["deviceId"]; deviceToken = res["data"]["token"].as<String>(); // Lưu token vào EEPROM EEPROM.begin(512); for (int i = 0; i < deviceToken.length(); i++) EEPROM.write(i, deviceToken[i]); EEPROM.write(deviceToken.length(), '\0'); EEPROM.write(200, (deviceId >> 24) & 0xFF); EEPROM.write(201, (deviceId >> 16) & 0xFF); EEPROM.write(202, (deviceId >> 8) & 0xFF); EEPROM.write(203, deviceId & 0xFF); EEPROM.commit(); Serial.printf("✓ Registered! ID=%d\n", deviceId); http.end(); return true; } Serial.printf("✗ Register failed. Code: %d\n", code); http.end(); return false; } void sendSensorData(float temp, float hum) { HTTPClient http; http.begin(String("http://") + SERVER_HOST + ":5175/api/datastream/" + deviceId + "/update"); http.addHeader("Content-Type", "application/json"); http.addHeader("Authorization", "Bearer " + deviceToken); StaticJsonDocument<256> doc; JsonArray pins = doc.createNestedArray("pins"); JsonObject p0 = pins.createNestedObject(); p0["pin"] = 0; p0["value"] = String(temp, 1); JsonObject p1 = pins.createNestedObject(); p1["pin"] = 1; p1["value"] = String(hum, 1); String body; serializeJson(doc, body); int code = http.POST(body); if (code == 200) Serial.printf("↑ Sent Data: Temp=%.1f°C, Hum=%.1f%%\n", temp, hum); else Serial.printf("✗ Send Data Failed: %d\n", code); http.end(); } void setup() { Serial.begin(115200); pinMode(LED_PIN, OUTPUT); dht.begin(); connectWiFi(); // Load token EEPROM.begin(512); char token[400]; int i = 0; while (i < 399) { token[i] = EEPROM.read(i); if (token[i] == '\0') break; i++; } deviceId = (EEPROM.read(200)<<24)|(EEPROM.read(201)<<16)|(EEPROM.read(202)<<8)|EEPROM.read(203); if (strlen(token) > 10 && deviceId > 0) { deviceToken = String(token); isRegistered = true; Serial.printf("✓ Token Loaded. ID=%d\n", deviceId); } } void loop() { webSocket.loop(); if (!isRegistered) { if (registerDevice()) { isRegistered = true; webSocket.begin(SERVER_HOST, SERVER_PORT, "/iotHub"); webSocket.onEvent(webSocketEvent); webSocket.setReconnectInterval(5000); } delay(5000); return; } unsigned long now = millis(); // Sensor Upload if (now - lastSendTime >= SEND_INTERVAL) { lastSendTime = now; float t = dht.readTemperature(); float h = dht.readHumidity(); if (!isnan(t) && !isnan(h)) sendSensorData(t, h); } // Ping if (now - lastPingTime >= PING_INTERVAL) { lastPingTime = now; HTTPClient http; http.begin(String("http://") + SERVER_HOST + ":5175/api/device/" + deviceId + "/ping"); http.addHeader("Content-Type", "application/json"); http.addHeader("Authorization", "Bearer " + deviceToken); http.POST("{}"); http.end(); } delay(10); }
5

Kiểm tra & Vận hành

Các cổng Virtual Pins Quy định

PinTên chức năngKiểu dữ liệuQuyền truy cập
V0 Nhiệt độ (°C) Double Read Only
V1 Độ ẩm (%) Double Read Only
V2 Trạng thái LED Boolean (0/1) Read / Write
Thử nghiệm ngay: Sau khi ESP32 báo kết nối thành công trong Serial Monitor, bạn có thể truy cập IoT Dashboard hoặc Swagger UI bên dưới để gửi lệnh bật/tắt LED (Virtual Pin 2, giá trị 1 hoặc 0) và quan sát mạch thực tế.

Xử lý sự cố (Troubleshooting)

WiFi không kết nối được

Kiểm tra lại SSID/Password. Đảm bảo bạn đang dùng WiFi 2.4GHz (ESP32 không hỗ trợ mạng 5GHz).

Đăng ký thất bại (HTTP 409)

Thiết bị đã tồn tại. Xóa thiết bị cũ từ Dashboard/Swagger UI hoặc thay đổi DEVICE_SECRET.

Gửi dữ liệu lỗi (HTTP 401)

Token có thể đã hết hạn hoặc không hợp lệ. Upload lại Sketch để ESP32 đăng ký và lấy token mới.

Cảm biến DHT22 báo NaN

Kiểm tra kết nối dây điện: DATA nối GPIO4, có điện trở kéo lên 10KΩ chưa?

Công cụ & API References

API Documentation

Tham khảo cách gọi API để tự xây dựng App Mobile hoặc Web Client riêng.

Swagger UI Testing

Giao diện tương tác trực tiếp với API Server. (Cần nhập JWT Token ở nút Authorize).

Web hosting by Somee.com