在ESP32上实现WEB交互界面

本文主要介绍在未联网(AP热点)情况下实现WEB交互界面的CSS和javascript库。
在ESP32上,有时需要借助WebServer以及网页对外提供交互界面,如WiFi配置,GPIO显示和操作等,如何实现好看和易操作的界面就需要CSS和javascript了,如果是联网的情况可以直接访问外部资源,本文主要介绍在未联网(AP热点)情况下实现WEB交互界面的CSS和javascript库。

mini.css

mini.css是一个极简、响应式的CSS框架,许多组件和功能在资源受限的环境内可以达到与bootstrap类似的效果。
网格系统
mini.css 的网格系统利用 Flexbox 布局为您的 Web 应用程序提供简单、现代、响应式的布局系统。与大多数现代 CSS 框架的网格系统一样,它由三个主要组件组成——容器、行和列。

每个列类都是通过指定屏幕大小(小 - sm、中 - md 或大 - lg)和列宽(值介于 1 到 12 之间的值,或者对于流体列可以省略它),用破折号分隔(例如,.col-sm-6 表示小屏幕上的 6 宽列)。使用这些,您可以通过使用多个类更改列的宽度来为不同的屏幕尺寸应用不同的布局。

【小屏幕】

在ESP32上实现WEB交互界面

【中、大屏幕】

在ESP32上实现WEB交互界面

卡片

mini.css 提供了卡片 (.card),这是帮助你组织 Web 应用内容的常规用途容器。卡片应与网格系统结合使用,这意味着它们需要放置在网格的行内才能正常工作。使用卡片创建的布局是响应式的,会根据屏幕上的可用大小重新对齐。

在ESP32上实现WEB交互界面

表单和输入

表单、标签和常见的 HTML5 输入元素已使用干净、现代的规则进行样式设置,从而提高了 Web 应用程序表单的可访问性和可用性。

在ESP32上实现WEB交互界面

更多特性请访问:https://minicss.us/

Zepto.js

Zepto.js 是一个轻量级的 JavaScript 库,专为移动端网页设计。它提供了类似于 jQuery 的 API,但体积更小,性能更高,特别适合在移动设备上运行。
优势:
1.轻量级:Zepto.js 的压缩版只有几KB大小,非常适合移动端应用。
2.兼容性:它支持大多数现代移动浏览器,包括 iOS 和 Android 设备。

3.丰富的API:提供了丰富的 DOM 操作、事件处理、动画效果等功能。

示例代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Zepto.js 示例</title>
    <script src="https://cdn.jsdelivr.net/npm/zepto@1.2.0/dist/zepto.min.js"></script>
</head>
<body>
    <button id="myButton">点击我</button>

    <script>
        $(document).ready(function() {
            $('#myButton').on('click', function() {
                alert('按钮被点击了!');
            });
        });
    </script>
</body>
</html>

更多特性请访问:https://zeptojs.com/

实例

本实例是一个配置WiFi的例子

初始化程序先检查preferences里有无wifi配置,若没有,则开启AP热点,启动配置服务,等待配置,用手机连接热点并访问配置,设置ssid和密码,若成功连接则保存信息到preferences内。

/***************************************************
 **  ESP32 开启热点配置WIFI信息
 * 
 **  author: 老张
 **  homesite: www.xpstem.com
 ****************************************************/
#include <Arduino.h>
#include <WiFi.h>         
#include <WebServer.h>    
#include <Preferences.h> 

//************** 常数数据 开始 **********************
// AP模式下信息
const IPAddress wifi_ap_ip(192,168,5,1);
const IPAddress wifi_ap_gateway(192,168,6,0);
const IPAddress wifi_ap_subnet(255,255,255,0);
String wifi_ap_ssid = "ssid-";
const char *wifi_ap_password = "abcd1234";

// mini.css v3.0.1(替代bootstrap) https://minicss.us/
const char *minicss = "代码过多,此处省略...";

// Zepto v1.2.0(替代jQuery)https://zeptojs.com/
const char *zeptojs = "代码过多,此处省略...";
//*************** 常数数据 结束 **********************

//************* 配置变量 开始 ************************
// WiFi Credentials
String ssid;                            // wifi账号
String password;                        // wifi秘密
//************* 配置变量 结束 *********************

//************* 运行时变量 开始 ********************
WebServer webServer(80);
Preferences prefs;
String chipId;
//************* 运行时变量 结束 *********************

const char *configHtml = "<html>\
  <head>\
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>\
    <meta name='viewport' content='width=device-width, initial-scale=1'>\
    <link rel='stylesheet' href='/mini.css'>\
    <script src='/zepto.js'></script>\
    <script src='/layer.js'></script>\
    <title>xxx配置</title>\
  </head>\
  <body>\
    <h2>xxx配置</h2>\
    <p></p>\
    <form action='' method='post'>\
    <fieldset>\
      <legend>WiFi配置</legend>\
      <div class='row responsive-label'>\
        <div class='col-sm-12 col-md-3'><label for='ssid'>WiFi名称:</label></div>\
        <div class='col-sm-12 col-md'><input type='text' style='width:90%' name='ssid'></div>\
      </div>\
      <div class='row responsive-label'>\
        <div class='col-sm-12 col-md-3'><label for='password'>WiFi密码:</label></div>\
        <div class='col-sm-12 col-md'><input type='text' style='width:90%' name='password'></div>\
      </div>\
    </fieldset>\
    <p>&nbsp;</p>\
      <input type='button' id='submit' class='primary' value=' 提交 '>\
    </form>\
    <script type='text/javascript'>\
      $(document).ready(function() { \
        $('#submit').on('click', function() { \
          $.ajax({ \
            url: 'config', \
            type: 'post', \
            data: $('#form').serialize(), \
            success: function(resp) { \
              alert(resp.msg); \
            },\
            error: function(xhr, status, error) { \
              console.error('Error', error); \
            } \
          });\
        });\
      }); \
    </script>\
    </body>\
</html>";

/***********************************************************
 ***  检查是否保存了配置
 **********************************************************/ 
boolean comm_haveConfig() {
  prefs.begin("config", true);
  bool exist = prefs.isKey("ssid");
  prefs.end();
  return exist;
}

/***********************************************************
 ***  保存配置
 **********************************************************/ 
void conf_saveConfig() {
  prefs.begin("config", false);
  prefs.clear();

  prefs.putString("ssid", ssid);
  prefs.putString("password", password);
  
  prefs.end();
  
  Serial.println("配置已保存。");
}

/***********************************************************
 ***  配置页提交处理
 ***  1.连接WiFI
 ***  2.硬件信息设定
 **********************************************************/ 
void conf_handleConfig() {
  if (webServer.method() != HTTP_POST) {
    conf_handleNotFound();
    return;
  }
  
  String staSsid = webServer.arg("ssid");
  String staPassword = webServer.arg("password");

  if (staSsid=="" || staPassword=="") {
    // 未连接上。
    webServer.send(200, "application/json", "{\"code\":-1,\"msg\":\"内容不能为空!\"}");
    return;
  }

  // if ok
  Serial.printf("connect wifi %s testing.", ssid.c_str());
  WiFi.begin(staSsid, staPassword);
  int n = 0;
  // 最多等待60s
  while (++n < 600) {
      delay(100);
      if (n % 30 == 0) { Serial.print("."); }
      if (WiFi.status() == WL_CONNECTED) {
        break; //已连接,中止等待
      }
  }
  Serial.println("");
  
  if (WiFi.status() != WL_CONNECTED) {
    // 未连接上。
    webServer.send(200, "application/json", "{\"code\":-2,\"msg\":\"无法连接WiFi,请检查配置!\"}");
    return;
  }
  
  ssid = staSsid;
  password = staPassword;
    
  conf_saveConfig();

  // 配置成功
  webServer.send(200, "application/json", "{\"code\":0,\"msg\":\"产品配置成功,设备重启中...\"}");

  delay(3000);
  Serial.println("restarting...");
  ESP.restart();
}

/***********************************************************
 ***  404处理
 **********************************************************/ 
void conf_handleNotFound() {
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += webServer.uri();
  message += "\nMethod: ";
  message += (webServer.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += webServer.args();
  message += "\n";

  for (uint8_t i = 0; i < webServer.args(); i++) {
    message += " " + webServer.argName(i) + ": " + webServer.arg(i) + "\n";
  }

  webServer.send(404, "text/plain", message);
}

/********************************************************
 ***  启动配置服务
 ********************************************************/
void conf_startConfigServer() {

    wifi_ap_ssid = "ssid-" + chipId.substring(0, 3);
    WiFi.softAPConfig(wifi_ap_ip, wifi_ap_gateway, wifi_ap_subnet);
    if (!WiFi.softAP(wifi_ap_ssid.c_str(), wifi_ap_password)) {
      Serial.println("Soft AP creation failed.");
      while(1);
    }
    Serial.printf("Wifi AP %s on 192.168.6.1\n", wifi_ap_ssid.c_str());
    
    webServer.on("/", [](){ webServer.send(200, "text/html", configHtml); });
    webServer.on("/mini.css", [](){ webServer.send(200, "text/css", minicss); });
    webServer.on("/zepto.js", [](){ webServer.send(200, "text/javascript", zeptojs); });
    webServer.on("/config", conf_handleConfig);
    webServer.onNotFound(conf_handleNotFound);
    webServer.begin();
    Serial.println("HTTP server started");
}

/***********************************************************
 ***  获取芯片ID
 **********************************************************/
String comm_getChipId() {
  uint64_t number = ESP.getEfuseMac();
  unsigned long long1 = (unsigned long)((number & 0xFFFF0000) >> 16);
  unsigned long long2 = (unsigned long)((number & 0x0000FFFF));

  return String(long1, HEX) + String(long2, HEX);
}

/***********************************************************
 ***  读取配置
 **********************************************************/ 
void main_loadConfig() {
  prefs.begin("config", true);
  
  ssid = prefs.getString("ssid");
  password = prefs.getString("password");
  
  prefs.end();
}

/***********************************************************
 ***  连接到WiFi
 **********************************************************/ 
void main_connectToWiFi() {

    WiFi.begin(ssid, password);
    Serial.print("正在连接 WiFi");
    while (WiFi.status() != WL_CONNECTED) {
        delay(100);
        Serial.print(".");
    }
    Serial.print("\n连接到 WiFi, localIP: ");
    Serial.println(WiFi.localIP());
}

/***********************************************************
 ***  初始化设置
 **********************************************************/
void setup() {
  Serial.begin(115200);
  Serial.println();

  chipId = comm_getChipId();
  Serial.printf("ChipId:%s\n", chipId);

  if (!comm_haveConfig()) {
    Serial.println("未发现配置,启动配置程序。");
    WiFi.mode(WIFI_AP);
    conf_startConfigServer();
    Serial.println("等待配置...");
    return;
  }

  Serial.println("发现配置,启动主程序。");
  
  main_loadConfig();
 
  main_connectToWiFi();
}

/***********************************************************
 ***  主循环
 **********************************************************/
void loop() {
  
  if (!comm_haveConfig()) {
    webServer.handleClient();
    delay(10);
    return;
  }

  Serial.println("主代码开始执行...");
  // your main code.
  
  delay(1000); //1s
} 

代码中minicss和zeptojs字符数组内容请替换成对应文件内容。

运行效果

在ESP32上实现WEB交互界面

- 本文由用户 发布,文中观点仅代表作者本人,不代表本站立场。
- 如需转载,请联系作者;如有侵权,请联系本站处理。

07-29   阅读(9)   评论(0)
 标签: 创客 ESP32

涨知识
四位数码管

四位数码管是一种常见的LED显示器件,主要用于显示数字信息。

评论:
相关文章
Arduino ESP32获取芯片、RAM信息

本文介绍如何使用Arduino-ESP32库中的API函数获取ESP32的芯片、RAM信息等,并提供了一个示例程序代码。


ESP32 FreeRTOS 双核使用

ESP32系列(包括ESP32-S3)搭载Xtensa双核处理器,默认情况下Arduino框架仅使用单核运行用户代码,通过多核编程,可以充分利用硬件资源来提升系统响应和性能。


ESP32 GPIO 矩阵和引脚多路复用

ESP32 芯片有34个物理GPIO管脚。每个GPIO管脚都可用作一个通用IO,或连接一个内部的外设信号。IO_MUX ¹、RTC IO MUX 和GPIO交换矩阵用于将信号从外设传输至GPIO管脚。


ESP32Encoder:高效的ESP32旋转编码器库

ESP32Encoder库是一个利用ESP32脉冲计数器硬件外设实现高效旋转编码器读取的软件库。


适合学习物联网的几款盒子

本文对比了几款适合物联网开发的盒子硬件参数,供大家参考。


乐动掌控

乐动掌控采用掌控板作为主控,塑胶一体式外壳,侧面和底面开具多个乐高扩展孔位,兼容乐高积木,可完成多种创意应用。


ESP32 MicroPython存储数据到闪存

在MicroPython的ESP32库中,NVS类用于管理非易失性存储,支持 32 位有符号整数和 二进制blob。


Arduino-ESP32 Preferences库使用详解

Arduino-ESP32项目提供的Preferences库是一个专为ESP32设计的非易失性存储解决方案,它替代了传统的Arduino EEPROM库,提供了更强大、更可靠的数据存储功能。


小鹏物联网 MicroPython 图像采集方案

本方案是一个基于ESP32-CAM + 物联网的图像采集方案。


esp32cam开发板烧录micropython固件

‌ESP32-CAM与MicroPython结合可实现摄像头图像采集、视频流传输等功能,不过Micropython官方没有支持ESP32-CAM的固件,需要烧录第三方的专有固件。

搜索
小鹏STEM教研服务

专属教研服务系统,助您构建STEM课程体系,打造一站式教学环境。