1、什么是 ESP32 Web Server?
ESP32 Web Server是在ESP32微控制器上運行的一個嵌入式網頁服務器。
它能夠處理HTTP請求并作出響應,使用戶可以通過網絡瀏覽器與設備進行通訊和交互。
這種能力使得開發者可以輕松為硬件設備構建用戶友好的接口,實時監控和控制設備。
溫馨提醒:公眾號后臺私信ESP32 Web Server可獲取完整工程;
2、為什么要在ESP32上運行Web Server
在 ESP32 上運行 Web Server 有以下幾個優勢:
前置條件:ESP32 天生自帶Wi-Fi,支持TCP/IP協議棧,是運行Web Server的前置條件;
用戶友好:無需復雜的客戶端軟件,任何設備的瀏覽器都可以訪問和控制。
實時監控與控制:通過簡單的網頁界面即可實時監控設備狀態,并執行控制。
跨平臺兼容:網頁界面可以在任何支持瀏覽器的設備上訪問,無需考慮不同操作系統的兼容性。
易于配置:用戶可以通過網頁便捷設置設備參數。
一個實際的例子,我之前開發過《一個雙無線串口數據記錄工具》,為了對設備進行配置,專門用QT開發了一個上位機,但是由于只出了windows版本,導致其他系統如Linux/MacOS的用戶用不了,所以Web Server將是一個好的解決思路;

上圖基于QT實現的上位機工具;
3、Web Server 原理

Web Server 原理邏輯圖
本質上Web Server就是利用tcp進行http協議通信,其中ESP32作為Server而瀏覽器作為Client。
那么在HTTP中,最常見的就是GET和POST,這兩種方法,其中GET用于從Server端獲取資源,POST用于把客戶端的信息上報給Server;
除了常見的GET、POST之外還有PUT、DELETE,具體的作用可以參考HTTP協議,這里就不展開了;
我們平時訪問Web Server的時候我們一般會獲取到兩種資源;
一種是靜態資源,比如我們通過網頁獲取到一張圖片,不管我們什么時候訪問一般都不會變化;
另一種是動態資源,比如我們訪問股票網頁,股市的數據是實時變化的;
所以當我們用瀏覽器訪問網站時,如果訪問的是靜態資源,服務器則把我們預制的文件(HTML)下發到客戶端的。而這些文件(HTML)則是開發人員提前放到服務器上的。
當訪問的是動態資源時,服務端會進行運算之后再把資源返回給客戶端;
客戶端也就是瀏覽器接收到這些資源,按照我們設計的頁面邏輯把接收到的數據展示出來就是我們看到的頁面了;
所以當我們把ESP32作為Web Server時也需要把預制的網頁保存到ESP32的存儲單元上,可以是Flash或者外接SD卡等方式。
然后等客戶端(瀏覽器)發起了GET請求之后,Server端遵循HTTP協議,加裝指定的html文件之后響應發送給客戶端,客戶端就加載顯示到瀏覽器上;
4、ESP32 上如何實現Web Server
我們這里以通過瀏覽器訪問esp32上的服務地址,然后瀏覽器上可以顯示一行字作為靜態資源,以及esp32的運行時長-作為動態資源,作為我們的實驗例子;
根據上述的原理,我們需要以下3個功能
實現一個http server;
預先存放html文件到esp32上的SD卡(這里我們把SD卡掛載到esp32);
處理瀏覽器發送過來的GET方法,判斷如果是獲取靜態資源則然后返回對應的html文件,如果是動態獲取動態資源則返回esp32的運行時長;
基于以上提到的三個功能,我們接著看看ESP32上的實現;
4.1 ESP32 HTTP Server的實現
在樂鑫的ESP-IDF SDK中,已經有官方提供的esp_http_server組件了,所以我們并不需要手動來造輪子;
組件位置:esp-idf-v5.2/components/esp_http_server主要的幾個函數如如下
創建一個http sever:esp_err_t httpd_start(httpd_handle_t *handle, const httpd_config_t *config);
注冊不同方法的處理函數:esp_err_t httpd_register_uri_handler(httpd_handle_t handle,const httpd_uri_t *uri_handler);
在本實驗中,我注冊了兩個處理函數;
- index:用于返回頁面的靜態資源;
- uptime擁有返回設備的運行時長,具體代碼如下:
staticconsthttpd_uri_tindex_page = {
.uri ="/",
.method = HTTP_GET,
.handler = index_get_handler,
/* Let's pass response string in user
* context to demonstrate it's usage */
.user_ctx ="Hello World!"
};
staticconsthttpd_uri_tuptime = {
.uri ="/uptime",
.method = HTTP_GET,
.handler = uptime_handler,
/* Let's pass response string in user
* context to demonstrate it's usage */
.user_ctx ="Hello World!"
};
statichttpd_handle_tstart_webserver(void)
{
httpd_handle_tserver =NULL;
httpd_config_tconfig = HTTPD_DEFAULT_CONFIG();
config.lru_purge_enable =true;
// Start the httpd server
ESP_LOGI(TAG,"Starting server on port: '%d'", config.server_port);
if(httpd_start(&server, &config) == ESP_OK) {
// Set URI handlers
ESP_LOGI(TAG,"Registering URI handlers");
httpd_register_uri_handler(server, &index);
httpd_register_uri_handler(server, &uptime);
returnserver;
}
ESP_LOGI(TAG,"Error starting server!");
returnNULL;
}
4.2 預先存放html文件到esp32上的SD卡
這個步驟主要分為2步
驅動SD卡,同理,ESP-IDF也給我們提供了組件vfs,看下例程很快就知道怎么用了,這里不展開了,如果確實不會,可以直接看本工程源碼;
編寫html文件,這里我簡單寫了一個界面,效果如下圖

4.3 兩個處理函數的實現
index_page,直接加裝我們指定的index.html文件,然后返回;
staticesp_err_tindex_get_handler(httpd_req_t*req)
{
char* buf;
size_tbuf_len;
/* Get header value string length and allocate memory for length + 1,
* extra byte for null termination */
buf_len = httpd_req_get_hdr_value_len(req,"Host") +1;
if(buf_len >1) {
buf =malloc(buf_len);
/* Copy null terminated value string into buffer */
if(httpd_req_get_hdr_value_str(req,"Host", buf, buf_len) == ESP_OK) {
ESP_LOGI(TAG,"Found header => Host: %s", buf);
}
free(buf);
}
/* Read URL query string length and allocate memory for length + 1,
* extra byte for null termination */
buf_len = httpd_req_get_url_query_len(req) +1;
if(buf_len >1) {
buf =malloc(buf_len);
if(httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
ESP_LOGI(TAG,"Found URL query => %s", buf);
}
free(buf);
}
/* Set some custom headers */
/* Send response with custom headers and body set as the
* string passed in user context*/
constchar* resp_str = (constchar*) req->user_ctx;
char*file_name ="/sdcard/html/index.html";
intfileSize = myLogFileSize(file_name);
FILE* fileFD = fopen( file_name,"r+");
if( fileFD ==NULL)
{
constchar* resp_str = (constchar*) req->user_ctx;
ESP_LOGI(TAG,"File not found => %s", file_name);
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
}
else
{
intread_len =0;
char* fileBuf =NULL;
fseek( fileFD,0, SEEK_END );
fileSize = ftell( fileFD );
fseek( fileFD,0, SEEK_SET );
fileBuf = (char*)malloc( fileSize +1);
memset( fileBuf,0, fileSize +1);
read_len = fread( fileBuf,1, fileSize, fileFD );
fclose( fileFD );
resp_str = fileBuf;
ESP_LOGI(TAG,"Found file => %s", resp_str);
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
free( fileBuf );
}
/* After sending the HTTP response the old HTTP request
* headers are lost. Check if HTTP request headers can be read now. */
if(httpd_req_get_hdr_value_len(req,"Host") ==0) {
ESP_LOGI(TAG,"Request headers lost");
}
returnESP_OK;
}
uptime_handler獲取系統 運行時長,返回
staticesp_err_tuptime_handler(httpd_req_t*req)
{
uint64_tuptime_microseconds = esp_timer_get_time();// 獲取運行時長(微秒)
uint32_tuptime_seconds = uptime_microseconds /1000000;// 轉換為秒
ESP_LOGI("System Uptime","System has been running for %lu seconds", uptime_seconds);
charresponse[64];
snprintf(response,sizeof(response)," %lu seconds", uptime_seconds);
httpd_resp_set_hdr(req,"Access-Control-Allow-Origin","*");
// httpd_resp_set_hdr(req, "Content-Type", "text/plain");
httpd_resp_send(req, response, HTTPD_RESP_USE_STRLEN);
returnESP_OK;
}
5、實驗效果
我們通過模組的IP或者綁定的mdns域名(什么是mdns可以見我之前的文章:你的ESP32設備有域名嗎?我的有!)訪問,可以獲取到靜態資源和動態的模組運行時長。
效果如下圖展示(運行秒數在遞增)

6、結論
通過樂鑫提供的esp_http_server組件,我們在ESP32上成功運行了一個簡單的web server,可以展示一些靜態和動態資源。
后續我將用這個技術原理來實現更多的功能,比如:
通過網頁對ESP32進行配網;
如何基于網頁進行實時通訊;
通過網頁控制ESP32的外設如GPIO、串口等功能;
溫馨提醒: 公眾號后臺私信ESP32 Web Server可獲取完整工程;
最后大家覺得這個技術還可以用來做什么有趣的應用,歡迎留言討論。
歡迎大家點贊、關注、轉發將是我創作的最大動力~
-
Web
+關注
關注
2文章
1285瀏覽量
70959 -
服務器
+關注
關注
13文章
9730瀏覽量
87462 -
ESP32
+關注
關注
21文章
1012瀏覽量
18977
發布評論請先 登錄
【FireBeetle ESP32-E開發板免費試用】+wifi功能測試&搭建web服務器
CH563運行WEB-SERVER 20分鐘后發熱嚴重怎么改善?
ESP32 Web服務器可以向外部Rest API發起HTTP請求嗎?
如何實現ESP32上運行運行HTTP服務器?
使用ESP8266作為Web服務器,如何將網頁上傳到SPIFFS?
最簡單DIY基于ESP8266的物聯網智能小車②(webserver服務器網頁高級遙控版)

ESP32 IDF創建WEB SERVER的流程

評論