了解如何使用 ESP8266 NodeMCU 构建网络服务器以在仪表盘中显示传感器读数。例如,我们将以两种不同的仪表显示 BME280 传感器的温度和湿度:线性和径向。您可以轻松修改项目以绘制任何其他数据。要构建仪表,我们将使用 canvas-gauges JavaScript 库。
项目概况
该项目将使用 ESP8266 构建一个 Web 服务器,该服务器显示来自BME280 传感器的温度和湿度读数。我们将创建一个看起来像温度计的线性仪表来显示温度,并创建一个径向仪表来显示湿度。
服务器发送的事件
使用服务器发送事件 (SSE) 在网页上自动更新读数。
保存在文件系统上的文件
为了让我们的项目更好地组织和更容易理解,我们将保存 HTML、CSS 和 JavaScript 文件以在开发板的文件系统 ( LittleFS )上构建网页。
先决条件
在继续该项目之前,请务必检查本节中的所有先决条件。
1.在Arduino IDE中安装ESP8266开发板
我们将使用 Arduino IDE 对 ESP8266 进行编程。因此,您必须安装 ESP8266 插件。如果您还没有,请自行搜索教程进行安装:在 Arduino IDE(Windows、Mac OS X、Linux)中安装ESP8266 开发板。
如果您想将 VS Code 与 PlatformIO 扩展一起使用,请自行搜索教程学习如何对 ESP8266 进行编程:开始适用于 ESP32 和 ESP8266 的 VS Code 和 PlatformIO IDE(Windows、Mac OS X、Linux Ubuntu)。
2.文件系统上传器插件
要将 HTML、CSS 和 JavaScript 文件上传到 ESP8266 文件系统 (LittleFS),我们将使用 Arduino IDE 的插件: LittleFS Filesystem Uploader。请自行搜索教程安装文件系统上传器插件:在 Arduino IDE 中安装 ESP8266 NodeMCU LittleFS 文件系统上传器。
如果您使用带有 PlatformIO 扩展的 VS Code,请自行搜索教程以了解如何将文件上传到文件系统:带有 VS Code 和 PlatformIO 的 ESP8266 NodeMCU:将文件上传到文件系统 (LittleFS)
3.安装库
要构建此项目,您需要安装以下库:
- Adafruit_BME280(Arduino 库管理器)
- Adafruit_Sensor 库(Arduino 库管理器)
- Arduino 版本 0.1.0 的 Arduino_JSON 库 (Arduino 库管理器)
- ESPAsyncWebServer (.zip 文件夹);
- ESPAsyncTCP (.zip 文件夹)。
您可以使用 Arduino 库管理器安装前三个库。转到 Sketch > Include Library > Manage Libraries 并搜索库的名称。
ESPAsyncWebServer 和 ESPAsynTCP 库无法通过 Arduino 库管理器安装,因此您需要将库文件复制到 Arduino Installation Libraries 文件夹。或者,下载库的 .zip 文件夹,然后在您的 Arduino IDE 中,转到 Sketch > Include Library > Add .zip Library 并选择您刚刚下载的库。
安装库(VS Code + PlatformIO)
如果您使用 PlatformIO 对 ESP8266 进行编程,则应将以下行添加到platformio.ini文件以包含库,将串行监视器速度更改为 115200,并将 LittleFS 用于文件系统:
所需零件
要学习本教程,您需要以下部分:
- ESP8266开发板
- BME280传感器
- 跳线
- 面包板
您可以使用任何其他传感器,或显示对您的项目有用的任何其他值。如果您没有传感器,您也可以尝试使用随机值来了解项目的工作原理。
原理图,示意图
我们将从 BME280 传感器发送温度和湿度读数。我们将使用 I2C 通信与 BME280 传感器模块。为此,将传感器连接到默认的 ESP8266 SCL(接口 5) 和 SDA (接口 4)管脚,如下图所示。
整理文件
为了使项目井井有条并使其更易于理解,我们将创建四个文件来构建 Web 服务器:
- 处理网络服务器的Arduino 服务器代码 ;
- index.html:定义网页内容;
- sytle.css:设置网页样式;
- script.js:对网页的行为进行编程——处理网络服务器响应、事件、创建仪表等。
您应该将 HTML、CSS 和 JavaScript 文件保存在 Arduino sketch 文件夹内名为 data 的文件夹中,如上图所示。我们会将这些文件上传到 ESP8266 文件系统 (LittleFS)。
HTML文件
将以下内容复制到index.html文件。
<!DOCTYPE html>
<html>
<head>
<title>ESP IOT DASHBOARD</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="favicon.png">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="style.css">
<script src="http://cdn.rawgit.com/Mikhus/canvas-gauges/gh-pages/download/2.1.7/all/gauge.min.js"></script>
</head>
<body>
<div class="topnav">
<h1>ESP WEB SERVER GAUGES</h1>
</div>
<div class="content">
<div class="card-grid">
<div class="card">
<p class="card-title">Temperature</p>
<canvas id="gauge-temperature"></canvas>
</div>
<div class="card">
<p class="card-title">Humidity</p>
<canvas id="gauge-humidity"></canvas>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
这个项目的 HTML 文件非常简单。它在 HTML 文件的头部包含JavaScript canvas-gauges 库:
<script src="https://cdn.rawgit.com/Mikhus/canvas-gauges/gh-pages/download/2.1.7/all/gauge.min.js"></script>
有一个<canvas>带有 id 的标签测量温度,稍后我们将在其中渲染温度计。
<canvas id="gauge-temperature"></canvas>
还有一个<canvas>带有 id 的标签测量湿度,稍后我们将在其中渲染湿度计。
<canvas id="gauge-humidity"></canvas>
文件
将以下样式复制到您的style.css文件。它使用简单的颜色和样式来设计网页。
html {
font-family: Arial, Helvetica, sans-serif;
display: inline-block;
text-align: center;
}
h1 {
font-size: 1.8rem;
color: white;
}
p {
font-size: 1.4rem;
}
.topnav {
overflow: hidden;
background-color: #0A1128;
}
body {
margin: 0;
}
.content {
padding: 5%;
}
.card-grid {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.card {
background-color: white;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title {
font-size: 1.2rem;
font-weight: bold;
color: #034078
}
JavaScript 文件(创建仪表)
将以下内容复制到script.js文件。
// Get current sensor readings when the page loads
window.addEventListener('load', getReadings);
// Create Temperature Gauge
var gaugeTemp = new LinearGauge({
renderTo: 'gauge-temperature',
width: 120,
height: 400,
units: "Temperature C",
minValue: 0,
startAngle: 90,
ticksAngle: 180,
maxValue: 40,
colorValueBoxRect: "#049faa",
colorValueBoxRectEnd: "#049faa",
colorValueBoxBackground: "#f1fbfc",
valueDec: 2,
valueInt: 2,
majorTicks: [
"0",
"5",
"10",
"15",
"20",
"25",
"30",
"35",
"40"
],
minorTicks: 4,
strokeTicks: true,
highlights: [
{
"from": 30,
"to": 40,
"color": "rgba(200, 50, 50, .75)"
}
],
colorPlate: "#fff",
colorBarProgress: "#CC2936",
colorBarProgressEnd: "#049faa",
borderShadowWidth: 0,
borders: false,
needleType: "arrow",
needleWidth: 2,
needleCircleSize: 7,
needleCircleOuter: true,
needleCircleInner: false,
animationDuration: 1500,
animationRule: "linear",
barWidth: 10,
}).draw();
// Create Humidity Gauge
var gaugeHum = new RadialGauge({
renderTo: 'gauge-humidity',
width: 300,
height: 300,
units: "Humidity (%)",
minValue: 0,
maxValue: 100,
colorValueBoxRect: "#049faa",
colorValueBoxRectEnd: "#049faa",
colorValueBoxBackground: "#f1fbfc",
valueInt: 2,
majorTicks: [
"0",
"20",
"40",
"60",
"80",
"100"
],
minorTicks: 4,
strokeTicks: true,
highlights: [
{
"from": 80,
"to": 100,
"color": "#03C0C1"
}
],
colorPlate: "#fff",
borderShadowWidth: 0,
borders: false,
needleType: "line",
colorNeedle: "#007F80",
colorNeedleEnd: "#007F80",
needleWidth: 2,
needleCircleSize: 3,
colorNeedleCircleOuter: "#007F80",
needleCircleOuter: true,
needleCircleInner: false,
animationDuration: 1500,
animationRule: "linear"
}).draw();
// Function to get current readings on the webpage when it loads for the first time
function getReadings(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
console.log(myObj);
var temp = myObj.temperature;
var hum = myObj.humidity;
gaugeTemp.value = temp;
gaugeHum.value = hum;
}
};
xhr.open("GET", "/readings", true);
xhr.send();
}
if (!!window.EventSource) {
var source = new EventSource('/events');
source.addEventListener('open', function(e) {
console.log("Events Connected");
}, false);
source.addEventListener('error', function(e) {
if (e.target.readyState != EventSource.OPEN) {
console.log("Events Disconnected");
}
}, false);
source.addEventListener('message', function(e) {
console.log("message", e.data);
}, false);
source.addEventListener('new_readings', function(e) {
console.log("new_readings", e.data);
var myObj = JSON.parse(e.data);
console.log(myObj);
gaugeTemp.value = myObj.temperature;
gaugeHum.value = myObj.humidity;
}, false);
}
以下是这段代码的作用摘要:
- 初始化事件源协议;
- 为new_readings事件;
- 创建仪表;
- 从获取最新的传感器读数new_readings事件并将其显示在相应的仪表中;
- 当您第一次访问网页时,为当前传感器读数发出 HTTP GET 请求。
获取读数
当您第一次访问网页时,我们会请求服务器获取当前的传感器读数。否则,我们将不得不等待新的传感器读数到达(通过服务器发送的事件),这可能需要一些时间,具体取决于您在服务器上设置的时间间隔。
添加一个调用的事件侦听器获取读数在网页加载时运行。
// Get current sensor readings when the page loads
window.addEventListener('load', getReadings);
这窗户对象表示浏览器中打开的窗口。这添加事件监听器()方法设置一个函数,当特定事件发生时调用。在这种情况下,我们将调用获取读数页面加载时的功能('加载') 获取当前传感器读数。
现在,让我们来看看获取读数功能。创建一个新的XMLHttpRequest目的。然后,发送一个得到向服务器请求/读数网址使用打开()和发送()方法。
function getReadings() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/readings", true);
xhr.send();
}
当我们发送该请求时,ESP 将发送包含所需信息的响应。因此,我们需要处理收到响应时发生的情况。我们将使用onreadystatechange定义一个函数的属性,当就绪状态属性变化。这就绪状态财产持有的地位XMLHttpRequest. 请求的响应准备好时就绪状态是4个,状态是200.
- 就绪状态 = 4表示请求已完成,响应已准备就绪;
- 状态 = 200意思是“好的”
因此,请求应如下所示:
function getStates(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
… DO WHATEVER YOU WANT WITH THE RESPONSE …
}
};
xhr.open("GET", "/states", true);
xhr.send();
}
ESP 发送的响应是以下 JSON 格式的文本(这些只是任意值)。
{
"temperature" : "25.02",
"humidity" : "64.01",
}
我们需要使用以下方法将 JSON 字符串转换为 JSON 对象parse()方法。结果保存在myObj变量里。
var myObj = JSON.parse(this.responseText);
这myObj变量是一个包含温度和湿度读数的 JSON 对象。我们想用相应的读数更新仪表值。
更新仪表的值很简单。例如,我们的温度计称为仪表温度(稍后我们会看到),要更新一个值,我们可以简单地调用:gaugeTemp.value = NEW_VALUE. 在我们的例子中,新值是保存在myObj的JSON 对象。
gaugeTemp.value = myObj.temperature;
它与湿度相似(我们的湿度计称为仪表嗡嗡声).
gaugeHum.value = myObj.humidity;
这是完整的获取读数()功能。
function getReadings(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
console.log(myObj);
var temp = myObj.temperature;
var hum = myObj.humidity;
gaugeTemp.value = temp;
gaugeHum.value = hum;
}
};
xhr.open("GET", "/readings", true);
xhr.send();
}
创建仪表
canvas-charts 库允许您构建线性和径向仪表来显示您的读数。它提供了几个示例,并且使用起来非常简单。我们建议查看文档并探索所有仪表功能:
温度计
以下几行创建了显示温度的仪表。
// Create Temperature Gauge
var gaugeTemp = new LinearGauge({
renderTo: 'gauge-temperature',
width: 120,
height: 400,
units: "Temperature C",
minValue: 0,
startAngle: 90,
ticksAngle: 180,
maxValue: 40,
colorValueBoxRect: "#049faa",
colorValueBoxRectEnd: "#049faa",
colorValueBoxBackground: "#f1fbfc",
valueDec: 2,
valueInt: 2,
majorTicks: [
"0",
"5",
"10",
"15",
"20",
"25",
"30",
"35",
"40"
],
minorTicks: 4,
strokeTicks: true,
highlights: [
{
"from": 30,
"to": 40,
"color": "rgba(200, 50, 50, .75)"
}
],
colorPlate: "#fff",
colorBarProgress: "#CC2936",
colorBarProgressEnd: "#049faa",
borderShadowWidth: 0,
borders: false,
needleType: "arrow",
needleWidth: 2,
needleCircleSize: 7,
needleCircleOuter: true,
needleCircleInner: false,
animationDuration: 1500,
animationRule: "linear",
barWidth: 10,
}).draw();
要创建新的线性仪表,请使用新的 LinearGauge() 方法并将仪表的属性作为参数传递。
var gaugeTemp = new LinearGauge({
在下一行中,定义要放置图表的位置(必须是<画布>元素)。在我们的例子中,我们想把它放在<画布>HTML 元素与测量温度id——参见 HTML 文件部分。
renderTo: 'gauge-temperature',
然后,我们定义其他属性来自定义我们的仪表。名称不言自明,但我们建议查看所有可能的配置并更改仪表以满足您的需求。
最后,您需要应用画()在画布上实际显示仪表的方法。
}).draw();
特别注意,如果需要改变量程,需要改变最小值和最大值特性:
minValue: 0,
maxValue: 40,
您还需要调整主要标记轴上显示的值。
majorTicks: [
"0",
"5",
"10",
"15",
"20",
"25",
"30",
"35",
"40"
],
湿度计
创建湿度计是类似的,但我们使用新的 RadialGauge()代替函数,它被呈现给<画布>与测量湿度ID。请注意,我们应用画()仪表上的方法,以便将其绘制在画布上。
// Create Humidity Gauge
var gaugeHum = new RadialGauge({
renderTo: 'gauge-humidity',
width: 300,
height: 300,
units: "Humidity (%)",
minValue: 0,
maxValue: 100,
colorValueBoxRect: "#049faa",
colorValueBoxRectEnd: "#049faa",
colorValueBoxBackground: "#f1fbfc",
valueInt: 2,
majorTicks: [
"0",
"20",
"40",
"60",
"80",
"100"
],
minorTicks: 4,
strokeTicks: true,
highlights: [
{
"from": 80,
"to": 100,
"color": "#03C0C1"
}
],
colorPlate: "#fff",
borderShadowWidth: 0,
borders: false,
needleType: "line",
colorNeedle: "#007F80",
colorNeedleEnd: "#007F80",
needleWidth: 2,
needleCircleSize: 3,
colorNeedleCircleOuter: "#007F80",
needleCircleOuter: true,
needleCircleInner: false,
animationDuration: 1500,
animationRule: "linear"
}).draw();
处理事件
当客户收到仪表上的读数时更新仪表上的读数new_readings事件
创建一个新的事件源对象并指定发送更新的页面的 URL。在我们的例子中,它是/事件.
if (!!window.EventSource) {
var source = new EventSource('/events');
一旦你实例化了一个事件源,你就可以开始监听来自服务器的消息了添加事件监听器().
这些是默认的事件侦听器,如 AsyncWebServer 文档中所示。
source.addEventListener('open', function(e) {
console.log("Events Connected");
}, false);
source.addEventListener('error', function(e) {
if (e.target.readyState != EventSource.OPEN) {
console.log("Events Disconnected");
}
}, false);
source.addEventListener('message', function(e) {
console.log("message", e.data);
}, false);
然后,添加事件侦听器new_readings.
source.addEventListener('new_readings', function(e) {
当有新的读数可用时,ESP8266 发送一个事件(new_readings) 给客户。以下几行处理浏览器收到该事件时发生的情况。
source.addEventListener('new_readings', function(e) {
console.log("new_readings", e.data);
var myObj = JSON.parse(e.data);
console.log(myObj);
gaugeTemp.value = myObj.temperature;
gaugeHum.value = myObj.humidity;
}, false);
基本上,在浏览器控制台上打印新读数,将数据转换为 JSON 对象并在相应的仪表上显示读数。
Arduino 概述
将以下代码复制到您的 Arduino IDE 或main.cpp如果您使用的是 PlatformIO 文件。
/*********
Rui Santos
Complete instructions at https://RandomNerdTutorials.com/esp8266-web-server-gauges/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "LittleFS.h"
#include <Arduino_JSON.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create an Event Source on /events
AsyncEventSource events("/events");
// Json Variable to Hold Sensor Readings
JSONVar readings;
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;
// Create a sensor object
Adafruit_BME280 bme; // BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)
// Init BME280
void initBME(){
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
}
// Get Sensor Readings and return JSON object
String getSensorReadings(){
readings["temperature"] = String(bme.readTemperature());
readings["humidity"] = String(bme.readHumidity());
String jsonString = JSON.stringify(readings);
return jsonString;
}
// Initialize LittleFS
void initFS() {
if (!LittleFS.begin()) {
Serial.println("An error has occurred while mounting LittleFS");
}
Serial.println("LittleFS mounted successfully");
}
// Initialize WiFi
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void setup() {
Serial.begin(115200);
initBME();
initWiFi();
initFS();
// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", "text/html");
});
server.serveStatic("/", LittleFS, "/");
// Request for the latest sensor readings
server.on("/readings", HTTP_GET, [](AsyncWebServerRequest *request){
String json = getSensorReadings();
request->send(200, "application/json", json);
json = String();
});
events.onConnect([](AsyncEventSourceClient *client){
if(client->lastId()){
Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
}
// send event with message "hello!", id current millis
// and set reconnect delay to 1 second
client->send("hello!", NULL, millis(), 10000);
});
server.addHandler(&events);
// Start server
server.begin();
}
void loop() {
if ((millis() - lastTime) > timerDelay) {
// Send Events to the client with the Sensor Readings Every 30 seconds
events.send("ping",NULL,millis());
events.send(getSensorReadings().c_str(),"new_readings" ,millis());
lastTime = millis();
}
}
代码如何工作
让我们看一下代码,看看它是如何使用服务器发送的事件将读数发送到客户端的。
包括图书馆
这Adafruit_Sensor和Adafruit_BME280需要库来与 BME280 传感器接口。
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
这ESP8266WiFi,ESPAsyncWebServer和ESPAsyncTCP库用于创建 Web 服务器。
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
我们将使用 LittleFS 保存文件以构建 Web 服务器。
#include "LittleFS.h"
您还需要包括Arduino_JSON使处理 JSON 字符串更容易的库。
#include <Arduino_JSON.h>
网络凭证
在以下变量中插入您的网络凭据,以便 ESP8266 可以使用 Wi-Fi 连接到您的本地网络。
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
AsyncWebServer 和 AsyncEventSource
创建一个异步网络服务器80 端口上的对象。
AsyncWebServer server(80);
下面一行创建了一个新的事件源/事件.
AsyncEventSource events("/events");
声明变量
这readings 是一个 JSON 变量,用于保存 JSON 格式的传感器读数。
JSONVar readings;
这上次时间和定时器延时变量将用于每 30秒更新一次传感器读数。例如,我们将每 30 秒(30000 毫秒)获取一次新的传感器读数。您可以在定时器延时变量赋值的。
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;
创建一个Adafruit_BME280称为对象bme在默认的 ESP I2C 引脚上。
Adafruit_BME280 bme;
初始化 BME280 传感器
可以调用以下函数来初始化 BME280 传感器。
// Init BME280
void initBME(){
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
}
获取 BME280 读数
要从 BME280 温度中获取温度和湿度,请使用以下方法在bme实例中获取:
- bme.readTemperature() 方法
- bme.readHumidity()
这获取传感器读数()函数获取传感器读数并将它们保存在读数JSON 数组。
// Get Sensor Readings and return JSON object
String getSensorReadings(){
readings["temperature"] = String(bme.readTemperature());
readings["humidity"] = String(bme.readHumidity());
String jsonString = JSON.stringify(readings);
return jsonString;
}
这读数然后使用 将数组转换为 JSON 字符串变量字符串化()方法并保存在json字符串多变的。
该函数返回json字符串随当前传感器读数而变化。JSON 字符串具有以下格式(值只是出于解释目的的任意数字)。
{
"temperature" : "25",
"humidity" : "50"
}
Setup()
在里面setup(), 初始化串行监视器、Wi-Fi、文件系统和 BME280 传感器。
void setup() {
// Serial port for debugging purposes
Serial.begin(115200);
initBME();
initWiFi();
initFS();
处理请求
当你在root上访问ESP8266的IP地址/URL,发送存储在index.html文件来构建网页。
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", "text/html");
});
服务客户端请求的其他静态文件(style.cs和script.js).
server.serveStatic("/", LittleFS, "/");
当您收到请求时,发送包含当前传感器读数的 JSON 字符串/读数网址。
// Request for the latest sensor readings
server.on("/readings", HTTP_GET, [](AsyncWebServerRequest *request){
String json = getSensorReadings();
request->send(200, "application/json", json);
json = String();
});
这JSON变量保存从获取传感器读数()功能。要发送 JSON 字符串作为响应,发送()方法接受响应代码作为第一个参数(200), 第二个是内容类型 (“应用程序/json”) 最后是内容 (JSON多变的)。
服务器事件源
在服务器上设置事件源。
events.onConnect([](AsyncEventSourceClient *client){
if(client->lastId()){
Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
}
// send event with message "hello!", id current millis
// and set reconnect delay to 1 second
client->send("hello!", NULL, millis(), 10000);
});
server.addHandler(&events);
最后,启动服务器。
server.begin();
Loop()
在里面loop(),每 30 秒向浏览器发送带有最新传感器读数的事件以更新网页。
events.send("ping",NULL,millis());
events.send(getSensorReadings().c_str(),"new_readings" ,millis());
使用发送()上的方法事件对象并将要发送的内容和事件名称作为参数传递。在这种情况下,我们要发送由获取传感器读数()功能。这发送()方法接受一个类型的变量字符,所以我们需要使用c_str()方法来转换变量。事件的名称是new_readings.
通常,我们还会每隔 X 秒发送一次 ping 消息。该行不是强制性的。它用于在客户端检查服务器是否处于活动状态。
events.send("ping",NULL,millis());
上传代码和文件
插入网络凭据后,保存代码。转到 Sketch > Show Sketch Folder,然后创建一个名为 data的文件夹。
在该文件夹中,您应该保存 HTML、CSS 和 JavaScript 文件。
然后,将代码上传到您的 ESP8266 板。确保选择了正确的板和 COM 端口。另外,请确保您已添加网络凭据。
上传代码后,需要上传文件。进入 工具 > ESP8266 LittleFS 数据上传 ,等待文件上传。
当一切都成功上传后,以 115200 的波特率打开串行监视器。按下 ESP8266 EN/RST 按钮,它应该打印 ESP8266 IP 地址。
示范
打开浏览器并输入 ESP8266 的 IP 地址。您应该可以访问显示带有最新传感器读数的仪表的网页。
您还可以使用智能手机检查您的仪表(该网页是移动响应的)。
总结
在本教程中,您学习了如何创建 Web 服务器以显示线性和径向仪表中的传感器读数。例如,我们显示了 BME280 传感器的温度和湿度。您可以使用这些仪表显示可能对您的项目有意义的任何其他值。