☰
DHT11+ESP8266+OneNet搭建温湿度物联网监控系统
2026/9/29 2:00:54 网站建设 项目流程

这两年经常有朋友问我:家里放个传感器,能不能在手机上远程看温湿度?我做过好几套方案之后发现,最省钱、最容易复现的就是 DHT11 + ESP8266 + OneNet 这条链路。整套材料成本不到三十块钱,从接线到云端看到数据,一个下午就能跑通,非常适合物联网入门练手。这篇文章我会把完整过程写下来,包括硬件选型、接线、OneNet 平台配置、Arduino 代码、数据可视化和常见坑。如果你手里有 NodeMCU 或者 Arduino Uno,想学“传感器数据上云”,拿这套练手再合适不过。

1. 这套方案的整体设计与选型逻辑

1.1 温湿度传感器为什么选 DHT11

DHT11 是入门级数字温湿度传感器,内部用单总线协议,一个引脚就能把温度和湿度读出来,内部还带了校准。它的测量范围是 0~50℃、20%~90% 相对湿度,精度不算高,温度 ±2℃,湿度 ±5%,但做家庭环境监测、小型温室、机房告警这类场景完全够用。真正吸引人的是它的易用性:在 Arduino 生态里,一个 DHT 库就能把两个数值读出来,新手照着抄也能跑。

它的缺点也很明显。第一,采样周期最长约 1 秒,也就是说两次读取之间的间隔必须大于 1 秒,读太快会反复失败。第二,长期使用后湿度数据容易漂移,毕竟是十几块钱以内的小传感器,不能拿它当实验室基准。如果你的项目要精确控温,或者对数据一致性要求高,直接换 DHT22/AM2302,精度高一个量级,代码几乎不用改。DHT11 真正的定位,是让你用最低的成本把“采集-联网-上云-展示”这条闭环跑通。

1.2 ESP8266 和 OneNet 各自解决什么问题

ESP8266 是一颗带 WiFi 的单片机,主频可以跑到 160MHz,内部已经集成了 TCP/IP 协议栈,所以它天生就是干联网这件事的。在 Arduino 生态里,ESP8266 有两种用法:一是以 NodeMCU 开发板的形式直接当主控芯片,二是作为普通 WiFi 透传模块配合 Arduino Uno 使用。不管哪种用法,它解决的核心问题只有一个:把 DHT11 读到的温湿度数据送进互联网。

OneNet 是中国移动的物联网开放平台,解决的问题是数据到了云端之后怎么办。它提供设备接入、数据存储、API 查询、可视化面板和告警规则,个人开发免费额度足够用。简单理解,OneNet 就是把传感器数据变成云端数据库,再通过网页、手机、API 让其他程序随时取用。数据链路上分工很明确:DHT11 负责感知,ESP8266 负责搬运,OneNet 负责保管和展示,三者各司其职,正好组成了物联网项目最典型的闭环。

1.3 NodeMCU 一体方案和 Uno+ESP8266 透传方案怎么选

标题里同时出现了 Arduino 和 ESP8266,实际落地有两条路线。我的建议是优先用 NodeMCU 开发板直接当主控,因为它本身就是 Arduino 兼容板,在 Arduino IDE 里写代码的方式和 Uno 几乎一样,一块板同时搞定主控和 WiFi,接线少、故障点少。这也是目前社区里最主流的做法,教程最多,遇到问题也最容易搜到答案。

另一条路线是手里只有 Arduino Uno,再外挂一个 ESP8266-01 模块,通过串口 AT 指令让 ESP8266 联网透传。这条路线不是不行,但要处理电平转换(ESP8266 是 3.3V,Uno 是 5V)、AT 固件刷写、串口数据分包解析,调试成本翻倍。除非你手头正好有 Uno 和 ESP8266-01,否则没必要折磨自己。我帮别人搭这套系统时,全部改用 NodeMCU,省下的时间都花在调云端业务逻辑上,性价比高得多。

2. 硬件清单、接线与供电注意事项

2.1 需要准备的材料清单

  • NodeMCU 开发板(ESP-12E/ESP-12F 均可)1 块,约 10~15 元
  • DHT11 温湿度传感器模块 1 个,约 3~8 元,建议买模块而不是裸传感器
  • 母对母杜邦线至少 3 根
  • 面包板 1 块(可选,方便插拔)
  • Micro USB 数据线 1 根,注意要能传数据的,不是纯充电线

这个清单里最需要留意的是数据线。很多 NodeMCU 插电脑没反应,八成是手里的线只带电源不带数据传输。另外建议多备一块 DHT11,这玩意儿便宜,但新手很容易因为接错线直接烧掉,我实验桌上至少烧过三块。买回来的模块先看丝印,一般标 VCC、DATA(有的标 OUT)、GND 三个脚,个别模块有四个脚,多出来的是 NC 空脚,不用接。

2.2 DHT11 的接线与上拉电阻问题

NodeMCU 和 DHT11 的接线非常简单:DHT11 的 VCC 接 NodeMCU 的 3V3,GND 接 GND,DATA 接一个 GPIO。代码里我习惯用 GPIO4,也就是开发板丝印上的 D2 引脚。如果你用的是裸 DHT11(三根引脚直接焊出来的那种),DATA 和 VCC 之间必须接一只 4.7kΩ 到 10kΩ 的上拉电阻,否则单总线空闲时电平不稳定,读数会时好时坏。买模块版就把这个电阻焊好了,所以新手我更推荐直接买模块。

单总线协议的原理不复杂:主机发起起始信号后,传感器回传 40 个 bit,依次是湿度整数、湿度小数、温度整数、温度小数和校验和。Arduino 里的 DHT 库把这些底层时序全部封装好了,你只需要在代码里指定引脚号和传感器型号为 DHT11,其他交给库处理。理解这一点就够了,真让你用 GPIO 模拟时序去读 DHT11,反而容易因为时序不准读不到数据。

2.3 供电与电平匹配:这块最容易踩坑

NodeMCU 板载逻辑电平是 3.3V,虽然很多 DHT11 模块标着支持 3~5.5V 供电,但为了电平匹配,我建议直接把 VCC 接 3V3,不要接 5V。原因在于:如果模块由 5V 供电,DATA 脚输出的高电平很可能接近 5V,直接灌进 ESP8266 的 GPIO,长期跑有击穿风险。很多老教程把 DHT11 接 5V 也能跑,那是运气好,不是设计对。

另外要注意 NodeMCU 的 3V3 引脚输出电流有限,如果板子上同时带 OLED 屏幕、舵机这类外设,要考虑总电流。只带 DHT11 是完全没问题的。整块板子用电脑 USB 供电就能跑,不需要额外电源。但如果你发现 WiFi 连接瞬间板子反复重启,十有八九是 USB 口供电不足,这时候换一个 5V/1A 以上的充电头供电,问题通常直接消失。

3. OneNet 云端配置:产品、设备、APIKey 一个都不能少

3.1 注册登录与新旧版本入口差异

打开 OneNet 官网,用手机号注册登录,进入控制台。这里必须先提醒一句:OneNet 平台这几年改版过几次,你看到的界面可能和网上很多老教程对不上。老教程里的“多协议接入”“创建产品→设备→数据流”入口,在某些账号下已经变成了“开发者中心”或“产品开发”。新注册用户通常进的是新版 OneNET Studio,旧版入口需要单独找“多协议接入”。

判断你在哪个版本,就看创建产品时要不要选择协议类型。旧版会让你选 MQTT、HTTP、TCP;新版则是先创建产品,再在产品下添加物模型。两边的数据流逻辑不同,代码接入方式也不同。下文我会以新版为主、旧版做对照说明。如果你照着老文章怎么配都不对,大概率就是踩了版本入口差异这个坑。

3.2 创建产品、设备和物模型数据流

以新版 OneNET Studio 为例:在控制台创建一个产品,产品名称随意,比如“客厅温湿度”,协议选 MQTT,数据格式选 JSON。创建完成后会得到一个产品 ID,这个要记下来,后面代码里要用。然后在这个产品下添加设备,设备名称填 device01,系统会生成一个设备密钥 DeviceSecret,同样要保存好。

接着是定义物模型。在产品开发页面找到物模型或产品模型,添加两个属性:temperature,类型 float,标识符填 temperature;humidity,类型 float,标识符填 humidity。这里的标识符必须和代码里上报 JSON 的字段名严格一致。比如物模型里标识符叫 temperature,代码里上报的是 temp,云端会直接丢弃数据,而且不一定给提示。旧版流程则是:多协议接入→MQTT 协议→创建产品→创建设备→为设备添加数据流模板,数据流 id 设为 temperature 和 humidity,本质都是在定义“你的设备会上报哪些字段”。

3.3 MQTT 和 HTTP 两种上传方式怎么选

对比项MQTTHTTP
实时性长连接,毫秒级推送每次请求独立建连,延迟较高
代码量需要 PubSubClient 库,约几十行用 ESP8266HTTPClient,代码更简单
设备在线状态平台能看到在线/离线在线状态需要自己维护
双向通信支持下行控制指令服务端难以主动推给设备
适用场景连续上报、远程控制低频上报、一次性查询

DHT11 项目要按固定周期连续上报温湿度,以后大概率还会接继电器、LED 做远程控制,所以我选 MQTT。MQTT 本质是一条长连接管道,设备连上之后可以持续发布消息,服务器也可以往下推指令。HTTP 则适合“每隔一分钟 POST 一次,发完就断开”的场景,代码更简单,但不太适合做双向控制。具体实现上,用 PubSubClient 库写 MQTT 客户端并不复杂,代码部分后面详细讲。

3.4 用 MQTTX 先把连接参数验证一遍

写 Arduino 代码之前,强烈建议先在电脑上装一个 MQTTX 客户端,把 OneNet 的连接参数先验证一遍。这样可以避免“代码看着没问题、实际参数填错”的无效排查。以新版 Studio 为例,在 MQTTX 里这样填:Host 填 mqtt.heclouds.com,端口填 1883,Client ID 填“产品ID.设备名称”,用户名填设备名称,密码填设备密钥 DeviceSecret。

连接成功后,向$sys/产品ID/设备名称/thing/property/post这个主题发布一条 JSON,内容类似{"id":"1","version":"1.0","params":{"temperature":26.5,"humidity":55}}。发布完去 OneNet 控制台的设备日志里看,如果能查到数据,说明平台侧一点问题都没有,接下来只管写板子代码。这一步看着多花了十分钟,实际能省掉后续一半的联调时间。

4. Arduino IDE 环境搭建与核心代码解析

4.1 开发环境准备:开发板包与第三方库

Arduino IDE 装好后,首先要添加 ESP8266 开发板支持。打开“文件→首选项→附加开发板管理器网址”,填入 ESP8266 官方的 JSON 地址,然后在“工具→开发板→开发板管理器”里搜索 esp8266,安装对应版本。国内网络下载可能会慢,耐心等,或者换成社区镜像源。这一步完成后,你的 Arduino IDE 才能识别 NodeMCU 这类 ESP8266 开发板。

接着安装两个库:一个是 DHT sensor library by Adafruit,用来读 DHT11;另一个是 PubSubClient by Nick O‘Leary,用来做 MQTT 客户端。在“项目→加载库→管理库”里搜索安装即可。DHT 库还依赖 Adafruit Unified Sensor 库,安装时会提示,一并装上。如果你用 PlatformIO 写代码,添加库的逻辑类似,只是在 platformio.ini 里声明库依赖即可。开发环境搞定后,就可以直接上手写代码了。

4.2 完整代码示例与逐段解释

以 NodeMCU 一体方案为例,下面是新版 Studio MQTT 接入的完整代码,用 Arduino IDE 编译上传。

#include <ESP8266WiFi.h> #include <PubSubClient.h> #include <DHT.h> #define DHTPIN 4 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); const char* ssid = "你的WiFi名"; const char* wifiPwd = "你的WiFi密码"; const char* mqttHost = "mqtt.heclouds.com"; const int mqttPort = 1883; const char* productId = "你的产品ID"; const char* deviceName = "device01"; const char* deviceSecret = "你的设备密钥"; WiFiClient espClient; PubSubClient client(espClient); void connectMqtt() { while (!client.connected()) { String clientId = String(productId) + "." + deviceName; Serial.print("MQTT连接中..."); if (client.connect(clientId.c_str(), deviceName, deviceSecret)) { Serial.println("成功"); } else { Serial.print("失败,状态码:"); Serial.print(client.state()); Serial.println(",5秒后重试"); delay(5000); } } } void setup() { Serial.begin(115200); dht.begin(); WiFi.mode(WIFI_STA); WiFi.begin(ssid, wifiPwd); Serial.print("连接WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("成功"); client.setServer(mqttHost, mqttPort); } void loop() { if (!client.connected()) { connectMqtt(); } client.loop(); float h = dht.readHumidity(); float t = dht.readTemperature(); if (isnan(h) || isnan(t)) { Serial.println("DHT11 读取失败"); return; } String payload = String("{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"temperature\":") + t + ",\"humidity\":" + h + "}}"; String topic = String("$sys/") + productId + "/" + deviceName + "/thing/property/post"; client.publish(topic.c_str(), payload.c_str()); Serial.println("上报:" + payload); delay(10000); }

代码逻辑很直观。setup 里先初始化串口、DHT11,再连 WiFi、设置 MQTT 服务器地址和端口。loop 里先检查 MQTT 连接是否存活,断开就重连,然后读一次温湿度,拼成 JSON,发布到指定 topic,最后延时 10 秒进入下一次上报。这里有两个容易忽略的点:一是client.loop()必须放在 loop 里持续调用,它是维持 MQTT 心跳和收包的核心函数,漏掉它连接很快就会断开;二是上报间隔设置成 10 秒,既满足 DHT11 的采样周期要求,也不会让云端数据点刷得太快。

4.3 几个必须理解的参数和格式

第一个是clientId,新版 Studio 严格要求是“产品ID.设备名称”,中间用点连接,顺序不能反。用户名是设备名称,密码是设备密钥,三者错一个都连不上。第二个是上报 topic 的格式:$sys/产品ID/设备名称/thing/property/post,这里的字符要和控制台显示的产品 ID、设备名称完全一致,大小写也不能错。第三个是 payload 的 JSON 结构,新版要求包含id、version、params三层,params里面的字段名要与物模型属性标识符一致。

很多人就是在这一步翻车的:平台里物模型标识符叫 temperature,代码里拼 JSON 时写成了 temp,云端直接静默丢弃,控制台查不到任何数据。所以写代码之前,先登录平台把物模型的标识符抄出来,再回去改代码。代码里拼接字符串时也要注意转义,String 类型的拼接在大括号和引号这里最容易出错,建议拼接完先在串口监视器里打印出来检查一遍。

5. 云端数据查看、可视化与告警

5.1 在 OneNet 控制台确认数据是否上报成功

板子跑起来后,回 OneNet 控制台看设备状态,正常情况下 10 秒内设备会显示“在线”。然后进入“设备调试”或“物模型数据”页面,应该能看到 temperature、humidity 两个属性在持续刷新数据点。如果你用的是旧版多协议接入,则在设备列表点进设备,切到“数据流”标签页,能看到 temperature、humidity 数据流下面的数据点。

如果设备显示在线但没有新数据,优先检查 topic 和 JSON 格式。OneNet 对格式错误的数据往往不会给明确提示,而是直接丢弃,所以这时候要把 Arduino IDE 的串口监视器打开,确认代码里 publish 的 payload 打印出来是合法 JSON。串口监视器波特率要选 115200,否则看到的就是乱码。数据能稳定刷新出来,整套链路就算真正通了。

5.2 用可视化面板做简易监控大屏

数据进云端只是第一步,能看得舒服才是目标。OneNet 控制台里提供了数据可视化能力,旧版叫“应用管理”,新版叫“数据可视化”或“项目”。创建一个可视化项目后,拖一个折线图组件,数据源绑定到 temperature 数据流,再拖一个仪表盘绑定 humidity,一个简单的监控页面就出来了。不需要写前端代码,全是图形化拖拽配置。

如果你只想自己看,登录控制台打开这个页面即可。想做成手机随时能看的小面板,可以看平台是否提供页面分享链接,生成后设好访问权限,在手机浏览器打开就行。可视化面板的本质是把平台查询 API 封装成了图形组件,所以它的刷新频率、数据范围这些参数都可以在组件设置里调。这一步虽然不会影响数据采集,但做完之后的成就感完全不一样,看着数字变成曲线,你会觉得这套系统真的“活”了。

5.3 加一个温度超限告警

OneNet 支持触发器或告警规则,可以新建规则:当 temperature 大于某个阈值,比如 30℃,就通过邮件、短信或 Webhook 通知你。这个功能在环境监测场景里特别有用,机房温度超标、温室湿度太低,系统能主动报警,而不是等人去查。设方法一般是:控制台里找到“触发器”或“告警规则”,新建规则,选择设备、数据流、比较条件和阈值,再配置通知方式。

短信通知通常有配额限制,测试阶段建议先用邮件或 Webhook。告警规则和可视化面板一样,属于锦上添花的功能,但能让这套系统从“能看”变成“会用”。举个例子,我在办公室搭的那套,就设了一个温度高于 32℃ 的邮件告警,夏天空调出问题的时候,人还没到工位邮件就先到了。等你把基础链路跑通,这些功能都可以慢慢加。

6. 常见问题与排查技巧实录

6.1 高频问题速查表

症状可能原因解决办法
DHT11 返回 NaN引脚接错、DHT 库型号不对、读取间隔太短核对接线和 DHTPIN,确认 DHTTYPE 为 DHT11,两次读取间隔大于 1 秒
串口输出乱码上位机波特率与代码不一致两边统一设 115200
WiFi 连不上密码错误、路由器开了 5G、信号太弱代码里确认 SSID 和密码,连 2.4GHz 频段
MQTT 连接失败clientId/用户名/密码不对、端口错误用 MQTTX 先验证参数,再对照代码逐一核对
设备在线但无数据topic 或 JSON 格式错误、标识符不一致打印 payload 和 topic,逐字符核对平台配置
上报几次后掉线WiFi 信号不稳定、供电不足降低上报频率,换 5V/1A 充电头供电
HTTP 方式 401/403APIKey 缺失或权限不足在请求头加 api-key,确认 APIKey 对设备和数据流有权限

这个表是我平时帮人排查问题时最常用的一张清单,基本覆盖了新手会踩的绝大多数坑。碰到问题时不要盯着代码看,先按症状归类,然后一项一项排除,比乱猜高效得多。

6.2 几个说出来都是泪的避坑经验

先说 DHT11 的采样周期。这颗传感器手册上写的最高采样频率是 1Hz,也就是说两次读取之间至少隔 1 秒。新手最容易犯的错是 loop 里读一次、打印一次,看起来没什么问题,但 Arduino 的循环跑得飞快,实际读取间隔可能不到 100ms,结果就是频繁返回错误值。我习惯把上报周期设在 10 秒以上,既满足传感器要求,也避免 OneNet 数据点刷得太快。

再说供电。NodeMCU 如果用电脑 USB 口供电,偶尔会出现 WiFi 连接瞬间电流不足导致重启,特别是同时带着传感器和屏幕的时候。遇到这种“灵异现象”,先别怀疑代码,换一个 5V/1A 以上的充电头供电试试,很多问题直接消失。最后是版本问题。OneNet 新旧平台切换这几年改得勤,很多老教程里的 IP 端口只适用于旧版。操作时以控制台“接入文档”里的实际参数为准,不要迷信博客里的截图,这是最稳妥的方法。

6.3 数据不稳定时的排查顺序

如果数据时有时无、断断续续,不要急着改代码。我习惯按这个顺序排查:先看串口监视器,DHT11 是否每次都能读到有效值,排除传感器本身的问题;再看 WiFi 信号强度,ESP8266 的板载天线很一般,离路由器太远就会发送失败;然后看 MQTT 是否频繁重连,如果client.state()反复变化,问题在链路而不是上传逻辑;最后再检查 JSON 格式和 topic。

我自己的做法是先把上报周期从 10 秒调到 60 秒,排除“刷太猛被平台限流”的干扰,稳定后再把周期调回来。还有一个技巧:把串口打印的 payload 复制到任何一个 JSON 校验工具里检查一下,很多字符串拼接错误都能在这一步暴露出来。数据稳定之后,再去做可视化、告警这些进阶功能,路子走顺了,后面加设备、换传感器都只是量的变化。

这套系统我自己前前后后搭了不下十遍,最大的感触是物联网项目七成的时间都花在联调上,而联调又集中在参数匹配和网络链路。DHT11 + ESP8266 + OneNet 这个组合虽然便宜又入门,但把这条链路完整跑通之后,你对传感器读取、WiFi 通信、MQTT 协议、云端建模的理解都会上一个台阶。后续想扩展,可以在同一条 MQTT 链路上加继电器做远程开关,或者把数据转发给微信小程序;如果觉得 DHT11 精度不够,传感器换成 DHT22,代码只需要改一行。就说这么多,动手去接线吧,数据上线那一刻的成就感,比看十篇教程都值。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询