



















Preview text:
HỌC VIỆN CÔNG NGHỆ BƯU CHÍNH VIỄN THÔNG
TRUNG TÂM ĐÀOTẠO BƯU CHÍNH VIỄN THÔNG I __________***__________
BÀI TẬP LỚN CUỐI KỲ
Môn: IoT và ứng dụng
Đề tài: Lập trình ESP32 dùng giao thức MQTT để chuyển dữ liệu nhiệt độ, độ ẩm
từ cảm biến DH211 và khoảng cách thừ cảm biến HC-SRF05 lên trang webserver.
GVHD: TS.Nguyễn Đức Minh
Danh sách sách thành viên nhóm 5 Họ và Tên Mã sinh viên Lớp Lưu Phúc Thọ B22DTCN035 D22TXCN01-B Lưu Cung Tuấn B22DTCN040 D22TXCN01-B Nguyễn Qúy Tài B22DTCN029 D22TXCN01-B Hà Nội, 03/2025 Mục lục
Nhóm 5- Lớp : D22TXCN01-B 2 LỜI MỞ ĐẦU
Trong thời đại công nghệ phát triển mạnh mẽ, Internet vạn vật (IoT - Internet of Things) đã trở
thành một trong những xu hướng quan trọng, mở ra một kỷ nguyên mới về kết nối và tự động
hóa. IoT cho phép các thiết bị, cảm biến và hệ thống có thể giao tiếp với nhau qua mạng internet,
giúp thu thập, xử lý và chia sẻ dữ liệu theo thời gian thực.
Sự phát triển của IoT mang lại nhiều lợi ích to lớn trong các lĩnh vực như công nghiệp, y tế, giao
thông, nông nghiệp và nhà thông minh. Các hệ thống IoT không chỉ giúp nâng cao hiệu suất làm
việc mà còn tối ưu hóa chi phí, giảm thiểu sức lao động thủ công và tạo ra những trải nghiệm
thông minh hơn cho con người.
Tuy nhiên, bên cạnh những lợi ích rõ ràng, IoT cũng đặt ra nhiều thách thức về bảo mật, độ tin
cậy của hệ thống và khả năng mở rộng. Do đó, việc nghiên cứu và ứng dụng IoT một cách hiệu
quả là một vấn đề quan trọng cần được quan tâm.
Báo cáo này sẽ trình bày tổng quan về các thiết bị sử dụng trong hệ thống IoT, các giao thức
truyền thông phổ biến, nền tảng CNTT hỗ trợ IoT trên cloud, cũng như cách IoT đang được ứng
dụng vào thực tế. Qua đó, giúp người đọc có cái nhìn sâu sắc hơn về công nghệ này và tiềm năng của nó trong tương lai.
Nhóm 5- Lớp : D22TXCN01-B 3
CHƯƠNG 1 : TỔNG QUAN VỀ CÁC THIẾT BỊ SỬ DỤNG TRONG HỆ THỐNG. 1.1 Vi điều khiển
1.1.1 Giới thiệu về ESP32
Hình 1: Sở đồ và Kit ESP 32.
ESP32 là một dòng vi điều khiển tích hợp Wi-Fi và Bluetooth do Espressif Systems phát
triển. Đây là phiên bản nâng cấp của ESP8266, với hiệu suất mạnh mẽ hơn, nhiều tính năng
hơn và khả năng ứng dụng rộng rãi hơn trong các hệ thống IoT (Internet of Things).
Vi điều khiển ESP32 được thiết kế để hỗ trợ các ứng dụng nhúng, kết nối mạng, điều khiển tự
động, nhà thông minh, và nhiều lĩnh vực khác nhờ vào bộ xử lý mạnh mẽ, kết nối không dây
ổn định và khả năng tiêu thụ điện năng thấp.
1.1.2 Thông số kỹ thuật của ESP32
ESP32 có nhiều phiên bản khác nhau, nhưng hầu hết đều có các thông số kỹ thuật chung sau: Bộ xử lý (CPU): o
Dual-core Tensilica LX6 hoặc single-core o
Tốc độ xung nhịp lên đến 240 MHz o
Hiệu suất cao hơn nhiều so với ESP8266 Bộ nhớ: o RAM: 520 KB SRAM o ROM: 448 KB o
Flash: Thường từ 4 MB trở lên Kết nối không dây: o
Wi-Fi 802.11 b/g/n (tốc độ lên đến 150 Mbps) o
Bluetooth v4.2 + Bluetooth Low Energy (BLE) Giao diện ngoại vi: o
GPIO (General Purpose Input/Output): Từ 30-40 chân tùy phiên bản o
ADC (Analog to Digital Converter): 18 kênh, độ phân giải 12-bit o
DAC (Digital to Analog Converter): 2 kênh, độ phân giải 8-bit
Nhóm 5- Lớp : D22TXCN01-B 4 o
PWM (Pulse Width Modulation): Điều chế độ rộng xung trên nhiều chân GPIO o
SPI, I2C, UART, I2S: Hỗ trợ nhiều giao tiếp với các thiết bị ngoại vi o
SDIO, CAN, Ethernet MAC: Hỗ trợ các ứng dụng mạng nâng cao
Tiêu thụ điện năng thấp: o
Hỗ trợ nhiều chế độ tiết kiệm điện như Deep Sleep, Light Sleep o
Có thể hoạt động bằng pin trong thời gian dài
1.1.3 Các phiên bản phổ biến của ESP32
ESP32 có nhiều phiên bản khác nhau, phục vụ các mục đích khác nhau. Một số phiên bản phổ biến gồm: 1. ESP32-WROOM-32: o
Phiên bản tiêu chuẩn, phổ biến nhất, có bộ nhớ Flash 4MB. 2. ESP32-WROVER: o
Tích hợp thêm PSRAM (Pseudo-SRAM) giúp mở rộng bộ nhớ RAM. 3. ESP32-CAM: o
Có hỗ trợ module camera OV2640, ứng dụng trong nhận diện hình ảnh. 4. ESP32-S3: o
Hỗ trợ AI (trí tuệ nhân tạo) và xử lý hình ảnh mạnh hơn. 5. ESP32-C3: o
Phiên bản giá rẻ, hỗ trợ RISC-V thay vì Tensilica LX6.
1.1.4 Ưu điểm của ESP32
ESP32 có nhiều ưu điểm vượt trội, giúp nó trở thành lựa chọn hàng đầu cho các ứng dụng IoT:
Hiệu suất cao: CPU mạnh mẽ, xử lý nhanh hơn nhiều so với ESP8266.
Kết nối linh hoạt: Hỗ trợ cả Wi-Fi và Bluetooth (BLE), dễ dàng tích hợp với các hệ thống IoT.
Nhiều cổng giao tiếp: SPI, I2C, UART, PWM, ADC, DAC,… hỗ trợ nhiều loại cảm biến và thiết bị ngoại vi.
Tiết kiệm điện năng: Hỗ trợ nhiều chế độ sleep, có thể hoạt động bằng pin trong thời gian dài.
Hỗ trợ AI và xử lý tín hiệu: Một số phiên bản như ESP32-S3 có khả năng hỗ trợ AI/ML.
Giá thành hợp lý: Dễ dàng tiếp cận với mức giá chỉ từ 5-10 USD cho một module ESP32 tiêu chuẩn.
1.1.5 Nhược điểm của ESP32
Bên cạnh những ưu điểm, ESP32 cũng có một số hạn chế:
Tốn tài nguyên hơn ESP8266: Do có nhiều tính năng hơn, ESP32 đòi hỏi nhiều tài nguyên hơn.
Lập trình phức tạp hơn: So với ESP8266, ESP32 có nhiều tính năng hơn, cần nhiều thư viện và cấu hình hơn.
Một số phiên bản không tương thích với Arduino IDE ngay từ đầu: Cần cài đặt driver và thư viện phù hợp.
1.1.6 Ứng dụng của ESP32 trong IoT
Nhóm 5- Lớp : D22TXCN01-B 5
ESP32 được ứng dụng rộng rãi trong nhiều lĩnh vực khác nhau: Nhà thông minh (Smart Home):
Điều khiển đèn, quạt, máy lạnh qua Wi-Fi/Bluetooth.
Hệ thống giám sát bằng camera ESP32-CAM.
Điều khiển từ xa qua MQTT hoặc Blynk. Nông nghiệp thông minh:
Hệ thống tưới cây tự động bằng cảm biến độ ẩm đất.
Giám sát nhiệt độ, độ ẩm môi trường. Công nghiệp 4.0:
Điều khiển máy móc, giám sát sản xuất qua mạng Wi-Fi.
Hệ thống đo lường không dây. Xe tự hành & Robot:
Điều khiển robot qua Wi-Fi/Bluetooth.
Nhận diện hình ảnh với ESP32-CAM.
Hệ thống giám sát & Cảnh báo:
Cảnh báo cháy bằng cảm biến nhiệt và khí gas.
Giám sát an ninh qua camera ESP32-CAM. 1.2 Các cảm biến
1.2.1 Cảm biến nhiệt độ và độ ẩm DHT11
1.2.1.1 Giới thiệu về DHT11
Hình 2: Cảm biến nhiệt độ và độ ẩm DHT11
DHT11 là một cảm biến đo nhiệt độ và độ ẩm phổ biến, được sử dụng rộng rãi trong các
hệ thống IoT, nhà thông minh và tự động hóa. Cảm biến này có thiết kế nhỏ gọn, dễ sử
dụng và chi phí thấp, phù hợp cho các ứng dụng đo lường môi trường.
1.2.1.2Thông số kỹ thuật của DHT11 Thông số Gía trị
Nhóm 5- Lớp : D22TXCN01-B 6 Nguồn cấp 3.3V - 5V Dòng tiêu thụ 0.5mA Dải đo nhiệt độ 0 - 50°C Sai số nhiệt độ ±2°C Dải đo độ ẩm 20% - 90% RH Sai số độ ẩm ±5% RH
Tần suất lấy mẫu 1 Hz (1 lần/s) Giao tiếp Digital (1 dây)
1.2.1.3 Cấu tạo của DHT11
Cảm biến DHT11 có 3 thành phần chính:
Cảm biến nhiệt độ: Đo nhiệt độ bằng điện trở nhiệt.
Cảm biến độ ẩm: Dùng vật liệu polymer để đo độ ẩm không khí.
Mạch điều khiển: Chuyển đổi tín hiệu analog sang digital và truyền qua giao tiếp 1 dây.
1.2.1.4 Nguyên lý hoạt động của DHT11
Khi cấp nguồn, DHT11 bắt đầu đo nhiệt độ và độ ẩm.
Cảm biến độ ẩm hoạt động dựa trên sự thay đổi điện dung của vật liệu polymer khi độ ẩm thay đổi.
Cảm biến nhiệt độ hoạt động dựa trên sự thay đổi điện trở của một phần tử bán dẫn khi nhiệt độ thay đổi.
Dữ liệu được mã hóa và gửi đến vi điều khiển qua một tín hiệu digital (1 dây).
1.2.1.5 Ứng dụng của DHT11 -
Giám sát nhiệt độ và độ ẩm trong nhà thông minh. -
Điều khiển tự động trong nông nghiệp (nhà kính, hệ thống tưới tiêu). -
Giám sát môi trường trong các kho hàng, phòng server. -
Thiết bị cảnh báo thời tiết, cảm biến khí hậu.
1.2.2 Cảm biến siêu âm HY-SRF05
1.2.2.1 Giới thiệu về SRF05
Nhóm 5- Lớp : D22TXCN01-B 7
Hình 3: Cảm biến siêu âm HY-SRF05
Cảm biến siêu âm SRF05 (Ultrasonic Sensor) được sử dụng để đo khoảng cách bằng cách phát ra
sóng siêu âm và tính toán thời gian phản hồi. SRF05 có độ chính xác cao, phạm vi đo lớn hơn so
với dòng HC-SR04, phù hợp với các ứng dụng robot, đo mức nước và phát hiện vật cản.
1.2.2.2 Thông số kỹ thuật của SRF05 Thông số Gía trị Nguồn cấp 5V DC Dòng tiêu thụ 4mA
Tần số sóng siêu âm 40kHz
Dải đo khoảng cách 2cm - 400cm Độ chính xác ±3mm Góc quét ~15 độ Giao tiếp
Digital (Trigger - Echo)
1.2.2.3 Cấu tạo của SRF05
Cảm biến SRF05 gồm 2 phần chính:
Bộ phát sóng siêu âm (Trigger): Phát sóng siêu âm ở tần số 40kHz.
Bộ thu sóng siêu âm (Echo): Nhận tín hiệu phản xạ từ vật thể.
1.2.2.4 Nguyên lý hoạt động của SRF05
Vi điều khiển gửi một xung điện áp cao (5V) đến chân Trigger (ít nhất 10µs).
Cảm biến phát sóng siêu âm với tần số 40kHz.
Khi sóng siêu âm gặp vật cản, nó phản xạ trở lại và được thu bởi bộ thu (Echo).
Cảm biến SRF05 đo thời gian từ khi phát sóng đến khi nhận lại và tính toán khoảng cách theo công thức:
Khoảng caˊch= (Thời gian x 340)/2
Với 340m/s là tốc độ truyền âm trong không khí.
Nhóm 5- Lớp : D22TXCN01-B 8
1.2.2.5 Ứng dụng của SRF05 Robot tránh vật cản.
Đo mức nước trong bể chứa.
Đo khoảng cách, kiểm soát không gian.
Hệ thống đỗ xe thông minh. 1.3 Relay 2 Kênh
1.3.1 Giới thiệu về Relay 2 Kênh
Hình ảnh 4: Module relay 2 kênh
Relay 2 kênh là một module điều khiển thiết bị điện sử dụng tín hiệu điện áp thấp (3.3V/5V)
để đóng ngắt các tải điện áp cao (AC hoặc DC). Relay thường được sử dụng trong các hệ
thống IoT, tự động hóa nhà thông minh, điều khiển động cơ, đèn, quạt, máy bơm, v.v.
Module này có 2 relay độc lập, cho phép điều khiển hai thiết bị riêng biệt bằng vi điều
khiển như ESP32, Arduino, Raspberry Pi.
1.3.2 Thông số kỹ thuật của Relay 2 Kênh Thông số Gía trị
Điện áp điều khiển 3.3V - 5V DC Điện áp tải 250V AC / 30V DC Dòng tải tối đa 10A Số kênh
2 kênh (2 relay độc lập) Loại relay
SPDT (Single Pole Double Throw)
Tín hiệu điều khiển
Mức thấp kích hoạt (HIGH trigger)
Đèn LED báo trạng thái Có
1.3.3 Cấu tạo của Relay 2 Kênh
Relay 2 kênh có các thành phần chính sau:
1. Relay cơ khí: Thành phần chính đóng/ngắt mạch điện.
2. Optocoupler: Cách ly tín hiệu điều khiển với tải, tăng độ an toàn.
3. Transistor kích relay: Khuếch đại dòng điện để điều khiển relay.
4. Diode bảo vệ: Ngăn dòng ngược khi relay tắt, bảo vệ vi điều khiển.
5. LED báo trạng thái: Báo hiệu relay đang bật hay tắt.
1.3.4 Chân kết nối của Relay 2 Kênh
Nhóm 5- Lớp : D22TXCN01-B 9 Chân Chức năng VCC
Cấp nguồn (3.3V - 5V) GND Nối đất (GND) IN1 Điều khiển relay 1 IN2 Điều khiển relay 2 COM (Common) Chân chung của relay NO (Normally Open)
Tiếp điểm thường mở (đóng khi kích hoạt) NC (Normally Closed)
Tiếp điểm thường đóng (mở khi kích hoạt)
1.3.5 Nguyên lý hoạt động của Relay 2 Kênh
Relay hoạt động dựa trên nguyên lý điện từ:
1. Khi cấp mức tín hiệu LOW (0V) vào chân IN1 hoặc IN2, relay tương ứng sẽ kích hoạt (đóng mạch).
2. Khi cấp mức tín hiệu HIGH (3.3V hoặc 5V) vào chân IN1 hoặc IN2, relay sẽ tắt (mở mạch). Relay có hai chế độ:
NO (Normally Open - Thường mở): Mạch hở khi relay tắt, mạch đóng khi relay bật.
NC (Normally Closed - Thường đóng): Mạch đóng khi relay tắt, mạch mở khi relay bật.
1.3.6 Ứng dụng của Relay 2 Kênh
Điều khiển thiết bị điện (bật/tắt đèn, quạt, máy bơm, v.v.).
Hệ thống nhà thông minh (tự động hóa ánh sáng, quạt, cửa...).
Điều khiển động cơ DC/AC.
Hệ thống an ninh (còi báo động, camera).
Tích hợp IoT với ESP32, MQTT, Blynk để điều khiển từ xa. 1.4
Màn hình LCD 1602 kèm Module I2C.
1.4.1 Giới thiệu chung
Hình 5: Màn hình LCD 1602 Xanh Lá.
Màn hình LCD 1602 I2C là loại màn hình hiển thị 16 ký tự trên 2 dòng, sử dụng công
nghệ tinh thể lỏng (Liquid Crystal Display - LCD). Khi kết hợp với module giao tiếp
I2C, màn hình giúp tiết kiệm chân kết nối, giúp dễ dàng sử dụng với vi điều khiển như ESP32, Arduino, Raspberry Pi.
LCD 1602 I2C thường được sử dụng để hiển thị thông tin cảm biến, trạng thái hệ thống
IoT, dữ liệu thời gian thực, v.v.
1.4.2 Thông số kỹ thuật của LCD 1602 I2C
Nhóm 5- Lớp : D22TXCN01-B 10 Thông số Gía trị
Kích thước hiển thị 16 ký tự x 2 dòng
Điện áp hoạt động 5V DC Giao tiếp I2C (SDA, SCL)
Địa chỉ I2C mặc định 0x27 hoặc 0x3F
Điều khiển hiển thị Chip HD44780 Màu nền
Xanh dương hoặc xanh lá Ký tự hiển thị
Trắng (nền xanh) hoặc đen (nền vàng)
1.4.3 Cấu tạo của LCD 1602 I2C
LCD 1602 khi sử dụng module I2C có 4 chân kết nối chính: Chân Ký hiệu Chức năng 1 GND Nối đất (0V) 2 VCC Cấp nguồn (5V) 3 SDA
Dữ liệu I2C (kết nối với SDA của ESP32) 4 SCL
Xung nhịp I2C (kết nối với SCL của ESP32) Lưu ý:
Địa chỉ I2C của module có thể là 0x27 hoặc 0x3F, tùy phiên bản.
Nếu màn hình không hiển thị, có thể cần chỉnh biến trở chiết áp (Potentiometer) trên
module I2C để điều chỉnh độ tương phản.
1.4.4 Ưu điểm khi sử dụng module I2C
Tiết kiệm chân kết nối: Chỉ cần 2 dây (SDA, SCL) thay vì 6-8 dây như LCD 1602 thông thường.
Dễ dàng kết nối với ESP32, Arduino: Sử dụng thư viện hỗ trợ có sẵn.
Hiệu suất cao: Tốc độ truyền dữ liệu nhanh và chính xác hơn so với giao tiếp song song. 1.5
Các giao thức truyền thông được sử dụng trong BTL
1.5.1 Giao thức MQTT (Message Queuing Telemetry Transport) 1.5.1.1 Giới thiệu
MQTT là giao thức truyền thông nhẹ được sử dụng phổ biến trong IoT, giúp các thiết bị trao đổi
dữ liệu với nhau qua broker (máy chủ trung gian). ESP32 trong BTL của bạn sử dụng MQTT để
gửi dữ liệu nhiệt độ, độ ẩm, khoảng cách lên HiveMQ Cloud (hoặc Mosquitto, CloudMQTT) và
nhận lệnh điều khiển relay từ cloud.
1.5.1.2 Cách hoạt động của MQTT
Publisher: Thiết bị gửi dữ liệu (ESP32 gửi nhiệt độ, độ ẩm...).
Subscriber: Thiết bị nhận dữ liệu (ESP32 nhận lệnh điều khiển relay từ cloud).
Broker: Máy chủ trung gian giúp quản lý các luồng dữ liệu.
1.5.1.2 Đặc điểm của MQTT
Nhẹ, nhanh, tiết kiệm băng thông → Phù hợp với IoT.
Hỗ trợ QoS (Quality of Service) đảm bảo truyền dữ liệu ổn định.
Hỗ trợ mô hình Pub/Sub giúp quản lý dữ liệu dễ dàng.
Có thể sử dụng trên cloud (HiveMQ, Mosquitto...).
1.5.2 Giao thức I2C (Inter-Integrated Circuit) 1.5.2.1 Giới thiệu
I2C là giao thức truyền thông nối tiếp sử dụng 2 dây (SDA, SCL) để trao đổi dữ liệu giữa các thiết
bị. Trong BTL, I2C được dùng để giao tiếp giữa ESP32 và LCD 1602.
1.5.2.2 Đặc điểm của I2C
Chỉ cần 2 dây (SDA, SCL) để truyền dữ liệu → Tiết kiệm chân GPIO.
Hỗ trợ nhiều thiết bị trên cùng bus I2C.
Nhóm 5- Lớp : D22TXCN01-B 11
Tốc độ truyền cao (100kHz - 400kHz). 1.6
Nền tảng CNTT hỗ trợ IoT trên cloud.
HiveMQ Cloud (hoặc Mosquitto, CloudMQTT) - MQTT Broker trên Cloud 1.6.1 Giới thiệu
HiveMQ Cloud là một MQTT Broker trên cloud giúp các thiết bị IoT trao đổi dữ liệu real-
time. ESP32 của bạn sử dụng HiveMQ Cloud để gửi dữ liệu nhiệt độ, độ ẩm, khoảng cách
và nhận lệnh điều khiển relay từ cloud.
1.6.2 Cách hoạt động của HiveMQ Cloud trong BTL
ESP32 đóng vai trò Publisher, gửi dữ liệu cảm biến lên cloud.
Ứng dụng Blynk hoặc MQTT Dashboard đóng vai trò Subscriber, nhận dữ liệu từ ESP32.
Khi người dùng gửi lệnh điều khiển relay từ Webserver, ESP32 nhận lệnh và bật/tắt relay.
1.6.3 Dữ liệu ESP32 gửi lên HiveMQ Cloud relay/1/command relay/2/command relay/1/state relay/2/state relay/status sensor/temperature sensor/ h umidity sensor/ d istance
CHƯƠNG 2: CẤU TẠO VÀ NGUYÊN TẮC HOẠT ĐỘNG CỦA HỆ THỐNG.
2.1 Sơ đồ khối chức năng.
Nhóm 5- Lớp : D22TXCN01-B 12
Hình ảnh 6: Sơ đồ khối chức năng
Luồng hoạt động của hệ thống:
1. Nguồn cấp điện cho ESP32 từ nút Power
2. Thu thập dữ liệu từ cảm biến DHT11 - Cảm biến nhiệt độ gửi dữ liệu về ESP32
3. Thu thập dữ liệu từ cảm biến HY-SRF05 - Cảm biến siêu âm gửi dữ liệu khoảng cách về ESP32
4. Điều khiển thiết bị - ESP32 gửi lệnh điều khiển đến Relay 2 kênh để bật/tắt thiết bị
5. Hiển thị thông tin - ESP32 hiển thị thông tin trên màn hình LCD 1602 I2C
6. Gửi dữ liệu lên MQTT - ESP32 đẩy dữ liệu lên HIVEMQ MQTT Broker
7. Lưu trữ dữ liệu - ESP32 gửi dữ liệu lên Firebase để lưu trữ
8. Hiển thị dữ liệu cho người dùng - Firebase gửi dữ liệu đến Web Client và Mobile Client
9. Nhận lệnh điều khiển từ xa - HIVEMQ gửi lệnh điều khiển từ người dùng về ESP32 (đường đứt khúc)
10. Người dùng gửi lệnh - Web Client và Mobile Client gửi lệnh điều khiển qua MQTT (đường đứt khúc)
2.2 Sơ đồ mạch điện chi tiết.
Nhóm 5- Lớp : D22TXCN01-B 13
Hình ảnh 7: Sơ đồ đấu nối mạch điện chi tiết
2.3 Hoạt động của hệ thống. Khởi động ESP32
ESP32 kết nối WiFi và đăng ký với MQTT Broker.
Kiểm tra trạng thái ban đầu của các cảm biến và relay.
Đọc dữ liệu cảm biến
Cảm biến DHT11 đo nhiệt độ và độ ẩm, gửi dữ liệu về ESP32.
Cảm biến HY-SRF05 đo khoảng cách, gửi tín hiệu về ESP32.
Xử lý và hiển thị dữ liệu
ESP32 xử lý dữ liệu thu được và hiển thị lên màn hình LCD 1602.
Dữ liệu cảm biến được hiển thị theo chu kỳ (VD: mỗi 2 giây).
Gửi dữ liệu lên MQTT Broker
ESP32 gửi dữ liệu nhiệt độ, độ ẩm và khoảng cách lên MQTT Broker.
Các thiết bị hoặc ứng dụng kết nối MQTT có thể nhận dữ liệu real-time. Điều khiển relay qua MQTT
Người dùng gửi lệnh bật/tắt cảm biến từ cloud qua MQTT. Khi nhận lệnh: o
Relay 1 điều khiển bật/tắt cảm biến DHT11. o
Relay 2 điều khiển bật/tắt cảm biến HY-SRF05.
ESP32 cập nhật trạng thái relay và gửi phản hồi về MQTT.
Hoạt động liên tục & kiểm tra lỗi
Hệ thống chạy liên tục, kiểm tra kết nối MQTT và WiFi.
Nếu mất kết nối, ESP32 sẽ tự động kết nối lại. Phụ lục 1: Mã nguồn I, KIT ESP 32 WIFI
Nhóm 5- Lớp : D22TXCN01-B 14 #include #include #include #include #include #include "DHT.h" #include // WiFi Credentials const char* ssid = "WIFI";
const char* password = "12356789"; // MQTT Broker
const char* mqtt_server = "186f18001d1e49f1bddeee963197cbe8.s1.eu.hivemq.cloud"; const int mqtt_port = 8883;
const char* mqtt_user = "tuanlc";
const char* mqtt_password = "123456aA@"; WiFiClientSecure espClient;
PubSubClient client(espClient); // DHT Sensor #define DHTPIN 5 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); // SRF05 Sensor #define TRIG_PIN 4 #define ECHO_PIN 15 // Relay Pins #define RELAY1 26 #define RELAY2 27 // LCD Setup
LiquidCrystal_I2C lcd(0x27, 16, 2); bool relay1State = false; bool relay2State = false; // Topic definitions
const char* TOPIC_RELAY1_COMMAND = "relay/1/command"; // Chỉ nhận lệnh
const char* TOPIC_RELAY2_COMMAND = "relay/2/command"; // Chỉ nhận lệnh
const char* TOPIC_RELAY1_STATE = "relay/1/state"; // Chỉ gửi trạng thái
const char* TOPIC_RELAY2_STATE = "relay/2/state"; // Chỉ gửi trạng thái
const char* TOPIC_REQUEST_STATUS = "relay/status";
const char* TOPIC_TEMPERATURE = "sensor/temperature";
const char* TOPIC_HUMIDITY = "sensor/humidity";
const char* TOPIC_DISTANCE = "sensor/distance"; // Biến thời gian
unsigned long lastSensorPublish = 0;
Nhóm 5- Lớp : D22TXCN01-B 15
const long sensorPublishInterval = 5000;
unsigned long lastRelayDebounceTime = 0;
const long relayDebounceDelay = 500; // Thời gian chống dội (debounce)
unsigned long lastRelayStatePublish = 0;
const long relayStatePublishInterval = 30000; // Gửi lại trạng thái relay mỗi 30 giây
// Biến cờ để theo dõi lỗi cảm biến bool dhtError = false; bool distanceError = false; int errorCount = 0; void setup_wifi(); void reconnect_mqtt();
void callback(char* topic, byte* payload, unsigned int length); void publish_sensor_data(); void publish_relay_state(); float getDistance();
void updateLCD(float t, float h, float d);
void setRelay(int relay, bool state); void setup() { Serial.begin(115200);
Serial.println("\n\n=== ESP32 IoT System Starting ==="); // Khởi tạo chân GPIO pinMode(TRIG_PIN, OUTPUT); pinMode(ECHO_PIN, INPUT); pinMode(RELAY1, OUTPUT); pinMode(RELAY2, OUTPUT);
// Đặt trạng thái ban đầu cho relay (OFF)
digitalWrite(RELAY1, HIGH); // HIGH = OFF
digitalWrite(RELAY2, HIGH); // HIGH = OFF // Khởi tạo LCD Wire.begin(); lcd.init(); lcd.backlight(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Starting..."); lcd.setCursor(0, 1); lcd.print("IoT System"); // Khởi tạo DHT dht.begin(); // Kết nối WiFi setup_wifi(); // Cấu hình MQTT espClient.setInsecure();
Nhóm 5- Lớp : D22TXCN01-B 16
client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); // Kết nối MQTT reconnect_mqtt(); // In thông tin debug
Serial.println("Setup completed");
Serial.printf("Relay 1 pin: %d, Relay 2 pin: %d\n", RELAY1, RELAY2); } void loop() {
// Kiểm tra kết nối MQTT if (!client.connected()) { reconnect_mqtt(); } // Xử lý các lệnh MQTT client.loop();
// Cập nhật dữ liệu cảm biến theo định kỳ
unsigned long currentMillis = millis();
if (currentMillis - lastSensorPublish >= sensorPublishInterval) {
lastSensorPublish = currentMillis; publish_sensor_data(); }
// Gửi lại trạng thái relay định kỳ
if (currentMillis - lastRelayStatePublish >= relayStatePublishInterval) {
lastRelayStatePublish = currentMillis; publish_relay_state(); }
// Xử lý thêm các lệnh MQTT client.loop();
// Thêm một khoảng thời gian nhỏ để tránh sử dụng quá nhiều CPU delay(10); }
// Hàm điều khiển relay với kiểm tra trạng thái
void setRelay(int relayPin, bool state) {
// Kiểm tra thời gian chống dội
if (millis() - lastRelayDebounceTime < relayDebounceDelay) {
Serial.println("Debounce: Ignoring relay command"); return; }
lastRelayDebounceTime = millis();
// Đặt trạng thái cho relay
digitalWrite(relayPin, state ? LOW : HIGH); // LOW = ON, HIGH = OFF
Nhóm 5- Lớp : D22TXCN01-B 17
// Cập nhật biến trạng thái if (relayPin == RELAY1) { relay1State = state;
Serial.printf("Relay 1 set to %s\n", state ? "ON" : "OFF");
} else if (relayPin == RELAY2) { relay2State = state;
Serial.printf("Relay 2 set to %s\n", state ? "ON" : "OFF"); } } void setup_wifi() {
Serial.print("Connecting to WiFi..."); WiFi.begin(ssid, password); int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) { delay(500); Serial.print("."); attempts++; }
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi Connected"); Serial.print("IP address: ");
Serial.println(WiFi.localIP()); // Hiển thị IP trên LCD lcd.clear(); lcd.setCursor(0, 0); lcd.print("WiFi Connected"); lcd.setCursor(0, 1);
lcd.print(WiFi.localIP().toString()); delay(2000); } else {
Serial.println("\nWiFi connection failed!"); lcd.clear(); lcd.setCursor(0, 0); lcd.print("WiFi Failed!"); delay(2000); } }
void callback(char* topic, byte* payload, unsigned int length) {
// Chuyển payload thành chuỗi char message[length + 1];
for (int i = 0; i < length; i++) {
message[i] = (char)payload[i]; } message[length] = '\0'; // In thông tin debug
Serial.printf("Received [%s]: %s\n", topic, message);
Nhóm 5- Lớp : D22TXCN01-B 18
// Xử lý lệnh điều khiển relay 1
if (strcmp(topic, TOPIC_RELAY1_COMMAND) == 0) {
if (strcasecmp(message, "ON") == 0) { setRelay(RELAY1, true);
client.publish(TOPIC_RELAY1_STATE, "ON", false); }
else if (strcasecmp(message, "OFF") == 0) { setRelay(RELAY1, false);
client.publish(TOPIC_RELAY1_STATE, "OFF", false); } }
// Xử lý lệnh điều khiển relay 2
else if (strcmp(topic, TOPIC_RELAY2_COMMAND) == 0) {
if (strcasecmp(message, "ON") == 0) { setRelay(RELAY2, true);
client.publish(TOPIC_RELAY2_STATE, "ON", false); }
else if (strcasecmp(message, "OFF") == 0) { setRelay(RELAY2, false);
client.publish(TOPIC_RELAY2_STATE, "OFF", false); } }
// Xử lý yêu cầu trạng thái
else if (strcmp(topic, TOPIC_REQUEST_STATUS) == 0) { publish_relay_state(); } } void publish_sensor_data() {
// Đọc dữ liệu cảm biến với timeout
unsigned long startTime = millis(); // Đọc DHT float h = dht.readHumidity();
float t = dht.readTemperature();
// Kiểm tra nếu việc đọc DHT mất quá nhiều thời gian
if (millis() - startTime > 2000) {
Serial.println("DHT reading timeout!"); dhtError = true; errorCount++; return; } // Đọc khoảng cách
float distance = getDistance();
// Tạo buffer cho các chuỗi char tempStr[10]; char humStr[10]; char distStr[10];
Nhóm 5- Lớp : D22TXCN01-B 19
// Xử lý từng cảm biến riêng biệt bool tempOk = false; bool humOk = false; bool distOk = false; // Xử lý nhiệt độ
if (!isnan(t) && t > -40 && t < 80) {
snprintf(tempStr, sizeof(tempStr), "%.1f", t);
client.publish(TOPIC_TEMPERATURE, tempStr, false);
Serial.printf("Temperature: %s°C\n", tempStr); tempOk = true; dhtError = false; } else {
Serial.println("Temperature sensor error!"); dhtError = true; } // Xử lý độ ẩm
if (!isnan(h) && h >= 0 && h <= 100) {
snprintf(humStr, sizeof(humStr), "%.1f", h);
client.publish(TOPIC_HUMIDITY, humStr, false);
Serial.printf("Humidity: %s%%\n", humStr); humOk = true; dhtError = false; } else {
Serial.println("Humidity sensor error!"); dhtError = true; } // Xử lý khoảng cách if (distance != -1) {
snprintf(distStr, sizeof(distStr), "%.2f", distance);
client.publish(TOPIC_DISTANCE, distStr, false);
Serial.printf("Distance: %s cm\n", distStr); distOk = true; distanceError = false; } else {
Serial.println("Distance sensor error!"); distanceError = true; }
// Cập nhật LCD nếu có ít nhất một cảm biến hoạt động
if (tempOk || humOk || distOk) {
updateLCD(tempOk ? t : 0, humOk ? h : 0, distOk ? distance : 0); errorCount = 0; } else { errorCount++; if (errorCount > 5) { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Sensor Error!");
Nhóm 5- Lớp : D22TXCN01-B 20