ESP8266 NodeMCU Web 服务器:在仪表盘中显示传感器读数

了解如何使用 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.安装库

要构建此项目,您需要安装以下库:

您可以使用 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_SensorAdafruit_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 传感器的温度和湿度。您可以使用这些仪表显示可能对您的项目有意义的任何其他值。

猜你喜欢

转载自blog.csdn.net/hhqidi/article/details/130983541