效果展示

本项目参考了这篇文章:ESP32/ESP8266 Plot Sensor Readings in Real Time Charts – Web Server

这个项目的灵感来源于单片机课程设计,我做了一个将温湿度上传到阿里云物联网平台的系统。中期汇报的时候,老师说,为什么不同时把温湿度曲线展现出来呢?嗯…我也想。但是阿里云不能同时展示现在的温湿度和历史曲线,需要手动点击,展示曲线的页面也不美观。而且阿里云功能比较多,界面不简洁,但我只需要其中很少一部分功能。

于是我有了用网页展示温湿度的想法。自己写的网页有比较大的自由度,可以根据自己的审美修改,界面更简洁。但是到了画曲线的地方,我卡住了,画曲线需要用到Java Script的库,我对此不熟悉。于是我上网找了篇文章,根据需要改动了一下。


用到的东西

硬件:

  • ESP8266-01S
  • USB-TTL
  • DHT11

软件:

  • Arduino

步骤

1. Arduino安装ESP8266的包

在Arduino的文件-首选项-其他开发板管理器地址中,粘贴此链接:http://arduino.esp8266.com/stable/package_esp8266com_index.json

安装包


2. 在Arduino中选择你的板子

我使用的是ESP8266-01S,所以在开发板这里选择的是Generic ESP8266 Module,通用ESP8266模块。如果使用ESP8266-12,可以选择Generic ESP8266 Module,也可以选择Node MCU。

选择你的板子


3. Arduino安装库

如果是ESP32,在Library中搜索并安装这些库

<WiFi.h>  
<ESPAsyncWebServer.h>  

如果是ESP8266,在Library中搜索并安装这些库

<ESP8266WiFi.h>  
<Hash.h>  
<ESPAsyncTCP.h>  
<ESPAsyncWebServer.h>  

DHT11使用的库:

<DHT11.h>

4. 使用LittleFS储存网页文件

一开始我尝试直接在Arduino的文件里写网页,但是网页代码量太大了,而ESP8266的内存比较小,只是写写很简单的网页还是可以的,但我们还需要展示曲线。于是直接把整个网页文件放在LittleFS里。只需要在开头加上一句

#include <LittleFS.h>

就可以读取了

4.1 安装LittleFS上传插件

点进这个网站:arduino-littlefs-upload
下载vsix文件

下载插件

打开文件夹,找到.arduinoIDE这个文件,一般放在这个地方:

C:\Users\YourUserName\.arduinoIDE

*YourUserName是你自己起的名字

然后创建一个文件夹,命名为plugins

创建plugins文件夹

把刚刚下载的vsix文件放进plugins

安装插件

重启Arduino,按住Ctrl+Shift+P,输入Upload LittleFS
出现了这个选项的话插件就安装成功啦

出现选项

打开工程文件夹,这个是放你的ino文件的文件夹,在你的ino文件旁边新建一个data文件夹

创建data

然后在data文件夹里面新建一个网页文件index.html
写入html和js代码


<!DOCTYPE HTML>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>温湿度监测</title>
  <script src="https://code.highcharts.com/highcharts.js"></script>
  <script src="https://code.highcharts.com/modules/exporting.js"></script>
  <script src="https://code.highcharts.com/modules/export-data.js"></script>
  <script src="https://code.highcharts.com/modules/accessibility.js"></script>
  <style>
    body {
      font-family: Arial, sans-serif;
      text-align: center;
      margin-top: 50px;
    }

    h1 {
      font-family: Arial;
      font-size: 2.5rem;
      text-align: center;
    }

    .data-container {
      display: flex;
      justify-content: center;
      align-items: center;
      gap: 150px;
      /* 控制左右之间的间距 */
      margin-bottom: 20px;
    }

    .data {
      font-size: 2em;
    }

    .container {
      max-width: 800px;
      margin: 0 auto;
    }
  </style>
</head>

<body>
  <h1>ESP Environment Station</h1>

  <!-- 温度和湿度并排显示 -->
  <div class="data-container">
    <p class="data" id="current-temperature">Temperature: -- ℃</p>
    <p class="data" id="current-humidity">Humidity: -- %RH</p>
  </div>

  <!-- 温度和湿度图表 -->
  <div id="chart-temperature" class="container"></div>
  <div id="chart-humidity" class="container"></div>

  <script>
    // 温度图表
    var chartT = new Highcharts.Chart({
      chart: { renderTo: 'chart-temperature' },
      title: { text: 'Temperature' },
      series: [{
        showInLegend: false,
        data: []
      }],
      plotOptions: {
        line: {
          animation: false,
          dataLabels: { enabled: true }
        },
        series: { color: '#059e8a' }
      },
      xAxis: {
        type: 'datetime',
        dateTimeLabelFormats: { second: '%H:%M:%S' }
      },
      yAxis: {
        title: { text: 'Temperature (Celsius)' }
      },
      credits: { enabled: false }
    });

    // 每隔30秒获取一次温度数据并更新图表和显示的温度
    setInterval(function () {
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
          var x = (new Date()).getTime() + (8 * 60 * 60 * 1000); // 加上8小时的时区差
          var y = parseFloat(this.responseText);

          // 更新显示的温度
          document.getElementById("current-temperature").innerHTML = "Temperature: " + y.toFixed(2) + " ℃";

          if (chartT.series[0].data.length > 40) {
            chartT.series[0].addPoint([x, y], true, true, true);
          } else {
            chartT.series[0].addPoint([x, y], true, false, true);
          }
        }
      };
      xhttp.open("GET", "/temperature", true);
      xhttp.send();
    }, 30000);

    // 湿度图表
    var chartH = new Highcharts.Chart({
      chart: { renderTo: 'chart-humidity' },
      title: { text: 'Humidity' },
      series: [{
        showInLegend: false,
        data: []
      }],
      plotOptions: {
        line: {
          animation: false,
          dataLabels: { enabled: true }
        }
      },
      xAxis: {
        type: 'datetime',
        dateTimeLabelFormats: { second: '%H:%M:%S' }
      },
      yAxis: {
        title: { text: 'Humidity (%)' }
      },
      credits: { enabled: false }
    });

    // 每隔30秒获取一次湿度数据并更新图表和显示的湿度
    setInterval(function () {
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
          var x = (new Date()).getTime() + (8 * 60 * 60 * 1000); // 加上8小时的时区差
          var y = parseFloat(this.responseText);

          // 更新显示的湿度
          document.getElementById("current-humidity").innerHTML = "Humidity: " + y.toFixed(2) + " %RH";

          if (chartH.series[0].data.length > 40) {
            chartH.series[0].addPoint([x, y], true, true, true);
          } else {
            chartH.series[0].addPoint([x, y], true, false, true);
          }
        }
      };
      xhttp.open("GET", "/humidity", true);
      xhttp.send();
    }, 30000);

  </script>

</body>

</html>

Highcharts 是一个图表库,专门用于在网页中绘制各种图表。
<script src="https://code.highcharts.com/highcharts.js"></script>
这行代码从 Highcharts 的 CDN(内容分发网络)加载 Highcharts 库,使得我们能够在网页中使用这个JavaScript库来创建图表。

4.2 把网页文件上传到ESP8266的LittleFS

连接ESP8266和USB-TTL,并设置成下载模式,RST要接一下地再接3V3

ESP8266USB-TTL
RXTXD
TXRXD
EN3V3
VCC3V3
GNDGND
GPIO0GND
RST3V3

打开Arduino,按住Ctrl+Shift+P,输入Upload LittleFS
点击出现的选项

出现选项

烧录成功如图

烧录成功

如果一直卡在Connecting...————...

  1. 检查一下接线
  2. RST接一下地再接回3V3
  3. GPIO0断开接线再接回GND

5. DHT11接线

DHT11和ESP8266的接线:

DHT11ESP8266
VCCVCC
GNDGND
DATAGPIO2

6. Arduino上的代码

关键代码:

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);

  // Initialize LittleFS
  if(!LittleFS.begin()){
    Serial.println("An Error has occurred while mounting LittleFS");
        return;
  }

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  // Print ESP32 Local IP Address
  Serial.println(WiFi.localIP());

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(LittleFS, "/index.html");
  });
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readDHT11Temperature().c_str());
  });
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readDHT11Humidity().c_str());
  });

  // Start server
  server.begin();
}

7.下载程序

下载Arduino程序时,ESP8266置于下载模式,像前面说过的那样


8.运行程序

运行程序的时候要将ESP8266置于运行模式,切换模式要让RST接一下地,然后悬空。接线如下:

ESP8266USB-TTL
RXTXD
TXRXD
EN3V3
VCC3V3
GNDGND

ESP8266连接WiFi之后,会在串口打印IP地址

打印IP地址

我们在浏览器打开这个IP地址,就可以看到网页在实时显示温湿度了

效果显示

手机上也可以看:

手机

获取到IP地址之后,其实RX和TX可以断开了,只要给ESP8266维持供电就可以。


原理

原理是ESP8266启动时连接到WiFi,通过AsyncWebServer库创建了一个HTTP服务器。这个服务器监听着端口80,提供HTTP请求响应。然后我们访问ESP8266的IP地址。浏览器发送一个HTTP GET请求到设备,要求访问这个IP地址上的根路径/,读取 index.html文件的内容并将其作为 HTTP响应发送给浏览器。浏览器收到响应后,解析HTML文件的内容,并呈现网页。

//请求ESP8266返回存储在 LittleFS 文件系统中的 index.html 网页  
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(LittleFS, "/index.html");
  });

ESP8266不断从 DHT11 传感器获取温度和湿度数据,然后网页每隔 30 秒向 ESP8266发送 HTTP 请求,分别获取温度和湿度数据。

//网页向ESP8266发送获取温度和湿度数据的HTTP请求
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readDHT11Temperature().c_str());
  });
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readDHT11Humidity().c_str());
  });

获取的数据在网页中显示,通过 Highcharts 实时更新温湿度变化曲线。


完结撒花~🎊

📁 附件