很多人第一次玩 WiFi 温湿度传感器时,最容易卡住的不是代码,而是不知道这东西到底怎么连上网、怎么把数据传到手机里。明明硬件都买回来了,传感器也接好了,结果卡在 WiFi 配置或者搞不懂 MQTT 是什么,最后只能吃灰。我当年也是这么走过来的,所以这篇就把 WiFi 温湿度传感器从连接配置到接入 MQTT 的完整链路讲透,包含选型思路、接线步骤、代码逻辑、常见坑点,照着做基本能一次跑通。
这篇内容适合三种人:一是想给家里做环境监测但刚接触嵌入式的小白,二是学校课程设计需要做温湿度采集上报的学生,三是想在办公室或机房做远程温湿度监控的运维朋友。不管你是用 ESP8266、ESP32 还是其他 WiFi 模组,核心配置思路都是通用的。
1. 方案选型与连接思路:2.4GHz 与 MQTT 的组合逻辑
先解决一个根本问题:为什么智能家居和物联网设备普遍选 2.4GHz WiFi,而不是 5GHz?为什么传输层要用 MQTT,而不是更常见的 HTTP?
1.1 为什么 WiFi 传感器几乎都工作在 2.4GHz 频段
WiFi 温湿度传感器本质上还是个小型嵌入式设备,天线尺寸、射频功耗都受硬件体积限制。2.4GHz 频段在穿墙能力、覆盖距离上比 5GHz 有明显优势。传感器往往被放到阳台、仓库角落、设备机柜这种犄角旮旯的地方,5GHz 信号容易被墙体或金属柜体削弱,而 2.4GHz 的绕射能力稍好一些。
更重要的是成本。主流 WiFi 模组,尤其是 ESP 系列和各类国产透传模组,多数只集成了 2.4GHz 射频前端。支持双频的模组成本会明显提升,对于温湿度采集这种每秒才几十字节的小流量场景,完全没必要多花那个钱。再说 2.4GHz 即使信道拥挤,传这点数据也绰绰有余。
配置时有个非常容易踩的坑:很多家用路由器默认开启了“双频合一”,即 2.4GHz 和 5GHz 共用同一个 SSID。此时传感器可能反复连接失败,因为设备只会尝试连接信号较弱的 5GHz 或两个频段间反复横跳。建议进路由器管理后台,把双频合一关闭,或者给 2.4GHz 设置一个专用的传感器 WiFi 名称。
另外一个容易被忽略的点是,WiFi 配置的 SSID 和密码中最好不要出现中文字符或特殊符号。部分模块对 UTF-8 字符集支持不好,遇到中文 SSID 会出现连不上或乱码。我曾经遇到过一台配了中文热点名称的测试路由,ESP8266 死活连不上,后来把热点名称改成纯英文,一次就通了。这不是玄学,是模块内部固件的字符编码问题,有兼容性风险就需要主动规避。
1.2 MQTT 比 HTTP 更适合传感器数据的几个理由
如果传感器采集数据后通过 HTTP POST 到服务器,也不是不行,但你会遇到几个麻烦:HTTP 是请求响应模式,设备必须知道服务器的具体接口地址,服务器还得维护一套鉴权、跨域等机制;为了一条温湿度数据,TCP 握手加 HTTP 头部可能要发几百字节,功耗和流量都浪费了;如果服务器没开,请求就失败,数据就丢了。
MQTT 是发布订阅模型,运行在 TCP 之上,协议头最小可以压缩到 2 字节。传感器作为发布者,把数据发布到某个主题(Topic),任何订阅了这个主题的客户端都能实时收到。设备完全不需要知道谁在消费数据,订阅方也不需要知道数据从哪里来。这种松耦合设计让扩展设备变得非常容易:加一个显示屏,订阅同一个主题就行;加一个手机 App 推送,同样也是订阅主题。
MQTT 还有个保留消息机制值得单独说。传感器每次上电后发布的最后一条消息,Broker 可以保存下来,新订阅者接入的瞬间就能立刻拿到最新的温湿度值,不需要等传感器下一次上报。这在做监控看板时特别有用,页面一打开就有数据,不用干等。
1.3 整体连接架构拆解
一个典型的 WiFi 温湿度传感器系统大致是这种结构:
传感器(DHT11/SHT30) -> 主控(ESP8266/ESP32) -> 家庭路由器(2.4GHz) -> MQTT Broker(Mosquitto等) -> 订阅端(手机/电脑/Home Assistant)数据流从传感器采集开始,主控读取温湿度数值后,按固定间隔(比如 10 秒)打包成 JSON 报文,通过 WiFi 推送到局域网内的 MQTT Broker,Broker 再转发给所有订阅了对应主题的客户端。
这套架构最核心的优点是:传感器跟订阅端完全解耦。我可以同时让手机 MQTT 客户端、Node-RED 看板、Home Assistant 三处订阅同一份数据,互不影响。以后想加推送服务,只用在 Broker 层面做规则配置,传感器端一行代码都不用改。
2. 硬件选型与环境准备:从传感器到 Broker 的搭建细节
方案定了之后,剩下就是选具体的元器件和搭建软件环境。这里我把自己试过的组合和参数列一下,照着买基本不会错。
2.1 温湿度传感器怎么选:DHT11、DHT22、SHT30 对比
市面常见的温湿度传感器有 DHT11、DHT22/AM2302、SHT30 这几款,参数差距还是不小的。我整理了一个对比表,方便你按项目需求选:
| 传感器型号 | 温度精度 | 湿度精度 | 采样周期 | 接口类型 | 典型价格 | 稳定度 |
|---|---|---|---|---|---|---|
| DHT11 | ±2℃ | ±5% RH | 1s 以上 | 单总线 | 几块钱 | 一般 |
| DHT22/AM2302 | ±0.5℃ | ±2% RH | 2s 以上 | 单总线 | 十几块 | 中等 |
| SHT30 | ±0.3℃ | ±2% RH | 可配 | I2C | 十几到二十几 | 高 |
DHT11 最大的优势是便宜、资料多、教程满地都是,做毕设和入门练手足够了。但你要准备长时间监测环境数据,它的漂移和误差会有点让人头疼,而且湿度的 ±5% 误差在实际项目中有时不太能接受。DHT22 精度相比 DHT11 提升不少,价格也适中,我目前的主力项目用的就是它。SHT30 走 I2C 接口,数据稳定性和一致性在三者中最好,适合对数据质量有要求的场景。不过 SHT30 是贴片封装,面包板接线需要转接板,新手需要多留意一下引脚间距的问题。
还有个注意点:不管用哪款传感器,如果你的主控电源是同一个开关电源供电,建议传感器供电跟主控之间加一个 100nF 去耦电容,放在传感器电源引脚附近,能明显减少读数跳变。这在电机、继电器等干扰源附近尤其重要。
2.2 主控选型:ESP8266 还是 ESP32
做 WiFi 温湿度采集,主控基本就是 ESP8266 和 ESP32 二选一。两者在 WiFi 连接上其实没有本质差异,都是 2.4GHz,都支持 MQTT 库,区别主要在别的方面:
- ESP8266:单核,主频 160MHz,只有一个 ADC,GPIO 较少,但价格便宜(板子正常十几块),烧录简单,功耗低。如果你只是接一个温湿度传感器,哪怕要再接个 OLED 屏,它的资源也完全够用。
- ESP32:双核,主频 240MHz,蓝牙和 WiFi 可以同时工作,ADC 精度更高,GPIO 多,支持电阻触摸、CAN、加密加速器等。如果你的项目后期要加摄像头、本地语音识别、显示屏刷 UI 这类重活儿,选 ESP32 更省心。
你搜过的“esp32蓝牙和wifi可以一起用吗”,答案是能,但它对传感器项目不来电。温湿度采集这么轻量的活,ESP32 的大算力有点浪费,反而因为硬件复杂导致功耗更高。所以我的建议是:只做传感器上报,选 ESP8266,省电省心;想顺便折腾点别的,再上 ESP32。
2.3 MQTT Broker:本地起一个服务还是用云端
MQTT 数据总要有地方接收,这个接收方就是 Broker。Mosquitto 是目前最流行的开源 Broker,支持 Windows、Linux、macOS,还支持 Docker 部署。我个人强烈建议先把 Broker 跑在局域网内的电脑或树莓派上,等系统稳定再考虑上云。
本地启动 Mosquitto(Windows 解压版大约 20MB 不到),装好后改一下配置文件mosquitto.conf,允许匿名访问和监听 1883 端口即可。关键配置项:
listener 1883 allow_anonymous true如果你想设置账号密码,加两行配置并生成密码文件:
mosquitto_passwd -c /etc/mosquitto/passwd sensor_user # 然后回到配置文件添加: password_file /etc/mosquitto/passwd allow_anonymous false如果要用云服务器跑 Broker,记得在云控制台的安全组里放行 1883 端口(TCP),同时服务器本地防火墙也要放行。这一步是新手最容易踩的坑,后面我会专门展开说。
3. 实操连接与代码实现:手把手把数据跑起来
硬件选好了、Broker 也搭起来了,接下来就是接线、写代码、验证数据。这一节的内容是全文的核心,每一步我都会说明目的和原理。
3.1 硬件接线:以 ESP8266 + DHT11 为例
接线是整个过程中最直观的一步,DHT11 模块通常是三针或四针引出。如果是三针模块(VCC、DATA、GND),接线如下:
| DHT11 引脚 | ESP8266 引脚 |
|---|---|
| VCC | 3.3V |
| DATA | GPIO2(D4) |
| GND | GND |
特别注意:老式 DHT11 裸元件需要 VCC 和 DATA 之间接一个 4.7kΩ-10kΩ 上拉电阻,但绝大多数市面上卖的 DHT11 蓝色模块已经内置了上拉电阻,直接接就行。如果你不确定自己的模块有没有内置,用万用表量一下 DATA 引脚对 VCC 的电阻,是几十 kΩ 就是有了。
接线完成之后,上电看模块上的电源指示灯。如果灯亮但串口输出乱码,先检查共地,也就是确认 ESP8266 的 GND 和 DHT11 的 GND 连到同一点。共地是电信号回流的必要条件,很多第一次玩单片机的朋友会在这里卡住。
3.2 开发环境准备:Arduino 还是 PlatformIO
代码编写环境我推荐 Arduino IDE,理由就一个:ESP8266 相关的物联网例程最多,出问题搜解决方案最好搜。PlatformIO 工程规范更适合大项目,但传感器采集这个小体量用不上它的模块化优势。如果你之前用过 PlatformIO,继续用也不影响,核心库是通用的。
Arduino IDE 里添加 ESP8266 开发板支持,在“文件 -> 首选项 -> 附加开发板管理器网址”里填上:
http://arduino.esp8266.com/stable/package_esp8266com_index.json然后在“开发板管理器”里搜索 ESP8266,安装对应版本。库方面需要装三个:
- DHT sensor library(Adafruit 维护)
- Adafruit Unified Sensor
- PubSubClient(MQTT 客户端)
3.3 核心代码实现:WiFi 连接与 MQTT 发布
下面这份代码是基于 ESP8266 和 DHT11 的最小可运行版本,做温湿度采集并按 10 秒间隔上报到 MQTT Broker。代码不复杂,但每个环节我都写了注释和选择理由。
#include <ESP8266WiFi.h> #include <PubSubClient.h> #include <DHT.h> // WiFi 配置:务必使用 2.4GHz 频段,且 SSID 建议不要有中文 const char* ssid = "Your_2.4G_WiFi"; const char* password = "Your_Password"; // MQTT Broker 地址,局域网内填电脑 IP,云端填服务器公网 IP const char* mqtt_server = "192.168.1.100"; const int mqtt_port = 1883; const char* topic = "home/sensor/temp_humidity"; // 传感器配置 #define DHTPIN 4 // GPIO2 对应 Arduino 引脚编号 4,即 D4 #define DHTTYPE DHT11 // DHT22 请改成 DHT22 DHT dht(DHTPIN, DHTTYPE); WiFiClient espClient; PubSubClient client(espClient); unsigned long lastSend = 0; const unsigned long interval = 10000; // 10 秒上报一次 void setup() { Serial.begin(115200); dht.begin(); // 连接 WiFi WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { // 这里加一个 500ms 延时,避免反复请求导致路由器负载过高 delay(500); Serial.print("."); } Serial.println("\nWiFi connected"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); // 配置 MQTT client.setServer(mqtt_server, mqtt_port); } void loop() { // 保持 MQTT 长连接,断线自动重连 if (!client.connected()) { reconnect(); } client.loop(); // 定时读取并发布数据 if (millis() - lastSend >= interval) { float h = dht.readHumidity(); float t = dht.readTemperature(); // 读取失败处理:DHT 传感器偶发超时非常常见,跳过本次上报即可 if (isnan(h) || isnan(t)) { Serial.println("Failed to read from DHT sensor!"); lastSend = millis(); return; } // 构建 JSON 报文,注意 JSON 里的双引号需要转义 String payload = "{\"temperature\": " + String(t, 1) + ", \"humidity\": " + String(h, 1) + "}"; // 发布并打印结果 if (client.publish(topic, payload.c_str())) { Serial.println("Published: " + payload); } else { Serial.println("Publish failed"); } lastSend = millis(); } } void reconnect() { // 最多重试 5 次,避免 Broker 挂掉时设备无限卡死 while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // 客户端 ID 必须唯一,如果多个传感器需要单独命名,比如 "sensor_livingroom" if (client.connect("ESP8266_Sensor_1")) { Serial.println("connected"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 2 seconds"); delay(2000); } } }几个细节值得说道一下。
GPIO2(D4)在 ESP8266 上是具备内部上拉的引脚,但这也是启动时必须处于高电平的引脚,如果 DHT11 模块没有内置上拉电阻,你外接一个 10kΩ 上拉到 3.3V 即可。为什么特别提醒这个?因为有些 DHT11 模块出厂接好了上拉,有些没有,接线前最好确认一下。
代码里的client.connect("ESP8266_Sensor_1")第二个参数可以传用户名和密码,client.connect(clientId, user, pass),如果你在 Mosquitto 里开启了账号验证,就在这里填上。
温湿度读取失败时我用了isnan()检查。DHT11 是单总线协议,时序要求非常严格,如果中断处理或供电波动导致时序被破坏,读出来就很可能是 NAN。这种情况下跳过上报、重试下一次采样,比卡死循环要合理得多。
3.4 验证数据链路:从 MQTTX 到命令行订阅
代码烧录完成后,打开串口监视器,波特率 115200。你可以看到 WiFi 连接日志、获取到的 IP 地址,以及每 10 秒一行“Published”输出。这说明设备端已经成功发布数据了。
但设备发布成功只代表数据到了 Broker,到底有没有人能收,还得验证订阅端。最简单的方法是用 MQTTX 这个图形化客户端(支持 Windows/macOS 和手机端),新建连接,Broker 地址填电脑局域网 IP,端口 1883,连上之后订阅home/sensor/temp_humidity主题,就应该能收到类似下面的消息:
{"temperature": 26.3, "humidity": 58.4}如果不想装图形化工具,直接用命令行也行。Linux/macOS 下如果安装了 Mosquitto 客户端工具包,一行命令就能订阅:
mosquitto_sub -h 192.168.1.100 -p 1883 -t "home/sensor/temp_humidity"数据能打印出来,整条链路就算彻底通了。接下来所有扩展,比如接小屏显示、接微信推送、接报表统计,都是基于这个主题再做文章。
4. 常见连接故障与排查技巧:我踩过的坑和解决实录
无论配置文档写得再详细,实际测试中总会碰到各种奇葩问题。我把最常见的连接故障和排查思路整理成表格,再补充几个我实际遇到的案例。
4.1 连接故障排查速查表
| 现象 | 排查方向 | 解决方案 |
|---|---|---|
| WiFi 连不上 / 一直打印点 | 频段问题 | 关闭路由器双频合一,为传感器单独设置 2.4GHz 频段的 SSID |
| WiFi 连不上 / SSID 有中文 | 字符编码问题 | 把 WiFi 名称临时改成纯英文测试 |
| WiFi 连上但 IP 获取失败 | DHCP 问题 | 给设备绑定静态 IP,或检查路由器地址池是否耗尽 |
| MQTT 连接失败 rc=-2 | Broker 未启动或地址错 | 确认 Mosquitto 服务已开,ping一下 Broker 地址 |
| MQTT 连接失败 rc=-4 | 网络不通 | 检查设备与 Broker 是否在同一网段,防火墙是否拦截 |
| 能连通但收不到数据 | 主题不匹配 | 检查发布端和订阅端的主题字符串是否完全一致 |
| 数据每隔几次就丢一次 | 采样周期过短 | DHT11 建议读取间隔不低于 1 秒,取平均后上报 |
4.2 案例一:双频合一导致的反复掉线
我给朋友装了一套温湿度监控,传感器在书房,路由器和电脑在客厅。设备刚通电时是好的,能连上,但每隔几分钟就掉线重连。一开始我以为是代码里的心跳间隔太短,或者是模块供电不足,排查了半天。后来登录路由器后台才发现,客厅路由开启了“WiFi 信号优选”功能,相当于双频合一。
手机在这种设置下是无感的,因为手机本身支持 5GHz,会自动切过去。但 ESP8266 只有 2.4GHz 射频,路由器每 5 分钟做一次频段引导扫描,就会把设备踢下线。关闭这个功能后,故障立即消失。所以当你遇到“过几分钟就掉线”的情况,先别急着改代码,进路由器后台看看频段设置。
4.3 案例二:公网 MQTT 连不上的三处防火墙
有次我在阿里云服务器上搭好 Mosquitto,本地 MQTTX 怎么都连不上,客户端报的是连接超时。排查过程基本是按网络顺序走下来的:
第一步,确认服务器本地监听是否正常,执行:
ss -tlnp | grep 1883看到0.0.0.0:1883说明 Mosquitto 没有只监听回环地址。
第二步,检查操作系统防火墙。以 Firewalld 为例:
firewall-cmd --permanent --add-port=1883/tcp firewall-cmd --reload第三步,也是新手最容易被坑的,检查云厂商安全组。阿里云、腾讯云的服务器外部流量要过安全组这一关,安全组没放行 1883,服务器内部怎么开放都是白搭。到控制台的“安全组 -> 配置规则”里入方向放行 TCP 1883 端口即可。
三层都打开后,连接就通了。这个排查顺序我建议形成肌肉记忆:先看本地监听,再看系统防火墙,最后看云安全组。
4.4 案例三:DHT11 读数反复跳变
另一个经常出现的问题是温湿度读数波动非常大,比如同一时刻温度从 25.3℃ 跳到 27.8℃ 再跳回 25.6℃。这不一定是传感器坏了,更可能是供电噪声干扰。ESP8266 的 WiFi 发射瞬间电流会突然增大,如果供电电路纹波大,DHT11 的单总线时序就容易受干扰。
解决方法是两个层面:硬件上在 DHT11 的电源引脚并联一个 0.1μF 陶瓷电容,靠近传感器放置效果最好;软件上,可以在连续读取 5 次之后取中位数。注意是中位数不是平均值,因为极端的跳变值会把平均值拉偏,而中位数可以比较稳定地反映真实数据。
4.5 一个值得保留的习惯:启用 MQTT 遗嘱消息
最后分享一个很多教程不会提到的实用细节。如果传感器断电,Broker 上不会主动告诉订阅端设备离线了,除非你设置了遗嘱消息。在代码里加这几行:
client.setWill("home/sensor/status", "offline", true);然后在设备成功连接后发布一条在线消息:
client.publish("home/sensor/status", "online", true);这样订阅端只要同时订阅home/sensor/status主题,就能实时知道设备是活着还是掉线了。对运维监控场景来说,这个功能比温湿度数据本身还要重要,能让你在设备离线第一时间收到通知,而不是翻看历史数据时才发现记录断了。
我在实际项目里有个习惯是给传感器取清晰的客户端 ID,比如按房间命名sensor_livingroom、sensor_serverroom。这么做不仅方便 Broker 层面做 ACL 权限隔离,也让你在 MQTT 面板里看到一堆设备时能快速区分谁是谁。等到设备数量超过 5 个再想改命名,就得一个个重新烧录,那时候就知道当初的懒有多耽误事了。
另外,如果你准备把这个系统长期跑下去,强烈建议在代码里把 WiFi 重连和 MQTT 重连做成独立的非阻塞逻辑,不要在loop()里用while(1)死等。ESP8266 SDK 底层的 lwIP 协议栈对频繁阻塞重连很不友好,连续重连 10 次以上有时会直接把协议栈搞死,只能断电重启。我当时为了解决这个问题,特意把重连间隔改成按指数退避,从 2 秒、4 秒、8 秒一直加到 60 秒上限,效果非常明显。这些细节看起来不起眼,但恰恰是设备稳定跑几个月不重启的关键。