
本项目参考了这篇文章: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

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

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

打开工程文件夹,这个是放你的ino文件的文件夹,在你的ino文件旁边新建一个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
| ESP8266 | USB-TTL |
|---|---|
| RX | TXD |
| TX | RXD |
| EN | 3V3 |
| VCC | 3V3 |
| GND | GND |
| GPIO0 | GND |
| RST | 3V3 |
打开Arduino,按住Ctrl+Shift+P,输入Upload LittleFS
点击出现的选项

烧录成功如图

如果一直卡在Connecting...————...:
- 检查一下接线
- RST接一下地再接回3V3
- GPIO0断开接线再接回GND
5. DHT11接线
DHT11和ESP8266的接线:
| DHT11 | ESP8266 |
|---|---|
| VCC | VCC |
| GND | GND |
| DATA | GPIO2 |
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接一下地,然后悬空。接线如下:
| ESP8266 | USB-TTL |
|---|---|
| RX | TXD |
| TX | RXD |
| EN | 3V3 |
| VCC | 3V3 |
| GND | GND |
ESP8266连接WiFi之后,会在串口打印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 实时更新温湿度变化曲线。
完结撒花~🎊
📁 附件