Điều khiển relay bằng điện thoại với Blynk IoT và ESP32: template, datastream, đồng bộ trạng thái

Hướng dẫn Blynk IoT với ESP32 từ đầu: tạo template, datastream V0–V5, thiết bị và token, nối relay 4 kênh, chương trình bật tắt bằng điện thoại kèm nút nhấn tại chỗ.

Blynk IoT là dịch vụ cho phép dựng nhanh một ứng dụng điện thoại để điều khiển ESP32 qua Internet: kéo thả công tắc, ô hiển thị số, rồi gắn mỗi thành phần với một "chân ảo" trong chương trình. Điện thoại và ESP32 không cần ở chung mạng Wi-Fi, không cần mở cổng modem hay thuê IP tĩnh. Bài này hướng dẫn từ đầu: tạo template và datastream trên Blynk Console, nối ESP32 với module relay 4 kênh, nạp chương trình bật tắt 4 thiết bị bằng điện thoại, kèm nút nhấn tại chỗ vẫn dùng được khi mất mạng và cách giữ trạng thái công tắc trong ứng dụng khớp với relay thật.

1. Blynk IoT hoạt động thế nào

Sơ đồ hoạt động: ứng dụng Blynk IoT trên điện thoại gửi lệnh lên máy chủ blynk.cloud, máy chủ chuyển xuống ESP32 điều khiển module relay 4 kênh, ESP32 gửi cường độ Wi-Fi và thời gian chạy ngược lên
Lệnh đi từ điện thoại lên máy chủ Blynk rồi mới xuống ESP32 (hình minh họa).

Có bốn khái niệm cần nắm trước khi bắt tay vào làm:

  • Template: "khuôn" của một loại thiết bị, gồm danh sách datastream và giao diện. Mười mạch giống nhau dùng chung một template.
  • Datastream: một kênh dữ liệu, ở bài này là các chân ảo (Virtual Pin) V0–V5. Chân ảo không phải chân GPIO thật; nó chỉ là số hiệu để ứng dụng và chương trình hiểu nhau. Bấm công tắc gắn V0 thì ESP32 nhận giá trị 1 hoặc 0 ở V0.
  • Device: một mạch cụ thể tạo từ template, có mã Auth Token riêng. Token là "mật khẩu" của mạch: ai có token đều điều khiển được mạch đó.
  • Máy chủ blynk.cloud: ESP32 giữ một kết nối mã hóa (cổng 443) tới máy chủ. Ứng dụng trên điện thoại cũng kết nối tới máy chủ. Mọi lệnh đi qua máy chủ, nên điện thoại dùng 4G hay Wi-Fi nhà nào cũng được.

Blynk có gói dùng miễn phí cho cá nhân, giới hạn số thiết bị và số datastream. Giới hạn cụ thể thay đổi theo thời gian; xem trang giá của Blynk trước khi làm nhiều thiết bị.

2. Chuẩn bị

Nếu máy tính chưa có gói ESP32, làm theo bài cài ESP32 vào Arduino IDE 2 trước.

3. Sơ đồ nối dây

Sơ đồ nối ESP32 DevKit V1 với module relay 4 kênh: IN1 GPIO32, IN2 GPIO33, IN3 GPIO26, IN4 GPIO27, VCC vào VIN 5 V, GND chung, nút nhấn nối GPIO4 xuống GND
Sơ đồ nối ESP32, relay 4 kênh và nút nhấn (hình minh họa).
Module relay, nútESP32 DevKit V1
IN1, IN2, IN3, IN4GPIO32, GPIO33, GPIO26, GPIO27
VCCVIN (5 V khi cấp qua cổng USB)
GNDGND
Nút nhấnMột chân vào GPIO4, chân kia vào GND

Bốn chân 32, 33, 26, 27 không phải chân khởi động của ESP32, nên module relay không làm mạch khởi động sai. Chân D21, D22 để dành cho màn hình OLED ở các bài sau. Cách hoạt động của module, jumper JD-VCC và chuyện kích mức thấp xem bài module relay 1, 2, 4 kênh.

An toàn điện: phía tiếp điểm relay đóng cắt điện 220 V. Thử chương trình với relay chưa nối tải; khi đấu tải thật, ngắt điện, lắp trong hộp kín, dây tải và dây tín hiệu đi cách xa nhau.

4. Tạo template, datastream và thiết bị trên Blynk Console

Năm bước trên Blynk Console: tạo template, tạo datastream, dựng giao diện, tạo thiết bị, chép ba dòng cấu hình; bảng datastream V0 đến V3 là relay K1 đến K4 kiểu Integer 0 đến 1, V4 Wi-Fi RSSI, V5 thời gian chạy
Các bước trên Blynk Console và bảng datastream của chương trình mẫu (hình minh họa).
  1. Đăng nhập blynk.cloud, vào Developer Zone > My Templates > New Template. Đặt tên (ví dụ "Relay 4 kenh"), phần cứng ESP32, kiểu kết nối WiFi.
  2. Trong template, mở thẻ Datastreams > New Datastream > Virtual Pin. Tạo V0, V1, V2, V3 kiểu Integer, Min 0, Max 1, giá trị mặc định 0. Tạo V4 (cường độ Wi-Fi, đơn vị dBm) và V5 (thời gian chạy, giây), kiểu Integer.
  3. Thẻ Web Dashboard: kéo 4 công tắc (Switch) gắn lần lượt V0–V3 và 2 ô hiển thị số gắn V4, V5. Bấm Save.
  4. Vào Devices > New Device > From template, chọn template vừa tạo, đặt tên thiết bị.
  5. Mở thiết bị, mục Device Info có ba dòng BLYNK_TEMPLATE_ID, BLYNK_TEMPLATE_NAME, BLYNK_AUTH_TOKEN. Chép nguyên ba dòng này dán đè lên ba dòng tương ứng ở đầu chương trình.

Trên điện thoại, đăng nhập ứng dụng Blynk IoT bằng cùng tài khoản: thiết bị vừa tạo hiện trong danh sách. Bật chế độ chỉnh sửa giao diện, thêm 4 nút bấm (Button) ở chế độ Switch gắn V0–V3 và 2 ô hiển thị giá trị gắn V4, V5. Tên menu có thể khác một chút giữa các phiên bản ứng dụng.

5. Cài thư viện Blynk

Trong Arduino IDE 2, mở Sketch > Include Library > Manage Libraries…, gõ "Blynk", chọn thư viện Blynk (tác giả Blynk) và bấm Install. IDE có thể hỏi cài thêm thư viện phụ BlynkNcpDriver: chọn cài cùng cũng được, chương trình trong bài không dùng tới thư viện này. Bài dùng gói esp32 phiên bản 3.3.10 và thư viện Blynk 1.4.0.

6. Chương trình

Thay TEN_WIFI, MAT_KHAU_WIFI bằng tên và mật khẩu Wi-Fi 2,4 GHz, dán ba dòng Device Info lên đầu file, chọn bo ESP32 Dev Module rồi nạp.

// PYWORLD.VN - Điều khiển relay 4 kênh bằng ứng dụng Blynk IoT trên điện thoại
// Bo mạch: ESP32 DevKit V1, module relay 4 kênh kích mức thấp, nút nhấn ở GPIO4
// Thư viện: Blynk 1.4.0, kết nối có mã hóa (SSL) tới máy chủ blynk.cloud

// Ba dòng này chép từ mục Device Info của thiết bị trên Blynk Console và phải đặt TRƯỚC các lệnh #include
#define BLYNK_TEMPLATE_ID "TMPLxxxxxxxxx"
#define BLYNK_TEMPLATE_NAME "Relay 4 kenh"
#define BLYNK_AUTH_TOKEN "MA_TOKEN_THIET_BI"

#define BLYNK_PRINT Serial  // In nhật ký kết nối của Blynk ra Serial Monitor

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

const char *TEN_WIFI = "TEN_WIFI";
const char *MAT_KHAU_WIFI = "MAT_KHAU_WIFI";

const uint8_t RELAY_PINS[4] = {32, 33, 26, 27};  // IN1, IN2, IN3, IN4
const bool RELAY_ACTIVE_LOW = true;              // Module kích mức thấp: IN = LOW thì relay đóng
const uint8_t NUT = 4;                           // Nút nhấn nối GPIO4 xuống GND

// false: sau khi mất điện, mọi relay tắt và ứng dụng được cập nhật theo ESP32.
// true:  ESP32 lấy lại trạng thái cuối cùng đang lưu trên máy chủ Blynk.
const bool LAY_LAI_TRANG_THAI = false;

bool relayBat[4] = {false, false, false, false};
BlynkTimer timer;
unsigned long lanThuKetNoi = 0;
bool chuaThuKetNoi = true;

void datRelay(uint8_t kenh, bool bat) {
  relayBat[kenh] = bat;
  bool muc = RELAY_ACTIVE_LOW ? !bat : bat;
  digitalWrite(RELAY_PINS[kenh], muc ? HIGH : LOW);
  Serial.printf("Relay K%u: %s\n", (unsigned)(kenh + 1), bat ? "BAT" : "TAT");
}

// Mỗi datastream V0..V3 ứng với một kênh relay: giá trị 1 là bật, 0 là tắt
BLYNK_WRITE(V0) { datRelay(0, param.asInt() == 1); }
BLYNK_WRITE(V1) { datRelay(1, param.asInt() == 1); }
BLYNK_WRITE(V2) { datRelay(2, param.asInt() == 1); }
BLYNK_WRITE(V3) { datRelay(3, param.asInt() == 1); }

// Chạy mỗi lần kết nối (hoặc kết nối lại) tới máy chủ Blynk
BLYNK_CONNECTED() {
  Serial.println("Da ket noi Blynk");
  if (LAY_LAI_TRANG_THAI) {
    Blynk.syncVirtual(V0, V1, V2, V3);  // Máy chủ gửi lại giá trị cuối, các hàm BLYNK_WRITE ở trên sẽ chạy
  } else {
    for (uint8_t i = 0; i < 4; i++) {
      Blynk.virtualWrite(V0 + i, relayBat[i] ? 1 : 0);  // Công tắc trong ứng dụng khớp với relay thật
    }
  }
}

// Gửi cường độ Wi-Fi và thời gian chạy lên V4, V5 mỗi 5 giây
void guiTrangThai() {
  if (!Blynk.connected()) return;
  Blynk.virtualWrite(V4, WiFi.RSSI());
  Blynk.virtualWrite(V5, millis() / 1000);
}

// Nút nhấn tại chỗ đảo trạng thái K1, vẫn dùng được khi mất Internet
void kiemTraNut() {
  static bool docTruoc = HIGH, onDinh = HIGH;
  static unsigned long lucDoi = 0;
  bool doc = digitalRead(NUT);
  if (doc != docTruoc) {
    docTruoc = doc;
    lucDoi = millis();
  }
  if (millis() - lucDoi > 30 && doc != onDinh) {  // Chống dội 30 ms
    onDinh = doc;
    if (onDinh == LOW) {
      datRelay(0, !relayBat[0]);
      if (Blynk.connected()) Blynk.virtualWrite(V0, relayBat[0] ? 1 : 0);
    }
  }
}

void setup() {
  Serial.begin(115200);
  for (uint8_t i = 0; i < 4; i++) {
    pinMode(RELAY_PINS[i], INPUT);                                   // Chân chưa xuất tín hiệu
    digitalWrite(RELAY_PINS[i], RELAY_ACTIVE_LOW ? HIGH : LOW);      // Ghi sẵn mức tắt
    pinMode(RELAY_PINS[i], OUTPUT);                                  // Bật ngõ ra, relay vẫn tắt
  }
  pinMode(NUT, INPUT_PULLUP);

  WiFi.mode(WIFI_STA);
  WiFi.begin(TEN_WIFI, MAT_KHAU_WIFI);
  Blynk.config(BLYNK_AUTH_TOKEN);  // Chỉ ghi cấu hình, chưa kết nối; vòng lặp tự kết nối khi có Wi-Fi
  timer.setInterval(5000L, guiTrangThai);
  Serial.println("Dang ket noi Wi-Fi...");
}

void loop() {
  kiemTraNut();
  if (WiFi.status() == WL_CONNECTED) {
    if (Blynk.connected()) {
      Blynk.run();
    } else if (chuaThuKetNoi || millis() - lanThuKetNoi > 10000) {
      chuaThuKetNoi = false;
      lanThuKetNoi = millis();
      Serial.printf("Wi-Fi OK, IP %s. Dang ket noi Blynk...\n", WiFi.localIP().toString().c_str());
      Blynk.connect(5000);  // Chờ tối đa 5 giây; không được thì 10 giây sau thử lại
    }
  }
  timer.run();
}

7. Giải thích các phần chính

Ba dòng cấu hình phải đứng trước #include

Thư viện đọc BLYNK_TEMPLATE_ID và BLYNK_TEMPLATE_NAME ngay khi được nạp. Đặt ba dòng này sau #include thì Arduino IDE báo lỗi "Please specify your BLYNK_TEMPLATE_ID and BLYNK_TEMPLATE_NAME".

Kết nối có mã hóa và không bị treo khi mất mạng

Chương trình dùng BlynkSimpleEsp32_SSL.h: dữ liệu và token đi qua kết nối mã hóa tới cổng 443, thư viện tự kèm chứng chỉ để kiểm tra máy chủ. Hàm Blynk.begin() trong ví dụ mẫu của thư viện chờ Wi-Fi mãi không thôi, nên nếu mất mạng lúc khởi động thì nút nhấn tại chỗ cũng không chạy. Bài này tách ra: Blynk.config() chỉ ghi cấu hình, vòng lặp tự gọi Blynk.connect(5000) mỗi 10 giây khi đã có Wi-Fi. Trong lúc chờ, kiemTraNut() vẫn chạy bình thường.

BLYNK_WRITE: nhận lệnh từ ứng dụng

Mỗi khi công tắc gắn V0 đổi giá trị, thư viện gọi hàm BLYNK_WRITE(V0); param.asInt() trả về 1 hoặc 0. Hàm datRelay() đổi ra mức điện phù hợp với module kích mức thấp.

BLYNK_CONNECTED: ai giữ trạng thái đúng sau khi mất điện?

Khi ESP32 khởi động lại sau mất điện, các relay đều tắt, trong khi công tắc trong ứng dụng có thể vẫn đang bật. Có hai cách cho khớp lại, chọn bằng hằng LAY_LAI_TRANG_THAI:

  • false (mặc định): ESP32 gửi trạng thái thật của mình lên (Blynk.virtualWrite), công tắc trong ứng dụng chuyển về tắt. An toàn hơn với máy bơm, lò sưởi, thiết bị không nên tự chạy lại.
  • true: ESP32 xin lại giá trị cuối cùng lưu trên máy chủ (Blynk.syncVirtual), relay trở lại như trước khi mất điện. Hợp với đèn, quạt.

BlynkTimer thay cho delay()

timer.setInterval(5000L, guiTrangThai) gọi hàm gửi V4, V5 mỗi 5 giây mà không chặn vòng lặp. Không dùng delay() dài trong chương trình Blynk: thư viện cần Blynk.run() được gọi thường xuyên để giữ kết nối. Cũng không nên gửi dữ liệu lên máy chủ nhiều lần mỗi giây.

Khởi tạo chân relay không làm relay đóng thoáng qua

Chân được ghi sẵn mức tắt trước khi chuyển sang ngõ ra, giống các bài relay khác trên pyworld.vn. Lý do xem bài relay làm ESP32 bị reset.

8. Kết quả

Giao diện minh họa trên điện thoại: bốn công tắc Đèn phòng khách, Quạt, Máy bơm, Ổ cắm gắn relay K1 đến K4, ô Wi-Fi −61 dBm và ô thời gian chạy
Bốn công tắc và hai ô số trên điện thoại (hình minh họa).
Serial Monitor khi ESP32 kết nối Blynk: kết nối Wi-Fi, Connecting to blynk.cloud:443, Certificate OK, Ready, Da ket noi Blynk, Relay K1 BAT, Relay K3 BAT, Relay K1 TAT
Thông báo trên Serial Monitor ở tốc độ 115200 (hình minh họa).

Bấm công tắc trong ứng dụng, relay tương ứng đóng sau khoảng nửa giây, đèn báo trên module sáng. Bấm nút nhấn trên mạch, K1 đổi trạng thái và công tắc K1 trong ứng dụng cũng đổi theo. Rút dây Wi-Fi của modem: nút nhấn vẫn dùng được; khi có mạng lại, ESP32 tự kết nối và cập nhật ứng dụng.

9. Mở rộng

  • Thông báo về điện thoại: Blynk có mục Events trong template; chương trình gọi sự kiện khi có chuyện cần báo (ví dụ mất nguồn lưới, cửa mở). Cách gửi cảnh báo không cần dịch vụ trả phí xem bài gửi cảnh báo qua Telegram trong cùng loạt.
  • Hẹn giờ, tự động hóa: thực hiện được trên Blynk Console tùy gói, hoặc tự viết trong chương trình bằng giờ Internet như bài đồng hồ Internet NTP.
  • Không muốn phụ thuộc dịch vụ bên ngoài: điều khiển trong mạng nội bộ bằng web server trên ESP32, hoặc qua MQTT.
  • Đóng hộp: hộp mica cho ESP32 DevKit 30 chân và nguồn 5 V riêng cho cuộn relay.

Giữ kín token: không đăng chương trình có token thật lên mạng. Lỡ để lộ, vào thiết bị trên Blynk Console tạo token mới rồi nạp lại chương trình.

10. Xử lý lỗi thường gặp

Hiện tượngNguyên nhân thường gặpCách xử lý
Biên dịch báo "Please specify your BLYNK_TEMPLATE_ID and BLYNK_TEMPLATE_NAME"Ba dòng cấu hình nằm sau #include hoặc bị xóaĐưa ba dòng Device Info lên đầu file
Serial in "Invalid auth token"Chép thiếu ký tự token, hoặc token đã bị tạo lạiChép lại cả ba dòng từ Device Info
Đứng mãi ở "Connecting to blynk.cloud:443", hoặc "Secure connection failed"Mạng chặn cổng 443 ra ngoài, Wi-Fi yếu, nguồn sụt khi phát Wi-FiThử Wi-Fi điện thoại phát; xem cường độ ở V4; cấp nguồn khỏe hơn (bài cấp nguồn cho ESP32)
Không vào được Wi-FiSai tên, mật khẩu, hoặc modem chỉ phát 5 GHzESP32 chỉ dùng Wi-Fi 2,4 GHz; kiểm tra theo bài kết nối Wi-Fi trên ESP32
Bấm công tắc, relay không đổi nhưng Serial có in "Relay K1: BAT"Module kích mức cao, hoặc dây IN cắm nhầm chânĐổi RELAY_ACTIVE_LOW thành false, dò lại dây theo bảng
Công tắc trong ứng dụng không có tác dụng, Serial không in gìCông tắc gắn nhầm datastream, hoặc datastream kiểu khác Integer 0–1Mở cài đặt công tắc, chọn đúng V0–V3
ESP32 khởi động lại khi relay đóngSụt áp hoặc nhiễu từ tảiXem bài relay làm ESP32 bị reset

11. Xem thêm


Tin tức liên quan

Hướng dẫn bắt đầu MicroPython trên ESP32 Lite với Thonny
Hướng dẫn bắt đầu MicroPython trên ESP32 Lite với Thonny

Hướng dẫn cài driver, cài Thonny và nạp firmware MicroPython cho mạch ESP32 Lite, dùng REPL, nháy LED, lưu main.py, đọc nút nhấn, quét I2C và xử lý lỗi thường gặp.

Tưới cây tự động với ESP32: cảm biến độ ẩm đất, relay và bơm mini, ngưỡng có trễ
Tưới cây tự động với ESP32: cảm biến độ ẩm đất, relay và bơm mini, ngưỡng có trễ

Làm hệ thống tưới cây tự động với ESP32: cảm biến độ ẩm đất điện dung, hiệu chỉnh khô ướt, relay điều khiển bơm mini, ngưỡng có trễ, giới hạn thời gian bơm và thí nghiệm STEM.

Hướng dẫn ESP32 làm web server điều khiển relay 4 kênh qua WiFi
Hướng dẫn ESP32 làm web server điều khiển relay 4 kênh qua WiFi

Hướng dẫn dùng ESP32 DevKit V1 làm web server trong mạng WiFi nội bộ, mở trang trên điện thoại để bật, tắt module relay 4 kênh; có sơ đồ nối dây, code Arduino IDE và lưu ý an toàn.

Từ breadboard đến thiết bị dùng thật: đưa ESP32 vào hộp, khoan lỗ jack Type-C, GX16, jack DC
Từ breadboard đến thiết bị dùng thật: đưa ESP32 vào hộp, khoan lỗ jack Type-C, GX16, jack DC

Đưa dự án ESP32 từ breadboard vào hộp: cấp nguồn USB 5 V hoặc adapter 12 V qua LM2596, bố trí linh kiện, khoan lỗ jack Type-C, jack DC, GX16 và chương trình hộp relay có nút nhấn.

ESP32 điều khiển máy CNC, máy laser với FluidNC: Wi-Fi, file cấu hình và giao diện web
ESP32 điều khiển máy CNC, máy laser với FluidNC: Wi-Fi, file cấu hình và giao diện web

Dùng ESP32 DevKit V1 chạy FluidNC điều khiển máy khắc laser 2 trục: sơ đồ nối hai A4988, cài firmware từ trình duyệt, file config.yaml mẫu giải thích từng dòng, lệnh hay dùng, Wi-Fi.

Hướng dẫn bắt đầu với Arduino Nano CH340: sơ đồ chân, driver và nạp code
Hướng dẫn bắt đầu với Arduino Nano CH340: sơ đồ chân, driver và nạp code

Hướng dẫn bắt đầu với Arduino Nano CH340: sơ đồ chân, cài driver, chọn Board và Processor, nạp Blink, in ra Serial Monitor, quét I2C trên A4/A5, cấp nguồn và xử lý lỗi thường gặp.

ESP32 điều khiển servo SG90 bằng PWM, không cần thư viện: quét góc, biến trở, hiệu chỉnh
ESP32 điều khiển servo SG90 bằng PWM, không cần thư viện: quét góc, biến trở, hiệu chỉnh

Hướng dẫn điều khiển servo SG90 bằng ESP32 với bộ PWM LEDC 50 Hz có sẵn: xung 0,5–2,4 ms, sơ đồ nối, quét góc, vặn biến trở, hiệu chỉnh hai đầu hành trình và thí nghiệm STEM.

Hướng dẫn dùng thanh cảm biến dò line 5 kênh TCRT5000 với ESP32
Hướng dẫn dùng thanh cảm biến dò line 5 kênh TCRT5000 với ESP32

Hướng dẫn nối thanh dò line 5 kênh TCRT5000 (BFD-1000) với ESP32 DevKit V1, đọc trạng thái 5 kênh trên Serial Monitor, tính vị trí vạch và gợi ý hướng lái cho xe dò line.


Bình luận
Đã thêm vào giỏ hàng