Hotline/Zalo: 0919.890.938 (Mr Hơn)
Bài 5. Chức năng wifi và web server trên ESP32
ESP32 là một vi điều khiển mạnh mẽ với tích hợp sẵn chức năng WiFi, giúp nó trở thành một lựa chọn lý tưởng cho các dự án IoT. Với khả năng kết nối WiFi, ESP32 có thể tạo và quản lý các mạng không dây, cho phép truyền và nhận dữ liệu từ các thiết bị khác. Bên cạnh đó, ESP32 còn có khả năng thiết lập web server, cho phép bạn dễ dàng tạo ra các ứng dụng web nhúng để giám sát và điều khiển thiết bị từ xa qua internet. Trong bài viết này Điện thông minh E-smart sẽ cùng các bạn tìm hiểu về về cách thiết lập tính năng wifi và web server trên ESP32.
ESP32 hỗ trợ cả hai chế độ thu (receive) và phát (transmit) Wi-Fi, cho phép thiết bị này có thể giao tiếp và truyền tải dữ liệu với các thiết bị khác qua mạng không dây. Với khả năng thu phát Wi-Fi, ESP32 có thể được sử dụng trong nhiều ứng dụng như điều khiển từ xa, giám sát, và hệ thống tự động hóa nhà thông minh.
Các chế độ Wi-Fi trên ESP32
ESP32 hỗ trợ nhiều chế độ Wi-Fi bao gồm: station mode, access point mode và station + accesspoint mode.
1. Chế độ Station (STA) trên ESP32:
Trong chế độ này, ESP32 kết nối với một mạng Wi-Fi hiện có, hoạt động như một thiết bị khách. ESP32 có thể nhận và gửi dữ liệu qua mạng này, tương tự như các thiết bị như smartphone, laptop.
Cách thiết lập station mode trên esp32:
#include <WiFi.h> //Thêm thư viện wifi
const char* ssid = "DTM E-SMART"; //Tên điểm phát wifi
const char* password = "0919890938";//Mật khẩu wifi
void setup(){
Serial.begin(115200);
WiFi.mode(WIFI_STA); //Thiết lập chế độ wifi STA
WiFi.begin(ssid, password); //Thực hiện kết nối wifi
Serial.println("\nConnecting to WiFi Network ..");
while(WiFi.status() != WL_CONNECTED){
Serial.print(".");
delay(100);
}
Serial.println("\nConnected to the WiFi network");
Serial.print("Local ESP32 IP: ");
Serial.println(WiFi.localIP()); //In địa chỉ IP đã kết nối wifi
}
void loop(){
// Do Nothing
}
2. Chế độ Access Point (AP) trên ESP32:
ESP32 tạo ra một điểm truy cập Wi-Fi riêng, cho phép các thiết bị khác kết nối vào. Chế độ này hữu ích khi bạn muốn ESP32 hoạt động như một router hoặc một hotspot di động.
Cách thiết lập access point mode trên ESP32:
#include <WiFi.h> //Thêm thư viện wifi
const char* ssid = "ESP32_AP"; //Tên wifi cần phát ra
const char* password = "12345678";//Mật khẩu wifi
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_OFF);//Tắt wifi trước khi khi khởi tạo
delay(100);
WiFi.mode(WIFI_AP); //Thiết lập chế độ wifi AP
delay(1000);
if(!WiFi.softAP(ssid,password)){ //Thực hiện phát wifi
Serial.println("Wifi AP fail!");
while(1);
}
Serial.println("WiFi AP started!");
Serial.print("IP host:");
Serial.println(WiFi.softAPIP()); //In đại chỉ IP host
}
void loop() {
// Do Nothing
}
3. Chế độ Station + Access Point (STA+AP) trên ESP32:
Đây là chế độ kết hợp, cho phép ESP32 vừa kết nối vào mạng Wi-Fi hiện có (như một thiết bị khách), vừa tạo ra một điểm truy cập Wi-Fi riêng. Chế độ này cung cấp tính linh hoạt cao trong việc giao tiếp và truyền tải dữ liệu.
Cách thiết lập station + access point mode trên esp32:
#include <WiFi.h> //Thêm thư viện wifi
const char* ssid = "DTM E-SMART"; //Tên điểm truy cập wifi
const char* password = "0919890938"; //Mật khẩu wifi
const char* ssidAP = "ESP32_AP"; //Tên wifi cần phát ra
const char* passwordAP = "12345678"; //Mật khẩu wifi
void setup(){
Serial.begin(115200);
WiFi.mode(WIFI_AP_STA); //Thiết lập chế độ wifi STA+AP
WiFi.begin(ssid, password); //Kết nối wifi
Serial.println("\nConnecting to WiFi Network ..");
while(WiFi.status() != WL_CONNECTED){
Serial.print(".");
delay(100);
}
Serial.println("\nConnected to the WiFi network");
Serial.print("Local ESP32 IP: ");
Serial.println(WiFi.localIP()); //In địa chỉ IP khi kết nối wifi
int channel = WiFi.channel(); //Đọc kênh wifi đã kết nối
//Phát wifi trên kênh đã kết nối
if(!WiFi.softAP(ssidAP, passwordAP,channel)){
Serial.println("Soft AP creation failed.");
while(1);
}
Serial.println("\nSuccessfully created soft AP");
Serial.print("AP IP address: ");
Serial.println(WiFi.softAPIP());//In địa chỉ IP host
}
void loop(){
// Do Nothing
}
Quản lý WiFi trên ESP32
ESP32 cung cấp các hàm sự kiện WiFi mạnh mẽ giúp bạn theo dõi và quản lý các trạng thái kết nối mạng. Các hàm sự kiện WiFi cho phép ESP32 phản hồi theo thời gian thực đối với các sự kiện như kết nối thành công, mất kết nối, và thay đổi địa chỉ IP. Bằng cách sử dụng các sự kiện WiFi, bạn có thể xây dựng các ứng dụng ổn định hơn, tối ưu hóa khả năng phản hồi và khắc phục sự cố nhanh chóng.
Cách sử dụng sự kiện WiFi trên ESP32:
#include <WiFi.h> //Thêm thư viện wifi
//Chương trình xử lý sự kiện wifi
void WiFiEvent(WiFiEvent_t event) {
switch (event) {
case SYSTEM_EVENT_STA_GOT_IP: //Gửi thông tin về PC khi kết nối wifi
Serial.println("Connected to WiFi");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
break;
case SYSTEM_EVENT_STA_DISCONNECTED: //Tự kết nối lại khi mất wifi
Serial.println("Disconnected from WiFi");
WiFi.begin("your_SSID", "your_PASSWORD");
break;
default:
break;
}
}
void setup() {
Serial.begin(115200);
WiFi.onEvent(WiFiEvent); //Đăng ký chương trình bắt sự kiện wifi
WiFi.begin("your_SSID", "your_PASSWORD");//Kết nối wifi chế độ STA
}
void loop() {
// Không cần làm gì trong loop này
}
Web server trên ESP32
Web server trên ESP32 là một tính năng mạnh mẽ cho phép thiết bị nhỏ gọn này phục vụ các trang web và giao tiếp với các thiết bị khác qua internet. Với khả năng tạo và quản lý một web server, ESP32 có thể xử lý các yêu cầu HTTP, gửi phản hồi HTML, và thậm chí cung cấp các API RESTful. Điều này mở ra rất nhiều ứng dụng đa dạng, từ điều khiển thiết bị gia đình thông minh đến giám sát và quản lý dữ liệu từ xa. Bằng cách sử dụng web server, người dùng có thể dễ dàng giám sát và điều khiển các thiết bị qua trình duyệt web trên điện thoại di động hoặc máy tính, làm cho việc tương tác và quản lý các dự án IoT trở nên trực quan và tiện lợi hơn.
Trong bài viết này chúng ta chỉ đề cập đến dịch vụ web server trên ESP32, và web server này chỉ hoạt động trong mạng cục bộ và những thiết bị đang kết nối chung mạng với ESP32.
Cách thiết lập web server trên ESP32
#include <WiFi.h>
#include <WebServer.h> //Thêm thư viện web server
WebServer webServer(80); //Khởi tạo đối tượng webServer port 80
const char* ssid = "DTM E-SMART"; //Tên wifi sẽ kết nối
const char* password = "0919890938"; //Mật khẩu wifi
//Tạo biến chứa mã nguồn trang web HTML để hiển thị trên trình duyệt
const char html[] PROGMEM = R"html(
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My ESP32 Web Page</title>
</head>
<body>
<h1>Hello from ESP32!</h1>
<!-- Other HTML content here -->
</body>
</html>
)html";
void setupWifi(){
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED){
delay(100);
}
Serial.println("\nConnected! ESP32 IP: "+WiFi.localIP().toString());
}
void setup() {
Serial.begin(115200);
setupWifi(); //Thiết lập wifi
//Thiết lập xử lý các yêu cầu từ client(trình duyệt web)
webServer.on("/",[]{
webServer.send(200, "text/html", html); //Gửi nội dung HTML
});
webServer.begin(); //Khởi chạy dịch vụ web server trên ESP32
}
void loop() {
webServer.handleClient(); //Lắng nghe yêu cầu từ trình client
}
Khi nạp đoạn mã này vào ESP32, thiết bị sẽ kết nối vào mạng Wi-Fi và khởi tạo một dịch vụ web server. Để truy cập vào web server này, bạn cần biết địa chỉ IP của ESP32 sau khi kết nối mạng. Bạn có thể vào mục Tools -> Serial Monitor trong Arduino IDE, chọn baud rate là 115200 và nhấn nút EN trên ESP32 để khởi động lại. Lúc này, ESP32 sẽ gửi địa chỉ IP lên máy tính qua UART. Để truy cập, bạn mở trình duyệt web và nhập địa chỉ IP nhận được. Trình duyệt sẽ tải nội dung trang web mà bạn đã lưu vào biến html.
Ứng dụng của web server trên ESP32
1. Hiển thị thông tin và điều khiển thiết bị
Sử dụng web server trên ESP32 có thể được nâng cao hơn nữa bằng việc tích hợp thư viện websocket. Điều này cho phép thiết kế giao diện hiển thị thông tin linh hoạt và tự động cập nhật mà không cần yêu cầu liên tục từ phía client (trình duyệt web) đến server. Nhờ đó, dữ liệu từ các cảm biến hoặc trạng thái thiết bị được cập nhật nhanh chóng và hiệu quả lên giao diện web phía client. Ngoài ra, các chức năng điều khiển thông qua giao diện web trở nên tiện lợi và nhanh chóng.
Cách sử dụng web socket trên ESP32
#include <WiFi.h>
#include <WebSocketsServer.h> //Thêm thư viện WebSocketsServer
#include <WebServer.h> //Thêm thư viện web server
WebServer webServer(80); //Khởi tạo đối tượng webServer port 80
WebSocketsServer webSocket = WebSocketsServer(81);//Khai báo websoket
const char* ssid = "DTM E-SMART"; //Tên wifi sẽ kết nối
const char* password = "0919890938"; //Mật khẩu wifi
//Tạo biến chứa mã nguồn trang web HTML để hiển thị trên trình duyệt
const char html[] PROGMEM = R"html(
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My ESP32 Web Page</title>
<style type="text/css">
button{width: 100px;height: 40px;margin-top: 10px;}
label, span{font-size: 28px;color: red;}
</style>
</head>
<body>
<h1>WebSocket ESP32!</h1>
<label>Temperature:</label><span id="temp">30℃</span><br>
<button onclick="send('ON')" style="background-color: green;">ON</button>
<button onclick="send('OFF')" style="background-color: yellow;">OFF</button>
<!-- Other HTML content here -->
<script type="text/javascript">
window.onload=function(){
init();
}
var Socket;
function init(){
Socket=new WebSocket('ws://' + window.location.hostname + ':81');
Socket.onmessage = function(event){
document.getElementById("temp").innerHTML = event.data+"℃";
}
}
function send(cmd){
Socket.send(cmd);
}
</script>
</body>
</html>
)html";
#define ledPin 2
unsigned long lastTime=millis();
void setupWifi(){
pinMode(ledPin,OUTPUT);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED){
delay(100);
}
Serial.println("\nConnected! ESP32 IP: "+WiFi.localIP().toString());
}
//Chương trình con xử lý sự kiện websoket
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("[%u] Disconnected!\n", num);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
webSocket.sendTXT(num, "Connected");// send message to client
}
break;
case WStype_TEXT: //Nhận lệnh từ websocket client(trình duyệt)
{
Serial.printf("[%u] get Text: %s\n", num, payload);
String cmd = (const char *)payload;
if(cmd=="ON") digitalWrite(ledPin,HIGH);
else if(cmd=="OFF") digitalWrite(ledPin,LOW);
}
break;
case WStype_BIN:
Serial.printf("[%u] get binary length: %u\n", num, length);
break;
case WStype_ERROR:
case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START:
case WStype_FRAGMENT:
case WStype_FRAGMENT_FIN:
break;
}
}
void setup() {
Serial.begin(115200);
setupWifi(); //Thiết lập wifi
//Thiết lập xử lý các yêu cầu từ client(trình duyệt web)
webServer.on("/",[]{
webServer.send(200, "text/html", html); //Gửi nội dung HTML
});
webServer.begin(); //Khởi chạy dịch vụ web server trên ESP32
webSocket.begin(); //Khởi chạy webSocket Server
webSocket.onEvent(webSocketEvent);//Đăng ký sự kiện websocket
}
void loop() {
webServer.handleClient(); //Lắng nghe yêu cầu từ trình client
webSocket.loop();
if(millis()-lastTime>=1000){
int temperature = random(30,40);
String data = String(temperature);
webSocket.broadcastTXT(data); //Gửi dữ liệu đến websocket client
lastTime=millis();
}
}
Để sử dụng đoạn mã trên, bạn cần tải thêm thư viện WebSockets của tác giả Markus Sattler version 2.4.0. Trên Arduino IDE, vào mục Sketch -> Chọn Library Manager, tìm kiếm và cài đặt thư viện. Khi nạp mã xong, bạn có thể truy cập vào web server thông qua địa chỉ IP kết nối của ESP32 với Wi-Fi. Lúc này, giao diện web sẽ được tải lên, trong đó ESP32 sẽ gửi giá trị nhiệt độ ngẫu nhiên lên web và cung cấp hai nút nhấn để điều khiển đèn LED trên board ESP32.
2. Cài đặt cấu hình và thông số thiết bị
Một trong những ứng dụng thực tế nhất của web server trên ESP32 là thiết lập cấu hình cho thiết bị khi sử dụng lần đầu hoặc khi cần thay đổi thông tin như tên và mật khẩu Wi-Fi, cùng các cài đặt ban đầu khác. Để thực hiện các cài đặt này một cách dễ dàng và tiện lợi, chúng ta thường sử dụng kỹ thuật Ajax. Ajax giúp cập nhật dữ liệu một cách linh hoạt và không cần làm mới toàn bộ trang web, tối ưu hóa quá trình cấu hình và mang lại trải nghiệm người dùng hiệu quả hơn.
Cách dùng ajax trong web server trên ESP32
#include <EEPROM.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <WebServer.h> //Thêm thư viện web server
WebServer webServer(80); //Khởi tạo đối tượng webServer port 80
String ssid = "DTM E-SMART"; //Tên wifi sẽ kết nối
String password = "0919890938"; //Mật khẩu wifi
#define btnPin 0
unsigned long lastTimePress=millis();
//Tạo biến chứa mã nguồn trang web HTML để hiển thị trên trình duyệt
const char html[] PROGMEM = R"html(
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My ESP32 Web Page</title>
<style type="text/css">
button{width: 100px;height: 40px;margin-top: 10px;}
label, span{font-size: 25px;}
input{margin-bottom: 10px;width:200px;}
select{margin-bottom: 10px;width: 210px;}
</style>
</head>
<body>
<h1>Ajax ESP32!</h1>
<label>Wifi name:</label><br>
<select id="ssid">
<option>Choise wifi name!</option>
</select><br>
<label>Password:</label><br>
<input id="password" type="text"><br>
<button onclick="saveWifi()" style="background-color: cyan;">SAVE</button>
<button onclick="reStart()" style="background-color: pink;">RESTART</button>
<script type="text/javascript">
window.onload=function(){
scanWifi();
}
var xhttp = new XMLHttpRequest();
function scanWifi(){
xhttp.onreadystatechange = function(){
if(xhttp.readyState==4&&xhttp.status==200){
data = xhttp.responseText;
// alert(data);
var obj = JSON.parse(data);
var select = document.getElementById("ssid");
for(var i=0; i<obj.length;++i){
select[select.length] = new Option(obj[i],obj[i]);
}
}
}
xhttp.open("GET","/scanWifi",true);
xhttp.send();
}
function saveWifi(){
ssid = document.getElementById("ssid").value;
pass = document.getElementById("password").value;
xhttp.onreadystatechange = function(){
if(xhttp.readyState==4&&xhttp.status==200){
data = xhttp.responseText;
alert(data);
}
}
xhttp.open("GET","/saveWifi?ssid="+ssid+"&pass="+pass,true);
xhttp.send();
}
function reStart(){
xhttp.onreadystatechange = function(){
if(xhttp.readyState==4&&xhttp.status==200){
data = xhttp.responseText;
alert(data);
}
}
xhttp.open("GET","/reStart",true);
xhttp.send();
}
</script>
</body>
</html>
)html";
void setupWifi(){
if(ssid!=""){
Serial.println("Connecting to wifi...!");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED){
delay(1000);
Serial.print(".");
checkButton();
}
Serial.println("\nConnected! ESP32 IP: "+WiFi.localIP().toString());
}else{
Serial.println("ESP32 wifi network created!");
WiFi.mode(WIFI_AP);
WiFi.softAP("ESP32");
Serial.println("Web server access address:"+WiFi.softAPIP().toString());
}
}
void checkButton(){
if(digitalRead(btnPin)==LOW){
Serial.println("Press and hold for 5 seconds to reset to default!");
if(millis()-lastTimePress>5000){
for(int i=0; i<200;i++){
EEPROM.write(i,0);
}
EEPROM.commit();
Serial.println("EEPROM memory erased!");
delay(3000);
ESP.restart();
}
delay(1000);
}else{
lastTimePress=millis();
}
}
void setup() {
Serial.begin(115200);
pinMode(btnPin,INPUT_PULLUP);
EEPROM.begin(200);
char ssid_temp[32], password_temp[64];
EEPROM.readString(0,ssid_temp, sizeof(ssid_temp));
EEPROM.readString(32,password_temp,sizeof(password_temp));
ssid = String(ssid_temp);
password = String(password_temp);
Serial.println("SSID:"+ssid);
Serial.println("PASSWORD:"+password);
setupWifi(); //Thiết lập wifi
//Thiết lập xử lý các yêu cầu từ client(trình duyệt web)
webServer.on("/",[]{
webServer.send(200, "text/html", html); //Gửi nội dung HTML
});
webServer.on("/scanWifi",[]{
Serial.println("Scanning wifi network...!");
int wifi_nets = WiFi.scanNetworks(true, true);
const unsigned long t = millis();
while(wifi_nets<0 && millis()-t<15000){
delay(20);
wifi_nets = WiFi.scanComplete();
}
DynamicJsonDocument doc(512);
for(int i=0; i<wifi_nets; ++i){
Serial.println(WiFi.SSID(i));
doc.add(WiFi.SSID(i));
}
//["tên wifi1","tên wifi2","tên wifi3",.....]
String wifiList = "";
serializeJson(doc, wifiList);
Serial.println("Wifi list: "+wifiList);
webServer.send(200,"application/json",wifiList);
});
webServer.on("/saveWifi",[]{
String ssid_temp = webServer.arg("ssid");
String password_temp = webServer.arg("pass");
Serial.println("SSID:"+ssid_temp);
Serial.println("PASS:"+password_temp);
EEPROM.writeString(0,ssid_temp);
EEPROM.writeString(32,password_temp);
EEPROM.commit();
webServer.send(200,"text/plain","Wifi has been saved!");
});
webServer.on("/reStart",[]{
webServer.send(200,"text/plain","Esp32 is restarting!");
delay(3000);
ESP.restart();
});
webServer.begin(); //Khởi chạy dịch vụ web server trên ESP32
}
void loop() {
checkButton();
webServer.handleClient(); //Lắng nghe yêu cầu từ trình client
}
Trong đoạn code này, tôi đã lập trình việc khởi tạo một web server trên ESP32 và sử dụng kỹ thuật Ajax để truyền tải dữ liệu thông tin kết nối wifi giữa client (trình duyệt web) và ESP32. Đoạn code này giúp chúng ta có khả năng thay đổi thông tin kết nối wifi ngay từ web server do ESP32 tạo ra mà không cần phải tải lại code vào chương trình.
Để nạp code này, bạn cần cài đặt thêm thư viện ArduinoJson, giúp tạo và xử lý dữ liệu JSON. Sau khi cài đặt thư viện và tải code thành công, bạn cần thực hiện các bước sau để thiết lập thông tin wifi. Thông tin kết nối wifi sẽ được đọc từ bộ nhớ Flash của ESP32 qua thư viện EEPROM. Khi khởi động lần đầu, bộ nhớ Flash sẽ không có thông tin kết nối, vì vậy bạn cần giữ nút BOOT trong 5 giây để xóa bộ nhớ Flash và thiết lập chế độ phát wifi. ESP32 sẽ phát một tên wifi là “ESP32“. Sử dụng điện thoại hoặc máy tính để kết nối với wifi “ESP32” và mở trình duyệt web để truy cập web server tại địa chỉ 192.168.4.1. Trên web server, chờ ESP32 quét các mạng wifi xung quanh khoảng 15 giây, sau đó chọn “Choise wifi name!” để chọn mạng wifi bạn muốn kết nối, nhập mật khẩu và nhấn “SAVE” để lưu thông tin. Cuối cùng, nhấn “RESTART” để khởi động lại ESP32, nó sẽ kết nối với mạng wifi bạn đã thiết lập.
Nếu bạn đã kết nối mạng wifi nhưng muốn thay đổi sang mạng khác, bạn có thể truy cập vào web server của ESP32 tại địa chỉ IP mà nó đã kết nối. Ví dụ, địa chỉ IP là 192.168.1.15 được Router Wifi cung cấp cho ESP32. Bạn cần kết nối máy tính hoặc điện thoại di động vào cùng mạng wifi với ESP32, sau đó mở trình duyệt web và nhập địa chỉ IP để thay đổi tên wifi và mật khẩu cho ESP32.
Hy vọng phần code này có thể giúp mọi người giải quyết vấn đề thay đổi thông tin kết nối wifi mà không cần phải nạp lại code vào chương trình.
Kết luận
Việc sử dụng ESP32 với các chức năng WiFi và web server mang lại nhiều tiện ích và ứng dụng đa dạng trong lĩnh vực IoT. Từ khả năng kết nối và quản lý mạng không dây, thiết lập cấu hình ban đầu, đến việc tạo ra các giao diện web. ESP32 thực sự là một vi điều khiển mạnh mẽ và linh hoạt cho các dự án thông minh. Hy vọng bài viết này Điện thông minh E-smart đã giúp bạn hiểu rõ hơn về các khả năng của ESP32 và cách tận dụng chúng trong dự án của mình. Chúc bạn thành công!