be105086a11075511200dde26b26890f.png

本文作者:。默是铁熊的创客好友,经常与铁熊分享创意项目。

2b6183cb27bc31b9664fde0dd8d797eb.png

前段时间有个老师对我说:每到开学季,学校就要印刷学生的录取名单并进行张贴,为此学校每年都要耗费大量的人力物力。学校里面教学活动很多,传统的通知都是通过张贴海报之类的方式进行公布,但是在信息化高速发展的今天,许多消息的发布已经不需要传统的纸质媒介了,我们可以通过网站在线查询。然而一个网站的开发是十分复杂的,涉及到的知识很多,大部分人不可能有这么多的时间和精力去学习网站开发。

考虑到这些难点,结合我与那位老师交流以及解决该问题的过程,本教程将教你利用 ESP32 开发板搭建一个实用的网络服务器。该方案利用 ESP32 开发板托管网页,通过数据库查询信息,然后通过网页进行显示。同时也可以对网页进行可视化编辑,让没有任何基础的人都能够轻松地设计一个实用网页 ,而你需要做的仅仅是提供你要呈现的数据 。

下面让我们先来看看这个项目的演示视频,该演示项目中我们托管了4个不同服务的网页:

M5 Server X名称的由来

M5 是指基于 ESP32 的 M5 Core2 开发板,Server 代表它是一个网络服务器,而 X 代表了无限可能,故名 M5 Server X,运用 M5 Server X 我们能够将任何数据或者服务通过网页的形式呈现,而无需任何前端或者后端开发的知识。

预期目标及功能

  • 通过访问 ESP32 的 IP 地址查看网页;

  • 设置自定义域名访问;

  • 服务后台管理功能;

  • 可视化网页修改;

  • 数据库数据处理;

  • SD 卡配置文件加载。

所用硬件

  • M5 Core2

c5637b636bc478edfea156803b264194.png

M5 Core2 特点

  • 基于 ESP32 开发,支持 WiFi、蓝牙;

  • 16M 闪存,8M PSRAM;

  • 内置扬声器,电源指示灯,震动马达,RTC,I2S 功放,电容式触摸屏,电源键,复位键;

  • TF 卡插槽(支持最大 16GB);

  • 内置锂电池,配备电源管理芯片;

  • 独立小板内置 6 轴 IMU,PDM 麦克风;

  • M-Bus 总线插座。

程序设计

下面开始详细讲解程序设计过程。

开发环境

我们使用 Arduino IDE 软件来编写本项目的程序,开发板选择 M5Stack-Core2。至于如何在 Arduino 中配置 ESP32 的开发环境,不在本文的介绍范围,请自行查阅相关资料。

程序思路

为了达到我们的预期目标,我们先绘制功能的思维导图,再根据思维导图逐步实现 M5 Server X 的程序设计。

90b6ee7b764f8a6d753a22f403709ed1.png

下面我们来具体讨论 M5 Server X 各个子功能是如何实现的。

如何显示网页

我们想要访问一个网页必须要知道网络的路径,那么 M5 Server X 如何获取我们访问的路径参数,以及发送对应的网页呈现给我们呢,下面是一个简单的例子,我们上传该程序 。

#include <WiFi.h>
#include <WebServer.h> //引入相应库

const char *ssid = "********";
const char *password = "********";

WebServer server(80); //声明WebServer对象

void handleArg1() //回调函数
{
  String arg = server.pathArg(0);
  server.send(200, "text/plain", "This is the link/{},The parameters are:" + arg);
}

void handleArg2() //回调函数
{
  String arg0 = server.pathArg(0);
  String arg1 = server.pathArg(1);
  server.send(200, "text/plain", "This is the link/{}/{},The parameters are:" + arg0 + " & " + arg1);
}

void setup() {
  Serial.begin(115200);
  Serial.println();

  WiFi.mode(WIFI_STA);
  WiFi.setSleep(false);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected");
  Serial.print("IP Address:");
  Serial.println(WiFi.localIP());

  server.on("/{}", handleArg1);        //注册链接与回调函数
  server.on("/{}/{}", handleArg2); //注册链接与回调函数

  server.begin(); //启动服务器
  Serial.println("Web server started");
}

void loop() {
  server.handleClient(); //处理来自客户端的请求
}

上传完程序,打开串口监视器。如下图所示,我们观察到路由器给 M5 Core2 分配的 IP 地址是 192.168.1.28,记住该地址。

fdb79c079972ac92cdc5269a022ac345.png

我们通过浏览器访问:192.168.1.28/arduino/png,发现浏览器返回数据如下:

84eecb09d62b7495d2721797abb936a6.png

‍‍‍‍‍‍在这里我们有两个路径参数,分别是 arduino 与 png,你也可以试一下只有一个路径参数的情况 。在这个例子当中,我们路径参数以文本的形式给我们呈现,那么如何访问某一个特定的路径发送一个HTML文件呢,在这里只需要判断的路径参数是否是我们定义的路径就行了,例子如下: ‍ ‍ ‍ ‍ ‍ ‍
const char HTML1[] PROGMEM = R"rawliteral(
//HTML源代码
)rawliteral";

const char HTML2[] PROGMEM = R"rawliteral(
//HTML源代码
)rawliteral";

const char HTML3[] PROGMEM = R"rawliteral(
//HTML源代码
)rawliteral";

void handleArg1() //回调函数
{
  String arg = server.pathArg(0); 
  if (String(arg).equals(String(""))) {
    // 访问路径为空(根目录)
    server.send(200, "text/html", HTML1);
  } else if (String(arg).equals(String("m5"))) {
    // 自定义路径"m5"
    server.send(200, "text/html", HTML2);
  } else {
    // 无效路径(未定义)
    server.send(200, "text/html", HTML3);
  }
}

在这个例子中,我们考虑了3种路径情况,分别是访问路径为空(根目录),自定义路径(m5)与无效路径(未定义)。当我们访问对应的路径时,M5 Server X 能够给浏览器返回的不同的 html 文本,浏览器将自动渲染该页面。

我们将网页内容定义在 HTML 字符串中。如何设计网页内容呢?我们可以在浏览器中访问一个喜欢的网页,然后点击鼠标右键选择“查看页面源代码”就能看到该网页的源代码,将页面源代码复制并替换到程序中注释的地方,同时将原 HTML 文件的资源引用的相对路径改为绝对路径,这样我们便能够得到由 M5 Server X 托管的网页。对于二级路径的情况也和一级路径类似,我们通过不同的层级路径就可以使用一个 M5 Core2 托管许多不同类型的网页。

这里推荐几个实用的网页模板网站:

  • 17 素材网(https://www.17sucai.com/)

  • highcharts 图表网(https://www.highcharts.com.cn/)

其中 17 素材网拥有大量的 html 网页特效、网站模板、素材等。提供在线预览功能,我们可以很方便的找到心仪的网页模板;highcharts 图表网拥有丰富的交互式图表,例如带交互特效的折线图、面积图、柱形图、散点图等,能够让我们以动态的方式直观地观察数据变换情况,是数据分析的不二选择。

如何可视化修改网页

通过查看网页源代码的方式,我们已经获取到了网页的模板,但是我们并没有 Web 开发的任何基础,似乎无从下手呀?有没有一种可视化、所见即所得的方式让我们修改网页呢?答案是肯定的,这里我介绍3个可视化网页修改的编辑器。

  • 菜鸟教程在线 HTML 编辑器(https://www.runoob.com/try/try.php?filename=tryhtml_headers)

  • W3School 网页编辑器(https://www.w3school.com.cn/tiy/t.asp?f=eg_html_basic)

  • HTML 编辑器(https://www.redcoolmedia.net/onlineeditor/samples/plugins/wysiwygarea/htmleditor.php?filenamex=/tmp/FZRNWIKZ)

其中菜鸟教程在线 HTML 编辑器与 W3School 网页编辑器均可以实时修改网页源代码并预览其各种网页特效,HTML 编辑器能够像 Word 一样编辑 HTML,十分便利,唯一的缺点就是不能渲染动态的 js 特效,适合静态网页的可视化修改。下面以 W3School 网页编辑器为例,简述如何获得网页模板并进行可视化编辑。

322d2d14201a5f3c24496ecb5c8ad296.png

9cc1efb2b43c4d9a6bee17f085eb81d4.png

  1. 通过 17 素材网查询关键词寻找合适的网页素材(例如我们需要一个登陆页面);

  2. 选择需要的网页素材;

  3. 点击查看预览效果;

  4. 右键单击,选择查看网页源代码并全选复制(所有网页均可使用此方法);

  5. 粘贴网页源代码到 W3School 网页编辑器,点击运行代码(网页未正确渲染);

  6. 将网页引用样式资源由相对路径修改为绝对路径(修改后网页成功渲染);

  7. 观察网页显示文字,在网页源代码中查找并替换对应的字符串,修改完成后重新运行代码;

  8. 增加调试代码,使用网页弹窗调试页面(目的是获取表单构造URL)。

M5 Server X 使用的要点是网页样式文件 CSS,JS 和多媒体等文件均放在云端,通过绝对路径的方式进行引用,这样做的目的是 M5 Server X 只需要少量的带宽也能流畅的使用。如何获取输入表单字符串网上有很多教程,这里不再赘述,这里介绍几个实用的网页调试函数:

  • window.location.href(获取当前URL路径)

  • window.location(跳转到指定URL)

  • alert()(网页弹窗)

获取数据库数据

现在我们能够可视化的修改任意网页,如果我们要获取的是一个动态网页呢?例如学生成绩单中,表格的模板是固定的,而变化的仅是姓名分数等信息。对于这种通用模板,变化的数据我们可以通过占位符来表示该数据,例如下图中的 data 占位符:

4b5af9971d103a3e12bd05f40e6b64c4.png

表中的 data0 ~ data9 都是数据变量 ,我们可以采取键值对的形式,将数据保存到云端或者本地的数据库当中。这里我们采取学号作为标签来保存这些数据,例如000 000,张三,男,六一班,90,80,90,90,90,100其中000作为标签,而000,张三,男,六一班,90,80,90,90,90,100作为值 data0 ~ data9,分别代表了标签值中的具体数据,将上面的表格进行文本替换后得到下面的表格:

1b35d960954b35abe30924afa9072f00.png

这里推荐一个支持批量数据提交的网络数据库 tinywebdb(http://tinywebdb.appinventor.space/)。至于它是什么,这里不赘述,大家可以百度搜索,这里仅介绍如何获取该数据库的标签值。我们注册 tinywebdb 账号并登录后可以看到它提供的 API 接口文档如下:

64c621986a61df288c263e6c14724781.png

我们先通过它的数据导入功能导入一条数据:

823aba358f92b0de648cc05430f49fb4.png

通过数据浏览功能查看刚导入的数据:

6b3456bf4f6c6fd12d5990ad1a5b5342.png

我们根据 tinywebdb 的 API 文档编写一个程序获取数据库的数据:

#include <WiFi.h>
#include <HTTPClient.h>

const char *ssid = "********";
const char *password = "********";

String User = "share"; //数据库用户账号名
String Secret = "everyone"; //数据库用户密钥
String tag = "000"; //标签

void setup() {
 Serial.begin(115200);
 Serial.println();

 WiFi.mode(WIFI_STA);
 WiFi.setSleep(false);
 WiFi.begin(ssid, password);
   
 while (WiFi.status() != WL_CONNECTED) {
   delay(500);
   Serial.print(".");
 }
 Serial.println("Connected");
 Serial.print("IP Address:");
 Serial.println(WiFi.localIP());
   
 if (WiFi.status() == WL_CONNECTED) {
   HTTPClient http;
   http.begin(String("http://tinywebdb.appinventor.space/api?user=" + User + "&secret=" + Secret + "&action=get&tag=") + String(tag));
   int httpCode = http.GET();
   if (httpCode > 0) {
     String Request_result = http.getString();
     Serial.println(Request_result);
   } else {
     Serial.println("Invalid response!");
   }
   http.end();
 }
}

void loop() {
}

打开串口监视器,返回数据如下,当访问有效标签时,返回我们保存的正确数据,当访问未定义的标签时返回 null,我们能都通过判断该值知道我们是否输入正确网页地址,从而返回不同的网页。

199fc119c6e78ddd363e0b84f3e87ba9.png

数据解析

通过 API 返回数据后,我们需要解析该 JSON 字符串。解析程序如下,这里我们需要引用ArduinoJson.h这个 JSON 字符串解析库。

StaticJsonDocument<64> doc;
  DeserializationError error = deserializeJson(doc, Request_result);
  if (error) {
    Serial.print("deserializeJson() failed: ");
    Serial.println(error.c_str());
    return;
  }
  const char* root_000 = doc["000"]; // "000,张三,男,六一班,90,80,90,90,90,100"

得到解析的数据后,再将该数据构造为 json 数组,对构造后的数据进行二次解析便能获取数组的每一项,将数组的每一项数据替换占位符 data 便能得到呈现的有效 html 文件,具体代码见附录程序。

域名解析

我们可以通过串口监视器获取设备的 IP 地址进行访问,但是路由器的分配的 IP 地址是变化的,这点很不方便,那么我们能不能给它设置一个好记的域名,让我们局域网内访问该设备呢?这里可以使用 ESPmDNS 域名解析达到该目的。代码如下:

#include <ESPmDNS.h>

void setup() {
  Serial.begin(115200);
  if (!MDNS.begin("M5Core2")) {//自定义域名
    Serial.println("Error setting up MDNS responder!");
  }
  MDNS.addService("http", "tcp", 80); //启用DNS服务
}

void loop() {
}

通过域名解析,我们只要和设备在同一局域网内,访问 http://m5core2 就能访问 M5 Server X 获取相应的网页服务了。

读取 SD 卡文件

通过前面的讲解,我们已经能够实现访问一个链接并跳转到某一个网页了。那么问题来了,如何快速修改网页呢?因为 M5core2 可以使用 SD 卡,所以我们可以这样做:将网页和账号信息保存到 SD 当中,需要更改网页或者连接网络等信息时,直接修改SD卡中的文件,设备初始化的时候读取 SD 卡,那么就完成了网页的修改,这比我们直接修改程序要简单便捷多了。读取 SD 卡文件的程序如下:

#include "FS.h"
#include <SD.h>
#include <SD_MMC.h>

SPIClass sdSPI(VSPI); //定义SD卡软SPI管脚
#define SD_MISO     38
#define SD_MOSI     23
#define SD_SCLK     18
#define SD_CS       4

String readFile(fs::FS &fs, const char * path) { //读取SD卡指定路径文件
  File file = fs.open(path);
  if (!file) {
    Serial.println("Failed to open file for reading");
  }
  String data = "";
  while (file.available()) {
    data = String(data) + String(char(file.read()));
  }
  file.close();
  return data;
}

void setup() {
  Serial.begin(115200);
  sdSPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS); //初始化SD卡SPI
  if (!SD.begin(SD_CS, sdSPI)) {
    Serial.println("Card Mount Failed");
    return;
  }
  Serial.println(readFile(SD, "/admin.txt"));
}

void loop() {
}

在程序中我们可以直接输入 TXT 或者 HTML 文件的路径,便可读取该文件中的内容。这里我们读取了 SD 卡根目录下的 admin.txt 文件,该文件作为配置文件用来保存网络信息、数据库信息与服务信息,该文件内容如下,不存在的服务用 null 表示:

{
  "ssid": "ChinaNet-5678",//连接WiFi名称
  "password": "1234567890",//连接WiFi密码
  "user": "peien",//数据库账号名
  "secret": "52e2c018",//数据库密钥
  "admin": "12345678",//管理密码
  "server1": "score",//服务1
  "server2": "arduino",//服务2
  "server3": "Login",//服务3
  "server4": "Light"//服务4
}

M5 Server X 网页逻辑

M5 Server X 服务框架如下:

8a025166527927fb9e34b52677dc651d.png

M5 Server X 通过域名或 IP 加服务名访问不同服务主页,例如 http://m5core2/score/000,其中 m5core2 为域名或者 IP,score 为服务名,000 为查询参数,数据库通过键值对存储数据,为了确保数据标签的唯一性,我们采取服务加参数的形式代表某个具体数据。如成绩查询服务当中,000 为实际的学号,那我们就将数据标签设置为 score_000,使用下划线增加标签的可读性,如果我们需要登录账号和密码那就将账号和密码构造为一个标签。例如演示视频案例四当中,我们就将账号和密码作为服务参数进行传递输入,当输入账号 peien、密码 123 时,数据标签被构造为 Login_peien_123。

服务响应逻辑

M5 Server X 服务响应的逻辑如下,访问根目录返回 Home_page.html 页面,该页面我们默认为代码雨,实际你可以设置为所有服务的导航页面,通过标签或者按钮跳转到子服务页面。Log_in.html 为某个子服务的服务主页,当服务开启时有两种情况,当提交参数正确时,通过 replace 函数查找占位符并替换数据,返回 success.html 页面,当提交参数错误时,返回 mistake.html(404)页面,当我们禁用某项服务时,无论提交参数是否正确,都会返回 Not_open.html(服务未开放或者无此服务)页面。

d68a9086b364e06ef54cd460887874d0.png

配置文件结构

配置文件下有七个文件,其中 admin.txt、Home_page.html、Not_open.html 为公共文件,不同子服务用不同文件夹(英文文件夹名)区分。每个子服务文件夹下均有 Log_in.html、success.html、mistake.html 三个 HTML 文件。示意图如下,其中子服务文件夹非必需,是否启用该服务由 admin.txt 配置决定。对于没有的服务用 null 表示,当服务名为 null 时设备初始化将跳过该服务不加载该服务文件  。

644923e497c99b4ba32b1d14b885a474.png

后台控制面板

M5 Server X 的后台功能主要有登录、服务器管理与设备信息查询,其中如何绘制控制页面与触摸屏的使用在往期《DIY掌上POS机,或许是最小的收银POS机了!》这篇教程中有详细的描述,这里就不再赘述。

试玩

以上就是 M5 Server X 的项目介绍,如果你不想下载 IDE 只想体验该项目,那么你可以访问 https://docs.m5stack.com/zh_CN/download 根据你自己的系统下载 M5Burner 烧录工具进行安装,打开软件按照下面的步骤进行烧录体验,其中 SD 卡网页模板与配置文件请通过本教程附件进行下载,直接解压到的 SD 卡修改网络信息即可体验。

d59274fbf3392b34a0c1b3e5fde7aaa0.png

使用说明

  1. 烧录固件;

  2. 将附件提供的模板解压到 SD 卡;

  3. 打开 admin.txt 文件修改网络信息;

  4. SD 卡插入 M5Core2 并重启设备;

  5. 等待 M5Core2 初始化并进入控制主页;

  6. 按演示视频控制设备与查看服务器管理与账号信息显示页面;

  7. 访问 http://m5core2/ 进入代码雨主页;

  8. 访问 http://m5core2/score 查看学生成绩(学号为000);

  9. 访问 http://m5core2/arduino 通过关键词m5core2进行搜索;

  10. 访问 http://m5core2/Login 查看学生成绩(用户名peien密码123);

  11. 访问 http://m5core2/Light 控制灯泡(开关分别代表了两个URL,自行修改为自己的接口);

  12. 分别输入正确信息与错误信息,启用服务与禁用服务,体验 M5 Server X。

总结

有了上面的理论基础,我们便能完成 M5 Server X 的项目制作了,其中具体实现细节由于篇幅限制,这里就不再讨论,大家可以下载程序源代码进行查看,其中必要的程序说明已经注释,对此项目有任何建议或者疑问均可评论区留言。

使用 M5 Server X 你能够轻松打造自己的个人网站,当然你也可以使用普通 ESP32 完成此项目,但可能相对麻烦些,但这样一个 10 多块钱的个人服务器还有什么可嫌弃的呢。如果你想给别人分享你的网页服务,可以使用内网穿透服务,这个大家就自行百度了,在上面的思维导图当中我们提供了本项目用到的网页素材网、可视化编辑平台、自建数据库等链接,大家可以下载附件进行查阅学习。

我是,我们下期见。

代码下载

关注本公众号“铁熊玩创客”,回复“ M5 Server X ”获取完整代码。



欢迎转发朋友圈。如需转载,请注明出处和原作者。

点个在看支持一下吧 ↓↓↓

Logo

华为云1024程序员节送福利,参与活动赢单人4000元礼包,更有热门技术干货免费学习

更多推荐