ESP8266-Arduino网络编程实例-BME280传感器数据仪表显示

BME280传感器数据仪表显示

本文将演示如何通过Canvas Gauges库以仪表形式显示BME280传感器数据。

在实例中,Web页面通过Http向ESP8266的Web服务器请求BME280传感器的温度的湿度数据,然后将请求的数据显示在仪表盘中。
在这里插入图片描述

1、硬件准备

  • ESP8266 NodeMCU开发板一块
  • 数据线一条

硬件接线如下:

在这里插入图片描述

2、软件准备

  • Arduino IDE或VSCode + PlatformIO

在前面的文章中,对如何搭建ESP8266开发环境做了详细的介绍,请参考:

ESP8266 NodeMCU的引脚介绍在前面的文章中做了详细的介绍,请参考:

3、代码实现

1)ESP8266服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#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>

// WiFi连接信息
const char\* ssid = "\*\*\*\*\*";
const char\* ssid_pwd = "\*\*\*\*\*";

// 异步Web服务器
AsyncWebServer server(80);

// 创建异步事件
AsyncEventSource events("/events");

// JSON数据
JSONVar readings;


unsigned long lastTime = 0;
unsigned long timerDelay = 30000;

// BME280传感器
Adafruit_BME280 bme;

// 初始化BME280
void initBME(){
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
}

// 创建JSON数据
String getSensorReadings(){
readings["temperature"] = String(bme.readTemperature());
readings["humidity"] = String(bme.readHumidity());
String jsonString = JSON.stringify(readings);
return jsonString;
}

// 初始化LittleFS
void initFS() {
if (!LittleFS.begin()) {
Serial.println("An error has occurred while mounting LittleFS");
}
Serial.println("LittleFS mounted successfully");
}

// 初始化WiFi
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, ssid_pwd);
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.on("/", HTTP_GET, [](AsyncWebServerRequest \*request){
request->send(LittleFS, "/index.html", "text/html");
});

// Web服务器静态页面文件储存位置
server.serveStatic("/", LittleFS, "/");
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest \*request){
request->send(LittleFS, "/style.css", "text/css");
});

server.on("/gauge.min.js", HTTP_GET, [](AsyncWebServerRequest \*request){
request->send(LittleFS, "/gauge.min.js", "text/javascript");
});

server.on("/script.js", HTTP_GET, [](AsyncWebServerRequest \*request){
request->send(LittleFS, "/script.js", "text/javascript");
});


// 传感数据读取请求
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());
}

client->send("hello!", NULL, millis(), 10000);
});
// 注册服务器事件
server.addHandler(&events);

// 启动Web服务器
server.begin();
}

void loop() {
if ((millis() - lastTime) > timerDelay) {
events.send("ping",NULL,millis());
events.send(getSensorReadings().c\_str(),"new\_readings" ,millis());
lastTime = millis();
}
}


2)Web页面文件(index.html)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!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="/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>

3)Web页面CSS文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
}

3)Web页面逻辑控制脚本(script.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Get current sensor readings when the page loads 
window.addEventListener('load', getReadings);

// 创建温度仪表
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();

// 创建湿度仪表
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);
}

文章来源: https://iotsmart.blog.csdn.net/article/details/127441944