FEATURED · 精选文章

ESP8266+DHT11+MQTT+OneNet远程温湿度监控实战指南

发布时间 / 2026/8/31 12:18:08
来源 / 创域科博编辑部
栏目 / 资讯中心
ESP8266+DHT11+MQTT+OneNet远程温湿度监控实战指南 简介本资源是一套基于ESP8266与DHT11传感器实现远程温湿度监控的嵌入式物联网实践方案面向嵌入式初学者、IoT开发者及高校课程设计者解决环境参数采集、Wi-Fi联网、MQTT协议接入云平台等典型物联网开发痛点。压缩包共46个文件含12个XML配置文件用于OneNet设备注册与数据流定义、10幅WebP格式界面截图展示OneNet仪表板效果、4个Java源码配套Android端简易监控客户端、3份README文档涵盖硬件连接、编译说明与部署流程以及核心C/Arduino代码main.cpp、mqtt_device_info.h等整体仅167KB轻量易导入。已有336人学习下载资源结构清晰分层include目录封装MQTT与传感器驱动头文件src/main.cpp实现温湿度周期采集、Wi-Fi连接、JSON数据组包与MQTT发布逻辑platformio.ini与CMakeLists.txt支持多环境编译适合快速复现、调试并拓展报警、OTA升级等进阶功能。 把 ESP8266、DHT11、MQTT 和 OneNet 这四个词拆开看每一个都是物联网入门圈里最常见的熟面孔但把它们串起来做一个远程温湿度监控这套组合直到今天依然是低成本 IoT 项目里最值得复刻的那个。我前后帮朋友做过好几版类似的监控终端从最开始在面包板上用杜邦线飞线到后来自己画 PCB 打样踩过的坑比写过的代码还多。这篇就把整个方案的来龙去脉、硬件接线、云端配置、代码实现和排障经验一次说透保证你照着做就能把数据稳定送上云端。这个项目本质上解决的是一个很朴素的痛点你想知道某个地方现在热不热、潮不潮但你又不能一直蹲在那儿盯着。无论是蔬菜大棚、机房、仓库、孵化箱还是家里养的多肉花房温湿度都是最基础也最关键的环境参数。用 ESP8266 做终端采集通过 MQTT 协议上报到 OneNet 平台你就能在手机、电脑上随时看到数据曲线甚至设置告警。整个过程没有复杂的前端后端开发一块十几块的开发板加一个几块钱的传感器就能跑起来非常适合刚入门物联网的朋友用来打通“采集-传输-上云”整条链路。我写这篇文章时尽量把原理和代码拆开讲不仅告诉你“怎么接”“怎么写”还会解释“为什么这么接”“为什么这么写”。因为你只有理解了背后的逻辑以后换传感器、换平台、换通信协议时才不会抓瞎。下面进入正题。1. 项目整体设计与方案选型1.1 核心架构拆解这个项目的完整数据链路是DHT11 传感器采集温度和湿度 → ESP8266 通过 GPIO 引脚读取数据 → 数据按照 MQTT 协议封装成报文 → 通过 WiFi 网络发送到 OneNet 平台的 MQTT Broker → 平台解析报文并存入数据库 → 用户在 OneNet 控制台查看实时数据或历史曲线。用一张图来表示就是“传感器 → 主控 → 网络 → 云平台 → 用户端”五层结构。每一层都有可替换的方案但我在这个项目里选的都是成熟度高、资料多、成本低的组合。比如传感器可以用 DHT22、SHT30主控可以用 ESP32平台可以用阿里云、巴法云、华为云但 DHT11 ESP8266 OneNet 这套组合对新手最友好踩坑成本最低。MQTT 在里面扮演的角色是“运输工”。它不关心你的数据是温湿度还是开关状态只负责把消息从一个节点搬运到另一个节点。ESP8266 作为发布者把温湿度数据发布到指定的主题TopicOneNet 平台作为订阅者接收这些数据。整个过程是异步的、解耦的设备端不需要关心云端处理逻辑云端下发指令时也不需要关心设备当前是否在线这种设计正是物联网场景下最常用的模式。1.2 为什么选这套方案ESP8266 DHT11 MQTT OneNet先说 ESP8266。市面上做 WiFi 模块的方案不少但 ESP8266 几乎是入门首选原因很简单便宜、功耗可控、生态成熟。NodeMCU 开发板带 USB 转串口芯片插上电脑就能烧录调试不需要额外的下载器。而且 Arduino 社区对 ESP8266 的支持非常完善库函数丰富到什么程度呢你基本不需要关心底层 WiFi 协议栈几行代码就能连上网。再说 DHT11。这个传感器的精度其实一般温度 ±2℃湿度 ±5%RH但它的优势是便宜且在绝大多数场景下够用。你要监控的是“变化趋势”和“异常报警”不是做精密计量所以没必要上 SHT30 这种高精度传感器。当然如果你预算充足、对精度有要求后面换 DHT22 也只是改一行代码的事两个传感器的库是同一套。MQTT 协议的选择就更明确了。HTTP 是请求-响应模式设备要主动上报数据必须由设备发请求服务器才能收到数据服务器想主动推消息给设备还得靠轮询或长连接。而 MQTT 基于发布/订阅模式设备连接服务器后保持长连接双方都能随时收发消息实时性和流量开销都比 HTTP 好。具体对比放到后面第 5 章详细说。OneNet 平台属于国内老牌的物联网云平台对个人开发者很友好。它的 MQTT 接入文档写得清楚控制台能看到实时数据流和历史曲线还支持 HTTP API 调用。更关键的一点是OneNet 允许你在产品里创建多个设备意味着将来你可以在同一个项目里接入多个监控点比如一个放在客厅、一个放在卧室、一个放在厨房统一管理非常方便。1.3 方案选型时避开的几个坑这套方案看起来顺理成章但我在选型阶段也走了一些弯路这里把经验写出来帮你避开。第一不要选裸的 ESP-01 模块做第一版。ESP-01 虽然便宜但引出引脚太少你接传感器就占掉两个 GPIO还得额外接 TTL 转串口模块才能烧录调试体验非常痛苦。建议直接上 NodeMCU 或 D1 Mini 这类带 USB 接口的开发板。第二DHT11 的国产兼容版质量参差不齐。我在淘宝买过一批几块钱的有的读出来湿度偏差特别大有的连续读取几次就超时。后来我发现关键不是品牌而是模块上有没有焊接上拉电阻。如果你买的是四针独立封装的裸传感器数据线上必须自己加一个 4.7kΩ 左右的上拉电阻到 VCC否则信号不稳定经常读到 0 或者超时。这个细节在后文接线部分还会详细讲。第三OneNet 平台有旧版 MQTT 和新版 OneNET Studio 的区别两者的接入域名、端口、Topic 格式都不一样。你在网上搜到的很多教程是旧版的如果你注册时默认进了新版控制台照着旧版教程配会连不上。我建议注册时仔细看一下产品类型选“多协议接入”还是“OneNET Studio”要想清楚最好跟着官方文档走别只抄教程里的 IP 地址和端口。具体参数在第 4 章会给出。2. 硬件准备与接线实操2.1 物料清单与选购建议这个项目的硬件成本极低我把清单列出来供你参考。ESP8266 开发板我推荐 NodeMCU 或者 D1 Mini都是带 USB 口、可以直接用 Arduino IDE 烧录的型号价格在 10 到 20 元之间。DHT11 传感器模块选蓝色四针小板就行板载了上拉电阻和滤波电容比自己买裸传感器再搭外围电路省事很多。接线用的杜邦线公对公、公对母各准备几根面包板一个用来快速验证。如果要做成成品还需要一个 3.3V 稳压模块和电池盒或者旧手机充电头供电。采购时注意区分 DHT11 模块的引脚顺序。蓝色模块一般标注 VCC、DATA、NC、GND但也有个别厂家把 GND 和 VCC 做成相反的上电前一定要对一下丝印别凭经验接。我在实际项目里就遇到过一次模块引脚顺序和网上教程相反的情况差点烧掉传感器。另外建议一次买 2 到 3 个 DHT11 备用这玩意儿便宜但也确实容易在焊接或插拔时损坏。2.2 接线原理图与电源注意事项接线其实非常简单整个电路只有三个连接点。DHT11 模块的 VCC 接 ESP8266 的 3.3V 引脚GND 接 GND 引脚DATA 接 GPIO2 引脚D4。这里有一个容易踩的坑DHT11 模块的电源要求是 3.3V 到 5.5V 都能工作但 ESP8266 的逻辑电平是 3.3V所以建议都用 3.3V 供电避免电平不匹配造成读数异常。DHT11 模块引脚接 ESP8266NodeMCU引脚VCC3.3VDATAGPIO2D4NC悬空GNDGND这里说明一下为什么要接 GPIO2 而不是其他引脚。GPIO2 在 NodeMCU 上对应 D4这个引脚在板载 LED 附近默认被拉高用做单总线数据读取是稳定的。有的教程用 GPIO0D3或 GPIO4D2也能跑通但 GPIO0 同时是启动模式选择引脚如果你接线不当可能会影响模块上电启动。新手我建议直接抄 GPIO2 这个方案减少不确定性。电源是很多人忽略的重灾区。ESP8266 在 WiFi 发射瞬间电流能达到 300mA 左右如果你用一个输出能力不足的 USB 口供电模块会反复重启表现为串口监视器里“重新连接 WiFi”刷屏。解决方法是第一优先用电脑 USB 口或者手机充电头供电不要用 Arduino 板的 5V 引脚转接除非你的稳压模块输出能力足够第二供电线尽量短质量差的长线会有明显压降第三如果传感器离开发板比较远超过 20cm 建议用屏蔽线或者加长线径否则 DHT11 的单总线信号会失真。2.3 硬件点亮与连接验证硬件接好后第一次上电不要急着写完整程序建议先用一个最简单的 Arduino 示例程序验证板子能不能正常启动。在 Arduino IDE 里选择 NodeMCU 对应的开发板烧录一个 Blink 示例让板载 LED 闪烁。这一步能确认三件事驱动是否装好、板卡是否选对、烧录链路是否通畅。确认板子能跑后再用下面这段代码验证 DHT11 能否正常读取数据。把 DHT 库和 Adafruit Unified Sensor 库安装好后编译上传然后打开串口监视器波特率设 9600如果能看到温度和湿度数值输出就说明硬件链路已经通了。#include DHT.h #define DHTPIN 2 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(9600); dht.begin(); } void loop() { float h dht.readHumidity(); float t dht.readTemperature(); Serial.print(Humidity: ); Serial.print(h); Serial.print(% Temperature: ); Serial.print(t); Serial.println(C); delay(2000); }注意 Arduino 里的数字 2 对应的是 GPIO2如果你用的是 NodeMCU 开发板板子上丝印写的 D4 就是 GPIO2代码里写 2 即可。如果你换成 D1 Mini同样也是 D4。这个对应关系建议记下来我在实际项目中经常看到有人把板子丝印的“D4”当成代码里的数字 4结果一直读不到数据排查半天才发现是引脚号写错了。3. 开发环境搭建Arduino IDE 与 ESP8266 离线包3.1 为什么推荐 Arduino IDE 而不是其他框架ESP8266 可以用的开发环境很多官方 ESP-IDF、PlatformIO、MicroPython、NodeMCU Lua 等等。但对于做“数据采集 上云”这种偏应用的场景Arduino 框架是最快的路径。因为你需要的大部分功能WiFi 连接、MQTT 客户端、传感器驱动社区都已经封装成库了你要做的是把它们组合起来而不是从零写协议栈。ESP-IDF 是乐鑫官方的开发框架功能最强但对新手来说门槛偏高配置工程、编译系统、分区表这些概念足以劝退很多人。MicroPython 开发效率高但运行时开销大对 GPIO 的时序控制不如 Arduino 精确尤其 DHT11 这种单总线协议对时序要求敏感用 MicroPython 读有时候会不稳定。所以我个人的建议是第一版用 Arduino IDE跑通后再根据需求决定要不要换框架。3.2 安装 Arduino IDE 与 ESP8266 离线安装包Arduino IDE 的安装本身没什么好说的官网下载对应系统的版本一路下一步即可。真正麻烦的是给 IDE 添加 ESP8266 开发板支持。国内网络访问 Arduino 官方板卡管理器地址经常超时所以更推荐用离线安装包的方式。具体步骤是先安装好 Arduino IDE打开“文件 - 首选项”在“附加开发板管理器网址”里填入 ESP8266 社区维护的 JSON 地址。这个地址在 GitHub 上搜 ESP8266 Arduino 就能找到。如果你网络状况不好下载离线包更方便。离线包的原理是把你需要的 esp8266 工具链和编译器预先打包好放进 Arduino 的硬件目录里不同操作系统的路径不同Windows 一般在C:\Users\你的用户名\AppData\Local\Arduino15或者 IDE 安装目录下的 hardware 文件夹里。用离线包时如果你之前已经添加过 JSON 地址建议先删掉这个地址否则 Arduino IDE 启动时还是会去尝试联网检查更新导致打开板卡管理器时卡住。我遇到过好几次这个情况最后直接把 JSON 填进去又删掉用离线包安装完反而省事。安装完成后在“工具 - 开发板 - 开发板管理器”里搜索 esp8266能看到“esp8266 by ESP8266 Community”选项点安装。如果你是用离线包的方式安装是自动完成的不需要走这个界面。装完后在“工具 - 开发板”菜单里选择“NodeMCU 1.0 (ESP-12E Module)”或者你手头板子对应的型号。3.3 CH340 驱动与开发板参数设置NodeMCU 和大多数国产 ESP8266 开发板用的 USB 转串口芯片是 CH340Windows 系统一般会自动识别但如果你的电脑没装上驱动串口列表里就看不到端口。这种情况去搜 CH340 驱动下载对应系统版本装一下即可。装完后在“设备管理器 - 端口COM 和 LPT”里能看到一个 CH340 开头的 COM 口记住这个 COM 号在 Arduino IDE 的“工具 - 端口”里选择它。开发板参数里有几个关键选项需要说明。CPU 频率默认 80MHz你不用去动跑这个项目完全够。Flash Size 一般选 4M1M SPIFFS后面做 OTA 升级或网页配网时需要足够大的 Flash 分区才会涉及这个参数。上传速度可以选 115200 或 921600后者更快但如果你的 USB 线质量不好可能出现烧录失败降到 115200 反而更稳。还有一个容易忽略的设置是“内置 LED”NodeMCU 的板载 LED 接在 GPIO2 上和 DHT11 的数据线是同一个引脚。这意味着烧录完成后你可能会看到 LED 轻微闪烁或行为怪异这是正常的不用管它。但如果你的程序里用了 GPIO2 做其他事就会和传感器冲突报错或者读数异常记住这个引脚不要重复使用。4. OneNet 平台侧配置产品、设备与 MQTT 接入参数4.1 注册账号与创建产品OneNet 平台的配置是整个项目的“云端一半”很多人在这一步卡住原因主要是平台改版导致新旧教程对不上。我的经验是无论页面怎么变核心要搞清楚三样东西——产品、设备、API Key以及它们之间的关系。登录 OneNet 官网用手机号注册并实名认证后进入控制台。找到“产品开发”或“多协议接入”入口不同版本叫法不同。点击创建产品时会让你填产品名称、选择产品分类、选择接入协议。这里就是新旧版分叉的地方如果你用的是新版 OneNET Studio创建的是“项目”维度接入方式里选 MQTT如果你用的是旧版多协议接入需要选择独立产品并记录产品 ID。我个人建议直接使用新版的 OneNET Studio因为它的数据流模板、设备影子、API 调用设计更合理官方文档也更完备。创建产品时设备接入协议选 MQTT数据格式可以选 JSON其他选项按默认来。创建之后系统会生成一个产品 ID这个 ID 在设备鉴权时要用到。4.2 创建设备并获取鉴权信息在产品详情页里找到“设备管理”点击添加设备。设备名称可以随便起比如“study-room-sensor”但最好别用中文和特殊字符避免 MQTT 报文编码问题。添加完成后设备列表里会出现你的设备状态是“未激活”等设备第一次成功上报数据后才会变成“在线”或“已激活”。点开设备详情你需要记下几样东西设备 ID、鉴权信息Access Token、产品 ID。在 OneNet 新版里MQTT 连接的 UserName 一般是产品 IDPassword 一般是设备的 Access TokenClientID 一般是设备名称。不同平台版本的鉴权字段可能叫法不一样但核心思路就是这样服务器通过这三元组确认“你是谁”“你属于哪个产品”“你有没有权限接入”。网上经常有人搜“mqtt 华为云三元组”说的就是同一个概念。另外在产品详情里你还需要配置数据流模板Data Stream。这个不是必须的但强烈建议配置。数据流模板定义了设备上传的数据结构比如温度字段叫什么、湿度字段叫什么、单位是什么。配置好了以后OneNet 控制台能自动解析数据并生成曲线否则光传上来一串 JSON平台不知道哪个值是温度哪个是湿度展示体验会差很多。4.3 MQTT 接入参数与 Topic 规则设备接入 OneNet 的 MQTT 服务器核心参数如下。Broker 地址mqtts.heclouds.com 或根据你创建产品时页面提示的地址来填端口一般是 1883明文或 8883TLS。如果你用的是新版 OneNET Studio域名和端口以官方文档为准不同地域可能不同。Topic 的规则是这个项目的关键。OneNet 支持设备通过发布消息到指定 Topic 来上报数据一般格式是$sys/{产品ID}/{设备名称}/thing/property/post。这里$sys开头的表示系统级 Topic不能随意修改。发布消息的 payload 需要按照平台要求的 JSON 结构来组织常见格式是{ id: 123, version: 1.0, params: { Temperature: 25.6, Humidity: 60.2 } }注意这里的Temperature和Humidity字段名必须和数据流模板里定义的一致否则平台解析不了。我在实际测试中遇到过数据能发到 Topic、但控制台曲线不更新的情况排查到最后就是 field 名称大小写不一致。MQTT 接入还有一个概念是订阅 Topic。设备可以订阅$sys/{产品ID}/{设备名称}/thing/property/set这个 Topic 用于接收平台下发的属性设置指令。对于纯粹的温湿度监控你可以不订阅但如果你想做远程控制比如通过平台下发指令让设备打开继电器就必须把订阅逻辑加进去。5. MQTT 协议核心机制与代码实践5.1 MQTT 核心概念Broker、Topic、QoS 与保留消息MQTT 的全称是 Message Queuing Telemetry Transport翻译过来叫消息队列遥测传输是物联网场景的事实标准协议。它最大的特点是轻量报文头很小非常省流量很适合 ESP8266 这种资源受限的设备。理解 MQTT 最直观的方式是类比“微信群”。群主Broker管理一个群群成员客户端可以往群里发消息发布也可以接收别人发的消息订阅。每次发消息必须指定说给谁听这就是 Topic。比如所有人都在“温湿度/客厅”这个群里聊客厅的温湿度传感器设备发消息到这个 Topic你的手机 App 订阅了这个 Topic就能收到消息。QoSQuality of Service是消息服务质量共分 3 级。QoS 0 是“发出去就不管了”消息可能丢失QoS 1 是“至少一次”发送方会等接收方确认但可能重复QoS 2 是“恰好一次”性能开销最大。对于温湿度这种周期性上报的数据用 QoS 0 完全够用丢一两条没关系下一周期又会补上。但如果是控制开关、报警这类关键消息建议至少用 QoS 1。Retained Message保留消息也是一个实用功能。当设备发布一条带 retain 标志的消息后Broker 会保存这条消息的最新值新的订阅者一上线就能立刻收到不用等设备再发一次。这个功能非常适合显示“最新状态”的场景比如一个显示面板它订阅 Topic 时立刻就能拿到上一次上报的温湿度值。5.2 MQTT 与 HTTP、Socket 的对比为什么 IoT 场景不选 HTTP很多人会问我直接用 HTTP POST 上传数据到平台不就行了吗为什么还要学 MQTT答案是HTTP 和 MQTT 解决问题的场景不同。HTTP 是典型的请求-响应模式客户端主动发起请求服务器返回响应。你的 ESP8266 要上传数据可以每隔 10 秒 POST 一次平台也能收到。但问题在于服务器无法主动给设备推送消息除非设备自己频繁轮询。轮询间隔短流量和功耗高间隔长实时性差。这就像你每隔 10 秒去收发室看一次有没有你的信有信要等没信也要跑一趟效率很低。而 MQTT 是长连接 发布/订阅模式设备连接 Broker 后保持通路双方都能随时发送消息实时性好而且协议头部开销极小。同样一条消息HTTP 请求头可能有几百字节MQTT 固定报文头只有 2 字节。在移动网络或 WiFi 环境下设备可能休眠后重连MQTT 的心跳机制也能很好地维持连接状态。Socket 和 MQTT 的区别就更明显了。Socket 是一种通用的通信方式你定义了二进制协议自己解析而 MQTT 在 Socket 之上定义了完整的消息格式、会话状态、QoS、主题路由等机制相当于你直接用一个现成的高层协议不需要自己造轮子。自己做 Socket 协议前期开发量大后期维护也麻烦除非有特殊的二进制私有协议需求否则物联网项目里直接用 MQTT 基本不会错。5.3 ESP8266 上的 MQTT 客户端库选型Arduino 生态里最常用的 MQTT 客户端库是 PubSubClient由 Nick OLeary 开发。这个库非常轻量完美适配 ESP8266。另一个选择是 EspMQTTClient它在 PubSubClient 基础上封装了 WiFi 连接和重连逻辑使用起来更省心但自由度稍低也引入了更多依赖。我个人的建议是如果你希望理解 MQTT 连接的全过程用 PubSubClient 自己写连接和重连逻辑如果你想快速出活用 EspMQTTClient。下面章节的代码示例基于 PubSubClient因为它的使用量最大、网上资料最多遇到问题也更容易搜到答案。代码里你需要处理几个关键生命周期连接 WiFi、连接 MQTT Broker、循环处理 MQTT 消息、断线重连。断线重连尤其重要因为 WiFi 和 MQTT 都可能因为网络波动断开如果程序不处理重连设备就会变成“僵尸节点”看起来程序还在跑但数据已经不上传了。实际的温度湿度数据不丢了但云端曲线连续性断了你说影响大不大所以我一般在loop()里先做重连检查再做发布。6. 核心代码实现从读取传感器到 MQTT 上报6.1 代码整体结构与全局配置写完前面这些准备工作现在可以进入最核心的部分了。整个程序分为这么几个模块全局变量和配置参数、WiFi 连接函数、MQTT 连接函数、DHT11 数据读取函数、数据组装与发布函数、主循环调度。下面先看全局配置#include ESP8266WiFi.h #include PubSubClient.h #include DHT.h // WiFi 配置 const char* ssid 你的WiFi名称; const char* password 你的WiFi密码; // OneNet MQTT 配置 const char* mqtt_server mqtts.heclouds.com; const int mqtt_port 1883; const char* mqtt_user 产品ID; const char* mqtt_password 设备AccessToken; const char* mqtt_clientId 设备名称; // DHT11 配置 #define DHTPIN 2 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); // MQTT 主题 const char* pubTopic $sys/产品ID/设备名称/thing/property/post; WiFiClient espClient; PubSubClient client(espClient); unsigned long lastPublishTime 0; const unsigned long publishInterval 10000; // 10秒上报一次这些配置里最需要注意的是 mqtt_user、mqtt_password、mqtt_clientId 三者的对应关系一定要和 OneNet 平台设备详情里的信息一致。我见过很多新手把这几个参数搞混导致反复出现“MQTT connect failed, rc-2”其实就是 Username 和 Password 填反了。WiFi 配置没有太多好说的直接写死SSID和密码。如果你希望程序更灵活能适配不同场所的 WiFi后面可以考虑用 WiFiManager 库来做网页配网我在第 7 章的扩展部分会提到这个方案。6.2 WiFi 连接与 MQTT 连接函数连接 WiFi 的代码比较标准。需要注意的一点是 WiFi 模式要设为 STA 模式不要保留 AP 模式防止 ESP8266 默认开启的 AP 热点占用资源。连接 WiFi 后等待直到 IP 地址拿到为止这种阻塞式等待在项目里是可以接受的因为设备上电时本来就需要等网络就绪。void setupWiFi() { delay(10); Serial.println(); Serial.print(Connecting to ); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(); Serial.println(WiFi connected); Serial.println(IP address: ); Serial.println(WiFi.localIP()); }MQTT 连接函数里核心是设置服务器地址、设置回调函数然后在loop()里循环调用client.loop()以维持心跳。PubSubClient 的连接函数是client.connect(clientId, user, password)返回布尔值表示是否连接成功。连接失败时client.state()可以拿到错误码这个对排查问题很有用。void setupMQTT() { client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); } void reconnectMQTT() { while (!client.connected()) { Serial.print(Attempting MQTT connection...); if (client.connect(mqtt_clientId, mqtt_user, mqtt_password)) { Serial.println(connected); client.subscribe(subTopic); } else { Serial.print(failed, rc); Serial.print(client.state()); Serial.println( try again in 5 seconds); delay(5000); } } }这里的回调函数callback用于处理平台下发的消息在纯粹的温度监控项目里可以先留空但定义好回调是一个好习惯因为后续你要做远程控制时会用到。回调函数会接收三个参数订阅的 Topic 字符串、消息内容、消息长度你可以在里面解析 JSON执行对应操作。6.3 DHT11 数据读取与容错处理DHT11 的数据读取在代码里是最简单的但在实际项目中却是最容易出问题的。问题的根源在于 DHT11 是单总线协议时序要求较严格。不过既然我们用的是 Arduino 的 DHT 库底层时序已经被封装好了我们需要关注的是上层的数据有效性判断。float readDHTTemperature() { float t dht.readTemperature(); if (isnan(t)) { Serial.println(Failed to read temperature from DHT11); return -255.0; } return t; } float readDHTHumidity() { float h dht.readHumidity(); if (isnan(h)) { Serial.println(Failed to read humidity from DHT11); return -255.0; } return h; }isnan检查是必须的。DHT 库在读取失败时会返回 NaNNot a Number如果不做处理直接拼 JSON 字符串OneNet 平台解析时会出错或者在控制台显示一个很大的负数。我在代码里把失败值设为 -255.0这样云端曲线会显示一个明显异常的值提示你设备端有问题需要处理。DHT11 的读取频率不能太快。数据手册建议两次读取间隔至少 1 秒实际上我测下来如果你每 100ms 读一次偶尔会遇到稳定的超时。我的经验是 2 秒以上没问题本项目设置的 10 秒上报间隔完全避开了这个限制。读取间隔太短不仅浪费电量还可能让传感器内部电容放电不充分导致后续读数漂移。6.4 MQTT 数据发布与 JSON 组包MQTT 发布的核心是把温湿度数据按 OneNet 要求的 JSON 格式组织好然后publish到指定的 Topic。OneNet 新版要求的 JSON 结构是{ id: 123, version: 1.0, params: { Temperature: 25.6, Humidity: 60.2 } }在 Arduino 代码里拼 JSON 字符串很不方便容易出错推荐用 ArduinoJson 库。这个库是 ESP8266 和 Arduino 开发中几乎绕不开的依赖安装后在“工具 - 管理库”里搜索 ArduinoJson选择最新版安装即可。下面是用 ArduinoJson 组织消息的代码void publishDHTData() { float temperature readDHTTemperature(); float humidity readDHTHumidity(); if (temperature -255.0 || humidity -255.0) { return; // 读取失败不发布 } StaticJsonDocument256 doc; doc[id] 123; doc[version] 1.0; JsonObject params doc.createNestedObject(params); params[Temperature] temperature; params[Humidity] humidity; char buffer[256]; serializeJson(doc, buffer); if (client.connected()) { boolean result client.publish(pubTopic, buffer); if (result) { Serial.print(Publish success: ); Serial.println(buffer); } else { Serial.println(Publish failed); } } else { Serial.println(MQTT not connected, skipping publish); } }注意client.publish的返回值表示发布是否成功。如果返回 false可能是 Broker 连接已断开也可能是消息体积超过限制。OneNet 对单条消息大小有限制通常 256 字节足够。数字精度方面保存两位小数就够展示和判断告警了完整的25.6789上传没有任何意义还占用带宽。6.5 主循环调度与定时发布主循环里的核心逻辑是维护 MQTT 连接、按固定间隔发布数据。你需要一个简单的时间调度机制而不是在loop()里用delay()因为delay()会阻塞整个程序导致 MQTT 心跳无法及时发送连接容易被 Broker 断开。void loop() { if (!client.connected()) { reconnectMQTT(); } client.loop(); unsigned long now millis(); if (now - lastPublishTime publishInterval) { lastPublishTime now; publishDHTData(); } }这个模式是 Arduino 开发里非常经典的“非阻塞调度”。millis()返回的是开盘以来的毫秒数用它来判断时间间隔既不会阻塞也不会因为loop()执行频率不恒定而影响时间准确性。如果你的程序以后要加更多功能比如按键响应、LED 闪烁、OTA 升级监听都用这种模式来写程序会一直保持流畅。整个代码编译烧录后打开串口监视器0 波特率 115200你会看到类似这样的输出WiFi 连接成功、MQTT 连接成功、每 10 秒一条发布成功的日志。然后到 OneNet 控制台看设备状态是不是“在线”数据流里有没有温度、湿度两条曲线。到这里一个完整的远程温湿度监控就真正跑通了。7. 常见问题与排查技巧实录7.1 典型问题速查表我在做这个项目的过程中积累了一份问题速查表这里整理成表格分享给你按“现象 - 可能原因 - 解决办法”的格式来查效率最高。现象可能原因解决办法串口监视器无输出波特率设置错误串口选择错误板子没有进入烧录模式检查波特率是否和代码一致设备管理器重新确认 COM 口按板子的 BOOT/FLASH 按键再烧录一次DHT11 读数恒为 0 或 NaN数据线没接对缺上拉电阻供电不足检查 GPIO 引脚号模块上接 4.7k 上拉电阻到 VCC换一个 USB 口供电MQTT 连接失败 rc-2服务器地址或端口不对客户端 ID 重复网络不通检查 Broker 域名和端口确保 ClientId 唯一用手机热点测试排除网络问题MQTT 连接失败 rc-4UserName 或 Password 错误对比 OneNet 设备详情确认产品 ID、Access Token、设备名称填对连接正常但控制台无数据Topic 写错payload 格式不对字段名不匹配逐字核对 Topic 和 JSON 字段名对比平台数据流模板定义设备频繁掉线重连WiFi 信号弱供电不稳KeepAlive 设置过短调整设备位置或增加中继检查电源输出能力在客户端配置合理的 KeepAlive 间隔温度湿度明显不准传感器离热源太近传感器本身质量问题换位置测试换一个 DHT11 模块做对比这里的 rc 错误码是 PubSubClient 库返回的 MQTT 连接状态码-2 表示网络连接失败-4 表示用户名密码验证失败3 表示服务器不可用。遇到问题先看串口打印的状态码缩小排查范围比盲目改代码高效得多。7.2 DHT11 读数异常的深度排查思路DHT11 读数异常是新手遇到最多的问题我把排查思路再详细展开一下。先确认代码里引脚号是不是和硬件接线对应。NodeMCU 的丝印“D4”对应 GPIO2但如果你用的是 D1 Mini丝印 D2 对应 GPIO4D4 才对应 GPIO2。不同板子的丝印和 GPIO 编号映射不一样千万别想当然。然后检查传感器类型定义是否正确的。DHT 库用DHT dht(DHTPIN, DHTTYPE)初始化时第二参数 DHTTYPE 如果写错了比如用了 DHT11 模块却写 DHT22读取出来的数据可能出现极其荒谬的值比如温度 300 度湿度 10000%。如果硬件和代码都确认无误还是读不到数据可以用逻辑分析仪或示波器看波形但新手通常没有这些工具。我教你一个土办法用另一块已知正常的开发板跑同样的代码交叉测试。如果传感器在别的板子上能正常读取说明传感器没问题问题在你这块 ESP8266 的供电或引脚上。如果传感器换到别的板子上也读不到那基本可以断定传感器坏了换一个新的。还有一个非常容易忽略的细节DHT11 通电后需要 1 到 2 秒的稳定时间如果你在setup()里上电后紧接着就读取大概率第一次读出的值是 0 或者 NaN。正确的做法是让程序先运行一两秒再去读。我们的程序里loop()每隔 10 秒才发一次数据第一次数据要等 10 秒这无形中避开了这个问题。7.3 MQTT 连接不稳定的几个隐藏原因MQTT 连接不稳定排查起来比传感器更隐蔽因为原因往往不在你写的代码里。我遇到过的最典型的一种情况是设备刚连上 WiFi 就去连接 MQTT而路由器还没有完全分配好 IP导致 TCP 连接失败。解决方法是连接 WiFi 后加一个短暂延时确认拿到 IP 后再连 MQTT。另一种情况是 ESP8266 本地时钟乱跳导致 TLS 证书验证失败。如果你用的是 8883 加密端口Broker 会校验设备时钟而 ESP8266 没有 RTC 电池刚上电时时间是 1970 年TLS 握手会失败。如果你用了加密连接而连接一直失败可以先换成 1883 明文端口测试排除 TLS 时间问题。实际生产环境才需要认真处理证书和时间的同步个人项目用明文就够了。还有一个网络层面的大坑有些路由器开启了 AP 隔离或客户端隔离导致接入设备之间、设备与外部网络之间通信受限。我在朋友家调试时就遇到过ESP8266 能连上 WiFi但访问外网一直失败后来才发现是路由器开了“访客网络隔离”。这个问题无法从设备端解决只能改路由器设置。最后是 KeepAlive 参数。PubSubClient 默认的连接心跳周期是 15 秒如果你所在网络环境不稳定可以把 KeepAlive 调低到 10 秒甚至 5 秒让 Broker 更快感知到设备失联减少“假在线”时间。不过 KeepAlive 太短会增加网络流量和功耗需要权衡。7.4 安全与合规提示做物联网项目绕不开安全话题虽然这个项目是个人学习和实验性质但我还是建议你从第一天就养成好习惯。第一不要把 WiFi 密码、平台 Access Token 硬编码在代码里之后又传到公开的 GitHub 仓库。我见过太多人把真实凭据直接写到博客示例里这是非常危险的行为。建议你把配置写在单独的头文件里并加入.gitignore或者从环境变量读取。第二如果你计划把这个设备部署到真实的公共环境比如办公室、机房建议在 MQTT 连接时使用 TLS 加密并且为设备配置独立的、权限最小的 Access Token不要使用产品管理员级别的密钥。OneNet 平台里你可以为每个设备生成独立的 Access Token这样即使某一个设备的凭据泄露也不会影响其他设备。第三不要用默认密码和默认凭据。OneNet 平台在创建设备时会生成默认的 Access Token你可以在设备详情里手动改成强随机字符串。WiFi 密码也不要使用弱口令。这些看似基础的习惯能在未来避免很多麻烦。8. 功能扩展方向与个人体会8.1 网页配网用 WiFiManager 告别硬编码 WiFi当你的设备要交给别人使用或者你自己需要经常切换 WiFi 环境时硬编码 WiFi 用户名密码的方式就变得非常痛苦。每次换地方都要改代码重新烧录来回折腾很费时间。WiFiManager 库专门解决这个问题。它的原理是设备上电后如果检测不到预先配置的 WiFi就自动开启一个 AP 热点你拿手机连上这个热点浏览器会自动弹出配置页面选择你要连接的 WiFi 并输入密码。设备保存配置后自动重启并连接到目标 WiFi。这个库还支持自定义参数比如你可以让用户同时配置 MQTT 服务器地址和设备名称对做小批量产品非常实用。结合热搜词里的“esp8266 安装wifimanager”和“esp8266 网页配置wifi”这个方向确实值得深入研究。引入 WiFiManager 后代码结构会有一个大的变化setup()里不再直接WiFi.begin()而是先初始化 WiFiManager然后调用autoConnect()。需要注意的是 WiFiManager 一次配置后会把信息存到 Flash 里下次上电直接连接不再自动开启 AP。如果你需要重新配置需要在程序里留一个按键触发resetSettings()这也是项目里常见的“长按按键恢复默认设置”功能的实现方式。8.2 远程控制与告警从单向上报到双向交互目前这个项目是单向的设备采集数据主动上报到云平台。但实际应用场景中我们往往需要反向控制。比如监测到一个花房的温度过高你想远程打开风扇或者监测到机房湿度太大你想启动除湿机。这时就需要用到 MQTT 的双向通信能力。实现方式是在代码里订阅一个下行 Topic在 OneNet 中通常是$sys/{产品ID}/{设备名称}/thing/property/set然后在回调函数里解析平台下发的 JSON 指令根据指令控制 GPIO 输出进而控制继电器、风扇、加热器等外围设备。这个扩展可以让项目从“监控”升级为“监控 控制”真正实现远程管理。告警功能同样可以通过 OneNet 平台的消息推送实现。你可以在平台侧配置规则引擎当温度超过某个阈值时通过短信、邮件或微信推送告警。这一部分的实现不涉及设备端代码完全在 OneNet 控制台配置但它的价值非常大以前你必须打开 App 才能看到数据是否异常现在系统主动告诉你设备出问题了这是从“被动查看”到“主动监控”的质变。8.3 本地显示与数据持久化把数据留一份在自己的系统里如果你不想完全依赖第三方平台或者希望数据保存在自己的服务器上可以考虑在树莓派、NAS、或者云服务器上搭建自己的 MQTT Broker比如 Mosquitto再用 Node-RED、Grafana 等工具做数据展示和存储。这种方案的优点是数据完全自主可控可以自己做后期分析比如统计某个月的平均温度判断设备健康状况等。很多人在网上搜“mqtt服务器搭建docker”就是想把 Mosquitto 用 Docker 跑起来。用 Docker 搭建 MQTT Broker 确实是现在最主流的方式一个docker run命令就能搞定不需要手动编译安装依赖。你甚至可以在此基础上用 Node-RED 做一套可视化大屏配合 InfluxDB 时序数据库存储历史数据做成一个相当完整的数据采集系统。不过这一套方案的学习曲线比 OneNet 高不少涉及 Linux 基础、Docker 使用、数据库配置、前端展示等多个技术点。我的建议是第一版先用 OneNet 跑通等确认传感器数据稳定、理解了 MQTT 的整个机制之后再考虑自建服务器方案。循序渐进比一步到位靠谱得多。8.4 低功耗改造电池供电的远程监控节点实话说ESP8266 在低功耗方面并不擅长它的 WiFi 模块工作电流较大如果直接电池供电几节 AA 电池撑不过一周。但如果你要部署一个没有电源插座的地方做长期监控就需要考虑低功耗改造。基本的思路是让设备大部分时间处于休眠状态定时唤醒采集数据并上传。ESP8266 支持 Deep Sleep 模式功耗可以降到几十微安配合一个定时器唤醒比如每 30 分钟醒来一次上传完数据继续睡。这种模式下一节 18650 锂电池理论上可以撑几周甚至一两个月。不过 DHT11 从睡眠唤醒到稳定读取需要时间所以唤醒后先延迟一两秒再读取传感器否则读数会不准。代码层面使用ESP.deepSleep(microseconds)进入休眠唤醒后程序从setup()重新开始执行所以数据上报逻辑要写在setup()里上报完成后立即进入休眠而不是放在loop()。这个模式设计好了你的远程监控节点就真的可以摆脱电源线束缚部署到温室大棚、果园、仓库阁楼这些不方便拉电线的角落里长期运行了。我个人在这套方案上花费的时间最多的地方不是代码而是排查各种环境问题。用了一段时间后你慢慢的就能理解为什么物联网项目没有“一招通吃”的解法传感器有适用场景的差异网络环境各不相同平台版本也在不断更新。项目最有价值的部分从来不是那一两行核心代码而是你对整条链路的理解和排错时练出来的感觉。最后分享一个我常用的调试技巧如果设备连不上网、连不上平台先把收发数据的链路拆开测试用手机开热点给 ESP8266 用确认能不能正常上报。如果手机热点能上报、家里的 WiFi 不行问题多半在路由器如果手机热点也不行问题多半在设备端或者平台配置。这种逐段排查的方式能帮你快速定位问题而不是漫无目的地乱改代码。希望这篇文章能帮你少走一些弯路早日把自己的第一套远程监控跑起来。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻