ESP32 / ESP8266 Web Server: Điều khiển Output qua công tắc tạm thời

Hôm nay, mình sẽ hướng dẫn bạn cách xây dựng một ESP32 / ESP8266 Web Server để điều khiển output (đầu ra) từ xa qua một công tắc tạm thời. Trạng thái đầu ra sẽ luôn là HIGH (luôn bật) khi bạn giữ nút trên website của mình. Khi thả nút trạng thái đầu ra chuyển sang LOW (tắt).

ESP32 / ESP8266 Web Server: Điều khiển Output qua công tắc tạm thời

Trong hướng dẫn này, IoTZone sẽ sử dụng đèn LED làm đầu ra minh họa, nhưng bạn có thể đổi thành bất kỳ đầu ra nào khác mình thích. Chúng ta sẽ lập trình ESP32 hoặc ESP8266 bằng phần mềm Arduino IDE.

Tổng quan dự án ESP32 / ESP8266 Web Server

Dưới đây là sơ đồ minh họa cách hoạt động của dự án ESP32 / ESP8266 Web Server:

Tổng quan dự án ESP32 / ESP8266 Web Server
Tổng quan dự án ESP32 / ESP8266 Web Server
  • ESP32 hoặc ESP8266 tạo một Web Server, cho phép người dùng có thể truy cập để điều khiển đầu ra
  • Trạng thái đầu ra mặc định là LOW (tắt), bạn có thể thay đổi trạng thái mặc định này tùy thích theo nhu cầu
  • Trang Web Server sẽ có một nút hoạt động như một công tắc tạm thời:
  • Khi nhấn giữ nút, trạng thái chuyển thành HIGH
  • Khi thả nút, trạng thái chuyển về LOW

Tải thư viện Async Web Server

Dự án này bạn cần cài đặt các thư viện sau:

Các Thư viện này không có sẵn trong trình quản lý thư viện của Arduino. Do đó, sau khi tải về, bạn cần sao chép chúng vào thư mục thư viện cài đặt Arduino. Bạn cũng có thể truy cập vào Sketch > Include Library > Add .zip Library để thêm thư viện vừa tải.

Lập trình

Bạn hãy copy đoạn mã sau vào Arduino IDE của mình và thay đổi thông tin mạng WiFi để chạy:

#ifdef ESP32
  #include <WiFi.h>
  #include <AsyncTCP.h>
#else
  #include <ESP8266WiFi.h>
  #include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>

// REPLACE WITH YOUR NETWORK CREDENTIALS
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

const int output = 2;

// HTML web page
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
  <head>
    <title>ESP Pushbutton Web Server</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
      body { font-family: Arial; text-align: center; margin:0px auto; padding-top: 30px;}
      .button {
        padding: 10px 20px;
        font-size: 24px;
        text-align: center;
        outline: none;
        color: #fff;
        background-color: #2f4468;
        border: none;
        border-radius: 5px;
        box-shadow: 0 6px #999;
        cursor: pointer;
        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -khtml-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        -webkit-tap-highlight-color: rgba(0,0,0,0);
      }  
      .button:hover {background-color: #1f2e45}
      .button:active {
        background-color: #1f2e45;
        box-shadow: 0 4px #666;
        transform: translateY(2px);
      }
    </style>
  </head>
  <body>
    <h1>ESP Pushbutton Web Server</h1>
    <button class="button" onmousedown="toggleCheckbox('on');" ontouchstart="toggleCheckbox('on');" onmouseup="toggleCheckbox('off');" ontouchend="toggleCheckbox('off');">LED PUSHBUTTON</button>
   <script>
   function toggleCheckbox(x) {
     var xhr = new XMLHttpRequest();
     xhr.open("GET", "/" + x, true);
     xhr.send();
   }
  </script>
  </body>
</html>)rawliteral";

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

AsyncWebServer server(80);

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WiFi Failed!");
    return;
  }
  Serial.println();
  Serial.print("ESP IP Address: http://");
  Serial.println(WiFi.localIP());
  
  pinMode(output, OUTPUT);
  digitalWrite(output, LOW);
  
  // Send web page to client
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html);
  });

  // Receive an HTTP GET request
  server.on("/on", HTTP_GET, [] (AsyncWebServerRequest *request) {
    digitalWrite(output, HIGH);
    request->send(200, "text/plain", "ok");
  });

  // Receive an HTTP GET request
  server.on("/off", HTTP_GET, [] (AsyncWebServerRequest *request) {
    digitalWrite(output, LOW);
    request->send(200, "text/plain", "ok");
  });
  
  server.onNotFound(notFound);
  server.begin();
}

void loop() {
 
}

Thông tin mạng cần thay đổi bao gồm tên và mật khẩu WiFi (SSID và password). Đoạn chương trình trên tương thích với cả mạch ESP32 lẫn ESP8266. Với chương trình trên, mình đang điều khiển đèn LED ngay trên bo mạch (ở cổng GPIO 2).

Giải thích chương trình

IoTZone đã giải thích chi tiết cách chương trình hoạt động ở bài hướng dẫn trước (Webserver đo nhiệt độ độ ẩm với DHT22 DHT11 ESP32). Do đó, trong bài này mình sẽ chỉ hướng dẫn các phần liên quan:

Xác thực mạng WiFi

Như đã trình bày, bạn cần thay đổi thông tin mạng WiFi thành WiFi của mình:

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Công tắc tạm thời trên Web Server

Chương trình sau giúp tạo công tắc tạm thời trên Web Server:

<button class="button" onmousedown="toggleCheckbox('on');" ontouchstart="toggleCheckbox('on');" onmouseup="toggleCheckbox('off');" ontouchend="toggleCheckbox('off');">LED PUSHBUTTON</button>

Mình sẽ giải thích chi tiết từng thành phần bên trong, cụ thể:

  1. Để tạo một nút bằng HTML chúng ta sử dụng thẻ <button></button> , ở giữa là nội dung văn bản trong nút:
<button>LED PUSHBUTTON</button>
  1. Một nút có thể có nhiều thuộc tính trong HTML. Các thuộc tính này sẽ cung cấp một số thông tin bổ sung về các phần tử HTML, trong trường hợp này là nút.

Chúng ta có một số phần tử như sau:

  • Class: Cung cấp tên class cho nút. Qua đó, Javascropt hoặc CSS có thể thực hiện một số tác dụng nhất định cho nút. Trong trường hợp này mình sử dụng chúng để định dạng nút bằng CSS. Thuộc tính được đặt tên là button, nhưng bạn có thể gọi bằng bất kỳ tên nào khác bạn thích.
<button class="button">LED PUSHBUTTON</button>
  • onmousedown: Đây là một thuộc tính sự kiện, Cho phép thực thi chức năng của JavaScript khi người dùng nhấn nút. Trong trường hợp này chúng sẽ gọi hàm toggleCheckbox(‘on’) – Cho phép gửi yêu cầu đến mạch ESP32/ESP8266 URL cụ thể, nhằm mục đích đổi trạng thái của output thành HIGH
  • ontouchstart: Đây là thuộc tính sự kiện tương tự như trên nhưng chúng hoạt động trên các thiết bị có màn hình cảm ứng như điện thoại hoặc máy tính bảng
  • onmouseup: Đây là thuộc tính sự kiện, cho phép chạy các chức năng Java Script khi người dùng thả click chuột trên laptop hoặc vi tính. Trong trường hợp này chúng sẽ gọi hàm toggleCheckbox(‘off’), giúp gửi yêu cầu đến mạch và thay đổi trạng thái đầu ra thành LOW
  • ontouchend: Tương tự như hàm trên nhưng được dùng cho các thiết bị có màn hình cảm ứng

Tổng kết lại, nút của chúng ta sẽ như sau:

<button class="button" onmousedown="toggleCheckbox('on');" ontouchstart="toggleCheckbox('on');" onmouseup="toggleCheckbox('off');" ontouchend="toggleCheckbox('off');">LED PUSHBUTTON</button>

HTTP nhận yêu cầu thay đổi trạng thái nút nhấn (JavaScript)

Khi bạn nhắn giữ hoặc thả nút, hệ thống sẽ gọi các hàm toggleCheckbox(). Qua đó, bạn có thể thay đổi trạng thái của đầu ra thành bậc hoặc tắt tùy thích.

Câu lệnh dưới đây sẽ giúp hàm đó gửi yêu cầu http tới mạch ESP32 hoặc ESSP8266:

function toggleCheckbox(x) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/" + x, true);
  xhr.send();
}

Xử lý yêu cầu

Sau đó, chúng ta cần lập trình để mạch ESP32 hoặc ESP8266 nhận được các yêu cầu đó và đưa ra hành động phù hợp. Cụ thể:

Khi nhận được yêu cầu trên địa chỉ URL /on, mạch sẽ chuyển trạng thái đầu ra thành HIGH (bật đèn LED):

server.on("/on", HTTP_GET, [] (AsyncWebServerRequest *request) {
  digitalWrite(output, HIGH);
  request->send(200, "text/plain", "ok");
});

Khi nhận được yêu cầu trên địa chỉ URL /off, mạch sẽ chuyển trạng thái đầu ra thành LOW (tắt đèn LED):

server.on("/off", HTTP_GET, [] (AsyncWebServerRequest *request) {
  digitalWrite(output, LOW);
  request->send(200, "text/plain", "ok");
});

Kết quả

Upload code lên mạch ESP32 hoặc ESP8266 của bạn.

Mở màn hìnhSerial Monitor và chọn tốc độ truyền là 115200. Nhấn vào nút EN/RST trên mạch để lấy địa chỉ IP:

Lấy địa chỉ IP của mạch

Mở trình duyệt trên mạng local của bạn, nhập địa chỉ IP vào thanh tìm kiếm để truy cập vào web sever:

Khi bạn nhấn giữ, nút đèn LED trên mạch sẽ bật mãi cho đến khi bạn thả nút ra.

Lưu ý: Với mạch  ESP8266, đèn LED sẽ hoạt động theo cách ngược lại vì chúng tuân theo logic đảo ngược.

ESP32 / ESP8266 Web Server: Điều khiển đèn LED qua công tắc tạm thời
ESP32 / ESP8266 Web Server: Điều khiển đèn LED qua công tắc tạm thời

Lời kết

Trong bài viết này, mình đã hướng dẫn bạn cách thêm các sự kiện vào các nút trên ESP32 / ESP8266 Web Server, để tạo thành một công tắc tạm thời. Qua đó, bạn có thể điều khiển các trạng thái đầu ra dễ dàng bằng cách nhấn giữ nút. Chúc các bạn thành công!

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *