Trong hướng dẫn này, bạn sẽ học cách xây dựng một máy chủ web không đồng bộ với bo mạch ESP8266 NodeMCU để kiểm soát đầu ra của nó. Bo mạch sẽ được lập trình bằng Arduino IDE và chúng ta sẽ sử dụng thư viện ESPAsyncWebServer.
Trang 1ESP8266 NodeMCU Async Web Server – Điều khiển
đầu ra với Arduino IDE (ESPAsyncWebServer thư viện)
Trong hướng dẫn này, bạn sẽ học cách xây dựng một máy chủ web không đồng bộ với
bo mạch ESP8266 NodeMCU để kiểm soát đầu ra của nó Bo mạch sẽ được lập trình
bằng Arduino IDE và chúng ta sẽ sử dụng thư viện ESPAsyncWebServer.
Bạn cũng có thể thích: Máy chủ web không đồng bộ ESP32 - Kiểm soát đầu ra bằng
Arduino IDE (thư viện ESPAsyncWebServer)
Máy chủ Web không đồng bộ
Để xây dựng máy chủ web, chúng tôi sẽ sử dụng thư viện ESPAsyncWebServer cung
cấp một cách dễ dàng để xây dựng một máy chủ web không đồng bộ Xây dựng một máy chủ web không đồng bộ có một số lợi thế như đã đề cập trong trang GitHub thư viện,
chẳng hạn như:
"Xử lý nhiều kết nối cùng một lúc";
"Khi bạn gửi phản hồi, bạn ngay lập tức sẵn sàng xử lý các kết nối khác trong khi
máy chủ đang xử lý việc gửi phản hồi ở chế độ nền";
"Công cụ xử lý mẫu đơn giản để xử lý các mẫu";
Và nhiều hơn nữa.
Hãy xem tài liệu thư viện trên trang GitHub của nó.
Trang 2Các bộ phận cần thiết
Trong hướng dẫn này, chúng ta sẽ kiểm soát ba kết quả đầu ra Ví dụ, chúng tôi sẽ điều khiển đèn LED Vì vậy, bạn cần các phần sau:
ESP8266 (đọc bảng phát triển ESP8266 tốt nhất)
3x đèn LED
Điện trở 3x 220 Ohm
Breadboard
Dây nhảy
Bạn có thể sử dụng các liên kết trước đó hoặc truy cập trực tiếp vào
MakerAdvisor.com/tools để tìm tất cả các phần cho các dự án của mình với giá tốt nhất!
Sơ
Trước khi tiếp tục mã, hãy nối 3 đèn LED với ESP8266 Chúng tôi đang kết nối đèn LED với GPIO 5, 4 và 2, nhưng bạn có thể sử dụng bất kỳ GPIO nào khác (đọc Hướng dẫn
tham khảo ESP8266 NodeMCU GPIO).
Trang 3Cài đặt thư viện - Máy chủ web không đồng bộ ESP
Để xây dựng máy chủ web, bạn cần cài đặt các thư viện sau Nhấp vào các liên kết bên dưới để tải xuống các thư viện.
ESPAsyncWebServer
ESPAsyncTCP
Các thư viện này không có sẵn để cài đặt thông qua Trình quản lý thư viện Arduino, vì
vậy bạn cần sao chép các tệp thư viện vào thư mục Thư viện cài đặt Arduino Ngoài ra,
trong Arduino IDE, bạn có thể vào Sketch > Include Library > Add zip Library và chọn
Trang 4các thư viện bạn vừa tải xuống.
Tổng quan dự án
Để hiểu rõ hơn về mã, hãy xem máy chủ web hoạt động như thế nào.
Máy chủ web chứa một tiêu đề "Máy chủ web ESP" và ba nút (công tắc chuyển đổi)
để kiểm soát ba đầu ra Mỗi nút trượt có một nhãn cho biết chân đầu ra GPIO Bạn
có thể dễ dàng xóa / thêm nhiều đầu ra hơn.
Khi thanh trượt màu đỏ, điều đó có nghĩa là đầu ra đang bật (trạng thái của nó là
CAO) Nếu bạn chuyển đổi thanh trượt, nó sẽ tắt đầu ra (thay đổi trạng thái thành
THẤP).
Khi thanh trượt có màu xám, điều đó có nghĩa là đầu ra bị tắt (trạng thái của nó là THẤP) Nếu bạn chuyển đổi thanh trượt, nó sẽ bật đầu ra (thay đổi trạng thái thành CAO).
Nó hoạt động như thế nào?
Trang 5Hãy xem điều gì sẽ xảy ra khi bạn chuyển đổi các nút Chúng ta sẽ xem ví dụ cho GPIO
2 Nó hoạt động tương tự cho các nút khác.
1 Trong trường hợp đầu tiên, bạn chuyển đổi nút để bật GPIO 2 Khi điều đó xảy ra, nó
sẽ tạo một yêu cầu HTTP GET trên URL /update?output=2&state=1 Dựa trên URL đó,
chúng tôi thay đổi trạng thái của GPIO 2 thành 1 (CAO) và bật đèn LED.
2 Trong ví dụ thứ hai, khi bạn chuyển đổi nút để tắt GPIO 2 Khi điều đó xảy ra, hãy thực
hiện yêu cầu HTTP GET trên URL /update?output=2&state=0 Dựa trên URL đó, chúng tôi thay đổi trạng thái của GPIO 2 thành 0 (THẤP) và tắt đèn LED.
Mã cho máy chủ Web không đồng bộ ESP
Sao chép mã sau vào Arduino IDE của bạn.
Trang 6/*********
Rui Santos
Complete project details at
https://RandomNerdTutorials.com/esp8266-nodemcu-async-web-server-espasyncwebserver-library/
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software
*********/
// Import required libraries
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
const char* PARAM_INPUT_1 = "output";
const char* PARAM_INPUT_2 = "state";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<title>ESP Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 3.0rem;}
p {font-size: 3.0rem;}
body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
.switch {position: relative; display: inline-block; width: 120px; height:
68px}
.switch input {display: none}
.slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 6px}
.slider:before {position: absolute; content: ""; height: 52px; width: 52px;
left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: 4s;
transition: 4s; border-radius: 3px}
input:checked+.slider {background-color: #b30000}
input:checked+.slider:before {-webkit-transform: translateX(52px);
-ms-transform: translateX(52px); -ms-transform: translateX(52px)}
</style>
</head>
<body>
<h2>ESP Web Server</h2>
%BUTTONPLACEHOLDER%
<script>function toggleCheckbox(element) {
var xhr = new XMLHttpRequest();
if(element.checked){ xhr.open("GET", "/update?output="+element.id+"&state=1",
true); }
else { xhr.open("GET", "/update?output="+element.id+"&state=0", true); }
xhr.send();
Trang 7}
</script>
</body>
</html>
)rawliteral";
// Replaces placeholder with button section in your web page
String processor(const String& var){
//Serial.println(var);
if(var == "BUTTONPLACEHOLDER"){
String buttons = "";
buttons += "<h4>Output - GPIO 5</h4><label class=\"switch\"><input
type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"5\" " + outputState(5) +
"><span class=\"slider\"></span></label>";
buttons += "<h4>Output - GPIO 4</h4><label class=\"switch\"><input
type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"4\" " + outputState(4) +
"><span class=\"slider\"></span></label>";
buttons += "<h4>Output - GPIO 2</h4><label class=\"switch\"><input
type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"2\" " + outputState(2) +
"><span class=\"slider\"></span></label>";
return buttons;
}
return String();
}
String outputState(int output){
if(digitalRead(output)){
return "checked";
}
else {
return "";
}
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
pinMode(5, OUTPUT);
digitalWrite(5, LOW);
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
pinMode(2, OUTPUT);
digitalWrite(2, LOW);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi ");
}
// Print ESP Local IP Address
Serial.println(WiFi.localIP());
// Route for root / web page
Trang 8server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
// Send a GET request to <ESP_IP>/update?output=<inputMessage1>&state=
<inputMessage2>
server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
String inputMessage1;
String inputMessage2;
// GET input1 value on <ESP_IP>/update?output=<inputMessage1>&state=
<inputMessage2>
if (request->hasParam(PARAM_INPUT_1) && request->hasParam(PARAM_INPUT_2)) {
inputMessage1 = request->getParam(PARAM_INPUT_1)->value();
inputMessage2 = request->getParam(PARAM_INPUT_2)->value();
digitalWrite(inputMessage1.toInt(), inputMessage2.toInt());
}
else {
inputMessage1 = "No message sent";
inputMessage2 = "No message sent";
}
Serial.print("GPIO: ");
Serial.print(inputMessage1);
Serial.print(" - Set to: ");
Serial.println(inputMessage2);
request->send(200, "text/plain", "OK");
});
// Start server
server.begin();
}
void loop() {
}
Xem mã thô
Mã hoạt động như thế nào
Trong phần này, chúng tôi sẽ giải thích cách mã hoạt động Hãy tiếp tục đọc nếu bạn
muốn tìm hiểu thêm hoặc chuyển đến phần Trình diễn để xem kết quả cuối cùng.
Nhập thư viện
Đầu tiên, nhập các thư viện cần thiết Bạn cần bao gồm WiFi, ESPAsyncWebserver và
các thư viện ESPAsyncTCP.
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
Đặt thông tin đăng nhập mạng của bạn
Trang 9Chèn thông tin đăng nhập mạng của bạn vào các biến sau, để ESP8266 có thể kết nối
với mạng cục bộ của bạn.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Thông số đầu vào
Để kiểm tra các tham số được truyền trên URL (số GPIO và trạng thái của nó), chúng tôi tạo hai biến, một cho đầu ra và một cho trạng thái.
const char* PARAM_INPUT_1 = "output";
const char* PARAM_INPUT_2 = "state";
Hãy nhớ rằng ESP8266 nhận được các yêu cầu như thế này: /update? đầu ra = 2&
trạng thái = 0
Đối tượng AsyncWebServer
Tạo một đối tượng AsyncWebServer trên cổng 80.
AsyncWebServer server(80);
Xây dựng trang Web
Tất cả văn bản HTML với kiểu và JavaScript được lưu trữ trong biến index_html Bây giờ chúng ta sẽ đi qua văn bản HTML và xem mỗi phần làm gì.
Tiêu đề nằm bên trong thẻ <title> và </tile> Tiêu đề chính xác như âm thanh của nó: tiêu
đề tài liệu của bạn, hiển thị trong thanh tiêu đề của trình duyệt web của bạn Trong
trường hợp này, đó là "Máy chủ web ESP".
<title>ESP Web Server</title>
Thẻ <meta> sau đây làm cho trang web của bạn đáp ứng trong bất kỳ trình duyệt nào
(máy tính xách tay, máy tính bảng hoặc điện thoại thông minh).
<meta name="viewport" content="width=device-width, initial-scale=1">
Trang 10Dòng tiếp theo ngăn các yêu cầu trên biểu tượng yêu thích Trong trường hợp này, chúng tôi không có biểu tượng yêu thích Favicon là biểu tượng trang web hiển thị bên cạnh tiêu
đề trong tab trình duyệt web Nếu chúng tôi không thêm dòng sau, ESP sẽ nhận được
yêu cầu cho biểu tượng yêu thích mỗi khi chúng tôi truy cập máy chủ web.
<link rel="icon" href="data:,">
Giữa các thẻ <style></style>, chúng tôi thêm một số CSS để tạo kiểu cho trang web.
Chúng tôi sẽ không đi vào chi tiết về cách thức hoạt động của kiểu CSS này.
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 3.0rem;}
p {font-size: 3.0rem;}
body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
.switch {position: relative; display: inline-block; width: 120px; height:
68px}
.switch input {display: none}
.slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 6px}
.slider:before {position: absolute; content: ""; height: 52px; width: 52px;
left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: 4s;
transition: 4s; border-radius: 3px}
input:checked+.slider {background-color: #b30000}
input:checked+.slider:before {-webkit-transform: translateX(52px);
-ms-transform: translateX(52px); -ms-transform: translateX(52px)}
</style>
Nội dung HTML
Bên trong thẻ <body></body> là nơi chúng tôi thêm nội dung trang web.
Thẻ <h2></h2> thêm tiêu đề vào trang web Trong trường hợp này, văn bản "Máy chủ
web ESP", nhưng bạn có thể thêm bất kỳ văn bản nào khác.
<h2>ESP Web Server</h2>
Sau tiêu đề, chúng ta có các nút Cách các nút hiển thị trên trang web (màu đỏ: nếu
GPIO đang bật; hoặc màu xám: nếu GPIO tắt) khác nhau tùy thuộc vào trạng thái GPIO hiện tại.
Khi bạn truy cập trang máy chủ web, bạn muốn nó hiển thị đúng trạng thái GPIO hiện tại.
Vì vậy, thay vì thêm văn bản HTML để xây dựng các nút, chúng tôi sẽ thêm trình giữ chỗ
%BUTTONPLACEHOLDER% Palceholder này sau đó sẽ được thay thế bằng văn bản
HTML thực tế để xây dựng các nút với các trạng thái phù hợp, khi trang web được tải.
%BUTTONPLACEHOLDER%
JavaScript
Sau đó, có một số JavaScript chịu trách nhiệm thực hiện yêu cầu HTTP GET khi bạn
chuyển đổi các nút như chúng tôi đã giải thích trước đây.
Trang 11<script>function toggleCheckbox(element) {
var xhr = new XMLHttpRequest();
if(element.checked){ xhr.open("GET", "/update?output="+element.id+"&state=1",
true); }
else { xhr.open("GET", "/update?output="+element.id+"&state=0", true); }
xhr.send();
}
</script>
Đây là dòng đưa ra yêu cầu:
if(element.checked){ xhr.open("GET", "/update?output="+element.id+"&state=1",
true); }
element.id trả về id của một phần tử HTML Id của mỗi nút sẽ là GPIO được điều khiển
như chúng ta sẽ thấy trong phần tiếp theo:
Nút GPIO 5 » element.id = 5
Nút GPIO 4 » element.id = 4
Nút GPIO 2 » element.id = 2
Xử lý
Bây giờ, chúng ta cần tạo hàm processor(), thay thế các trình giữ chỗ trong văn bản
HTML bằng những gì chúng ta định nghĩa.
Khi trang web được yêu cầu, hãy kiểm tra xem HTML có bất kỳ chỗ dành sẵn nào không Nếu nó tìm thấy chỗ dành sẵn %BUTTONPLACEHOLDER%, nó sẽ trả về văn bản HTML
để tạo các nút.
String processor(const String& var){
//Serial.println(var);
if(var == "BUTTONPLACEHOLDER"){
String buttons = "";
buttons += "<h4>Output - GPIO 5</h4><label class=\"switch\"><input
type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"5\" " + outputState(5) +
"><span class=\"slider\"></span></label>";
buttons += "<h4>Output - GPIO 4</h4><label class=\"switch\"><input
type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"4\" " + outputState(4) +
"><span class=\"slider\"></span></label>";
buttons += "<h4>Output - GPIO 2</h4><label class=\"switch\"><input
type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"2\" " + outputState(2) +
"><span class=\"slider\"></span></label>";
return buttons;
}
return String();
}
Bạn có thể dễ dàng xóa hoặc thêm nhiều dòng hơn để tạo thêm các nút.
Chúng ta hãy xem cách các nút được tạo ra Chúng tôi tạo một biến String được gọi là
các nút có chứa văn bản HTML để xây dựng các nút Chúng tôi nối văn bản HTML với
trạng thái đầu ra hiện tại để nút bật tắt có màu xám hoặc đỏ Trạng thái đầu ra hiện tại