ESP32 Smart Home tự động với Web Server
Trong dự án IoT, chủ đề ESP32 Smart Home này, chúng ta hãy cùng làm một sản phẩm nhà thông minh với Web Server. Bạn có thể dùng trang Web trên điện thoại hoặc laptop, máy tính bảng để điều khiển căn nhà của mình (thông qua 4 relay).
Sau khi bật thiết bị, ESP32 sẽ kết nối với mạng WiFi của bạn và tạo Website. Khi dùng địa chỉ IP của mạch ESP32 đó, bạn có thể truy cập vào Website và điều khiển Smart Home bằng ESP32. Bằng cách bật / tắt trên Website, chúng ta có thể thay đổi trạng thái của 4 Relay.
Giới thiệu dự án ESP32 Smart Home
Để nâng cao tính di động và sự tùy chỉnh cho Smart Home, chúng ta sẽ dùng PCB tùy chỉnh trong dự án này. Trong bài viết dưới có kèm sẵn sơ đồ kết nối, bố cục PCB, tập tin Gerbet, vật liệu cần dùng và chương trình lập trình đầy đủ để bạn làm một ESP32 Smart Home.
Dự án ESP32 Smart Home này có thể hoạt động độc lập, không phụ thuộc vào bất kỳ ứng dụng IoT nào bên ngoài. Nhờ đó, chúng ta có thể tích hợp chúng vào hệ thống tự động hóa mini trong nhà.
Chuẩn bị
Dưới đây là danh sách vật liệu cần dùng trong dự án
- 8 Tụ điện 100nf
- 3 tụ điện 10uf
- 1 tụ điện 220uf, 25V
- 4 đi ốt
- 1 SP4322-01ETG
- 4 Bộ ghép quang PC817C
- 1 ESP32 WROOM-32
- 1 Khối đầu cuối 2 chân
- 4 Khối đầu cuối 3 chân
- 4 Relay SRD05VDC-SLC
- 5 đèn LED đỏ
- 1 đầu nam 6 pin
- 1 HLK 10M05
- 6 Transistor
- 8 điện trở 220R
- 4 DNP
- 3 điện trở 12K
- 4 điện trở 1K
- 1 điện trở 470R
- 4 điện trở 10K
- 4 nút nhấn Swift
- 4 Swift thủ công
- 1 Voltage Regulator
Sơ đồ kết nối
Dưới đây là sơ đồ kết nối các thiết bị, được vẽ bằng Altium Designer:
Chúng ta sẽ dùng tụ điện, điện trở và đèn LED. Để đổi điện áp 220V thành 5 V DC, bạn có thể dùng bộ chuyển đổi AC to DC.
Để cung cấp điện cho ESP32 và các thiết bị ngoại vi khác, chúng ta dùng IC LDO HT7333 công suất thấp.
Chúng ta dùng thêm bộ ghép quang PC817 để tách dây công suất cao ra khỏi mạch 3.3V.
Chúng ta dùng LED5 được dùng để biểu thị nguồn điện.
Tương tự, các LED từ 1 đến 4 được dùng lần lượt cho các Relay từ 1 đến 4. LED số 5 dùng để báo nguồn.
Các Relay từ 1 dến 4 được kết nối lần lượt với ESP32 qua các chân GPIO 12, 14, 27 và 26. Các nút nhấn được dùng để kết nối và điều khiển Relay bằng tay, chúng được kết nối với chân GPIO 5, 17, 13 và 16 trên ESP32. Bạn có thể gắn 1 công tắc thủ công tại đó và lập trình bộ điều khiển để điều khiển.
Nếu muốn điều khiển thiết bị gia dụng trong nhà, bạn kết nối thiết bị gia dụng bằng kết nối Relay tại 3 chân đầu cuối là J2, J3, J4 và J5. Trong đó, đầu nối 2 chân J1 được dùng để cấp nguồn AC trực tiếp với mạch. Ta kết nối tụ điện C12 220uf, 25V với các dao động điện áp dừng PCB.
Tải PCB Gerber File
PCB được dùng trong dự án ESP32 SMart Home này cũng được thiết kế bằng phần mềm thiết kế Altium, chúng trông như hình dưới:
Dưới đây là chế độ 3D khi xem PCB:
Bạn có thể tải xuống tập tin Gerber qua link bên dưới và đặt mua PCB từ nước ngoài qua link PCBGOGO.
- Tải xuống tập tin: Tệp Gerbet Smart Home
Sau đó, bạn có thể upload tập tin Gerbet bằng cách click vào Quote now. Tại đó, bạn có thể chọn loại vật liệu, kích cỡ, độ dày, số lượng, màu sắc và một số thông số quan trọng khác:
Sau khi chọn các thông số trên, bạn chọn quốc gia và phương thức vận chuyển rồi chọn đặt hàng.
Hàn PCB
Sau khi nhận PCB về, bạn tiến hành hàn các thành phần như điện trở, tụ điện, relay, đèn LED,… lên mạch. Quan trọng là bạn cần chú ý về cực của đèn LED SMD:
Sau khi hàn tất cả linh kiện trên, bạn tiến hành hàn chip thô ESP32. Sau khi hàn tất cả thiết bị, chúng ta đã có một mạch hoàn hảo để dùng cho dự án ESP32 Smart Home.
Code cho EPS32 Smart Home
Dưới đây là đoạn code đơn giản để làm dự án Smart Home, giúp điều khiển 4 thiết bị được nối với các chân GPIO thông qua 1 Website.
Bạn hãy thay đổi thông tin mạng WiFi (tên mạng WiFi và mật khẩu WiFi), sau đó sử dụng bình thường nhé:
#include <WiFi.h> // Replace with your network credentials const char* ssid = "***************"; // Network SSID (name) const char* password = "***************"; // Network password // Set web server port number to 80 (HTTP default) WiFiServer server(80); // Variable to store the HTTP request from the client String header; // Variables to store the current state of each device (ON/OFF) String Device1State = "off"; String Device2State = "off"; String Device3State = "off"; String Device4State = "off"; // Assign each device to a GPIO pin const int Device1 = 12; const int Device2 = 14; const int Device3 = 27; const int Device4 = 26; // Variables to track the current time and last time a client made a request unsigned long currentTime = millis(); unsigned long previousTime = 0; // Define timeout time in milliseconds (2000ms = 2 seconds) const long timeoutTime = 2000; void setup() { Serial.begin(115200); // Initialize the GPIO pins for the devices as outputs and set them to LOW pinMode(Device1, OUTPUT); pinMode(Device2, OUTPUT); pinMode(Device3, OUTPUT); pinMode(Device4, OUTPUT); digitalWrite(Device1, LOW); digitalWrite(Device2, LOW); digitalWrite(Device3, LOW); digitalWrite(Device4, LOW); // Connect to Wi-Fi network with SSID and password Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // Print the local IP address once connected Serial.println(""); Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); server.begin(); } void loop() { WiFiClient client = server.available(); // Listen for incoming clients if (client) { // If a new client connects, Serial.println("New Client."); // print a message out in the serial port String currentLine = ""; // make a String to hold incoming data from the client currentTime = millis(); previousTime = currentTime; while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected currentTime = millis(); if (client.available()) { // if there's bytes to read from the client, char c = client.read(); // read a byte, then Serial.write(c); // print it out the serial monitor header += c; if (c == '\n') { // if the byte is a newline character // if the current line is blank, you got two newline characters in a row. // that's the end of the client HTTP request, so send a response: if (currentLine.length() == 0) { // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // and a content-type so the client knows what's coming, then a blank line: client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println("Connection: close"); client.println(); // turns the Relays on and off if (header.indexOf("GET /1/on") >= 0) { Serial.println("Device 1 on"); Device1State = "on"; digitalWrite(Device1, HIGH); } else if (header.indexOf("GET /1/off") >= 0) { Serial.println("Device 1 off"); Device1State = "off"; digitalWrite(Device1, LOW); } else if (header.indexOf("GET /2/on") >= 0) { Serial.println("Device 2 on"); Device2State = "on"; digitalWrite(Device2, HIGH); } else if (header.indexOf("GET /2/off") >= 0) { Serial.println("Device 2 off"); Device2State = "off"; digitalWrite(Device2, LOW); } else if (header.indexOf("GET /3/on") >= 0) { Serial.println("Device 3 off"); Device3State = "on"; digitalWrite(Device3, HIGH); } else if (header.indexOf("GET /3/off") >= 0) { Serial.println("Device 3 off"); Device3State = "off"; digitalWrite(Device3, LOW); } else if (header.indexOf("GET /4/on") >= 0) { Serial.println("Device 4 off"); Device4State = "on"; digitalWrite(Device4, HIGH); } else if (header.indexOf("GET /4/off") >= 0) { Serial.println("Device 4 off"); Device4State = "off"; digitalWrite(Device4, LOW); } // Display the HTML web page client.println("<!DOCTYPE html><html>"); client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"); client.println("<link rel=\"icon\" href=\"data:,\">"); // Enhanced CSS for a compact look client.println("<style>"); client.println("html { font-family: 'Roboto', sans-serif; background: #f5f5f5; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }"); client.println("body { max-width: 600px; background: #fff; padding: 20px; margin: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); }"); client.println("h1 { color: #333; text-align: center; }"); client.println(".device { background: linear-gradient(to right, #dae2f8, #d6a4a4); padding: 15px; margin: 10px 0; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); text-align: center; }"); // Reduced padding and margin client.println("p { font-size: 18px; color: #555; margin: 10px 0; }"); client.println(".button { border: none; padding: 15px 35px; text-align: center;"); // Slightly reduced padding client.println("text-decoration: none; display: inline-block; font-size: 22px; margin: 10px; cursor: pointer; border-radius: 5px; transition: all 0.3s ease; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); }"); client.println(".button:hover { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4); }"); client.println(".button-on { background-color: #4CAF50; color: white; }"); client.println(".button-off { background-color: #f44336; color: white; }"); client.println("</style></head>"); // Web Page Heading client.println("<body><h1>Smart Home Automation</h1>"); // Display current state, and ON/OFF buttons for Relay 1 client.println("<div class=\"device\"><p>Device 1 - State " + Device1State + "</p>"); if (Device1State == "off") { client.println("<a href=\"/1/on\"><button class=\"button button-on\">ON</button></a>"); } else { client.println("<a href=\"/1/off\"><button class=\"button button-off\">OFF</button></a>"); } client.println("</div>"); // Display current state, and ON/OFF buttons for Relay 2 client.println("<div class=\"device\"><p>Device 2 - State " + Device2State + "</p>"); if (Device2State == "off") { client.println("<a href=\"/2/on\"><button class=\"button button-on\">ON</button></a>"); } else { client.println("<a href=\"/2/off\"><button class=\"button button-off\">OFF</button></a>"); } client.println("</div>"); // Display current state, and ON/OFF buttons for Relay 3 client.println("<div class=\"device\"><p>Device 3 - State " + Device3State + "</p>"); if (Device3State == "off") { client.println("<a href=\"/3/on\"><button class=\"button button-on\">ON</button></a>"); } else { client.println("<a href=\"/3/off\"><button class=\"button button-off\">OFF</button></a>"); } client.println("</div>"); // Display current state, and ON/OFF buttons for Relay 4 client.println("<div class=\"device\"><p>Device 4 - State " + Device4State + "</p>"); if (Device4State == "off") { client.println("<a href=\"/4/on\"><button class=\"button button-on\">ON</button></a>"); } else { client.println("<a href=\"/4/off\"><button class=\"button button-off\">OFF</button></a>"); } client.println("</div>"); client.println("</body></html>"); // The HTTP response ends with another blank line client.println(); // Break out of the while loop break; } else { // if you got a newline, then clear currentLine currentLine = ""; } } else if (c != '\r') { // if you got anything else but a carriage return character, currentLine += c; // add it to the end of the currentLine } } } // Clear the header variable header = ""; // Close the connection client.stop(); Serial.println("Client disconnected."); Serial.println(""); } }
Lưu ý rằng bạn hãy kết nối module FTDI với chân FTDI của PCB nhé:
Sau đó, bạn hãy upload code vào mạch. Khi quá trình hoàn tất, bạn mở Serial Monitor.
Trên màn hình hiển thị thông tin ESP32 kết nối với mạng WiFI, sau đó chúng hiển thị địa chỉ IP của mạch ESP32.
Khi đó, bạn có thể truy cập vào địa chỉ IP ESP32 này trên trình duyệt Internet của điện thoại / laptop để truy cập vào Website và điều khiển các thiết bị. Chúc bạn thành công!
Lời kết
Trên đây là các hướng dẫn chi tiết về dự án ESP32 Smart Home, chúng là dự án ở mức độ nâng cao vì bạn cần hàn PCB và chuẩn bị nhiều công đoạn khác. Trên Website IoTZone hiện nay đã có sẵn các bài viết hướng dẫn đơn giản hơn, bạn có thể tham khảo: