Hướng dẫn này chỉ ra cách xây dựng một máy chủ web với bảng ESP8266 NodeMCU hiển thị một trang web có nhiều thanh trượt. Các thanh trượt điều khiển chu kỳ làm việc của các tín hiệu PWM khác nhau để kiểm soát độ sáng của nhiều đèn LED. Thay vì đèn LED, bạn có thể sử dụng dự án này để điều khiển động cơ DC hoặc các thiết bị truyền động khác yêu cầu tín hiệu PWM. Giao tiếp giữa máy khách và ESP8266 được thực hiện bằng giao thức WebSocket. Ngoài ra, bất cứ khi nào có thay đổi, tất cả khách hàng sẽ cập nhật đồng thời các giá trị thanh trượt của họ.
Trang 1ESP8266 Máy chủ Web NodeMCU (WebSocket) với
nhiều thanh trượt: Điều khiển độ sáng đèn LED (PWM)
Hướng dẫn này chỉ ra cách xây dựng một máy chủ web với bảng ESP8266 NodeMCU
hiển thị một trang web có nhiều thanh trượt Các thanh trượt điều khiển chu kỳ làm việc của các tín hiệu PWM khác nhau để kiểm soát độ sáng của nhiều đèn LED Thay vì đèn LED, bạn có thể sử dụng dự án này để điều khiển động cơ DC hoặc các thiết bị truyền
động khác yêu cầu tín hiệu PWM Giao tiếp giữa máy khách và ESP8266 được thực hiện bằng giao thức WebSocket Ngoài ra, bất cứ khi nào có thay đổi, tất cả khách hàng sẽ
cập nhật đồng thời các giá trị thanh trượt của họ.
Bạn cũng có thể sửa đổi mã được trình bày trong hướng dẫn này để thêm thanh trượt
vào dự án của mình để đặt giá trị ngưỡng hoặc bất kỳ giá trị nào khác mà bạn cần sử
* Dự án này chỉ ra cách xây dựng một máy chủ web với một thanh trượt, nhưng nó sử
dụng các yêu cầu HTTP — trong hướng dẫn này, chúng ta sẽ sử dụng giao thức
WebSocket.
Chúng tôi có một hướng dẫn tương tự cho bảng ESP32:
Trang 2Máy chủ web ESP32 (WebSocket) với nhiều thanh trượt: Điều khiển độ sáng đèn
LED (PWM)
Tổng quan dự án
Hình ảnh sau đây cho thấy trang web mà chúng ta sẽ xây dựng cho dự án này:
Trang web chứa ba thẻ;
Mỗi thẻ có một đoạn để hiển thị tiêu đề thẻ (Fader 1, Fader 2, Fader 3);
Có một thanh trượt phạm vi trong mỗi thẻ mà bạn có thể di chuyển để đặt độ sáng của đèn LED tương ứng;
Trong mỗi thẻ, một đoạn khác hiển thị độ sáng LED hiện tại (theo tỷ lệ phần trăm); Khi bạn đặt vị trí mới cho thanh trượt, nó sẽ cập nhật tất cả các máy khách (nếu
bạn đã mở nhiều tab trình duyệt web (hoặc nhiều thiết bị), chúng sẽ cập nhật gần
như đồng thời bất cứ khi nào có thay đổi).
Nó hoạt động như thế nào?
ESP lưu trữ một máy chủ web hiển thị một trang web với ba thanh trượt;
Khi bạn đặt vị trí mới cho thanh trượt, máy khách sẽ gửi số thanh trượt và giá trị
thanh trượt đến máy chủ thông qua giao thức WebSocket Ví dụ: nếu bạn đặt thanh trượt số 3 thành vị trí số 40, nó sẽ gửi thông báo này 3s40 đến máy chủ.
Trang 3Máy chủ (ESP) nhận số thanh trượt và giá trị tương ứng và điều chỉnh chu kỳ
nhiệm vụ PWM cho phù hợp Ngoài ra, nó cũng thông báo cho tất cả các máy
khách khác với các giá trị thanh trượt hiện tại mới — điều này cho phép chúng tôi
cập nhật tất cả các máy khách gần như ngay lập tức.
Trang 4ESP8266 xuất tín hiệu PWM với chu kỳ làm việc tương ứng để kiểm soát độ sáng LED Chu kỳ làm việc 0% có nghĩa là đèn LED tắt hoàn toàn, chu kỳ làm việc 50%
có nghĩa là đèn LED sáng một nửa và chu kỳ làm việc 100% có nghĩa là đèn LED sáng;
Bất cứ khi nào bạn mở một cửa sổ trình duyệt web mới (đây là khi một máy khách mới kết nối), nó sẽ gửi một tin nhắn đến ESP8266 (cũng thông qua giao thức
WebSocket) với thông báo getValues Khi ESP8266 nhận được thông báo này, nó
sẽ gửi các giá trị thanh trượt hiện tại Bằng cách này, bất cứ khi nào bạn mở một
tab mới, nó luôn hiển thị các giá trị hiện tại và cập nhật.
Điều kiện tiên quyết
Trước khi tiếp tục với hướng dẫn này, hãy đảm bảo bạn kiểm tra tất cả các điều kiện tiên quyết sau.
1) Các bộ phận cần thiết
Để theo dõi dự án này, bạn cần:
Trang 5Bảng mạch ESP8266 NodeMCU đọc Bảng phát triển WiFi ESP8266 tốt nhất
Bạn không cần ba đèn LED để kiểm tra dự án này, bạn chỉ cần xem kết quả trong Màn
hình nối tiếp hoặc sử dụng các thiết bị truyền động khác yêu cầu tín hiệu PWM để hoạt
động.
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!
2) Tiện ích bổ sung bảng Arduino IDE và ESP8266
Chúng tôi sẽ lập trình ESP8266 bằng Arduino IDE Vì vậy, bạn phải cài đặt tiện ích bổ
sung ESP8266 Thực hiện theo hướng dẫn tiếp theo nếu bạn chưa có:
Cài đặt bo mạch ESP8266 trong Arduino IDE (Windows, Mac OS X, Linux)
Nếu bạn muốn sử dụng VS Code với tiện ích mở rộng PlatformIO, hãy làm theo hướng
dẫn tiếp theo để tìm hiểu cách lập trình ESP8266:
Bắt đầu với VS Code và PlatformIO IDE cho ESP32 và ESP8266 (Windows, Mac
OS X, Linux Ubuntu)
3) Plugin tải lên hệ thống tệp
Để tải lên các tệp HTML, CSS và JavaScript cần thiết để xây dựng dự án này lên bộ nhớ flash ESP8266 (LittleFS), chúng tôi sẽ sử dụng một plugin cho trình tải lên hệ thống tệp
Arduino IDE: LittleFS Làm theo hướng dẫn tiếp theo để cài đặt plugin tải lên hệ thống
tệp nếu bạn chưa có:
Cài đặt ESP8266 NodeMCU LittleFS Filesystem Uploader trong Arduino IDE
Nếu bạn đang sử dụng VS Code với tiện ích mở rộng PlatformIO, hãy đọc hướng dẫn
sau để tìm hiểu cách tải tệp lên hệ thống tệp:
ESP8266 NodeMCU với VS Code và PlatformIO: Tải tệp lên hệ thống tệp (LittleFS)
4) Thư viện
Để xây dựng dự án này, bạn cần cài đặt các thư viện sau:
Trang 6Bạn có thể cài đặt thư viện đầu tiên bằng Trình quản lý thư viện Arduino Đi tới Sketch >
Include Library > Manage Libraries và tìm kiếm tên thư viện.
Các thư viện ESPAsyncWebServer và ESPAsynTCP 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 các thư viện bạn vừa tải xuống.
Cài đặt thư viện (VS Code + PlatformIO)
Nếu bạn đang lập trình ESP8266 bằng PlatformIO, bạn nên thêm các dòng sau vào tệp platformio.ini để bao gồm các thư viện (cũng thay đổi tốc độ Serial Monitor thành 115200
Trang 7Đề xuất đọc: Tham khảo sơ đồ chân ESP8266: Bạn nên sử dụng chân GPIO nào?
Sắp xếp các tệp của bạn
Để giữ cho dự án được tổ chức và dễ hiểu hơn, chúng tôi sẽ tạo bốn tệp để xây dựng
máy chủ web:
Bản phác thảo Arduino xử lý máy chủ web;
index.html: để xác định nội dung của trang web;
Trang 8Sytle.css: để tạo kiểu cho trang web;
script.js: để lập trình hành vi của trang web—xử lý những gì xảy ra khi bạn di
chuyển thanh trượt, gửi, nhận và giải thích các tin nhắn nhận được qua giao thức WebSocket.
Bạn nên lưu các tệp HTML, CSS và JavaScript bên trong một thư mục được gọi là dữ
liệu bên trong thư mục phác thảo Arduino, như thể hiện trong sơ đồ trước Chúng tôi sẽ
tải các tệp này lên hệ thống tệp ESP8266 (LittleFS).
Trang 9<! Complete project details:
https://randomnerdtutorials.com/esp8266-nodemcu-web-server-websocket-sliders/ >
<!DOCTYPE html>
<html>
<head>
<title>ESP IOT DASHBOARD</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="favicon.png">
<link rel="stylesheet" type="text/css" href="style.css">
<input type="range" onchange="updateSliderPWM(this)"
id="slider1" min="0" max="100" step="1" value ="0" class="slider">
<input type="range" onchange="updateSliderPWM(this)"
id="slider2" min="0" max="100" step="1" value ="0" class="slider">
<input type="range" onchange="updateSliderPWM(this)"
id="slider3" min="0" max="100" step="1" value ="0" class="slider">
Chúng ta hãy xem nhanh các phần có liên quan nhất của tệp HTML.
Tạo thanh trượt
Trang 10Các thẻ sau tạo thẻ cho thanh trượt đầu tiên (Fader 1).
<div class="card">
<p class="card-title">Fader 1</p>
<p class="switch">
<input type="range" onchange="updateSliderPWM(this)" id="slider1" min="0"
max="100" step="1" value ="0" class="slider">
Để tạo thanh trượt trong HTML, bạn sử dụng thẻ <input> Thẻ <input> chỉ định một
trường nơi người dùng có thể nhập dữ liệu.
Có rất nhiều loại đầu vào Để xác định thanh trượt, hãy dùng thuộc tính type với giá trị
range Trong thanh trượt, bạn cũng cần xác định phạm vi tối thiểu và tối đa bằng cách sử dụng các thuộc tính tối thiểu và tối đa (trong trường hợp này là 0 và 100, tương ứng).
Bạn cũng cần xác định các thuộc tính khác như:
Thuộc tính STEP chỉ định khoảng thời gian giữa các số hợp lệ Trong trường hợp
của chúng tôi, chúng tôi đặt nó thành 1;
lớp để tạo kiểu cho thanh trượt (class = "thanh trượt");
id để chúng ta có thể thao tác với giá trị thanh trượt bằng JavaScript (id = "slider1"); thuộc tính onchange để gọi một hàm (updateSliderPWM(this)) khi bạn đặt vị trí mới cho thanh trượt Hàm này (được định nghĩa trong tệp JavaScript) gửi giá trị thanh
trượt hiện tại thông qua giao thức WebSocket đến máy khách Từ khóa này đề cập đến phần tử thanh trượt HTML.
Thanh trượt nằm bên trong một đoạn văn với tên lớp chuyển đổi Vì vậy, đây là các thẻ
thực sự tạo thanh trượt.
<p class="switch">
<input type="range" onchange="updateSliderPWM(this)" id="slider1" min="0"
max="100" step="1" value ="0" class="slider">
</p>
Cuối cùng, có một đoạn văn với thẻ <span>, để chúng ta có thể chèn giá trị thanh trượt
hiện tại vào đoạn đó bằng cách tham chiếu đến id của nó (id = "sliderValue1").
<p class="state">Brightness: <span id="sliderValue1"></span> %</p>
Tạo thêm thanh trượt
Trang 11Để tạo thêm thanh trượt, bạn cần sao chép tất cả các thẻ HTML tạo thẻ hoàn chỉnh Tuy nhiên, trước tiên, bạn cần xem xét rằng bạn cần một id duy nhất cho mỗi giá trị thanh
trượt và thanh trượt Trong trường hợp của chúng tôi, chúng tôi có ba thanh trượt với các
id sau: slider1, slider2, slider3 và ba trình giữ chỗ cho giá trị thanh trượt với các id sau:
sliderValue1, sliderValue2, sliderValue3.
Ví dụ: đây là thẻ cho thanh trượt số 2.
<div class="card">
<p class="card-title"> Fader 2</p>
<p class="switch">
<input type="range" onchange="updateSliderPWM(this)" id="slider2" min="0"
max="100" step="1" value ="0" class="slider">
Trang 12/* Complete project details: server-websocket-sliders/ */
Trang 13Chúng ta hãy xem nhanh các phần có liên quan của tệp CSS tạo kiểu cho thanh trượt.
Trong ví dụ này, chúng ta cần sử dụng tiền tố vendor cho thuộc tính appearance.
Trang 14Tiền tố của nhà cung cấp cho phép trình duyệt hỗ trợ các tính năng CSS mới trước khi
chúng được hỗ trợ đầy đủ Các trình duyệt được sử dụng phổ biến nhất sử dụng các tiền
tố sau:
-webkit- Chrome, Safari, các phiên bản Opera mới hơn, hầu hết tất cả các trình
duyệt iOS,
-moz- Firefox,
-o- Phiên bản cũ của Opera,
-ms- Microsoft Edge và Internet Explorer.
Tiền tố nhà cung cấp là tạm thời Khi các thuộc tính được hỗ trợ đầy đủ bởi trình duyệt
bạn sử dụng, bạn không cần chúng Bạn có thể sử dụng tham chiếu sau để kiểm tra xem thuộc tính bạn đang sử dụng có cần tiền tố hay không: http://shouldiprefix.com/
Chúng ta hãy xem bộ chọn slider (tạo kiểu cho thanh trượt):
Trang 16// Complete project details: server-websocket-sliders/
https://randomnerdtutorials.com/esp8266-nodemcu-web-var gateway = `ws://${window.location.hostname}/ws`;
console.log('Trying to open a WebSocket connection…');
websocket = new WebSocket(gateway);
var sliderNumber = element.id.charAt(element.id.length-1);
var sliderValue = document.getElementById(element.id).value;
var myObj = JSON.parse(event.data);
var keys = Object.keys(myObj);
for (var i = 0; i < keys.length; i++){
var key = keys[i];
document.getElementById(key).innerHTML = myObj[key];
document.getElementById("slider"+ (i+1).toString()).value = myObj[key];
}
}
Trang 17khởi tạo kết nối WebSocket với máy chủ;
gửi tin nhắn đến máy chủ để nhận các giá trị thanh trượt hiện tại;
sử dụng phản hồi để cập nhật các giá trị thanh trượt trên trang web;
xử lý trao đổi dữ liệu thông qua giao thức WebSocket.
Chúng ta hãy xem mã JavaScript này để xem nó hoạt động như thế nào.
Cổng là điểm vào giao diện WebSocket window.location.hostname lấy địa chỉ trang hiện tại (địa chỉ IP máy chủ web).
var gateway = ws://${window.location.hostname}/ws;
Tạo một biến toàn cục mới gọi là websocket.
Hàm initWebSocket() khởi tạo kết nối WebSocket trên cổng được xác định trước đó.
Chúng tôi cũng gán một số chức năng gọi lại khi kết nối WebSocket được mở, đóng hoặc khi nhận được tin nhắn.
function initWebSocket() {
console.log('Trying to open a WebSocket connection…');
websocket = new WebSocket(gateway);
Hàm getValues() gửi một thông báo đến máy chủ getValues để lấy giá trị hiện tại của tất
cả các thanh trượt Sau đó, chúng ta phải xử lý những gì xảy ra khi chúng ta nhận được thông báo đó ở phía máy chủ (ESP8266).
function getStates(){
websocket.send("getValues");
}
Trang 18Chúng tôi xử lý các tin nhắn nhận được qua giao thức websocket trên hàm onMessage().
function onMessage(event) {
console.log(event.data);
var myObj = JSON.parse(event.data);
var keys = Object.keys(myObj);
for (var i = 0; i < keys.length; i++){
var key = keys[i];
Hàm onMessage() chỉ đơn giản là đi qua tất cả các giá trị và đặt chúng vào các vị trí
tương ứng trên trang HTML.
Hàm updateSliderPWM() chạy khi bạn di chuyển thanh trượt.
function updateSliderPWM(element) {
var sliderNumber = element.id.charAt(element.id.length-1);
var sliderValue = document.getElementById(element.id).value;
Tin nhắn được gửi theo định dạng sau:
thanh trượtsốsthanh trượt
Ví dụ: nếu bạn di chuyển thanh trượt số 3 đến vị trí 40, nó sẽ gửi thông báo sau:
3s40
Bản phác thảo Arduino
Sao chép mã sau vào Arduino IDE của bạn hoặc vào tệp chính.cpp nếu bạn đang sử
Trang 19/*
Rui Santos
Complete project details at server-websocket-sliders/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create a WebSocket object
AsyncWebSocket ws("/ws");
// Set LED GPIO
const int ledPin1 = 14;
const int ledPin2 = 12;
const int ledPin3 = 13;
Trang 20void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
AwsFrameInfo *info = (AwsFrameInfo*)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode ==
Trang 21}
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType
type, void *arg, uint8_t *data, size_t len) {
// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", "text/html");
Trang 22Mã hoạt động như thế nào
Chúng ta hãy xem nhanh các phần liên quan cho dự án này Để hiểu rõ hơn về cách mã hoạt động, chúng tôi khuyên bạn nên làm theo hướng dẫn này về giao thức WebSocket với ESP8266 và hướng dẫn này về PWM với ESP8266.
Chèn thông tin đăng nhập mạng của bạn vào các biến sau để kết nối ESP8266 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";
Hàm getSliderValues() tạo một chuỗi JSON với các giá trị thanh trượt hiện tại.
Hàm notifyClients() thông báo cho tất cả các máy khách với các giá trị thanh trượt hiện
tại Gọi chức năng này là những gì cho phép chúng tôi thông báo các thay đổi trong tất
cả các máy khách bất cứ khi nào bạn đặt một vị trí mới cho thanh trượt.
void notifyClients(String sliderValues) {
ws.textAll(sliderValues);
}
HandleWebSocketMessage(), như tên cho thấy, xử lý những gì xảy ra khi máy chủ nhận được tin nhắn từ máy khách thông qua giao thức WebSocket Chúng ta đã thấy trong tệp JavaScript, rằng máy chủ có thể nhận được thông báo getValues hoặc một tin nhắn với
số thanh trượt và giá trị thanh trượt.
Khi nó nhận được thông báo getValues, nó sẽ gửi các giá trị thanh trượt hiện tại.