ESP8266+DHT22物联网环境监测仪项目总结
一、项目概述
本项目旨在基于ESP8266开发板、DHT22温湿度传感器,搭建一套可实现公网远程访问的物联网环境监测系统。系统核心功能为实时采集环境温湿度数据,通过WiFi传输至本地服务器,再借助内网穿透技术实现全球公网访问,最终通过Web页面直观展示监测数据,完成从“硬件采集→数据传输→云端访问→可视化展示”的物联网全链条闭环。
项目从基础的局域网监测入手,逐步升级为可公网访问的标准物联网项目,全程解决了硬件接线、开发环境配置、数据传输、公网穿透等核心问题,最终实现“随时随地查看环境温湿度”的目标,适用于家庭、实验室、小型机房等场景的环境监测,同时为物联网入门学习提供了完整的实操案例。
二、项目目标
2.1 基础目标
完成ESP8266开发板与DHT22传感器的正确接线,实现温湿度数据的稳定采集。
配置Arduino IDE开发环境,编写ESP8266代码,实现WiFi连接与数据上传功能。
搭建Flask后端服务器,实现数据接收、存储与Web前端实时展示。
2.2 升级目标
通过ngrok内网穿透技术,打破局域网限制,实现公网远程访问监测数据。
解决数据传输过程中的兼容性问题(如HTTPS不兼容、网段不一致等),确保系统稳定运行。
形成完整的物联网全链条架构,为后续功能拓展(如报警、多设备管理)奠定基础。
三、硬件选型与接线
3.1 硬件选型
| 硬件名称 | 型号规格 | 用途 |
|---|---|---|
| 开发板 | ESP8266 Type-C口(NodeMCU 1.0) | 核心控制单元,负责传感器数据采集、WiFi连接、数据上传 |
| 温湿度传感器 | DHT22模块(带4.7kΩ上拉电阻) | 采集环境温度、湿度数据,输出数字信号 |
| 数据线 | Type-C数据线(带数据传输功能) | 连接ESP8266与电脑,用于代码上传和串口调试 |
3.2 硬件接线
⚠️ 接线前需断电操作,避免短路烧毁硬件;ESP8266为3.3V逻辑,严禁将DHT22模块VCC接5V。
| DHT22模块引脚 | ESP8266开发板引脚 | 备注 |
|---|---|---|
| VCC | 3.3V | 供电引脚,必须接3.3V,接5V会烧毁ESP8266 |
| GND | GND | 共地引脚,确保传感器与开发板电位一致,避免数据乱跳 |
| DATA | D4(GPIO2) | 数据引脚,与板载LED共用,不影响传感器正常工作 |
四、软件设计与实现
4.1 开发环境配置
4.1.1 Arduino IDE配置(ESP8266开发)
打开Arduino IDE,进入“文件→首选项”,添加ESP8266开发板索引地址(国内镜像源):https://mirrors.tuna.tsinghua.edu.cn/arduino-esp8266/package_esp8266com_index.json
进入“工具→开发板→开发板管理器”,搜索“ESP8266”并安装开发板包。
安装传感器依赖库:进入“工具→管理库”,搜索并安装“Adafruit DHT sensor library”和“Adafruit Unified Sensor”。
安装USB转串口驱动(CH340芯片),确保电脑能识别ESP8266的COM口。
4.1.2 后端环境配置(Flask服务器)
安装Python3环境,在终端执行命令安装依赖库:pip install flask flask-cors
创建Flask后端文件(server.py),实现数据接收、存储和Web前端展示功能。
4.1.3 公网穿透配置(ngrok)
注册ngrok免费账号,获取专属Authtoken,并在终端配置:ngrok config add-authtoken 你的Authtoken
启动HTTP隧道(兼容ESP8266):ngrok http --scheme=http 5000,获取公网域名。
4.2 核心代码实现
4.2.1 ESP8266端代码(数据采集与上传)
核心功能:连接WiFi、采集DHT22温湿度数据、通过HTTP POST请求将数据上传至公网服务器,关键代码如下(已适配ngrok公网访问):
#include <ESP8266WiFi.h>
#include <DHT.h>
// WiFi配置(替换为自身WiFi信息)
const char* WIFI_SSID = "你的WiFi名称";
const char* WIFI_PASS = "你的WiFi密码";
// 公网服务器配置(ngrok HTTP域名)
const char* SERVER_IP = "xxxx-xx-xx-xx-xx.ngrok.io";
const int SERVER_PORT = 80;
// DHT22配置(DATA接D4引脚,GPIO2)
#define DHT_PIN 2
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);
WiFiClient client;
void setup() {
Serial.begin(115200);
dht.begin();
// 连接WiFi
Serial.print("正在连接WiFi: ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n✅ WiFi连接成功! 本地IP: " + WiFi.localIP().toString());
}
void loop() {
delay(5000); // 每5秒采集一次数据
// 读取温湿度数据
float humidity = dht.readHumidity();
float temp = dht.readTemperature();
// 检查数据读取是否成功
if (isnan(humidity) || isnan(temp)) {
Serial.println("❌ DHT22读取失败!");
return;
}
Serial.printf("✅ 采集成功: 温度=%.1f℃ 湿度=%.1f%%\n", temp, humidity);
// 连接公网服务器并发送数据
if (!client.connect(SERVER_IP, SERVER_PORT)) {
Serial.println("❌ 服务器连接失败!");
return;
}
// 构建JSON数据
String postData = "{\"temp\":" + String(temp) + ",\"humidity\":" + String(humidity) + "}";
// 发送HTTP POST请求
client.println("POST /api/upload HTTP/1.1");
client.println("Host: " + String(SERVER_IP));
client.println("Content-Type: application/json");
client.println("Content-Length: " + String(postData.length()));
client.println("Connection: close");
client.println();
client.println(postData);
// 读取服务器响应
delay(100);
while (client.available()) {
String line = client.readStringUntil('\r');
Serial.println(line);
}
client.stop();
Serial.println("----------------------------------------");
}
4.2.2 Flask后端代码(数据接收与展示)
核心功能:提供API接口接收ESP8266上传的数据,存储数据(内存存储,适合测试),并提供Web页面实时展示温湿度,关键代码如下:
from flask import Flask, request, jsonify, render_template_string
from flask_cors import CORS
import time
from threading import Lock
app = Flask(__name__)
CORS(app) # 允许跨域请求,适配公网访问
# 内存存储数据(重启后清空,可替换为MySQL实现持久化)
sensor_data = []
data_lock = Lock()
# Web前端页面模板(嵌入式,无需单独创建HTML文件)
HTML_PAGE = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESP8266 物联网环境监测站</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', sans-serif; }
body { background: #f0f2f5; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
.card { background: white; padding: 40px 60px; border-radius: 16px; box-shadow: 0 8px 32px rgba(0,0,0,0.1); text-align: center; }
h1 { color: #1a1a1a; margin-bottom: 30px; font-size: 28px; }
.data-group { margin: 20px 0; }
.data-label { color: #666; font-size: 16px; margin-bottom: 8px; }
.data-value { font-size: 56px; font-weight: bold; }
.temp { color: #ff6b6b; }
.hum { color: #4dabf7; }
.update-time { color: #999; font-size: 14px; margin-top: 20px; }
</style>
</head>
<body>
<div class="card">
<h1>🌡️ 实时环境监测</h1>
<div class="data-group">
<div class="data-label">当前温度</div>
<div class="data-value temp" id="temp">--.- °C</div>
</div>
<div class="data-group">
<div class="data-label">当前湿度</div>
<div class="data-value hum" id="hum">--.- %</div>
</div>
<div class="update-time">最后更新: <span id="time">--</span></div>
</div>
<script>
// 每2秒刷新一次数据
function fetchData() {
fetch('/api/latest')
.then(res => res.json())
.then(data => {
if (data) {
document.getElementById('temp').innerText = data.temp.toFixed(1) + ' °C';
document.getElementById('hum').innerText = data.humidity.toFixed(1) + ' %';
document.getElementById('time').innerText = new Date().toLocaleString();
}
})
.catch(err => console.error('获取数据失败:', err));
}
setInterval(fetchData, 2000);
fetchData(); // 页面加载时立即获取一次
</script>
</body>
</html>
"""
# 1. 接收ESP8266上传数据的接口
@app.route('/api/upload', methods=['POST'])
def upload_data():
try:
data = request.get_json()
if not data or 'temp' not in data or 'humidity' not in data:
return jsonify({"status": "error", "msg": "数据格式错误"}), 400
# 添加时间戳
data['timestamp'] = time.time()
data['time_str'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(data['timestamp']))
with data_lock:
sensor_data.append(data)
# 只保留最近100条数据,防止内存溢出
if len(sensor_data) > 100:
sensor_data.pop(0)
print(f"✅ 收到数据: {data['time_str']} 温度={data['temp']}℃ 湿度={data['humidity']}%")
return jsonify({"status": "success"}), 200
except Exception as e:
return jsonify({"status": "error", "msg": str(e)}), 500
# 2. 前端获取最新数据的接口
@app.route('/api/latest')
def get_latest_data():
with data_lock:
if sensor_data:
return jsonify(sensor_data[-1])
return jsonify(None)
# 3. 首页,展示监测页面
@app.route('/')
def index():
return render_template_string(HTML_PAGE)
if __name__ == '__main__':
# host=0.0.0.0 允许局域网和公网访问,port=5000与ESP8266代码一致
app.run(host='0.0.0.0', port=5000, debug=False)
五、系统实现与测试
5.1 系统实现流程
硬件搭建:按接线表完成ESP8266与DHT22的连接,用Type-C数据线连接开发板与电脑。
环境配置:完成Arduino IDE、Flask后端、ngrok的配置,确保各环境正常运行。
代码上传:修改ESP8266代码中的WiFi信息和ngrok公网域名,上传代码至开发板。
系统启动:运行Flask后端服务器,启动ngrok HTTP隧道,ESP8266自动连接WiFi并上传数据。
公网测试:用手机流量(外网)访问ngrok公网域名,查看实时温湿度数据。
5.2 测试结果
5.2.1 硬件测试
ESP8266开发板供电正常(红灯常亮),DHT22传感器采集数据稳定,串口监视器显示“采集成功: 温度=xx.x℃ 湿度=xx.x%”,无数据乱跳或读取失败现象。
5.2.2 数据传输测试
ESP8266成功连接WiFi,能正常向公网服务器发送数据,Flask后端终端显示“收到数据”日志,串口监视器显示“HTTP/1.1 200 OK”,说明数据传输成功。
5.2.3 公网访问测试
用手机、外网电脑访问ngrok公网域名,能正常打开Web监测页面,页面每2秒刷新一次温湿度数据,与传感器采集的数据一致,公网访问稳定。
5.3 系统运行状态
系统整体运行稳定,数据采集间隔5秒,传输延迟≤1秒,公网访问响应迅速,无卡顿、断连现象,达到项目预设目标。
六、项目过程中遇到的问题与解决方案
| 问题描述 | 解决方案 | 解决效果 |
|---|---|---|
| Arduino IDE安装ESP8266开发板包失败,下载编译器工具链卡住 | 更换国内镜像源,清理缓存,或手动下载开发板包和工具链进行离线安装 | 成功安装ESP8266开发板包,能正常选择开发板型号 |
| ESP8266代码上传失败,提示“串口占用”“espcomm_upload_mem failed” | 关闭串口监视器,换带数据传输的Type-C线,上传时按住FLASH按键 | 代码成功上传至ESP8266,无上传报错 |
| ESP8266无法连接服务器,提示“服务器连接失败” | 确认ESP8266与电脑连同一个2.4G WiFi,修改SERVER_IP为电脑局域网IP,关闭防火墙 | ESP8266成功连接服务器,能正常发送数据 |
| ngrok启动报错“authentication failed” | 注册ngrok免费账号,获取Authtoken并在终端配置,完成邮箱验证 | ngrok成功启动,获取公网域名 |
| ESP8266通过ngrok公网域名无法上传数据 | 启动ngrok时添加--scheme=http参数,强制使用HTTP隧道,修改ESP8266代码端口为80 | ESP8266成功通过公网域名上传数据,公网访问正常 |
七、项目总结与展望
7.1 项目总结
本项目成功完成了ESP8266+DHT22物联网环境监测仪的搭建,实现了从硬件采集到公网访问的全链条功能。通过实操,掌握了ESP8266开发、传感器数据采集、WiFi数据传输、Flask后端开发、ngrok内网穿透等核心技术,解决了物联网项目中常见的环境配置、数据传输、公网访问等问题。
项目最终实现了“实时采集温湿度→WiFi传输→公网访问→Web可视化”的完整闭环,达到了预设的基础目标和升级目标,系统运行稳定,可满足小型场景的环境监测需求,同时为物联网入门学习提供了完整、可复现的实操案例。
7.2 项目展望
本项目可在现有基础上进行以下拓展,提升项目的实用性和专业性:
数据持久化:将内存存储替换为MySQL数据库,实现历史数据查询、导出报表功能。
报警功能:添加温湿度超标报警(蜂鸣器本地报警、微信/短信远程报警)。
硬件拓展:增加气压、光照、空气质量等传感器,实现多参数环境监测。
低功耗优化:对ESP8266进行深度睡眠配置,采用电池供电,实现便携化监测。
固定公网域名:升级ngrok付费版或使用云服务器,实现固定公网域名,无需每次重启ngrok修改代码。
多端适配:开发微信小程序、手机APP,实现更便捷的远程访问和设备管理。
八、项目心得
本次项目从基础的硬件接线到复杂的公网物联网落地,全程遇到了诸多问题,但通过逐步排查、查阅资料和实操调试,最终都得到了有效解决。通过本次项目,我深刻认识到物联网项目的核心是“全链条闭环”,任何一个环节(硬件、软件、网络)出现问题,都会导致整个系统无法正常运行。
同时,我也掌握了物联网开发的基本思路和方法,明白了“从简单到复杂、从本地到公网”的进阶逻辑,为后续学习更复杂的物联网项目(如多设备管理、远程控制)奠定了坚实的基础。此外,本次项目也让我体会到实操的重要性,只有动手实践,才能真正理解技术原理,解决实际开发中的问题。
评论区
暂无评论,快来抢沙发吧~