冰序小站

ESP8266+DHT22物联网环境监测仪项目总结

发布时间:2026-04-04 22:27:56

一、项目概述

本项目旨在基于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开发)

  1. 打开Arduino IDE,进入“文件→首选项”,添加ESP8266开发板索引地址(国内镜像源):https://mirrors.tuna.tsinghua.edu.cn/arduino-esp8266/package_esp8266com_index.json

  2. 进入“工具→开发板→开发板管理器”,搜索“ESP8266”并安装开发板包。

  3. 安装传感器依赖库:进入“工具→管理库”,搜索并安装“Adafruit DHT sensor library”和“Adafruit Unified Sensor”。

  4. 安装USB转串口驱动(CH340芯片),确保电脑能识别ESP8266的COM口。

4.1.2 后端环境配置(Flask服务器)

  1. 安装Python3环境,在终端执行命令安装依赖库:pip install flask flask-cors

  2. 创建Flask后端文件(server.py),实现数据接收、存储和Web前端展示功能。

4.1.3 公网穿透配置(ngrok)

  1. 注册ngrok免费账号,获取专属Authtoken,并在终端配置:ngrok config add-authtoken 你的Authtoken

  2. 启动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 系统实现流程

  1. 硬件搭建:按接线表完成ESP8266与DHT22的连接,用Type-C数据线连接开发板与电脑。

  2. 环境配置:完成Arduino IDE、Flask后端、ngrok的配置,确保各环境正常运行。

  3. 代码上传:修改ESP8266代码中的WiFi信息和ngrok公网域名,上传代码至开发板。

  4. 系统启动:运行Flask后端服务器,启动ngrok HTTP隧道,ESP8266自动连接WiFi并上传数据。

  5. 公网测试:用手机流量(外网)访问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,实现更便捷的远程访问和设备管理。

八、项目心得

本次项目从基础的硬件接线到复杂的公网物联网落地,全程遇到了诸多问题,但通过逐步排查、查阅资料和实操调试,最终都得到了有效解决。通过本次项目,我深刻认识到物联网项目的核心是“全链条闭环”,任何一个环节(硬件、软件、网络)出现问题,都会导致整个系统无法正常运行。

同时,我也掌握了物联网开发的基本思路和方法,明白了“从简单到复杂、从本地到公网”的进阶逻辑,为后续学习更复杂的物联网项目(如多设备管理、远程控制)奠定了坚实的基础。此外,本次项目也让我体会到实操的重要性,只有动手实践,才能真正理解技术原理,解决实际开发中的问题。

评论区

暂无评论,快来抢沙发吧~