回收站计划:esp8266 文件系统 web交互 天气获取 mqtt 串口通信 2024/7/27 16:00

esp8266  文件系统 web交互 天气获取 mqtt 串口通信

main.cpp:

#include <FS.h>                // 文件系统库
#include <ArduinoJson.h>       // Arduino JSON解析库
#include <PubSubClient.h>      // MQTT客户端库
#include <ESP8266WebServer.h>  // ESP8266 Web服务器库
#include <WiFiManager.h>       // WiFi管理库
#include <ESP8266WiFi.h>       // ESP8266 WiFi库
#include <WiFiClient.h>        // WiFi客户端库
#include <Arduino.h>           // Arduino核心库
#include <html.h>              // HTML相关库
#include <ArduinoHttpClient.h> // HTTP客户端库
#include <fsrots.h>            // 文件系统相关库
FSRots fsA;                    // 文件系统相关实例
WiFiManager wifi;              // WiFi管理实例

int ihead = 0;        // 串口接收缓冲区
int wlank = true;     // 控制串口读取标志位
char head[256] = "";  // 串口接收头部缓冲区
String head_str = ""; // 串口接收头部缓冲区
//============================================//

// 函数声明
void wlan();                                                    // 换页函数
void tjs(String name);                                          // 串口屏输出函数
void HTTPA();                                                   // Web服务器处理函数
void cls();                                                     // 清除串口缓存函数
void testMQtt();                                                // 尝试连接MQTT函数
void mqttmsgg(char *topic, byte *payload, unsigned int length); // MQTT消息回调函数
void setup();                                                   // 初始化函数
void loop();                                                    // 主循环函数
void handleFileUpload();                                        // 文件上传处理函数
void SerialHead();                                              // 串口头处理函数

//============================================//

ESP8266WebServer server(80); // 创建Web服务器,监听端口80
WiFiClient ClientA;          // WiFi客户端实例
// PubSubClient ClientB(ClientA); // MQTT客户端实例,使用ClientA作为网络客户端

String subget; // 存储MQTT订阅主题的字符串

void clientaa();

// 测试HTTP请求函数

// Web服务器处理函数
void HTTPA()
{
  String text = server.uri(); // 获取请求的URI
  if (text.endsWith("/"))
  { // 如果请求的URI以"/"结束
    if (SPIFFS.exists("/index.html"))
    {                                                // 如果文件系统中有主页
      File inhtml = SPIFFS.open("/index.html", "r"); // 打开主页文件
      server.streamFile(inhtml, "text/html");        // 通过Web服务器流式传输文件
      inhtml.close();                                // 关闭文件
    }
    else
    { // 如果没有主页,则使用内置主页
      server.send(200, "text/html", html);
    }
  }
  // 其他请求处理逻辑...
}

// 清除串口缓存函数
void cls()
{
  while (Serial.available())
  {                // 当串口有数据可读时
    Serial.read(); // 读取并丢弃,以清空缓存
  }
}

// 尝试连接MQTT函数
void testMQtt()
{
  if (SPIFFS.exists("/config.txt"))
  {                                               // 如果配置文件存在
    File respi = SPIFFS.open("/config.txt", "r"); // 打开配置文件
    String cc;
    for (int i = 0; i < respi.size(); i++)
    { // 读取文件内容
      cc += (char)respi.read();
    }
    Serial.println(cc);
    respi.close();
    // 提取配置信息
    int indeu = cc.indexOf(";");
    int indeu1 = cc.indexOf(";", indeu + 1);
    int indeu2 = cc.indexOf(";", indeu1 + 1);
    String pat1 = cc.substring(0, indeu);
    String pat2 = cc.substring(indeu + 1, indeu1);
    String pat3 = cc.substring(indeu1 + 1, indeu2);
    String pat4 = pat1 + pat2 + pat3;
    Serial.print(pat4.c_str());
  }
  else
  {
    Serial.println("没有找到配置文件");
  }
}

// MQTT消息回调函数
void mqttmsgg(char *topic, byte *payload, unsigned int length)
{
  String msmgg = (String)topic; // 转换主题为字符串
  for (int i = 0; i < length; i++)
  { // 处理payload
    msmgg += (char)payload[i];
  }
  Serial.println(msmgg.c_str()); // 输出MQTT消息
}

// 初始化函数
void setup()
{
  Serial.begin(9600);               // 初始化串口通信
  wifi.autoConnect("ESP-8266AUTO"); // 自动连接WiFi
  fsA.fsrots();                     // 文件系统初始化
  if (WiFi.status() != WL_CONNECTED)
  {
    delay(2500); // 延时2.5秒
  }
  else
  {
    if (WiFi.status() != WL_CONNECTED)
    { // 如果WiFi未连接
    }
  }
  if (WiFi.status() == WL_CONNECTED)
  {                           // 如果WiFi已连接
    server.begin();           // 开始Web服务器
    server.onNotFound(HTTPA); // 设置HTTPA为未找到页面的处理函数
  }
}

// 获取天气信息函数==================================//
void clientaa()
{

  HttpClient clienta(ClientA, "weather.cma.cn", 80);
  clienta.kUserAgent = "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
  clienta.get("/api/now/53698");

  String buf = clienta.responseBody();
  Serial.println(buf);

  // json数据解析
  DynamicJsonDocument doc(1024);                                     // 动态分配内存用于存储JSON数据
  deserializeJson(doc, buf);                                         // 将JSON数据反序列化为doc
  JsonObject locationobj = doc["data"]["location"].as<JsonObject>(); // 获取JSON对象 data中location

  JsonObject nowobj = doc["data"]["now"].as<JsonObject>(); // 获取JSON对象data中now
  JsonObject lastUpdateobj = doc["data"]["lastUpdate"];    // 获取JSON对象data中lastUpdate
  String strjson = locationobj["path"];                    // 获取JSON对象data中location中的path属性

  int index1 = strjson.indexOf(",");             // 查找第一个逗号的位置
  int index2 = strjson.indexOf(",", index1 + 1); // 查找第二个逗号的位置

  String part1 = strjson.substring(0, index1);          // 截取第一个部分
  String part2 = strjson.substring(index1 + 1, index2); // 截取第二个部分
  String part3 = strjson.substring(index2 + 1);         // 截取第三个部分

  Serial.println("国家" + part1); // 输出第一个部分
  Serial.println("城市" + part2); // 输出第二个部分
  Serial.println("区县" + part3); // 输出第三个部分
  Serial.println("温度" + String(nowobj["temperature"]) + "℃");
  Serial.println("湿度" + String(nowobj["humidity"]) + "%");
  Serial.println("气压" + String(nowobj["pressure"]) + "hPa");

  // 获取时间
  Serial.println("时间:" + String(lastUpdateobj["lastUpdate"]));
}

//====================================串口数据读取
void SerialHead()
{
  int Sh = 0;
  head_str.reserve(ihead); // 分配内存
  for (Sh; Sh < ihead; Sh++)
  {
    head_str += String(head[Sh]);
  }

  if (head_str.endsWith("/天气"))
  {
    clientaa();
 
  }
  if (head_str.endsWith("/MQTT"))
  {
    testMQtt();
   
  
  } 
    cls(); // 清空缓存
    ihead = 0;
    head_str = "";
    wlank = true;
}

// 主循环函数
void loop()
{

  if (WiFi.status() == WL_CONNECTED)
  {                        // 如果WiFi已连接
    server.handleClient(); // 处理Web服务器的客户端请求
  }
  if(wlank==true){

  //进入读取模式
  if (Serial.available())
  { wlank = false; // 退出循环
    while (Serial.available() > 0 && ihead < 255)
    {
      head[ihead] = Serial.read();
      ihead++;
    }
    head[ihead] = '\0'; // 字符串结束符

    if (ihead >= 256)
    {

      wlank = false; // 退出循环
    }
   

    SerialHead(); // 处理数据
  }}

  delay(200); // 等待200毫秒
}

FSROTS库:

#ifndef FSROTS_H
#define FSROTS_H
#include <FS.h> // 文件系统库
#include <ArduinoJson.h>//json库
#include <ESP8266WebServer.h>//web服务器
/**
 * @brief 功能描述:文件系统
 * FSRots 自定义名 ; 实例化 fsrots
 * 自定义名.fsrots();文件系统初始化
 * 自定义名.fsread(文件名);读取文件  返回内容
 * 自定义名.getContentType(文件名);获取文件类型 返回内容
 * 自定义名.sFlash(); // 获取系统信息并以JSON格式返回
 * 自定义名.sDir(); // 获取目录信息并以JSON格式返回
 * 自定义名.fsServer(服务器实例); // 处理服务器请求,发送文件或404响应
 * 
 */
class FSRots
{
private: 
    FSInfo csd; // 存储文件系统信息的结构体,如总空间、已用空间等

public:
    // 初始化文件系统
    void fsrots()
    {
        SPIFFS.begin(); // 开始SPIFFS文件系统,确保文件系统可用
    }

    // 读取指定名称的文件内容
    String fsread(const String &fsname)
    {
        // 检查文件是否存在
        if (SPIFFS.exists(fsname))
        {
            String fsdata; // 用于存储文件内容的字符串
            File file = SPIFFS.open(fsname, "r"); // 以只读模式打开文件
            // 循环读取文件内容
            while (file.available())
            {
                fsdata += (char)file.read(); // 读取文件的每一个字节并追加到fsdata中
            }
            file.close(); // 关闭文件
            return fsdata; // 返回文件内容
        }
        else
        {
            return "文件不存在"; // 如果文件不存在,返回错误信息
        }
    }


/**---------------------分割线-------------------------------**/

    // 查询系统信息并返回JSON格式的字符串
    String sFlash()
    {
        SPIFFS.info(csd); // 获取文件系统信息并存储在csd结构体中
        StaticJsonDocument<256> doc; // 创建一个静态的JSON文档,用于构建JSON数据
        // 填充JSON文档
        doc["bootv"] = ESP.getBootVersion(); // 获取启动版本
        doc["id"] = ESP.getChipId(); // 芯片ID
        doc["mac"] = WiFi.macAddress(); // MAC地址
        doc["ip"] = WiFi.localIP().toString(); // IP地址
        doc["sdall"] = csd.totalBytes; // 总空间
        doc["sdused"] = csd.usedBytes; // 已用空间
        String output; // 创建一个字符串对象,用于存储序列化后的JSON数据
        serializeJson(doc, output); // 将JSON文档序列化为字符串
        return output; // 返回序列化后的JSON字符串
    }

    //查询目录信息
    String sDir()
    {   DynamicJsonDocument doc(1024);
        int  i=0;
        String output;
        Dir dir=SPIFFS.openDir("/");
        while (dir.next())
        {   i++;
      
         String    pastr="dir"+String(i);
            doc[pastr]=dir.fileName();
        }
        serializeJson(doc, output);
        return output;
        
    }
/**---------------------分割线-------------------------------**/
    // 处理服务器请求
    template <typename T>
    void fsServer(T &ServerG)
    {
        String path = ServerG.uri(); // 获取请求的URI
        String BackContentType = getContentType(path); // 获取文件类型
        size_t lastSlashPos = path.lastIndexOf('/'); // 查找最后一个'/'的位置,用于提取文件名
        String fileNameStr =path.substring(lastSlashPos + 1); // 提取文件名
        // 检查文件是否存在
        if (SPIFFS.exists(fileNameStr))
        {
            File fileName = SPIFFS.open(fileNameStr, "r"); // 打开文件
            ServerG.streamFile(fileName, BackContentType); // 发送文件到客户端
            fileName.close(); // 关闭文件
        }
        else
        {
            // 如果文件不存在,发送404错误
            ServerG.send(404, "text/plain", "File Not Found");
        }
    }

    // 根据文件名获取文件类型
    String getContentType(String filename)
    {
        // 检查文件后缀,返回对应的MIME类型
        if (filename.endsWith(".htm"))
            return "text/html";
        else if (filename.endsWith(".html"))
            return "text/html";
        else if (filename.endsWith(".css"))
            return "text/css";
        else if (filename.endsWith(".js"))
            return "application/javascript";
        else if (filename.endsWith(".png"))
            return "image/png";
        else if (filename.endsWith(".gif"))
            return "image/gif";
        else if (filename.endsWith(".jpg"))
            return "image/jpeg";
        else if (filename.endsWith(".ico"))
            return "image/x-icon";
        else if (filename.endsWith(".xml"))
            return "text/xml";
        else if (filename.endsWith(".pdf"))
            return "application/x-pdf";
        else if (filename.endsWith(".zip"))
            return "application/x-zip";
        else if (filename.endsWith(".gz"))
            return "application/x-gzip";
        // 如果文件后缀不匹配任何已知类型,则默认返回纯文本类型
        return "text/plain";
    }
};






#endif

HTML库:

#ifndef html_h
#define html_h
const char* html=R"(<!DOCTYPE html><html lang='en' id='myhtml1'><head>  <meta charset='UTF-8'>  <meta name='viewport' content='width=device-width, initial-scale=1.0'>  <title id='mytitle'>勇敢向前冲!</title></head><style id='mystyle'>  * {    box-sizing: border-box;    margin: 0;    padding: 0;  }  :root {    --t: 10s;  }  body {    width: 100vw;    height: 100vh;    overflow: hidden;    display: grid;    grid-template-columns: repeat(3, 1fr);    grid-row: 0 1fr;  }  h1 {    text-align: center;    margin-top: 30px;    grid-column: 1/span 3;    grid-row: 1;    height: 0;  }  h3 {    position: relative;    margin: 0;    border: 2px solid black;    z-index: 2;    background-color: white;    text-align: center;  }  #box1 {    visibility: hidden;    grid-column: 2;    grid-row: 2;    border: 2px solid black;    width: 80%;    left: 10%;    height: 75%;    overflow: hidden;    text-align: center;    position: relative;    background-color: white;  }  #box1>table {    height: 50%;    text-align: center;    border-collapse: collapse;    width: 100%;  }  th {    position: relative;    z-index: 1;    border: 1px solid black;    background-color: white;  }  td {    height: 10px;    position: relative;    padding: 0;    margin: 0;    border-left: 1px solid black;    animation: move 20s linear infinite;    z-index: -1;  }  @keyframes move {    0% {      transform: translateY(0);    }    100% {      transform: translateY(-100px);    }  }  #box2 {    visibility: visible;    /* visibility: hidden; */    /*调试专用*/    grid-column: 2;    grid-row: 2;    border: 2px solid black;    width: 80%;    left: 10%;    height: 80%;    position: relative;    background-color: black;  }  #box2>input {    width: 100%;    text-align: center;  }  #box3 {    visibility: hidden;    /* visibility: visible;调试专用 */    grid-column: 1/span 3;    grid-row: 2;    border: 2px solid black;    overflow: hidden;    display: grid;    grid-template-columns: repeat(3, 1fr);    grid-template-rows: 40% 1fr;  }  #keyname {    grid-column: 1;    grid-row: 1;    position: relative;    top: 0;    left: 0;    width: 50%;    height: 40%;    display: grid;    grid-template-columns: 1fr;    grid-template-rows: repeat(4, 1fr);  }  #keyname>button {    width: 100%;    height: 100%;    font-size: 2vw;    background-color: white;    position: relative;    transform: rotate(-10deg);    z-index: -1;  }  #keyname2 {    grid-column: 3;    grid-row: 1;    justify-self: end;    /* 对齐到网格单元格的右侧 */    align-self: start;    /* 对齐到网格单元格的顶部 */    position: relative;    top: 0;    right: 0;    width: 50%;    height: 40%;    display: grid;    grid-template-columns: 1fr;    grid-template-rows: repeat(4, 1fr);  }  #keyname2>button {    width: 100%;    height: 100%;    font-size: 2vw;    background-color: white;    position: relative;    transform: rotate(10deg);    z-index: -1;  }  #game {    grid-column: 1/span 3;    grid-row: 2;    border-bottom: 2vh solid black;    position: relative;    overflow: hidden;  }  #car {    width: 3vh;    height: 3vh;    border-radius: 3vh;    background-color: black;    position: absolute;    bottom: 0;  }  #room {    border-radius: 1vh 1vh 0 0;    position: absolute;    right: 0;    width: 3vw;    height: 6vh;    bottom: 0;    background-color: black;  }  input[name='youname'] {    margin-top: 20%;    font-size: 2em;    background-color: black;    width: 100%;    border: none;    outline: none;    color: black;    text-overflow: hidden;    animation:      textshow 3s linear infinite,      text var(--t) linear infinite;    -webkit-box-reflect: below 0px linear-gradient(transparent, rgb(255, 255, 255));  }  @keyframes textshow {    0% {      color: aqua;    }    50% {      color: rgb(255, 255, 255);      transform: translateY(-10px);      text-shadow: 0 0 10px aqua,        0 0 20px rgba(0, 255, 255, 0.8),        0 0 30px rgba(0, 255, 255, 0.6),        0 0 40px rgba(0, 255, 255, 0.8),        0 0 50px aqua;    }    100% {      transform: translateY(0px);    }  }  #colorA,  #colorB {    animation: colorC 10s linear infinite;  }  @keyframes colorC {    0% {      color: rgb(0, 0, 0);    }    /* 黑色 */    14.28% {      color: rgb(255, 0, 0);    }    /* 红色 */    28.56% {      color: rgb(255, 255, 0);    }    /* 黄色 */    42.84% {      color: rgb(255, 127, 0);    }    /* 橙色 */    57.12% {      color: rgb(0, 255, 0);    }    /* 绿色 */    71.4% {      color: rgb(75, 0, 130);    }    /* 靛色 */    85.68% {      color: rgb(0, 0, 255);    }    /* 蓝色 */    100% {      color: rgb(143, 0, 255);    }    /* 紫色 */  }  input[name='youname']:focus {    --t: 100s;  }  @keyframes text {    0% {      transform: translateY(0);    }    50% {      transform: translateY(-20px);    }    100% {      transform: translateY(0);    }  }  #box3ts {    grid-column: 2;    grid-row: 1;    width: 100%;    height: 100%;  }</style><body>  <h1>勇敢向前冲</h1>  <div id='box1'>    <h3>排行榜</h3>    <!-- 在此处填入你们熟悉的人姓名 -->    <table>      <thead>        <tr>          <th>排名</th>          <th>玩家名字</th>          <th>当前关卡</th>        </tr>      </thead>      <tbody>        <tr>          <td>1</td>          <td>周文轩</td>          <td>第8关</td>        </tr>        <tr>          <td>2</td>          <td>王芳芳</td>          <td>第6关</td>        </tr>        <tr>          <td>3</td>          <td>张伟华</td>          <td>第6关</td>        </tr>        <tr>          <td>4</td>          <td>刘洋子</td>          <td>第5关</td>        </tr>        <tr>          <td>5</td>          <td>陈娜丽</td>          <td>第3关</td>        </tr>        <tr>          <td>6</td>          <td>杨明杰</td>          <td>第2关</td>        </tr>        <tr>          <td>7</td>          <td>虚位以待</td>          <td></td>        </tr>        <tr>          <td>8</td>          <td>虚位以待</td>          <td></td>        </tr>        <tr>          <td>9</td>          <td>虚位以待</td>          <td></td>        </tr>        <tr>          <td>10</td>          <td>虚位以待</td>          <td></td>        </tr>      </tbody>    </table>  </div>  <div id='box2'>    <h3>实名认证</h3>    <input type='text' name='youname' placeholder='填入姓名'>    <button id='play' style='width: 100%;position:absolute;bottom: 6%;left: 0;'>开始游戏</button>    <button id='Box1Show' style='width: 100%;height: 6%; position:absolute;bottom: 0;left: 0;'>排行榜</button>  </div>  <div id='box3'>    <div id='keyname'>      <button id='but1'>A</button>      <button id='but2'>W</button>      <button id='but3'>D</button>      <button id='but4'>J</button>    </div>    <div id='box3ts'>      <h3 id='box3ts1'>第1关</h3>      <p id='colorA' style='display: inline-block;'>您当前已移动:</p>      <p id='numts1' style='display: inline-block;'>0</p>      <p id='colorB' style='display: inline-block;'>步</p>    </div>    <div id='keyname2'>      <button id='but5'>A</button>      <button id='but6'>W</button>      <button id='but7'>D</button>      <button id='but8'>J</button>    </div>    <div id='game'>      <div id='car'></div>      <div id='room'></div>    </div>  </div>  <script>    // 定义七彩色列表    const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];    var namea;    window.onload = function () {      var play = document.getElementById('play');      var Box1Show = document.getElementById('Box1Show');      play.onclick = function () {        var youname = document.getElementsByName('youname')[0].value;        namea=youname;        // 这里填写你女朋友名字        if (youname == '染染') {          console.log(youname);          var box2 = document.getElementById('box2');          box2.style.visibility = 'hidden';          var box3 = document.getElementById('box3');          box3.style.visibility = 'visible';          document.addEventListener('keypress', function (event) {            console.log(event.key);            keytest(event.key);          });        } else if (youname == '') { alert('不能为空!'); } else { alert('请输入您的真实姓名!'); }      }      Box1Show.onclick = function () {        var box1 = document.getElementById('box1');        box1.style.zIndex = 2;        if (box1.style.visibility == 'visible') {          box1.style.visibility = 'hidden';        } else {          box1.style.visibility = 'visible';        }      }    }    var xa = 0, xb, gamepam = 1;    function keytest(code) {      var but1 = document.getElementById('but1');      var but2 = document.getElementById('but2');      var but3 = document.getElementById('but3');      var but4 = document.getElementById('but4');      var car = document.getElementById('car');      var numts1 = document.getElementById('numts1');      var box3ts1 = document.getElementById('box3ts1');      if (code === 'a') {        if (xa != 0) {          xa -= 1;          xb = xa + 'vw';        }        if (xa < 0) {          xa = 0;        }        console.log('后退' + xb);        car.style.transform = 'translateX(' + xb + ')';        butshow(but1);        butshow(but5);      }      if (code === 'w') {        butshow(but2);        butshow(but6);      }      if (code === 'd') {        butshow(but3);        butshow(but7);        if (xa < 100) {          xa += 1;          xb = xa + 'vw';        }        if (xa === 97) {          xa = 0;          xb = xa + 'vw';          gamepam += 1;          box3ts1.innerHTML = '第' + gamepam + '关';          gameover();        }        console.log('前进' + xb);        car.style.transform = 'translateX(' + xb + ')';        numts1.innerHTML = xa;        numts1.style.color = colors[Math.floor(Math.random() * colors.length)];      }      if (code === 'j') {        butshow(but4);        butshow(but8);      }    }    function butshow(buts) {      buts.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];      setTimeout(function () {        buts.style.backgroundColor = 'white';      }, 500);    }    //这里放表白网页    function gameover() {      var myhtml1=document.getElementById('myhtml1');      myhtml1.innerHTML=`<!DOCTYPE html><html lang='en'><head>    <meta charset='UTF-8'>    <meta name='viewport' content='width=device-width, initial-scale=1.0'>    <title>女友相册html代码</title>    <style>        *{            margin: 0;            padding: 0;            background-color: black;                    }        :root{            --uu: 100px;            --rot:-100px;            --fu:-200px;        }        .box{            width: 200px;            height: 200px;            background-color: transparent;            position: relative;                       top: 30vh;            left: 30vw;            animation: move 10s infinite;            animation-timing-function: linear;            transform-style: preserve-3d; /* Preserve 3D space */                    }        .box div{            position: absolute;            width: 200px;            height: 200px;            border: 2px solid white;                  }        .box:hover{            --uu:200px;            --rot:-200px;        }        @keyframes move{            0%{                transform: rotateY(0deg) rotateX(-25deg) ;            }            100%{                transform: rotateY(360deg)  rotateX(-25deg);            }        }        .front {    transform: translateZ(var(--uu));}.back {    transform: translateZ(var(--rot)) rotateY(180deg);} .right {    transform: rotateY(90deg) translateZ(var(--uu));}.left {    transform: rotateY(-90deg) translateZ(var(--uu));}.top {    transform: rotateX(90deg) translateZ(var(--uu));}.bottom {    transform: rotateX(-90deg) translateZ(var(--uu));}    </style></head><body>    <div class='box'>        <div class='front'><img src='img/1.png' ></div>        <div class='back'><img src='img/2.png' ></div>        <div class='right'><img src='img/3.png' ></div>        <div class='left'><img src='img/4.png' ></div>        <div class='top'><img src='img/5.png' ></div>        <div class='bottom'><img src='img/6.png' ></div>    </div></body></html>`;    }    // //===========调试专用    // box3.style.visibility = 'visible';    // document.addEventListener('keypress', function (event) {    //   console.log(event.key);    //   keytest(event.key);    // });  </script></body></html>
)";
#endif

html界面效果:

主页面:

MQTT页面:

升级页面:

内存页面:

设备页面:

工程代码: 

蓝奏:ESP8266回收编号#2024727.zip 

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值