Bài 2: Lập trình ESP32 Webserver chế độ Access Point (WIFI AP Mode)

Lập trình ESP32 Webserver chế độ Access Point

Trong bài này chúng ta cùng nhau học cách lập trình ESP32 Webserver chế độ Wifi Access Point hay còn gọi là Wifi AP mode, bật tắt led bằng web browser. Cùng tìm hiểu AP mode là gì và các hàm lập trình AP mode nhé!

Bài 2 Networking trong serie Lập trình ESP32 từ A tới Z

Access Point là gì

Access Point hay điểm truy cập, còn được gọi là Hostpot là thiết bị phát sóng Wifi, cung cấp khả năng kết nối giữa các máy trạm (Station) với nó và các máy trạm với nhau. Sau đó kết nối với Internet thông qua mạng có dây.

Ví Du: Trong gia đình cục Router wifi chính là một Access Point, nó cho phép chúng ta kết nối máy tính, điện thoại … thông qua mạng wifi và từ đó kết nối với internet.

ESP32 cung cấp khả năng tạo kết nối Wifi Acces Point thế nhưng nó không thể kết nối với mạng dây để truy cập Internet, vậy nên được gọi là Soft-AP.

ESP32 Soft AP
ESP32 Soft AP

Soft AP thường được sử dụng khi chúng ta cần lấy thông tin của mạng Wifi khác cho thiết bị IOT khi chúng bắt đầu hoạt động. Ứng dụng thường thấy nhất đó là AP Config wifi, mà chúng ta sẽ học trong các bài sau.

Lập trình ESP32 Webserver chế độ Access Point

Trong bài này chúng ta sẽ sử dụng ESP32 bật tắt led bằng Web Browser. Nhưng thay vì kết nối ESP32 tới một điểm phát Wifi ( Router), chúng ta sẽ cho ESP32 phát Wifi.

Chuẩn bị:

  • ESP32 development board
  • 2x 5mm LED
  • 2x 330 Ohm trở
  • Breadboard
  • Dây cắm

Sơ đồ nguyên lý

Tương tự như bài ESP32 Station mode chúng ta sẽ nối Led với 2 chân GPIO 26 và 27

esp32 webserver che do wifi Access Point
Esp32 webserver che do wifi Access Point

Code và giải thích code

#include <Arduino.h>;

#include <WiFi.h>;
//khai báo chân sử dụng led 
const int led1 = 26;
const int led2 = 27;

const char* ssid = "ESP32-Wifi-AP-Mode";
const char* password = "12345678";
//Tạo một web server tại cổng 80 - cổng mặc định cho web
WiFiServer webServer(80);

String led1Status = "OFF";
String led2Status = "OFF";

String header;

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);

  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  // Set outputs to LOW
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);

  Serial.print("Setting AP mode");
  WiFi.softAP(ssid, password);

  IPAddress IP = WiFi.softAPIP(); //mặc định là 192.168.4.1
  Serial.print("AP IP address: ");
  Serial.println(IP);
  //khởi tạo webserver
  webServer.begin();
}

void loop() {
  WiFiClient webClient = webServer.available();

  if(webClient)
  {
    //khoi tao gia tri ban dau cho time
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New web Client");
    //biến lưu giá trị response
    String currentLine = "";
    //nếu có client connect và không quá thời gian time out
    while(webClient.connected() &amp;&amp; currentTime - previousTime <= timeoutTime)
    {
      //đọc giá trị timer tại thời điểm hiện tại
      currentTime = millis();
      //nếu client còn kết nối
      if(webClient.available())
      {
        //đọc giá trị truyền từ client theo từng byte kiểu char
        char c = webClient.read();
        Serial.write(c);
        header += c; // lưu giá trị vào Header
        if(c == '\n') //Nếu đọc được kí tự xuống dòng (hết chuỗi truyền tới)
        {
          if (currentLine.length() == 0) 
          {
            // HTTP headers luôn luôn bắt đầu với code HTTP (ví d HTTP/1.1 200 OK)
            webClient.println("HTTP/1.1 200 OK");
            webClient.println("Content-type:text/html"); // sau đó là kiểu nội dụng mà client gửi tới, ví dụ này là html
            webClient.println("Connection: close"); // kiểu kết nối ở đây là close. Nghĩa là không giữ kết nối sau khi nhận bản tin
            webClient.println();

            // nếu trong file header có giá trị
            if (header.indexOf("GET /led1/on") >;= 0) 
            {
              Serial.println("Led1 on");
              led1Status = "on";
              digitalWrite(led1, HIGH);
            } 
            else if (header.indexOf("GET /led1/off") >;= 0) 
            {
              Serial.println("Led1 off");
              led1Status = "off";
              digitalWrite(led1, LOW);
            } 
            else if (header.indexOf("GET /led2/on") >;= 0) 
            {
              Serial.println("Led2 on");
              led2Status = "on";
              digitalWrite(led2, HIGH);
            } 
            else if (header.indexOf("GET /led2/off") >;= 0) 
            {
              Serial.println("Led2 off");
              led2Status = "off";
              digitalWrite(led2, LOW);
            }
            // Response trang HTML 
            webClient.println("<!DOCTYPE html>;<html>;");
            webClient.println("<head>;<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">;");
            //thêm font-awesome 
            webClient.println("<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css\">;");
            // code CSS cho web
            //css cho toan bo trang
            webClient.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            //css cho nut nhan
            webClient.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
            webClient.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            webClient.println(".button2 {background-color: #5e0101;}</style></head>");
            
            // Web Page Heading H1 with CSS
            webClient.println("<body>;<h1 style=\"color:Tomato;\">;ESP32 Access Point Web Server</h1>;");

            // Web Page Heading H2
            webClient.println("<h2 style=\"color:#077a39;\">;<a href=\"https://khuenguyencreator.com\">;khuenguyencreator.com</a>;</h2>;");
            webClient.println("<i class=\"fa fa-home\" aria-hidden=\"true\">;</i>;");

            // Display current state, and ON/OFF buttons for Led1
            webClient.println("<p>;Led1 - State " + led1Status + "</p>;");
            // If the Led1Status is off, it displays the ON button       
            if (led1Status=="off") 
            {
              //khởi tạo một nút nhấn có đường dẫn đích là /led1/on
              webClient.println("<p>;<a href=\"/led1/on\">;<button class=\"button\">;ON</button>;</a>;</p>;");
            } 
            else 
            {
              //khởi tạo một nút nhấn có đường dẫn đích là /led1/off
              webClient.println("<p>;<a href=\"/led1/off\">;<button class=\"button button2\">;OFF</button>;</a>;</p>;");
            } 
               
            // Display current state, and ON/OFF buttons for Led2
            webClient.println("<p>;Led2 - State " + led2Status + "</p>;");
            // If the led2 is off, it displays the ON button       
            if (led2Status=="off") 
            {
              //khởi tạo một nút nhấn có đường dẫn đích là /led2/on
              webClient.println("<p>;<a href=\"/led2/on\">;<button class=\"button\">;ON</button>;</a>;</p>;");
            } 
            else 
            {
              //khởi tạo một nút nhấn có đường dẫn đích là /led2/on
              webClient.println("<p>;<a href=\"/led2/off\">;<button class=\"button button2\">;OFF</button>;</a>;</p>;");
            }
            webClient.println("</body>;</html>;");
            
            // The HTTP response ends with another blank line
            webClient.println();
            // Break out of the while loop
            break;
          }
          else 
          {
            currentLine = "";
          }
        }
        else if (c != '\r')   //nếu giá trị gửi tới khác xuống duòng
        {
          currentLine += c;     //lưu giá trị vào biến
        }
      }
    }
    // Xoá header để sử dụng cho lần tới
    header = "";
    // ngắt kết nối
    webClient.stop();
    Serial.println("Client disconnected.");
    Serial.println("");

  }
}

 

Phần thực thi giữ Web Server và Client sẽ tương tự như bài trước. Thế nên mình chỉ giải thích lại những điểm khác biệt khi khởi tạo ESP32 Access Point.

Đầu tiên chúng ta khởi tạo tên wifi và mật khẩu. Đây là tên wifi và mật khẩu để truy cập vào ESP32, bạn có thể thay đổi thành tên bất kì nhé.

Tiếp tới khởi tạo Web server tại port 80.

const char* ssid = "ESP32-Wifi-AP-Mode";
const char* password = "12345678";
//Tạo một web server tại cổng 80 - cổng mặc định cho web
WiFiServer webServer(80);

Trong Setup()

Khởi tạo Soft-AP với tên wifi và mật khẩu bạn tạo phía trên. In ra địa chỉ IP mà soft-AP khởi tạo. Mặc định là 192.168.4.1

Serial.print("Setting AP mode");
WiFi.softAP(ssid, password);

IPAddress IP = WiFi.softAPIP(); //mặc định là 192.168.4.1

Phần xử lý trong web server tương tự bài phía trước. Các bạn có thể chuyển qua để đọc nhé.

Nạp code cho ESP32

Nhấn build để biên dịch và Upload để nạp code

ap mode

Truy cập vào Wifi ESP32 nhập mật khẩu đã tạo bên trên

ap mode 2

Vào trình duyệt gõ: 192.169.4.1 sau đó bạn đã có thể điều khiển được led với ESP32 rồi

access point

Kết Quả

Các hàm thường gặp trong ESP32 Access Point

softAP

Cách thiết lập đơn giản nhất chỉ yêu cầu một tham số và được sử dụng để thiết lập một mạng Wi-Fi mở.

WiFi.softAP (ssid)

Để thiết lập mạng được bảo vệ bằng mật khẩu, hoặc để cấu hình các thông số mạng bổ sung, sử dụng quá tải sau đây:

WiFi.softAP(ssid, password, channel, hidden)

Tham số đầu tiên của hàm này là bắt buộc, còn lại ba tùy chọn.

  • ssid: chuỗi ký tự chứa SSID mạng (tối đa 63 ký tự)
  • password: chuỗi ký tự tùy chọn với mật khẩu. Đối với mạng WPA2-PSK, nó phải có ít nhất 8 ký tự. Nếu không có mật khẩu, thì đây sẽ là mạng WiFi mở.
  • channel: Tham số tùy chọn để thiết lập kênh Wi-Fi, từ 1 đến 13. Kênh mặc định = 1.
  • hidden: Tham số tùy chọn, thiết lập là true để ẩn SSID

Trả về true hoặc false phụ thuộc vào kết quả của việc cài đặt soft-AP.

softAPConfig

softAPConfig(local_ip, gateway, subnet)

Tất cả các thông số đều có kiểu IPAddress và được định nghĩa như sau:

  • local_ip: Địa chỉ IP của điểm truy cập mềm
  • gateway: địa chỉ IP gateway
  • subnet: subnet mask

Trả về true hoặc false phụ thuộc vào kết quả của việc thay đổi cấu hình.

Ví dụ:

#include <ESP8266WiFi.h>

IPAddress local_IP(192,168,4,22);
IPAddress gateway(192,168,4,9);
IPAddress subnet(255,255,255,0);

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.print("Setting soft-AP configuration ... ");
  Serial.println(WiFi.softAPConfig(local_IP, gateway, subnet) ? "Ready" : "Failed!");

  Serial.print("Setting soft-AP ... ");
  Serial.println(WiFi.softAP("ESPsoftAP_01") ? "Ready" : "Failed!");

  Serial.print("Soft-AP IP address = ");
  Serial.println(WiFi.softAPIP());
}

void loop() {}

output

Setting soft-AP configuration ... Ready
Setting soft-AP ... Ready
Soft-AP IP address = 192.168.4.22

 

Quản lý kết nối

Khi đã thiết lập softAP, bạn có thể kiểm tra các trạm đã kết nối, hoặc tắt chúng, sử dụng các hàm sau:

 

softAPgetStationNum

Lấy số lượng các station kết nối đến softAP

WiFi.softAPgetStationNum()
Serial.printf("Stations connected to soft-AP = %d\n", WiFi.softAPgetStationNum());

Ví dụ:

Trả về số lượng các thiết bị (station) kết nối tới mạng Wifi thiết lập bởi ESP8266

Ví dụ:

#include <ESP8266WiFi.h>

void setup()
{
WiFi.softAP("31/8/2017");
Serial.begin(115200);

}
void loop()
{
Serial.printf("Stations connected to soft-AP = %d \n", WiFi.softAPgetStationNum());
delay(2000); //delay trong 2s để kiểm tra xem có thiết bị nào mới kết nối với module không ?
}

softAPdisconnect

Ngắt kết nối các trạm từ mạng được thiết lập bởi softAP.

WiFi.softAPdisconnect(wifioff)

Chức năng sẽ thiết lập cấu hình SSID và password của soft-AP giá trị là null. Tham số wifioff là tùy chọn. Nếu thiết lập là true nó sẽ tắt chế độ soft-AP.

Trả về true nếu hoạt động đã thành công, false nếu không.

 

Cấu hình Mạng

Các hàm dưới đây cung cấp địa chỉ IP và MAC của soft-AP của ESP8266.

 

softAPIP

Trả lại địa chỉ IP của mạng softAP.

WiFi.softAPIP()

Trả về giá trị có kiểu là IPAddress.

Serial.print("Soft-AP IP address = ");
Serial.println(WiFi.softAPIP());

output

Soft-AP IP address = 192.168.4.1

 

softAPmacAddress

Trả lại địa chỉ MAC của softAP. Chức năng này có hai phiên bản khác nhau về kiểu trả về. Trả về một con trỏ hoặc một String.

Với kiểu trả về là Con trỏ

WiFi.softAPmacAddress(mac)

Tham số mac là một con trỏ trỏ đến vị trí bộ nhớ (một mảng uint8_t có 6 phẩn tử) để lưu địa chỉ mac. Cùng một giá trị con trỏ được trả về bởi chính hàm đó.

uint8_t macAddr[6];
WiFi.softAPmacAddress(macAddr);
Serial.printf("MAC address = %02x:%02x:%02x:%02x:%02x:%02x\n", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);

output

MAC address = 5e:cf:7f:8b:10:13

MAC như một String

WiFi.softAPmacAddress()

Kiểu trả về là một String chứa địa chỉ MAC của softAP.

Serial.printf("MAC address = %s\n", WiFi.softAPmacAddress().c_str());

output

MAC address = 5E:CF:7F:8B:10:13

Kết

Access Point trong ESP32 cũng rất đơn giản, và dễ nắm bắt. Kết hợp giữa Access Point và Station mode sẽ giúp chúng tao tạo ra các sản phẩm IOT một cách linh hoạt hơn.

Nếu bạn thấy bài viết này có ích hãy để lại bình luận và đừng quên ra nhập Hội Anh Em Nghiện Lập trình nhé.

5/5 - (2 bình chọn)

Để lại một bình luận

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 *