当前位置:   article > 正文

基于ESP32搭建物联网服务器十(用LittleFS保存设置和从LittleFS读取设置[下])_esp32 web

esp32 web

前文中已经详细地介绍了用LittleFS保存设置和从LittleFS读取设置所用到的函数和方法:

https://blog.csdn.net/m0_50114967/article/details/126976629

因为这个WEB服务器功能越来越多,所有代码都在同一个文件,可读性也会变得越来越差,这里先介绍一下arduino IDE的多文件管理功能。

arduino IDE保留了和C语言一样的引入.h头文件的功能,但也有自已独特的多文件管理功能。

引入头文件的方法

我们先新建一个用于测试的.h头文件,test.h

 文件的内容为

  1. void hardware_begin(){
  2. Serial.begin(9600);
  3. }

里面包含一个hardware_begin函数,下面在主文件中引用

  1. #include "test.h"
  2. void setup() {
  3. // put your setup code here, to run once:
  4. hardware_begin();
  5. Serial.print("abcd");
  6. }
  7. void loop() {
  8. // put your main code here, to run repeatedly:
  9. }

无需引入头文件的方法

这是arduino IDE特有的多文件管理,用相同的方法,新建一个文件,无需输入扩展名或输入.ino扩展名。

 

内容和之前的test.h文件一样:

  1. void hardware_begin(){
  2. Serial.begin(9600);
  3. }

 在引用时,无需引入该头件就可以直接调用test.ino文件里的函数

  1. //#include "test.h" 无需引入头文件
  2. void setup() {
  3. // put your setup code here, to run once:
  4. hardware_begin();
  5. Serial.print("abcd");
  6. }
  7. void loop() {
  8. // put your main code here, to run repeatedly:
  9. }

其原理就是在编译时会把项目文夹下的所有ino文件合并编译,基本上不用担心文件名。

在测试中,把setup和loop分开放在不同的文件中也是可以的。对比引入头文件,显然后面的方法比较方便。

现在我们可以把之前所实现的功能做一些分类整理,把各种类型的函数分别放到不同的文件中。

第一个文件用来保存配网所需要的函数:

  1. /*WIFI连接*/
  2. #include <WiFi.h>
  3. #include <DNSServer.h>
  4. DNSServer dnsserver;
  5. /***********************************************************************************
  6. * 函数:连接WIFI
  7. * ssid: WIFI名称
  8. * password: WIFI密码
  9. * return: 连接成功返回true
  10. ***********************************************************************************/
  11. void connect_WIFI(String ssid, String password){
  12. WiFi.begin(ssid.c_str(), password.c_str()); //连接WIFI
  13. Serial.print("连接WIFI");
  14. //循环,10秒后连接不上跳出循环
  15. int i = 0;
  16. while(WiFi.status() != WL_CONNECTED){
  17. Serial.print(".");
  18. delay(500);
  19. i++;
  20. if(i>20){
  21. Serial.println();
  22. Serial.println("WIFI连接失败");
  23. return;
  24. }
  25. }
  26. Serial.println();
  27. IPAddress local_IP = WiFi.localIP();
  28. Serial.print("WIFI连接成功,本地IP地址:"); //连接成功提示
  29. Serial.println(local_IP);
  30. }
  31. /***********************************************************************************
  32. * 设置AP和STA共存模式,设置DNS服务器
  33. ***********************************************************************************/
  34. void connect_NET(){
  35. const byte DNS_PORT = 53; //DNS端口
  36. const String url = "ESPAP.com"; //域名
  37. IPAddress APIp(10,0,10,1); //AP IP
  38. IPAddress APGateway(10,0,10,1); //AP网关
  39. IPAddress APSubnetMask(255,255,255,0); //AP子网掩码
  40. const char* APSsid = "esp32_AP"; //AP SSID
  41. const char* APPassword = "12345678"; //AP wifi密码
  42. wifi_connect(); //连接WIFI
  43. WiFi.mode(WIFI_AP_STA); //打开AP和STA共存模式
  44. WiFi.softAPConfig(APIp, APGateway, APSubnetMask); //设置AP的IP地址,网关和子网掩码
  45. WiFi.softAP(APSsid, APPassword, 6); //设置AP模式的登陆名和密码
  46. dnsserver.start(DNS_PORT, url, APIp); //设置DNS的端口、网址、和IP
  47. Serial.print("AP模式IP地址为:");
  48. Serial.println(WiFi.softAPIP());
  49. }
  50. /***********************************************************************************
  51. * DNS处理请求的循环
  52. ***********************************************************************************/
  53. void DNS_request_loop(){
  54. dnsserver.processNextRequest();
  55. }

第二个文件用来保存WEB所需要的函数,包含了读写文件函数,JSON格式解析或创建函数

  1. #include "ESPAsyncWebServer.h"
  2. #include <ArduinoJson.h>
  3. #include <LittleFS.h>
  4. //AsyncWebServer server(80); //创建一个服务器对象,WEB服务器端口:80
  5. /**************************************************************************************
  6. * 函数:字符串写入文件,文件如果存在,将被清零并新建,文件不存在,将新建该文件
  7. * path: 文件的绝对路径
  8. * str: 要写入的字符串
  9. *************************************************************************************/
  10. void str_write(String path, String str){
  11. Serial.println("写入文件");
  12. File wf = LittleFS.open(path,"w"); //以写入模式打开文件
  13. if(!wf){ //如果无法打开文件
  14. Serial.println("打开文件写入时错误"); //显示错误信息
  15. return; //无法打开文件直接返回
  16. }
  17. wf.print(str); //字符串写入文件
  18. wf.close(); //关闭文件
  19. File rf = LittleFS.open(path,"r"); //以读取模式打开文件
  20. Serial.print("FILE:");Serial.println(rf.readString()); //读取文件
  21. rf.close(); //关闭文件
  22. }
  23. /**********************************************************************************
  24. * 函数:响应网站/setwifi目录的POST请求,收到请求后,运行get_WIFI_set_CALLback回调函数
  25. * 获取并格式化收到的POST数据
  26. *********************************************************************************/
  27. void get_WIFI_set_CALLback(AsyncWebServerRequest *request){
  28. Serial.println("收到设置WIFI按钮");
  29. if(request->hasParam("wifiname",true)){
  30. AsyncWebParameter* wifiname = request->getParam("wifiname",true); //获取POST数据
  31. AsyncWebParameter* wifipassword = request->getParam("wifipassword",true); //获取POST数据
  32. String wn = wifiname->name().c_str();
  33. String wnv = wifiname->value().c_str();
  34. String wp = wifipassword->name().c_str();
  35. String wpv = wifipassword->value().c_str();
  36. //把SSID和password写成一个JSON格式
  37. StaticJsonDocument<200> wifi_json; //创建一个JSON对象,wifi_json
  38. wifi_json[wn] = wnv; //写入一个建和值
  39. wifi_json[wp] = wpv; //写入一个键和值
  40. String wifi_json_str; //定义一个字符串变量
  41. serializeJson(wifi_json, wifi_json_str); //生成JOSN的字符串
  42. str_write("/WIFIConfig.conf",wifi_json_str); //字符串写入
  43. }
  44. }
  45. /**********************************************************************************
  46. * 函数:从文件path中读取字符串
  47. * path: 文件的绝对路径
  48. * return: 返回读取的字符串
  49. *********************************************************************************/
  50. String str_read(String path){
  51. Serial.println("读取文件");
  52. File rf = LittleFS.open(path,"r"); //以读取模式打开文件
  53. if(!rf){ //如果无法打开文件
  54. Serial.println("打开文件读取时错误"); //显示错误信息
  55. return ""; //无法打开文件直接返回
  56. }
  57. String str = rf.readString(); //读取字符串
  58. rf.close(); //关闭文件
  59. return str;
  60. }
  61. /***************************************************************************************
  62. * 函数:解析JSON字符串,从JSON字符串名称得到该值
  63. * str: JSON字符串
  64. * Name: JSON集合的名称
  65. * return: 返回值的字符串
  66. ***************************************************************************************/
  67. String analysis_json(String str, String Name){
  68. DynamicJsonDocument doc(str.length()*2); //定义一个JSON对象
  69. deserializeJson(doc, str); //反序列数据
  70. String value = doc[Name].as<String>(); //从Name中读取对应的值
  71. return value;
  72. }
  73. /***********************************************************************************
  74. * 函数:/WIFIConfig.conf文件中读取设置数据并连接WIFI
  75. ***********************************************************************************/
  76. void wifi_connect(){
  77. Serial.println("在conf文件中读取数据并连接WIFI");
  78. String str = str_read("/WIFIConfig.conf"); //读取文件内容
  79. String wifiname = analysis_json(str, "wifiname"); //解析WIFI名称
  80. String wifipassword = analysis_json(str, "wifipassword"); //解析WIFI密码
  81. connect_WIFI(wifiname, wifipassword); //连接WIFI
  82. }
  83. /***********************************************************************************
  84. * web服务器初始化
  85. ***********************************************************************************/
  86. void web_server(){
  87. Serial.println("初始化WEB服务器");
  88. server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); //响应网站根目录的GET请求,返回文件index.html
  89. server.on("/setwifi" ,HTTP_POST , get_WIFI_set_CALLback); //响应设置WIFI按钮的请求
  90. server.begin(); //初始化
  91. }
  92. /********************************************************************************
  93. * LittleFS文件系统初始化
  94. *********************************************************************************/
  95. void LittleFS_begin(){
  96. Serial.println();
  97. Serial.println("初始化文件系统");
  98. if(!LittleFS.begin(true)){
  99. Serial.println("An Error has occurred while mounting LittleFS");
  100. return;
  101. }
  102. }

第三个文件就是主文件,包括了ESPAsyncWebServer库的全局服务器变量和setup和loop两个接口

  1. #include "ESPAsyncWebServer.h"
  2. AsyncWebServer server(80); //创建一个服务器对象,WEB服务器端口:80
  3. void setup() {
  4. Serial.begin(9600); //串口波特率初始化
  5. LittleFS_begin(); //LittleFS文件系统初始化
  6. connect_NET(); //网络初始化
  7. web_server(); //WEB服务器初始化
  8. }
  9. void loop() {
  10. DNS_request_loop(); //DNS服务请求处理
  11. }

最后是网页的html代码:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <link rel="stylesheet" type="text/css" href="mystyle.css">
  6. <title>EPS32教程</title>
  7. </head>
  8. <body>
  9. <div id="pal">
  10. <form name="wifiset" onsubmit="return validateForm()" action="\setwifi" method="post" target="myframe">
  11. <label for="wifiname">WIFI SSID</label>
  12. <input name="wifiname" type="text" value="ESP32">
  13. <label for="wifipassward">WIFI PASSWARD</label>
  14. <input name="wifipassword" type="text" value="ESP32">
  15. <input type='submit' value='设置WIFI'>
  16. </form>
  17. <iframe src="" width="200" height="200" frameborder="0" name="myframe" style="display:NONE" ></iframe>
  18. </div>
  19. </body>
  20. <script>
  21. /******************************
  22. 表单验证,WIFI名称输入框为空时提示
  23. ******************************/
  24. function validateForm(){
  25. var wifiname=document.forms["wifiset"]["wifiname"].value; //得到name输入框的文字
  26. if (wifiname==null || wifiname==""){ //如果输入框为空
  27. alert("WIFI SSID必需输入"); //显示提示
  28. return false;
  29. }
  30. }
  31. </script>
  32. </html>

运行流程:

        1、初始化LittleFS文件系统

        2、连接WIFI,如果超时将跳过

        3、设置AP模式和STA模式(如果WIFI已连接)

        4、初始化服务器

        5、如果未能连接WIFI,只能用手机或电脑通过AP模式WIFI直接连接ESP32

                可以通过IP地址:10.0.10.1或域名espap.com用浏览器进入ESP32的WEB页面

                设置WIFI名称和WIFI密码,点击设置,如果设置正确,下次启动就可以直接连接WIFI了

至此,一个可以通过WEB页面配置WIFI的WEB服务器就完成了,在下一章中,将会介绍ESP32的远程互动,介绍通过WEB页面控制ESP32和通过MQTT协议控制ESP32。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/351591
推荐阅读
相关标签
  

闽ICP备14008679号