2

Xây dựng ESP8266 Web Server với Arduino IDE

esp8266-web-server

Bài viết này hướng dẫn các bạn các bước xây dựng ESP8266 thành một Web Server có thể điều khiển 2 ngõ ra LED. ESP8266 Web Server có thể truy cập từ bất cứ thiết bị nào có sẵn một trình duyệt, trong mạng Wifi local.

esp8266-web-server

Cài đặt trên Arduino IDE

1. Download và cài đặt Arduino IDE trên máy của bạn.

2. Cài đặt ESP8266 add-on trên Arduino IDE, File > Preferences

3. Nhập chuỗi http://arduino.esp8266.com/stable/package_esp8266com_index.json vào mục “Additional Board Manager URLs” sau đó chọn “OK”.

esp8266-arduino-ide-preferences

4. Chọn Tools > Board > Boards Manager

Arduino-IDE-boards-manager

5. Tìm kiếm ESP8266 và chọn cài đặt “esp8266 by ESP8266 Community”.

installing-esp-board

6. Tools > Board, sau đó chọn loại board ESP8266 của bạn và khởi động lại Arduino IDE.

Code

Copy đoạn code dưới đây vào Sketch và thay đổi các thông số cho phù hợp.

// Load Wi-Fi library
#include <ESP8266WiFi.h>

// Replace with your network credentials
const char* ssid     = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

// Auxiliar variables to store the current output state
String output5State = "off";
String output4State = "off";

// Assign output variables to GPIO pins
const int output5 = 5;
const int output4 = 4;

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0; 
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);
  // Initialize the output variables as outputs
  pinMode(output5, OUTPUT);
  pinMode(output4, OUTPUT);
  // Set outputs to LOW
  digitalWrite(output5, LOW);
  digitalWrite(output4, 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 local IP address and start web server
  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 GPIOs on and off
            if (header.indexOf("GET /5/on") >= 0) {
              Serial.println("GPIO 5 on");
              output5State = "on";
              digitalWrite(output5, HIGH);
            } else if (header.indexOf("GET /5/off") >= 0) {
              Serial.println("GPIO 5 off");
              output5State = "off";
              digitalWrite(output5, LOW);
            } else if (header.indexOf("GET /4/on") >= 0) {
              Serial.println("GPIO 4 on");
              output4State = "on";
              digitalWrite(output4, HIGH);
            } else if (header.indexOf("GET /4/off") >= 0) {
              Serial.println("GPIO 4 off");
              output4State = "off";
              digitalWrite(output4, 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:,\">");
            // CSS to style the on/off buttons 
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #77878A;}</style></head>");
            
            // Web Page Heading
            client.println("<body><h1>ESP8266 Web Server</h1>");
            
            // Display current state, and ON/OFF buttons for GPIO 5  
            client.println("<p>GPIO 5 - State " + output5State + "</p>");
            // If the output5State is off, it displays the ON button       
            if (output5State=="off") {
              client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>");
            } 
               
            // Display current state, and ON/OFF buttons for GPIO 4  
            client.println("<p>GPIO 4 - State " + output4State + "</p>");
            // If the output4State is off, it displays the ON button       
            if (output4State=="off") {
              client.println("<p><a href=\"/4/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/4/off\"><button class=\"button button2\">OFF</button></a></p>");
            }
            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("");
  }
}

Thay đổi thông tin về Wifi nhà bạn tại đây

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

Nạp Sketch vào board

Cắm board của bạn vào máy tính và chọn đúng COM port. Sau đó chọn Upload để nạp, khi nạp xong bạn sẽ nhận được “Done uploading.

Nguyên lí mạch

Yêu cầu:

Kết nối mạch như hình vẽ sau đây – kết nối chân GPIO4 (D2) và GPIO5 (D1) tới 2 LED.

esp8266-web-server-schematics

Chạy thử

Sau khi Upload sketch chọn Serial monitor (baud 115200) và quan sát.

Cấp phát địa chỉ IP

esp8266-ip-address

Lưu lại IP này để có thể truy cập từ trình duyệt của bạn.

Truy cập Web Server

Mở một trình duyệt bất kỳ, sau đó nhập địa chỉ IP đã lưu ở trên

esp8266-web-server

Tại của sổ Serial Monitor bạn sẽ thấy thông tin HTTP Request của bạn, trong trường hợp này là Trình duyệt.

http-response

Điểu khiển trên Web Server

Trên giao diên Web Server, bấm chọn GPIO5 ON. ESP sẽ nhận được môt Request tại /5/on và bật sáng LED

serial-monitor-gpio5-on

Trang thái LED cũng sẽ được cập nhật trên giao diện Web Server.

esp8266-web-server-state

Thử điều khiển GPIO4 tương tự nhự vậy.

Chi tiết Code

Đầu tiên chúng ta cần khai báo thư viện ESP8266WiFi.

#include <ESP8266WiFi.h>

Tiếp tục khai báo thông tin về Wifi nhà bạn.

const char* ssid = "your-wifi-ssid"; 
const char* password = "your-wifi-password";
Khai báo port của Web Server là 80
WiFiServer server(80);

Tiếp theo, chúng ta khai báo các biến lưu trữ trạng thái của GPIO

String output5State = "off"; 
String output4State = "off";

Bãn cũng cần khai báo các chân ngõ ra tương ứng.

const int output5 = 5; 
const int output4 = 4;

setup()

Hàm setup() chỉ chạy một lần duy nhất. Đầu tiên, chúng ta khai báo tốc độ baud của Serial.

Serial.begin(115200);

Khai báo các chân tương ứng là ngõ ra.

pinMode(output5, OUTPUT); 
pinMode(output4, OUTPUT); 
digitalWrite(output5, LOW); 
digitalWrite(output4, LOW);

Hàm WiFi.begin(ssid, password), ESP sẽ bắt đầu kết nối Wifi. Sẽ mất một chút thời gian để ESP được cấp phát IP.

Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();

loop()

Trong loop() chúng ta lập trình sự kiện xảy ra khi có một kết nối được tạo.

ESP luôn lắng nghe kết nối.

WiFiClient client = server.available();

Khi có một kết nối tới, ESP sẽ lưu các thông tin lại. Các lệnh thực hiện trong while() sẽ tiếp tục đến khi Client mất kết nối.

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
 while (client.connected()) { // loop while the client's connected
 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();

Tiếp theo chúng ta xử lý việc điều khiển chân GPIO tưng ứng với nút được nhấn.

if (header.indexOf("GET /5/on") >= 0) {
  Serial.println("GPIO 5 on");
  output5State = "on";
  digitalWrite(output5, HIGH);
} else if (header.indexOf("GET /5/off") >= 0) {
  Serial.println("GPIO 5 off");
  output5State = "off";
  digitalWrite(output5, LOW);
} else if (header.indexOf("GET /4/on") >= 0) {
  Serial.println("GPIO 4 on");
  output4State = "on";
  digitalWrite(output4, HIGH);
} else if (header.indexOf("GET /4/off") >= 0) {
  Serial.println("GPIO 4 off");
  output4State = "off";
  digitalWrite(output4, LOW);
}

Và sau đó lưu lại trạng thái nút nhấn để phản hồi với Client.

Hiển thị trang HTML

Để hiên thị trên trình duyệt ESP8266 sẽ gửi các Response dưới dạng chỗi HTML. Trang web sẽ được gửi tới Client dùng hàm client.println().

Trang web luôn bắt đầu với thẻ:

<!DOCTYPE html><html>

Sử dụng Style trên Web

Khai báo Style cho button

client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");

Màu sắc, kích thước, …

client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;"); 
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");

Khai báo cho nút nhấn OFF

client.println(".button2 {background-color: #77878A;}</style></head>");

Khai báo header của trang web

client.println("<h1>ESP8266 Web Server</h1>");

Hiển thị các nút nhấn và trạng thái

Sau khi nhấn, trạng thái các nút nhấn thay đổi sẽ được lưu lại và được..

client.println("<p>GPIO 5 - State " + output5State + "</p>");

…phản hồi tới Client

if (output5State=="off") {
 client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>");
} else {
 client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>");
}

Ngắt kết nối

Khi Respone kết thúc, ESP ngắt kết nối và xóa các biến lưu trữ.

// Clear the header variable
header = "";
// Close the connection
client.stop();

Tổng kết

Bài viết đã hướng dẫn các bạn xây dựng và tùy biến một Web Server trên ESP8266. Hy vọng các bạn có thể ứng dụng kiến thức từ bài viết vào các dự án của mình.

Đừng quên theo dõi các bài hướng dẫn ESP8266 và ESP32 trên ESPITEK.

Chúc các bạn thành công!

thanhbinh89

2 Bình luận

  1. anh ơi! em muốn thêm một nút nhấn phải làm sao ạ, tổng cộng là 3 nút nhấn. em cảm ơn ạ

    • Chào bạn, bạn theo dõi code mẫu có đoạn dưới: đây là đoạn code tạo ra 1 giao diện nút nhấn, để tạo thêm nút bạn chỉ cần copy và thay đổi tên nút mới

      // Display current state, and ON/OFF buttons for GPIO 5 client.println(“

      GPIO 5 – State ” + output5State + “

      “); // If the output5State is off, it displays the ON button if (output5State==”off”) { client.println(“

      “); } else { client.println(“

      “); }

      Nhớ thêm các biến cho nút thứ 3 nhé !

Trả lời

Email của bạn sẽ không được hiển thị công khai.