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.
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
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() && 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
Truy cập vào Wifi ESP32 nhập mật khẩu đã tạo bên trên
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
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é.