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 8: WebSocket – Điều khiển LED realtime từ trình duyệt

Th11 2025
Lập trình ESP32 – Bài 8: WebSocket – Điều khiển LED realtime từ trình duyệt

Dùng WebSocket để điều khiển LED ESP32 theo thời gian thực từ trình duyệt. Bài viết có sơ đồ kết nối, mã ví dụ đầy đủ, giải thích rõ ràng và gợi ý mở rộng.

Mục lục

  1. Giới thiệu
  2. Tại sao dùng WebSocket?
  3. Phần cứng cần chuẩn bị
  4. Sơ đồ kết nối
  5. Mã nguồn ESP32 (WebSocket + Web UI)
  6. Giải thích mã
  7. Cách truy cập & kiểm thử
  8. Gợi ý mở rộng

1) Giới thiệu

So với HTTP thông thường, WebSocket tạo kết nối 2 chiều bền vững giữa trình duyệt và ESP32. Nhờ vậy, việc bật/tắt LED hoặc hiển thị trạng thái realtime mượt mà, không cần reload trang hoặc polling liên tục.

2) Tại sao dùng WebSocket?

  • Realtime: cập nhật ngay khi có sự kiện.
  • Tiết kiệm băng thông: không cần gửi request lặp lại.
  • Đơn giản hóa logic: một kênh cho cả gửi và nhận.

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

Linh kiệnSố lượngGhi chú
ESP32 DevKit V11
LED đỏ1
Điện trở 220Ω1Nối tiếp LED
Dây nối/BreadboardVài sợi

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

  • GPIO2 → (220Ω) → Anode LED → Cathode → GND
  • USB cấp nguồn cho ESP32.
  • Truy cập WebSocket qua cùng mạng Wi-Fi.

5) Mã nguồn ESP32 (WebSocket + Web UI)

Thư viện dùng sẵn trong core ESP32: WiFi.h, WebServer.h, WebSocketsServer.h (nằm trong arduinoWebSockets). Nếu IDE của bạn chưa có, cài arduinoWebSockets (by Links2004) trong Library Manager.

#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketsServer.h>

#define LED_PIN 2

// ==== WiFi (đổi theo mạng của bạn) ====
const char* ssid     = "YourWiFiName";
const char* password = "YourPassword";

// HTTP server (phục vụ trang web)
WebServer http(80);

// WebSocket server trên cổng 81
WebSocketsServer ws(81);

// ---- HTML UI (inline) ----
const char INDEX_HTML[] PROGMEM = R"HTML(
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>ESP32 WebSocket - Realtime LED</title>
<style>
 body { font-family: system-ui, Arial; text-align:center; padding:30px; }
 button { font-size:18px; padding: 12px 24px; margin:8px; border:0; color:#fff; cursor:pointer;}
 .on{background:#10b981;} .off{background:#ef4444;}
 .state{margin-top:14px; font-weight:700}
</style>
</head>
<body>
<h1>ESP32 WebSocket - Realtime LED</h1>
<div id="ip"></div>
<button class="on"  onclick="send('ON')">LED ON</button>
<button class="off" onclick="send('OFF')">LED OFF</button>
<div class="state" id="s">Connecting...</div>
<script>
let ws;
function connect(){
  const host = location.hostname || prompt('ESP32 IP?');
  ws = new WebSocket('ws://' + host + ':81/');
  ws.onopen  = () => { document.getElementById('s').textContent='Connected'; ws.send('STATE'); };
  ws.onclose = () => { document.getElementById('s').textContent='Disconnected. Reconnecting...'; setTimeout(connect, 1500); };
  ws.onmessage = (e) => { document.getElementById('s').textContent = 'LED: ' + e.data; };
}
function send(cmd){ if(ws && ws.readyState===1) ws.send(cmd); }
document.getElementById('ip').textContent = 'Open this page via http://' + location.host;
connect();
</script>
</body></html>
)HTML";

// ---- Handlers ----
void handleRoot(){ http.send_P(200, "text/html", INDEX_HTML); }

void onWsEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length){
  switch(type){
    case WStype_CONNECTED: {
      // Gửi trạng thái hiện tại khi client vừa kết nối
      String s = digitalRead(LED_PIN) ? "ON" : "OFF";
      ws.sendTXT(num, s);
      break;
    }
    case WStype_TEXT: {
      String msg = String((char*)payload).substring(0, length);
      if (msg == "ON") digitalWrite(LED_PIN, HIGH);
      else if (msg == "OFF") digitalWrite(LED_PIN, LOW);
      else if (msg == "STATE") { /* chỉ yêu cầu trạng thái */ }
      // phát lại trạng thái tới tất cả client
      String s = digitalRead(LED_PIN) ? "ON" : "OFF";
      ws.broadcastTXT(s);
      break;
    }
    default: break;
  }
}

void setup(){
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  WiFi.begin(ssid, password);
  Serial.print("Connecting WiFi");
  while(WiFi.status()!=WL_CONNECTED){ delay(500); Serial.print("."); }
  Serial.println("\n✅ WiFi: " + WiFi.localIP().toString());

  http.on("/", handleRoot);
  http.begin();
  Serial.println("✅ HTTP server :80 started");

  ws.begin();
  ws.onEvent(onWsEvent);
  Serial.println("✅ WebSocket   :81 started");
}

void loop(){
  http.handleClient();
  ws.loop();
}

6) Giải thích mã

  • WebSocketsServer ws(81): mở server WebSocket cổng 81.
  • ws.onEvent: nhận lệnh "ON", "OFF", "STATE".
  • broadcastTXT: đẩy trạng thái LED tới tất cả client đang mở trang.
  • Trang HTML kết nối ws://<esp_ip>:81/ và cập nhật UI tức thì khi có tin nhắn.

7) Cách truy cập & kiểm thử

  1. Nạp code, mở Serial Monitor xem IP: 192.168.x.x.
  2. Trên điện thoại/PC cùng mạng, mở trình duyệt: http://<ESP32_IP>/
  3. Nhấn LED ON/OFF. Bạn sẽ thấy trạng thái cập nhật theo thời gian thực.
  4. Mở 2 thiết bị cùng lúc: bật/tắt trên một thiết bị → thiết bị kia cập nhật ngay.

8) Gợi ý mở rộng

  • Dùng Secure WebSocket (wss://) với chứng chỉ khi phục vụ qua HTTPS reverse proxy.
  • Thêm nhiều GPIO hoặc slider PWM để điều chỉnh độ sáng.
  • Hiển thị số liệu cảm biến (DHT11, LDR) realtime qua WebSocket.
  • Tách UI ra SPIFFS/LittleFS, thêm chart (Chart.js) để trực quan.