ESP32 Web 服务器(异步技术和内部文件系统)






3.81/5 (15投票s)
一项探索异步 Web 服务器、SPIFFS 文件系统和双核利用的工程
引言
文章重点介绍了使用异步 Web 服务器创建复杂应用程序的简便性,以及如何以及在哪里存储必要的文件(JavaScript 源文件、样式表、图像等)以及如何利用双核板。 任何拥有浏览器的设备都可以访问 Web 服务器,此应用程序尤其考虑了手机访问。 您也可以从 我的网站获取源代码。 | ![]() |
背景
用户必须熟练使用 Arduino IDE 并用 C++ 编程。
文章假设用户已安装某些组件,但在专门的段落中,他们可以找到使用该应用程序所需的参考。
用户访问应用程序,该应用程序向浏览器发送一个表单,在该表单中可以更改板上的时间、请求湿度和温度值(DHT22 传感器)1) 并查看文件系统的内容。
Arduino IDE 注意事项
如果 IDE 无法关联 COM
端口,则表示缺少相应的驱动程序,以下是我为解决此问题而遵循的步骤。
- 我已识别出我的 ESP32 板上的 USB 转串行转换器芯片
- 在 Windows 设备管理器中,它出现在
其他设备
下方的芯片名称(我的是CP2102 USB to UART Bridge Controller
), - 我从制造商网站下载了包含芯片驱动程序的
.zip
文件;
- 在 Windows 设备管理器中,它出现在
- 我通过右键单击
silabser.inf
文件并选择安装
来安装驱动程序。
Using the Code
包含的源代码是一个包含所有必要数据的文件夹。当它安装在 ESP32 板上时,您必须激活 Sermig_Condor
WiFi 服务,并通过浏览器访问 IP 地址 192.168.1.1
。
最终,可以通过串行端口将某些命令发送到板。
主要组件是
- 异步 Web 服务器
- SPIFFS (SPI Flash File Storage) 文件系统托管在 Flash 内存中。文件系统包含应用程序所需的所有文件
- index.html
- formgen.js 一个用于生成表单的脚本(请参阅我的文章 A JavaScript Form Generator)
- formgen.css 一个用于生成表单的样式表
- 图像文件
- 同时使用 ESP32 板的两个处理器核心。
Web 服务器的创建和行为
...
#include <WiFi.h>
#include <AsyncTCP.h>
#include "ESPAsyncWebServer.h"
...
// SSID & Password ******************************************************
const char* ssid = "Sermig_Condor";
const char* password = "";
// IP Address ***********************************************************
IPAddress local_ip(192, 168, 1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
AsyncWebServer server(80); // Object of WebServer(HTTP port, 80 is default)
---
void setup() {
...
WiFi.softAP(ssid, password);
delay(2000); // to avoid crash on WiFi connection
WiFi.softAPConfig(local_ip, gateway, subnet);
Serial.printf("Connect to Access Point: %s\n",ssid);
server.on("/", HTTP_ANY, [](AsyncWebServerRequest *request) {
...
});
server.onNotFound([](AsyncWebServerRequest *request){request->send(404);});
server.serveStatic("/", SPIFFS, "/");
server.begin();
...
}
void loop() {
// this can be empty
}
在上面的片段中,请注意所需的源代码、访问参数(名称、IP 地址等)的设置以及请求的处理。
请求的处理在
server.on(...
其中第一个参数是资源请求,在示例中是根目录,第二个参数指示接受哪种类型的请求,HTTP_ANY
同时接受HTTP_GET
和HTTP_PUT
。这意味着请求的任何参数都可以采用内联形式?key=value
,就像在提交的表单中一样;第三个参数是处理请求的函数。对于每个需要特殊处理的请求,都必须存在server.on
。server.onNotFound(...
用于处理未知资源请求。server.serveStatic("/", SPIFFS, "/");
这告诉 Web 服务器发送浏览器请求的、包含在SPIFFS
文件系统中的文件,例如图像、样式表、JavaScript 源文件等。这意味着我们不必处理请求文件的 MIME 类型。
与板交互的选择是将请求直接放在地址之后
server.on("/", HTTP_ANY, [](AsyncWebServerRequest *request) {
if(request->hasArg("fnz")) {
String type = request->arg("fnz");
AsyncResponseStream *response = request->beginResponseStream("text/html");
if (type == "Dir") { // send Filesystem contents
response->print(dir());
request->send(response);
} else if (type == "Clock") { // set an internal Clock
setTime(toSeconds(request->arg("time").c_str()));
response->printf("New time: %s", getTime());
request->send(response);
} else if (type == "Temp") { // get humidity and temperature
response->printf("%s %s",getTime(),getTemperature());
request->send(response);
}
} else request->send(SPIFFS, "/index.html"); // send the form
上面的片段处理形式为 /[GET data]
的请求,对象请求公开了获取参数和发送响应的方法;如果没有找到参数,则发送初始页面,即文件 index.html;因此,请求和响应可以是
192.168.1.1 | 发送表单(index.html) |
192.168.1.1/fnz=Clock&time=hh:mm:ss | 内部时钟已更新 |
192.168.1.1/fnz=Dir | 发送文件系统内容 |
192.168.1.1/fnz=Temp | 发送湿度和温度值 |
请求的数据以纯文本形式发送,但可以包含 HTML 标签,例如下面显示文件系统内容的函数
String dir(void) {
String x = "<table>";
File root = SPIFFS.open("/");
if(!root) {
return "Failed to open directory";
}
if(!root.isDirectory()) {
return "Not a directory";
}
File file = root.openNextFile();
while(file) {
x += "<tr><td>"+String(file.name());
if(file.isDirectory()){
x += "<td>DIR";
} else {
x += "<td style='text-align:right'>"+String(file.size());
}
file = root.openNextFile();
}
x += "<tr><td>Occupied space<td style='text-align:right'>"+String(SPIFFS.usedBytes());
x += "<tr><td>Total space<td style='text-align:right'>"+String(SPIFFS.totalBytes());
return x+"</table>";
}
可以通过串行链接发送命令与板进行交互
d[ir]
用于显示文件系统内容r
重启板t
查看湿度和温度
串行监听器在核心 0 上运行,在下面的片段中,展示了它是如何实现的。
void serialListener( void * pvParameters ) { // this runs in core 0
Serial.print("Serial Listener running on core ");
Serial.println(xPortGetCoreID());
delay(100);
for(;;){
while (Serial.available() > 0) {
char cmd = Serial.read() | 0b00100000;
switch (cmd) {
case 100: // d[ir]
dir_ls();
break;
case 114: // r reset Board
Serial.print("\nReset board\n");
delay(200);
ESP.restart();
break;
case 116: // t get temperature/humidity
sprintf(workBuffer, "%s %s", getTime(),getTemperature());
Serial.println(workBuffer);
break;
}
}
vTaskDelay(150 / portTICK_PERIOD_MS); // 150 millisecond
}
}
void setup() {
...
xTaskCreatePinnedToCore (
serialListener, /* Function to implement the task */
"WiFi-WEBServer", /* Name of the task */
10000, /* Stack size in words */
NULL, /* Task input parameter */
1, /* Priority of the task */
NULL, /* Task handle. */
0); /* Core where the task should run */
}
组件说明
异步 Web 服务器
文档: https://github.com/me-no-dev/ESPAsyncWebServer
我们需要以下两个库
并将它们解压缩到 Arduino 的 libraries 文件夹中,注意删除文件夹名称中的 -master
后缀。
SPIFFS 文件系统
SPIFFS 文件系统很有用,但也有一些限制,请在此 处查看文档。
- 它具有扁平结构,即不支持目录。
- 目前,它不会检测或处理坏块。
- 闪存的写入次数限制为 10,000 次。
- 带扩展名的文件名最多限制为 31 个字符。
安装(来自此 教程)
- 在 sketch 文件夹中创建一个名为 data 的文件夹,并将“site”文件放在其中。
- 下载文件 ESP32FS-1.0.zip。
- 将下载的 .zip 文件夹解压缩到 Arduino 的 Tools 文件夹(如果位于
...\ArduinoData\packages
并且不存在,则必须创建它)。
如果安装成功,IDE 菜单 Tools
中会出现 ESP32 Sketch Data Upload
项,它允许将 data 文件夹的内容上传到 SPIFFS 文件系统。2)
我们可以通过 **Tools** −> **Partition Scheme** 查看文件系统大小。
结论
异步 Web 服务器与文件系统结合使用,可以构建非平凡的应用程序,开发者只需关注应用程序的逻辑。
注释
1) 该应用程序可以独立于此传感器运行。
2) 上传使用串行端口,请关闭任何串行监视器。
历史
- 2021 年 4 月 27日:初始版本