前阵子帮朋友搭一套设备远程监控系统,对方给的需求很直接:车间里有几十个传感器点位,数据要能实时看到,最好还要能上云。我第一反应就是上MQTT。这套协议在物联网领域基本已经是事实标准了,本地Broker用EMQX,云端平台用OneNET,链路清晰、成本低、可查的资料也多。更关键的是,整个流程零基础的人完全可以跟着做下来,不用非得懂底层网络原理。
写这篇东西,是因为我发现大部分教程都只讲其中一段:要么只教你部署一个EMQX,要么只讲MQTT协议概念,很少有把“本地采集 -> 云端接入”整条链路串起来讲的。所以我干脆把完整搭建过程重新走了一遍,从EMQX部署、MQTT核心概念、MQTTX本地验证,到OneNET云平台接入,再到ESP8266硬件端采集,最后附上我实际踩过的一堆坑。刚接触物联网的小白,或者在搞课程设计、毕业设计、小项目验证的开发者,照着走基本能少折腾半个月。
1. 方案为什么这么选:MQTT、EMQX与OneNET的分工
1.1 数据采集场景下,为什么MQTT比HTTP顶用
设备数据采集有个典型特点:设备数量多、数据产生频繁、服务端需要及时拿到变化。这种场景如果用HTTP,常见做法是设备端定时轮询上报,服务端开一堆接口等着收。问题是,轮询间隔短了,设备多的时候服务端压力很大,网络开销也大;间隔长了,实时性又跟不上。而且HTTP是“一问一答”模式,服务端想主动下发指令给设备,还得靠设备先请求,很别扭。
MQTT是长连接模式,设备连上Broker之后保持一条TCP连接,消息随时能推。它天然是发布/订阅模型,设备之间不用互相知道对方IP,不用处理复杂的点对点通信。简单理解:HTTP像你打电话给客服问一句“我的订单发货没”,MQTT像你关注了一个公众号,商家一更新物流状态,消息就自动推到你手机上,你不用反复刷页面。
所以做数据采集,尤其是传感器数据、状态上报、远程控制这类场景,MQTT基本是首选。它省流量、省电、支持大量并发连接,还自带消息确认机制,虽然不保证绝对不丢,但比裸TCP可靠得多。
1.2 EMQX本地Broker加OneNET云端:这条链路怎么串起来
整套系统的架构大概是这样的:
传感器 -> 采集端(ESP8266/网关) -> 本地EMQX -> OneNET云平台 -> 手机/网页/应用
EMQX在这里扮演的是“本地消息总线”的角色,所有设备先把数据发给它,再由它转发或者推送到其他订阅者。OneNET则是云端的数据汇聚和展示平台,你可以把它理解为一个“数据仓库加可视面板”,设备数据通过MQTT上报到OneNET后,能直接以数据流、图表、API等形式使用。
这里有个很关键的思路:为什么设备不直接连OneNET,而是先经过本地EMQX?因为很多采集场景设备处于内网,或者数量很大,直接全部连公网云平台,一是带宽压力大,二是断网时本地数据就断了,三是本地如果有实时控制需求(比如报警联动、大屏展示),走云平台绕一圈延迟太高。让数据先汇聚到本地EMQX,再由EMQX按需转发给OneNET或者其他应用,是最合理的结构。
1.3 这套方案适合哪些项目
有朋友问,这玩意儿除了传感器采集还能干吗?其实适用范围比想象中广:
- 课程设计/毕业设计:温湿度采集、智能家居、环境监测之类,这套方案能快速跑通Demo。
- 小规模设备监控:车间设备运行状态上报、能耗数据采集,几十个点位以内完全够用。
- 智慧农业/大棚监控:土壤湿度、光照、温度采集并上报云端,再配合告警。
- 停车场/门禁类项目:车牌识别相机、道闸控制器等设备的对接和数据汇聚,后面我会单独聊这个场景。
成本方面,EMQX社区版开源免费,OneNET平台有免费额度,ESP8266开发板十几块钱,整套下来硬件成本不超过三十块钱,就能跑通一个完整的物联网数据链路。
2. MQTT协议核心概念:不懂这几个词,后面全踩坑
2.1 Broker、Client、Topic:用微信群模型一次讲明白
新手接触MQTT最容易懵的就是一堆名词。其实用一个微信群模型就能讲清楚:
Broker就是微信服务器,负责转发消息;Client就是群里的每个成员,可能是手机、传感器、服务器程序;Topic就是群名,发消息的人指定发到哪个群,想收消息的人先进群(订阅)。整个模型里,发消息的人不关心谁在听,听消息的人也不关心谁发的,全靠Broker中转。
Topic本身是层级结构的,用斜杠分隔。比如你有一个温度传感器,可以这样设计:
sensor/device001/temperature sensor/device002/temperature history/parking/camera001订阅的时候还支持通配符,“+”代表单层通配,“#”代表多层匹配。比如订阅“sensor/+/temperature”,就能收到所有设备的温度;订阅“sensor/#”,就是接收sensor下的所有消息。这个机制让数据路由变得非常灵活。
2.2 QoS、遗嘱消息、保留消息:三个必须吃透的机制
QoS是消息服务质量等级,一共三档:
- QoS 0:最多发一次,发出去就不管了,可能丢消息,适合周期性上报的非关键数据。
- QoS 1:至少送达一次,Broker收到后会回ACK,没收到就重发,但可能重复,适合大部分数据采集场景。
- QoS 2:恰好一次,消息不丢失不重复,但握手过程复杂、开销大,适合计费、告警这类要求严格的场景。
实际项目里如果对消息丢失不敏感,用QoS 0;如果数据重要,用QoS 1;QoS 2用得少,因为性能开销不划算。
遗嘱消息是设备异常掉线时,Broker替它发布一条预设消息。比如一个设备连上MQTT时声明“如果我掉线了,就发一条 offline 消息”,这样服务端就能及时感知设备掉线,做报警处理。保留消息则是指Broker会存住某Topic的最后一条消息,新订阅者一上线立刻能收到,比如设备当前的开关状态、最新温度值。这两个机制在设备状态检测和状态同步上非常实用。
2.3 抓一条真实MQTT报文看看
MQTT报文不像HTTP那么直观,但拆开来也不复杂。设备连接Broker时会发CONNECT包,包含ClientID(客户端唯一标识)、Username和Password(如果Broker要求鉴权)、CleanSession(是否清除旧会话)、KeepAlive(心跳时间)。连接成功后Broker回CONNACK,里面带了返回码。发布消息发的是PUBLISH包,包含Topic、Payload和QoS级别;订阅发的是SUBSCRIBE包。
你可能不需要手动构造这些报文,MQTT客户端库全部帮你处理好了。但是当你调试的时候,看到连接失败返回码,能快速定位是ClientID重复、密码错误还是协议版本问题。后面排查章节我会列常见返回码。
3. EMQX部署实操:Docker一条命令起步
3.1 为什么第一步推荐Docker:零基础最不容易出错的方式
部署EMQX有好几种方式,物理机直接装、用K8s部署、用Docker部署。对于零基础或者只想快速跑通的人来说,Docker是最省事的。
为什么这么说?因为直接用二进制包或者包管理器安装,要处理依赖库、Java环境(EMQX新版基于Erlang)还有系统服务配置,经常遇到“装好了但是起不来”的情况,排查半天发现是某个依赖没装。Docker把EMQX和它的运行环境打包成一个镜像,一条命令拉下来就能跑,跟系统环境完全隔离,删掉也干净。
另外强调一下,Docker部署不是“玩具方案”,生产环境照样可以这么用,配合数据卷和容器编排工具就是标准的服务化部署方式。你从Docker起步,后续平滑切到集群部署也容易。
3.2 部署并登录Dashboard
部署前确认机器上装好了Docker。没有的话,Windows装Docker Desktop,Linux装Docker Engine,官方文档都有很详细的步骤。
打开终端,执行:
docker run -d --name emqx \ -p 1883:1883 \ -p 8083:8083 \ -p 8084:8084 \ -p 18083:18083 \ -e EMQX_DASHBOARD__DEFAULT_PASSWORD=admin123 \ emqx/emqx:5.8.4稍微解释下这几个端口的作用:
| 端口 | 用途 |
|---|---|
| 1883 | MQTT标准协议端口,客户端连接用 |
| 8083 | WebSocket端口,浏览器或Web应用连MQTT用 |
| 8084 | MQTT over TLS/SSL端口,加密连接用 |
| 18083 | Dashboard管理界面端口 |
启动后,浏览器打开 http://localhost:18083 ,就能看到EMQX的Dashboard登录页。默认账号是admin,密码要么是public(老版本镜像),要么是你通过环境变量设置的admin123。我特意在启动命令里加了一个环境变量,把默认密码改掉,省得登录后还要找地方改。
第一次登录建议立刻检查一下Dashboard的整体布局,左边菜单有连接管理、认证、规则引擎等模块。后面加认证用户、查看客户端连接列表都会用到这里。
3.3 非Docker环境部署补充
如果机器上确实没有Docker,或者项目要求直接安装,我补充几种常见方式。
CentOS/Ubuntu可以用EMQX官方提供的APT/YUM源安装,或者直接下载二进制zip包解压运行。以CentOS 7为例子,先去EMQX官网下载中心找到对应版本的rpm包,然后:
sudo yum install -y emqx-5.8.4-1.el7.x86_64.rpm sudo emqx startWindows本机的做法更简单,下载Windows版本zip包,解压后进入bin目录,执行:
emqx start然后同样访问 http://localhost:18083 打开Dashboard。
有一点要提前说清楚,EMQX基于Erlang/OTP,对内存有一定要求。我见过有人在只有512MB内存的服务器上硬跑EMQX 5.x,结果频繁OOM。保守建议至少分配1GB内存,2GB更稳。如果只是本机开发调试,一般电脑都带得动。
3.4 给EMQX加上用户认证:从“裸奔”到“要密码”
EMQX部署完默认是允许匿名连接的,也就是说任何客户端只要知道Broker地址和端口,就能随便连接、随便发消息。这在公网环境是致命的,本地调试倒无所谓,但为了养成好习惯,我建议一开始就加上用户名密码认证。
登录Dashboard,找到“访问控制 -> 认证”菜单,添加一个认证数据源,选择“内置数据库”,然后添加用户。例如创建一个用户名mqttuser、密码mqttpass123的用户。这样客户端连接时就必须带用户名和密码,否则连接会被拒绝。
有人可能会问,EMQX不是自带一个admin账号吗?能不能直接用admin连MQTT?答案是不要这样做。admin是Dashboard的管理员账号,和MQTT客户端的认证是两套体系。专门给设备建独立的MQTT用户,权限好控制,也方便一个用户对应一类设备。
4. 本地链路验证:用MQTTX把Hello World发起来
4.1 MQTTX:调试协议最顺手的客户端
EMQX部署好之后,下一步别急着接硬件,先用一个MQTT客户端工具模拟设备发消息,验证Broker是不是真的通了。这个阶段用MQTTX最方便。
MQTTX是EMQX官方出的一款开源跨平台MQTT客户端工具,Windows、macOS、Linux都有安装包,界面清爽,支持多个连接并存、消息收发记录、主题订阅管理。相比用命令行mqtt cli或者自己写脚本,它对新手友好多了。
打开MQTTX,点击“新建连接”,填写连接信息。因为EMQX就在本机,Host填127.0.0.1,端口1883,ClientID可以随便填一个(比如mqttx_test_001),用户名填mqttuser,密码填mqttpass123。点连接,如果一切正常,界面上会显示连接成功。
4.2 发布与订阅测试:验证EMQX工作正常
连接成功后,先建一个订阅,主题填 test/topic。然后回到发布区域,往同一个主题发一条消息,比如“hello emqx”。你会看到订阅区域立刻收到了这条消息。
这个流程看着简单,但其实把“发布-订阅”模型跑通了:一个客户端发布,Broker转发,另一个订阅关系收到消息。这是整个MQTT系统最核心的动作。
多测几个场景:开两个MQTTX连接,一个只入群(订阅),一个只发言(发布),看能不能收到;再试试QoS 0和QoS 1在消息发送速度上的差异。实测下来QoS 1会稍慢一点点,因为多了一次确认流程,但在本地网络感知不明显。
4.3 实测保留消息和遗嘱消息
这两个机制光看文档容易忘,实际手动测一遍就记住了。
保留消息测试:发布一条消息到 topic/status,内容“online”,勾选Retain选项。然后新建一个连接,订阅 topic/status,注意选择“从保留消息中接收”之类的选项(MQTTX默认会带),你会发现一订阅就立刻收到“online”,而不是等下一轮发布。
遗嘱消息测试:在MQTTX连接配置里,找到遗嘱(Will)相关的选项,设置主题will/topic,内容“device_offline”。然后故意把这个连接断开(比如杀掉进程),再用另一个连接订阅will/topic,它会收到一条“device_offline”。这就模拟了设备异常掉线后,Broker帮它广播遗言的过程。
理解这两个机制后,你在做设备在线状态监测时就会很轻松,设备心跳丢了能第一时间发现。
5. OneNET云平台接入:从建产品到接收数据
5.1 OneNET平台上的准备:产品、设备、数据流
本地链路通了之后,接下来把数据送到云端。OneNET是中国移动运营的物联网开放平台,有免费额度,注册就能用,很适合教学和个人项目。注册登录后进入控制台,创建产品,产品品类可以根据你的设备类型选,比如环境监测、智能家居。
创建完产品,在“设备管理”里添加设备,填写设备名称,平台会自动分配产品ID、设备ID、APIKey等参数。这几个参数后面都要用到,建议提前复制到文本里。然后想好在设备下建哪些数据流,比如温度、湿度、PM2.5,数据流名字可以自定义,后面上报的数据会按照数据流组织起来。
顺便提醒一句:OneNET平台这些年改版过好几次,新老版本的控制台界面和接入方式有差异。我这里讲的是经典但兼容性较好的流程,如果你在控制台看到的是新版Studio界面,以平台提供的“设备接入”文档为准,核心的鉴权三要素概念是一致的。
5.2 平台鉴权三要素:ClientID、Username、Password到底填什么
OneNET的MQTT接入,最核心的问题是搞懂三个字段怎么填。很多人卡在这里,填错了就一直连接失败。
| 参数 | 填什么 | 示例 |
|---|---|---|
| Broker地址 | 平台MQTT接入地址,老版常用 mqtt.heclouds.com,新版以控制台为准 | mqtt.heclouds.com |
| 端口 | 老版MQTT非加密端口6002,TLS加密端口8883,新版可能是1883/8883 | 6002 |
| ClientID | 产品ID + "_" + 设备名,注意中间下划线 | 12345678_mydevice |
| Username | 产品ID | 12345678 |
| Password | 设备APIKey或签名Token(以平台文档为准) | 一串密钥字符串 |
| 上报Topic | 老版是 $dp | $dp |
| Payload格式 | 数据流JSON格式 | {"datastreams":[...]} |
为什么ClientID要拼成“产品ID_设备名”?因为平台用这个字段来定位设备和产品,相当于MQTT会话的“身份证”。Username填产品ID,让平台知道你要操作哪个产品;Password填APIKey,做身份校验。这三个字段组合起来,平台才能判断你是某一个产品下合法设备。
新版OneNET Studio可能使用签名方式生成password,需要拼接时间戳、签名算法生成Token。这个属于平台策略差异,你拿到设备的鉴权信息后,如果显示有“密钥”或“签名”字样,按平台接入文档生成即可。
5.3 用MQTTX先打通一次OneNET连接
为了不在硬件上反复烧录调试,先在MQTTX里模拟一次OneNET连接,成功后再换成真实设备。
新建一个连接,配置和上一节的表格一致。Broker地址填mqtt.heclouds.com,端口6002,ClientID填“产品ID_设备名”,Username填产品ID,Password填APIKey。点连接,如果返回连接成功,说明你从公网到OneNET的MQTT通道全部打通了。
如果连接失败,MQTTX会显示CONNACK返回码,常见的有:
- 1:协议层面错误,检查端口和协议版本。
- 2:ClientID无效,多半是“产品ID_设备名”格式有问题。
- 4:用户名密码错误,检查Username是不是产品ID,Password是不是APIKey。
- 5:未授权,可能设备未生效或已被禁用。
把这个阶段打通非常重要,因为如果云端连接没通,后面接硬件时会以为是代码问题,其实可能是平台配置问题。
5.4 数据上报的topic和payload设计
设备向OneNET上报数据,老版MQTT协议用的是$dp这个主题,消息体是标准JSON格式:
{ "datastreams": [ { "id": "temperature", "datapoints": [ { "value": 25.6 } ] }, { "id": "humidity", "datapoints": [ { "value": 60 } ] } ] }在MQTTX里发布一条这样的消息到$dp,然后回到OneNET控制台,打开设备的“数据流”页面,就能看到temperature和humidity这两个数据流的最新数据了。
有一点要注意,$dp这个主题里的美元符号不能去掉,也不要拼错。这和前面本地测试用的普通主题(比如sensor/temp)不同,本地Broker接受任何你定义的主题,但OneNET平台的接入层只认自己规定的主题和消息协议,必须在它设定的规则里说“人话”。
6. 硬件端数据采集:ESP8266/ESP32把传感器数据送上去
6.1 板子和传感器选型
软件链路全部验证通过后,终于可以上真实硬件了。最推荐新手用的是ESP8266开发板,比如NodeMCU或者Wemos D1 Mini,价格十几块钱,自带WiFi,可以直接通过Arduino环境编程。预算稍微高一点可以选ESP32,性能更强,还支持蓝牙。
传感器方面,最常见的是DHT11/DHT22温湿度传感器,三根线(VCC、GND、DATA)就能接。想采集土壤湿度就买土壤湿度传感器,模块输出的是模拟量,直接用ADC读取。控制类需求(比如继电器开关设备)也能在这套流程里一并实现。
6.2 Arduino环境准备与依赖库
写ESP8266的程序,我建议用Arduino IDE,虽然界面朴素,但资料多、对新手友好。先安装Arduino IDE,然后在“文件 -> 首选项 -> 附加开发板管理器网址”里填上ESP8266的支持包地址:
http://arduino.esp8266.com/stable/package_esp8266com_index.json接着在“开发板管理器”里搜索ESP8266,安装支持包。库方面需要两个:PubSubClient(MQTT客户端)和DHT sensor library(DHT传感器驱动)。直接在库管理器里搜索安装即可。
6.3 核心代码:WiFi连接、MQTT连接、传感器上报
下面这段代码实现了:连接WiFi -> 连接本地EMQX -> 每5秒读取一次DHT11温湿度 -> 以JSON格式发布到EMQX的sensor/temp主题。
#include <ESP8266WiFi.h> #include <PubSubClient.h> #include <DHT.h> const char* ssid = "你的WiFi名称"; const char* wifiPassword = "你的WiFi密码"; const char* mqttServer = "192.168.1.100"; // EMQX所在电脑IP const int mqttPort = 1883; const char* mqttUser = "mqttuser"; const char* mqttPassword = "mqttpass123"; #define DHTPIN 2 // DHT11数据引脚,NodeMCU D4 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); WiFiClient espClient; PubSubClient client(espClient); void connectWiFi() { WiFi.begin(ssid, wifiPassword); while (WiFi.status() != WL_CONNECTED) { delay(500); } } void connectMQTT() { while (!client.connected()) { if (client.connect("ESP8266_TempSensor", mqttUser, mqttPassword)) { client.publish("sensor/status", "online"); } else { delay(5000); } } } void setup() { Serial.begin(115200); dht.begin(); connectWiFi(); client.setServer(mqttServer, mqttPort); } void loop() { if (!client.connected()) { connectMQTT(); } client.loop(); float h = dht.readHumidity(); float t = dht.readTemperature(); if (!isnan(h) && !isnan(t)) { String payload = String("{\"temperature\":") + t + ", \"humidity\":" + h + "}"; client.publish("sensor/temp", payload.c_str()); } delay(5000); }这段代码里有两个地方容易踩坑。第一,client.connect的第一个参数是ClientID,这个ID在同一台Broker上不能重复,如果你同时开了MQTTX里那个连接,再运行ESP8266,就必须换一个ClientID,否则会互相挤下线。第二,client.loop()必须放在loop函数里高频调用,它是用来维持MQTT心跳和接收消息的,如果被delay阻塞太久,Broker会判定设备掉线。
6.4 本地+云端双通道上报的思路
有的项目需要数据同时进本地EMQX和OneNET,这样本地能实时控制,云端能远程访问。实现上有两种方式。
方式一是设备端双连接,创建两个WiFiClient和两个PubSubClient,分别指向EMQX和OneNET,在loop里各自调用loop。代码思路类似:
WiFiClient emqxWifiClient; WiFiClient onenetWifiClient; PubSubClient emqxClient(emqxWifiClient); PubSubClient onenetClient(onenetWifiClient); // 初始化 emqxClient.setServer("192.168.1.100", 1883); onenetClient.setServer("mqtt.heclouds.com", 6002); // 循环里 emqxClient.loop(); onenetClient.loop();注意两个PubSubClient要共用一个串口和WiFi网络没问题,但底层WiFiClient对象要分开,不能复用同一个。
方式二是在EMQX里配置规则引擎,让EMQX把收到的消息自动转发到OneNET。这属于进阶玩法,好处是设备端逻辑简单,只连本地Broker即可,云端转发由EMQX负责。EMQX的规则引擎功能很强大,在Dashboard里的“规则”模块创建一条规则,当sensor/#主题有消息时,触发动作把消息重新发布到OneNET。这种方式在你有很多设备、但不想每个设备都处理双连接时,非常好用。
7. 常见问题与排查技巧实录
7.1 EMQX Docker环境里“密码总是自动换了”是怎么回事
这个现象我见过太多次了:Docker部署的EMQX,明明设置过Dashboard密码和MQTT用户密码,过几天重启容器或者重新部署,密码又变回默认值,或者之前创建的MQTT用户没了,设备全部连不上。
原因基本只有一个:没有做数据持久化。Docker容器运行期间产生的数据,默认保存在容器内部的可写层,容器一旦被删除、重建,内部数据全部丢失。EMQX的配置、Dashboard账号、认证用户数据都存在容器里的 /opt/emqx/data 目录下,不加数据卷的话,删容器等于格式化。
解决办法是在启动容器时挂载数据卷:
docker run -d --name emqx \ -p 1883:1883 \ -p 8083:8083 \ -p 8084:8084 \ -p 18083:18083 \ -v emqx_data:/opt/emqx/data \ -v emqx_etc:/opt/emqx/etc \ emqx/emqx:5.8.4这样数据卷 emqx_data 会持久保存EMQX的数据,容器重建后数据还在。
还有一个更隐蔽的坑:如果你之前已经用一个数据卷跑过EMQX,并且改过默认密码,这次用-e EMQX_DASHBOARD__DEFAULT_PASSWORD=xxx启动新容器,也会发现密码没变。因为环境变量只在“首次初始化”时生效,当数据卷里已经有旧的数据库文件时,它不会被覆盖。你表面上觉得“密码自动换了”,其实是新环境变量没生效,旧密码还在。
最后一个容易被误认为“密码自动换”的情况是:EMQX默认允许匿名连接,你虽然配置了认证用户,但匿名连接也没关,导致你用任何密码都能连上,过一会又用错误密码连上,就像没设密码一样。解决方法是到Dashboard的认证配置里,把匿名认证关闭,只允许认证过的用户连接。
7.2 OneNET连接失败的排查
OneNET连接失败的排查顺序,我建议按照“网络 -> 端口 -> 鉴权 -> 消息格式”来:
第一,网络层面。如果用MQTTX连接OneNET失败,先确认设备能上公网,再用ping或者telnet测试MQTT接入地址的6002端口是否通。很多校园网和公司内网会限制非常规端口,导致连不上。
第二,端口和协议。确认用的端口是不是平台要求的,老版6002,新版可能是1883。混用端口是最常见的低级错误。
第三,鉴权三要素。ClientID必须是“产品ID_设备名”格式,注意下划线不能少;Username必须是产品ID本身,不是设备名;Password必须和DeviceKey或APIKey严格一致,包括大小写。
第四,CleanSession设置。MQTTX连接时如果开了“清理会话”,可能会导致平台上原有的设备会话被清除。设备上线时正常新连接没问题,但如果是重复连接,建议把CleanSession设为true,避免旧连接占用导致新连接被踢。
7.3 设备掉线、数据不上报怎么办
设备掉线问题在硬件端最常见,而且往往不是MQTT本身的问题。我总结几个高频原因:
- 供电不足。ESP8266在WiFi传输瞬间电流较大,如果用电脑USB口供电还好,用劣质充电宝供电就容易反复重启。
- 网络不稳定。WiFi信号弱或者路由器开启了AP隔离,设备连上WiFi但连不上MQTT Broker。建议先打印WiFi连接状态,确认拿到了IP。
- PubSubClient没有处理好重连。如果设备长时间运行,WiFi或信号问题导致连接断开,代码里必须有断线重连逻辑。我上面的示例代码中connectMQTT里已经写了循环重连,但记得在loop里先检查client.connected()。
- Broker的KeepAlive设置太短。EMQX默认心跳时间是60秒左右,设备如果因为任务阻塞导致没有及时发送心跳包,会被Broker判定离线。硬件端建议把KeepAlive设成30秒或45秒,同时确保loop调用足够频繁。
数据不上报还有一个容易被忽略的地方:OneNET的$dp消息payload格式必须严格符合平台的JSON规范。比如数据流字段名写错、value值类型不对(字符串当数字传),平台会直接丢弃。遇到收不到数据,先在MQTTX里发一条固定格式的消息,确认平台能收到,再怀疑硬件代码。
7.4 一个常见真实场景:停车场车牌识别相机的MQTT对接思路
有个比较受关注的场景是停车场项目:用MQTT协议搞定海康、大华等主流车牌识别相机的对接。这类相机本身不一定原生支持MQTT,但通常有HTTP回调或者SDK接口。实战中,典型做法是用一个边缘网关或PC做“协议转换”,把相机的HTTP抓拍结果转成MQTT消息,发布到本地EMQX,再供后台、道闸、云平台使用。
假设相机识别到一辆车进场,通过HTTP POST把车牌和抓拍时间推给网关程序,网关程序将其封装为MQTT消息:
主题:parking/camera/entry 内容:{"plate":"京A12345","time":"2025-06-01 08:30:00","image":"http://192.168.1.50/snap/202506010830.jpg"}停车场后台订阅了这个主题,就能实时得到进场记录;道闸控制器订阅出场主题,就能自动抬杆;同时边缘网关也可以把汇总后的数据通过MQTT上报到OneNET,实现远程的车位统计。这个案例和数据采集项目的本质完全一致:MQTT作为数据总线,把多个异构设备的数据统一成标准消息,汇聚、流转、上云。
所以别看标题写的是“零基础搭建”,这套链路跑通之后,往停车场、