在这个项目中,您将学习如何使用 Arduino IDE 构建一个带有 DHT11 或 DHT22 的异步 ESP32 网络服务器来显示温度和湿度。
我们将构建的网络服务器会自动更新读数,而无需刷新网页。
通过这个项目,您将学到:
- 如何从 DHT 传感器读取温度和湿度;
- 使用ESPAsyncWebServer 库构建异步 Web 服务器;
- 无需刷新网页即可自动更新传感器读数。
目录
异步网络服务器
要构建 Web 服务器,我们将使用ESPAsyncWebServer 库,它提供了一种构建异步 Web 服务器的简单方法。构建异步 Web 服务器有几个优点,如库 GitHub 页面中所述,例如:
- “同时处理多个连接”;
- “当您发送响应时,您可以立即准备好处理其它连接,而服务器正在后台负责发送响应”;
- “处理模板的简单模板处理引擎”;
所需零件
要完成本教程,您需要以下部分:
- ESP32 开发板
- DHT22 或 DHT11 温湿度传感器
- 4.7k欧姆电阻
- 面包板
- 连接线
原理图
在进入网络服务器之前,您需要将 DHT11 或 DHT22 传感器连接到 ESP32,如下面的示意图所示。
在这种情况下,我们将数据引脚连接到通用输入接口 27, 但您可以将其连接到任何其它数字引脚。您可以将此示意图用于 DHT11 和 DHT22 传感器。
(该原理图使用带有 36 个 GPIO 的 ESP32 DEVKIT V1 模块版本——如果您使用的是其它型号,请检查您正在使用的电路板的引出线。)
注意:如果您使用带有 DHT 传感器的模块,它通常只有三个引脚。应标记引脚,以便您知道如何连接它们。此外,这些模块中的许多已经带有内部上拉电阻,因此您无需在电路中添加一个电阻。
安装库
您需要为此项目安装几个库:
- 从 DHT 传感器读取的DHT和Adafruit 统一传感器驱动程序库:
按照以下说明安装这些库:
安装 DHT 传感器库
要使用 Arduino IDE 从 DHT 传感器读取数据,您需要安装上面的DHT 传感器库。按照后续步骤安装库:
- 您的下载文件夹中应该有一个 .zip 文件夹
- 解压 .zip 文件夹,你应该得到 DHT-sensor-library-master 文件夹
- 重命名您的文件夹从 DHT-传感器-库-master 到DHT_sensor
- 将DHT_sensor 文件夹移动到您的 Arduino IDE 安装库文件夹
- 最后,重新打开你的 Arduino IDE
安装 Adafruit 统一传感器驱动程序
您还需要安装Adafruit 统一传感器驱动程序库才能使用 DHT 传感器。按照后续步骤安装库:
- 下载文件夹中应该有一个 .zip 文件夹
- 解压缩 .zip 文件夹,你可以看到 Adafruit_sensor-master 文件夹
- 重命名您的文件夹从 Adafruit_sensor-master 到 Adafruit_sensor
- 将Adafruit_sensor文件夹移动到您的 Arduino IDE 安装库文件夹
- 最后,重新打开你的 Arduino IDE
安装 ESPAsyncWebServer 库
按照以下步骤安装 ESPAsyncWebServer 库:
- 下载文件夹中应该有一个 .zip 文件夹
- 解压缩 .zip 文件夹,你可以看到ESPAsyncWebServer-master文件夹
- 重命名您的文件夹从 ESPAsyncWebServer-master 至ESPAsyncWebServer
- 将ESPAsyncWebServer 文件夹移动到 Arduino IDE 安装库文件夹
为 ESP32 安装异步 TCP 库
ESPAsyncWebServer 库需要 AsyncTCP库才能工作 。按照以下步骤安装该库:
- 单击此处下载 AsyncTCP 库。您的下载文件夹中应该有一个 .zip 文件夹
- 解压缩 .zip 文件夹,你应该得到AsyncTCP-master文件夹
- 重命名您的文件夹从 AsyncTCP 主机 到AsyncTCP
- 将AsyncTCP文件夹移动到 Arduino IDE 安装库文件夹
- 最后,重新打开你的 Arduino IDE
代码
我们将使用 Arduino IDE 对 ESP32 进行编程,因此请确保在继续之前安装了 ESP32环境。
打开您的 Arduino IDE 并复制以下代码:
在以下变量中插入您的网络凭据,代码将立即运行。
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
如何运作
在接下来的段落中,我们将解释代码的工作原理。如果您想了解更多信息或跳至演示部分查看最终结果,请继续阅读。
导入库
首先,导入所需的库。这无线上网,ESPAsyncWeb服务器和ESPA同步TCP需要构建 Web 服务器。这Adafruit_传感器和分布式哈希表需要从 DHT11 或 DHT22 传感器读取库。
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include <ESPAsyncTCP.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
WiFi网络凭据
在以下变量中插入您的网络凭据,以便 ESP32 可以连接到您的本地网络。
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
变量定义
定义 DHT 数据引脚连接到的 GPIO。在这种情况下,它连接到通用输入接口 27.
#define DHTPIN 27 // Digital pin connected to the DHT sensor
然后,选择您正在使用的 DHT 传感器类型。在我们的示例中,我们使用的是 DHT22。如果您使用的是另一种类型,您只需要取消注释您的传感器并注释所有其它类型。
#define DHTTYPE DHT22 // DHT 22 (AM2302)
实例化一个分布式哈希表具有我们之前定义的类型和引脚的对象。
DHT dht(DHTPIN, DHTTYPE);
创建一个异步网络服务器80 端口上的对象。
AsyncWebServer server(80);
读取温湿度函数
我们创建了两个函数:一个是读取温度(读取DHT温度()) 和另一个读取湿度 (读DHTHumidity()).
String readDHTTemperature() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
//float t = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(t);
return String(t);
}
}
获取传感器读数就像使用readTemperature()和readHumidity()上的方法dht目的。
float t = dht.readTemperature();
float h = dht.readHumidity();
我们还有一个返回两个破折号 (–) 的条件,以防传感器无法获取读数。
if (isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
读数以字符串类型返回。要将浮点数转换为字符串,请使用String()功能。
return String(t);
默认情况下,我们以摄氏度为单位读取温度。要获得华氏温度,请注释摄氏温度并取消注释华氏温度,以便您具有以下内容:
//float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float t = dht.readTemperature(true);
构建网页
进入 Web 服务器页面。
如上图所示,网页显示了一个标题和两个段落。有一段显示温度,另一段显示湿度。还有两个图标来undefined我们页面的样式。
让我们看看这个网页是如何创建的。
所有包含样式的 HTML 文本都存储在index_html 变量。现在我们将浏览 HTML 文本并查看每个部分的作用。
以下<meta>标记使您的网页在任何浏览器中都能响应。
<meta name="viewport" content="width=device-width, initial-scale=1">
从 fontawesome 网站加载图标需要<link>标签。
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
样式
在<style></style>标签之间,我们添加了一些 CSS 来undefined网页的样式。
<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h2 { font-size: 3.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 1.2rem; }
.dht-labels{
font-size: 1.5rem;
vertical-align:middle;
padding-bottom: 15px;
}
</style>
基本上,我们将 HTML 页面undefined为在没有边距的块中显示 Arial 字体的文本,并居中对齐。
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
我们undefined标题的字体大小(h2), 段落 (p) 和单位 (。单位) 的读数。
h2 { font-size: 3.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 1.2rem; }
读数标签的样式如下所示:
dht-labels{
font-size: 1.5rem;
vertical-align:middle;
padding-bottom: 15px;
}
所有前面的标签都应该放在<head>和</head>标签之间。这些标签用于包含用户不直接可见的内容,例如<meta>、<link>标签和样式。
正文
<body></body>标签内是我们添加网页内容的地方。
<h2></h2>标签向网页添加标题。在这种情况下,“ESP32 DHT 服务器”文本,但您可以添加任何其它文本。
<h2>ESP32 DHT Server</h2>
然后,有两段。一个显示温度,另一个显示湿度。段落由<p>和</p>标记分隔。温度段落如下:
<p>
<i class="fas fa-thermometer-half" style="color:#059e8a;"</i>
<span class="dht-labels">Temperature</span>
<span id="temperature">%TEMPERATURE%</span>
<sup class="units">°C</sup>
</p>
湿度的段落在以下片段中:
<p>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span class="dht-labels">Humidity</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units">%</sup>
</p>
<i>标签显示字体图标。
如何显示图标
要选择图标,请访问Font Awesome Icons 网站。
搜索您要查找的图标。例如,“thermometer”。
单击所需的图标。然后,您只需复制提供的 HTML 文本。
<i class="fas fa-thermometer-half">
要选择颜色,只需要将颜色以十六进制形式传递给样式参数即可,如下所示:
<i class="fas fa-tint" style="color:#00add6;"></i>
继续处理 HTML 文本……
下一行将“温度”一词写入网页。
<span class="dht-labels">Temperature</span>
% 符号之间的 TEMPERATURE 文本是温度值的占位符。
<span id="temperature">%TEMPERATURE%</span>
这意味着这个%TEMPERATURE%文本就像一个变量,它将被 DHT 传感器的实际温度值替换。HTML 文本上的占位符应位于 % 符号之间。
最后,我们添加度数符号。
<sup class="units">°C</sup>
<sup> </sup>标签使文本成为上标。
我们对湿度段落使用相同的方法,但它使用不同的图标和%HUMIDITY%占位符。
<p>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span class="dht-labels">Humidity</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units">%</sup>
</p>
自动更新
最后,我们的网页中有一些 JavaScript 代码可以每 10 秒自动更新一次温度和湿度。
HTML 文本中的脚本应该位于<script></script>标记之间。
<script>
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperature").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("humidity").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/humidity", true);
xhttp.send();
}, 10000 ) ;
</script>
为了更新后台的温度,我们有一个每 10 秒运行一次的函数setInterval()。
基本上,它在/temperature URL中发出请求以获取最新的温度读数。
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 10000 ) ;
当它收到该值时,它会更新 id 为温度.
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperature").innerHTML = this.responseText;
}
综上所述,上一节负责异步更新温度。对湿度读数重复相同的过程。
重要提示:由于 DHT 传感器获取读数的速度非常慢,如果您计划让多个客户端同时连接到 ESP32,我们建议增加请求间隔或删除自动更新。
处理器
现在,我们需要创建处理器()函数,它将用实际温度和湿度值替换我们 HTML 文本中的占位符。
String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATURE"){
return readDHTTemperature();
}
else if(var == "HUMIDITY"){
return readDHTHumidity();
}
return String();
}
当请求网页时,我们检查 HTML 是否有任何占位符。如果它找到%TEMPERATURE%占位符,我们通过调用读取DHT温度()之前创建的函数。
if(var == "TEMPERATURE"){
return readDHTTemperature();
}
如果占位符是%HUMIDITY%,我们返回湿度值。
else if(var == "HUMIDITY"){
return readDHTHumidity();
}
setup()
在函数 setup() 里面,初始化串行监视器以进行调试。
Serial.begin(115200);
初始化 DHT 传感器。
dht.begin();
连接到您的本地网络并打印 ESP32 IP 地址。
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
最后,添加下一行代码来处理 Web 服务器。
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readDHTTemperature().c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readDHTHumidity().c_str());
});
当我们对根 URL 发出请求时,我们发送存储在index_htmlvariable。我们还需要通过处理器函数,它将用正确的值替换所有占位符。
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
我们需要添加两个额外的处理程序来更新温度和湿度读数。当我们收到关于/temperature URL的请求时,我们只需要发送更新后的温度值。它是纯文本,应该作为字符发送,所以,我们使用c_str()方法。
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readDHTTemperature().c_str());
});
对湿度重复相同的过程。
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readDHTHumidity().c_str());
});
最后,我们可以启动服务器。
server.begin();
因为这是一个异步网络服务器,我们不需要在undefined().
void loop(){
}
这几乎就是代码的工作原理。
上传代码
现在,将代码上传到您的 ESP32。确保选择了正确的板和 COM 端口。
上传后,以115200的波特率打开串口监视器。按下ESP32复位按钮。ESP32 的 IP 地址应该打印在串口监视器中。
Web 服务器演示
打开浏览器并输入 ESP32 IP 地址。您的网络服务器应显示最新的传感器读数。
请注意,无需刷新网页即可自动更新温度和湿度读数。
总结
在本教程中,我们向您展示了如何使用 ESP32 构建异步 Web 服务器以显示来自 DHT11 或 DHT22 传感器的传感器读数以及如何自动更新读数。
不错