最近把手上一批Air780EP模组从自建MQTT Broker切换到OneNET平台,整个过程比预想中顺利,但中间也踩了几个不算难但很典型的坑,比如APIKey拼错、Topic格式搞混、直接往公网TCP连接上就发MQTT包结果被平台静默丢弃。
如果你也打算用合宙Air780EP这类Cat.1模组,通过AT指令快速接入OneNET,这篇文章基本可以当一份“照着抄”的作业来用。整套方案不需要写复杂的MCU端SDK,不需要移植MQTT协议栈,只要一个串口、一个SIM卡、一组AT指令,就能把数据送上云平台。文章会覆盖平台侧设备创建、APIKey生成、模组网络自检、AT+MQTT全流程上云,以及我在实战中遇到的高频问题排查方法。
1. 这套组合凭什么省心:Air780EP、OneNET与AT指令的选型逻辑
1.1 为什么是Air780EP而不是Wi-Fi模块或更高成本的方案
很多做物联网产品的朋友会纠结一个问题:设备现场没有Wi-Fi,或者不想把配网流程做进产品里,怎么办?
Air780EP这类Cat.1模组解决的就是这个场景。它走运营商LTE网络,插上SIM卡就能上网,不需要路由器、不需要配网,开机即连云。和传统2G/3G模组相比,Cat.1在覆盖率、速率、功耗上取得了相对均衡的折中,尤其适合智能表计、充电桩、共享设备、农业监测这类数据量不大但对网络稳定性要求较高的场景。
选择Air780EP还有几个现实原因:第一,合宙的模组在AT指令生态上做得比较完善,官方文档和示例代码齐全;第二,模块单价在Cat.1方案里处于较低档位,整体BOM成本可控;第三,也是我最看重的一点,Air780EP的MQTT AT指令设计得比较直观,不需要像某些模组那样去拼接复杂的PDP上下文参数。对于用AT指令开发产品的团队来说,这套体验非常友好。
1.2 AT指令和MQTT协议搞懂这几个概念就够了
先帮基础薄弱的读者串一下关键词,有经验的朋友可以直接跳过这段。
AT指令可以理解成“人和模组对话的文本协议”,我们通过串口发送以“AT”开头的命令,模组解析后执行并返回结果。MQTT则是一种基于发布/订阅模型的轻量级消息协议,专门为低带宽、高延迟、网络不稳定的物联网环境设计。它与HTTP这类请求/响应协议最大的区别在于:客户端不需要频繁轮询,而是先订阅感兴趣的Topic,当服务端有消息时主动推送给客户端。
OneNET是移动物联网开放平台,它对外提供MQTT接入能力。设备侧通过MQTT协议连接到OneNET的Broker,上报数据和接收下行命令。三者配合后的数据链路是:
传感器/MCU --AT指令--> Air780EP --MQTT--> OneNET Broker --消息推送--> 应用端/手机App这里要特别理解“连接”的层级关系。MQTT协议虽然承载在TCP之上,但模组默认不会自动建立TCP连接,需要我们先用AT指令发起TCP连接,再在TCP连接之上发送MQTT连接报文。很多新手在调试时只做了TCP连接就急着发MQTT数据,结果平台侧完全收不到消息,原因就在这里。
2. OneNET平台侧准备:APIKey生成与设备参数一次讲清
2.1 创建产品和添加设备,别把这三组数字搞混
先说结论:在使用MQTT协议接入OneNET时,我们需要在模组里配置三组关键信息——产品ID、设备ID、APIKey。这三组信息搞错任何一个,MQTT连接都会被平台拒绝。
登录OneNET控制台后,进入“多协议接入”或者“产品开发”相关页面,选择MQTT协议创建一个产品。创建成功后,在设备管理页面添加真实设备。设备添加完成后,就能看到设备对应的ID和APIKey。
这里有一个非常容易踩的坑:产品ID是数字形式的项目标识,创建产品时就能看到;设备ID是设备实例的唯一编号,通常也是一串数字;APIKey则是身份密钥,需要在设备详情页单独生成或查看。很多教程会把它们统称为“三元组”,但实际复制时经常有人把产品ID当成设备ID填到模组的ClientID里,导致MQTT连接认证失败。
以Air780EP的AT指令为例,常见配置方式是这样的:
AT+MCONFIG=<设备ID>,<产品ID>,<APIKey>也就是说,模组配置的ClientID对应OneNET的设备ID,用户名对应OneNET的产品ID,密码对应OneNET的APIKey。如果配置反了,平台侧会直接拒绝连接并返回鉴权失败的错误。
2.2 数据流与Topic:OneNET的云端数据结构
OneNET平台的数据组织方式和通用MQTT Broker不太一样。通用MQTT里,我们想上报什么数据就发布到任意Topic,服务端自己决定怎么消费。OneNET则要求数据以“数据流”的形态组织,设备上报时需要按照平台规定的JSON格式发布到特定Topic。
以最常用的旧版接入方式为例,设备上报数据的Topic固定为$dp,payload格式是带数据流结构的JSON。假设我们要上报一个温度数据,数据流名称叫temp,那么payload长这样:
{"datastreams":[{"id":"temp","datapoints":[{"value":26.5}]}]}平台收到之后,会自动把这条消息解析成“设备temp数据流的最新值为26.5”这样一个数据点,并在控制台的数据流页面画出曲线。
如果设备还要接收平台或应用端下发的命令,还需要订阅下行Topic。在OneNET的旧版接入中,下行命令请求的Topic通常是$sys/{产品ID}/{设备ID}/cmd/request,设备处理完成后可以发布$sys/{产品ID}/{设备ID}/cmd/response来返回执行结果。
理解这套结构之后,你在配置AT指令时就不会迷茫了。订阅Topic、发布Topic、payload格式,这三件事是OneNET里数据互通的根基。
3. 模组接线与AT指令基础自检:百分之九十的失败都栽在这
3.1 接线与供电:新手最容易忽略的大坑
Air780EP模块本身不能直接接电脑USB调试,通常需要配合合宙官方的开发板或者自制的转接底板。开发板上一般会引出UART接口、SIM卡槽、天线座,插上SIM卡、接好天线、连接USB转串口模块后,才能通过PC端的串口工具发送AT指令。
供电是第一个大坑。Air780EP在LTE网络注册和发包瞬间电流尖峰可能到2A左右,如果供电能力不足,会出现一个典型现象:模组刚开机还能正常回AT,一旦执行网络注册或者MQTT连接就掉电重启。我调试时遇到过类似情况,排查了一圈后才意识到是USB转串口模块供电能力不够,换成外接5V/2A电源并共用GND之后问题才消失。
接线时还有一个细节容易被忽略:模组的UART_TXD要接USB转串口模块的RXD,模组的UART_RXD接模块的TXD,也就是交叉连接。如果搞成直连,串口工具里只能看到乱码或者完全没有回显。
另外,天线一定要接好。Air780EP的天线座一般是IPEX接口,模组在没接天线或天线接触不良的情况下,信号强度会非常低,甚至出现能搜到网但注册不上的情况。调试时尽量把天线放到靠近窗户的位置,模拟真实使用时的开阔环境。
3.2 AT指令三步自检:SIM卡、信号、网络注册
接好线之后,打开串口助手,选择正确的串口号和波特率。Air780EP的默认AT口波特率一般是115200,如果没反应可以尝试9600和230400,但以官方手册为准。
先发一个基础AT指令确认串口通信正常:
AT正常返回OK。如果没有任何回显,先检查串口号是否选对、接线是否交叉、波特率是否匹配。
模块正常响应后,依次检查三件事:
第一步:查SIM卡状态
AT+CPIN?如果返回+CPIN: READY,说明SIM卡识别正常。如果返回ERROR,可能是SIM卡没插好、卡槽方向不对,或者卡本身损坏。这是最基础的排查,但经常有人忽略。
第二步:查信号强度
AT+CSQ返回值格式是+CSQ: <rssi>,<ber>。rssi表示接收信号强度,范围0到31,数字越大信号越好。一般大于10就可以勉强联网,大于20属于良好,低于10就要检查天线和位置了。
第三步:查网络注册状态
AT+CEREG?对于LTE网络,这个指令返回+CEREG: <n>,<stat>。stat为1表示已注册到本地网络,为5表示已注册且是漫游状态。只有stat为1或5时,模组才具备上网条件。如果返回0或2,说明网络注册失败,需要检查SIM卡是否欠费、天线信号、以及所处位置的基站覆盖情况。
这三步自检做完,基本就能确定模组是否具备接入MQTT的网络条件。我在项目里要求所有测试人员必须先跑完这三条指令再继续,能省掉后面一大半连接类问题的排查时间。
4. Air780EP跑通AT+MQTT完整流程:从连接OneNET到数据上云
4.1 配置MQTT连接参数并建立TCP链路
网络自检通过之后,正式开始MQTT接入。先把模组的三元组信息准备好,假设如下:
- 产品ID:
123456 - 设备ID:
987654321 - APIKey:
abcdef1234567890abcdef1234567890
在串口工具中依次执行:
AT+MCONFIG=987654321,123456,abcdef1234567890abcdef1234567890这条指令的作用是写入MQTT客户端的身份信息,也就是上一节说的ClientID、用户名、密码。模组收到后会返回OK,表示参数已保存。
接着建立TCP连接:
AT+MIPSTART=mqtt.heclouds.com,6002这里要特别注意,OneNET旧版MQTT接入的Broker地址是mqtt.heclouds.com,端口是6002。不要填错成1883,那是通用MQTT端口,OneNET旧版接入并不使用。
执行后,模组会去解析域名并尝试建立TCP连接。成功时返回:
CONNECT OK如果在执行这一步时返回CONNECT FAIL或者超时,建议先用电脑ping一下mqtt.heclouds.com确认域名解析正常,再检查SIM卡是否有流量权限。另外,部分运营商的物联网卡默认没有开通公网访问能力,需要在运营商管理后台申请。
TCP建立成功之后,发起MQTT连接:
AT+MQTTCONN=120参数120表示KeepAlive间隔为120秒。模组会向平台发送MQTT CONNECT报文,OneNET校验设备身份通过后返回:
+MQTTCONN: OK此时模组已经成功接入OneNET,可以自由发布和订阅消息了。
有一点要提醒:MCONFIG只需要在更换设备或修改身份信息时重新执行。如果模组断电重启,之前配置的MQTT参数仍会保存在flash中,MIPSTART和MQTTCONN可以直接重新执行,不需要再配置一次身份信息。
4.2 发布数据到$dp与订阅下行指令
连接建立后,先测试订阅Topic。以订阅下行命令Topic为例:
AT+MQTTSUB=$sys/123456/987654321/cmd/request,0这条指令让模组订阅平台下发给该设备的命令请求。参数0表示QoS级别为0。OneNET的订阅场景通常使用QoS 0即可,既满足需求又节省流量。
订阅成功后会返回:
+MQTTSUB: OK接着测试数据上报。执行:
AT+MQTTPUB=$dp,{"datastreams":[{"id":"temp","datapoints":[{"value":26.5}]}]},0,0这条指令的四个参数分别是:Topic、payload、QoS、Retain标志。返回:
+MQTTPUB: OK说明消息已经交给模组处理,并成功发送到OneNET平台。这时登录OneNET控制台,进入设备详情页的数据流展示页面,就能看到名为temp的数据流,最新值为26.5。
这里有一个实战细节:如果payload里的JSON包含逗号,AT指令解析时并不会出错,因为模组是按第一个逗号之后的所有内容作为payload处理的。但如果你用了某些自制的串口发送工具,该工具可能自作主张地按逗号拆分了发送内容,导致发送不完整。建议用普通的串口调试工具,开启“发送新行”功能,让AT指令以换行符结尾。
4.3 OneNET新版Studio的token鉴权差异
如果你使用的是OneNET Studio新版平台,而不是旧版多协议接入,那接入参数和鉴权方式会有较大差异。旧版是产品ID+设备ID+APIKey,新版更多使用productID、deviceName、deviceSecret三元组,并且连接密码需要通过HMAC算法动态生成token。
Studio版的MQTT连接参数拼接规则大致如下:
- ClientID:
productID_deviceName - 用户名:
productID - 密码:使用res、et、method、sign四个字段拼接的token字符串
其中res通常为products/{productID}/devices/{deviceName},et为过期时间戳,method为加密方式(如sha1或md5),sign是通过deviceSecret做HMAC计算得到的签名值。
Air780EP的AT+MCONFIG同样支持填入这些字段,username填productID,password填完整的token字符串。由于token的生成逻辑相对繁琐,建议在PC端写个小脚本生成好,再填入模组。不同固件版本对token长度和字符类型可能有要求,如果MCONFIG后执行MQTTCONN失败,优先检查password是否完整、et是否大于当前时间。
具体新旧平台该选哪个,我的建议是:如果只是做产品原型验证,旧版多协议接入最快捷;如果是长期商用项目,优先用Studio新版,因为新版平台在设备管理、数据存储、规则引擎和API开放程度上都更完善。
5. 常见问题与排查技巧实录
5.1 连接阶段的失败速查表
把我在调试Air780EP接入OneNET时遇到的问题整理成一张速查表,方便大家对照。
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| AT无回显 | 接线错误/串口号错误/波特率不匹配 | 检查TXD/RXD交叉;确认串口被占用;逐个波特率尝试 |
| +CPIN?返回ERROR | SIM卡未识别 | 重新插拔SIM卡;检查卡座焊接;换卡测试 |
| +CSQ值极低或返回99 | 天线未接好或基站信号弱 | 检查IPEX天线连接;移到信号好的位置 |
| +CEREG?返回0或2 | 网络注册失败 | 确认SIM卡能正常上网;检查运营商制式 |
| MIPSTART返回CONNECT FAIL | 域名解析失败/网络被限制 | 确认模组已附着网络;检查物联网卡公网权限 |
| MQTTCONN后返回ERROR或长时间无响应 | 三元组错误/平台鉴权失败 | 核对产品ID、设备ID、APIKey是否匹配 |
| 能连接但发布消息后平台看不到数据 | Topic或payload格式不合法 | 确认使用$dp;检查JSON格式严格符合要求 |
特别提醒:MQTTCONN执行失败时,不要反复重试同样的配置,大概率是三元组或APIKey的问题。先把平台侧和模组侧的三组数字逐位核对一遍,再检查设备是否被平台禁用了。
5.2 数据上报成功但平台看不到数据的排查
AT指令返回+MQTTPUB: OK只代表模组把数据交给了协议栈并成功发送到网络,不代表OneNET平台一定接收成功。如果平台侧看不到新数据点,常见原因有三个。
第一,Topic不对。OneNET不是任意Topic都接收数据,必须发布到$dp这个数据上报Topic,平台才会解析。如果你发布到了自建的Topic,平台默认不处理。
第二,payload格式不合法。OneNET对$dp消息的JSON结构有严格要求,数据流内部的id、datapoints、value层级不能错。曾经我把value写成了字符串"26.5",平台直接拒绝了这条数据。数字就不要加引号,这点在拼JSON时一定要注意。
第三,设备被禁用了。如果设备在平台侧被禁用,模组虽然能建立MQTT连接,但发布数据时平台会静默丢弃。登录控制台检查设备状态,确保是非禁用状态。
5.3 掉线、重启与重连机制的工程化建议
产品在实验室调试时很少掉线,但到了实际环境,网络抖动、基站切换、模组异常重启都可能发生。如果做的是商用产品,一定不能依赖人工重启来恢复连接,要在MCU端写一个简单的重连逻辑。
我的做法是在MCU中维护一个MQTT状态机:模组正常连接时,周期上报数据;当模组返回连接断开的URC通知,或者MCU连续几次发送MQTTPUB后没有收到OK响应时,MCU进入重连流程。重连时先执行MQTTCONN,再订阅之前订阅过的Topic。不要每次重连都重新执行MCONFIG,频繁写入flash会影响模组flash寿命。
还有一个和OneNET平台策略相关的坑:平台会在KeepAlive超时后主动断开TCP连接。模组侧的KeepAlive参数我建议设置在60秒到120秒之间,太短会增加无效心跳流量,太长则可能被NAT或运营商超时踢掉连接。实测下来120秒是性价比比较高的配置。
如果模组长时间空闲不发数据,OneNET可能会在TCP层面把连接回收。常见做法是让设备每60秒发一条心跳消息,可以是空数据或者设备状态信息,保持链路活跃。
最后再分享一点实际操作中的体会
我最早开始用Air780EP的时候,习惯先拿电脑上的MQTTX工具去验证OneNET平台的接入参数。MQTTX里填上设备ID、产品ID、APIKey,如果能连上并且收发消息,那平台侧就没问题;然后再去调模组的AT指令,这样把“平台问题”和“模组问题”分开排查,效率会高很多。
后来调STM32+Air780EP组合时,我在MCU端加了一个串口日志透传功能,把所有AT指令交互过程实时打印到调试串口。这样一旦设备在现场出现连接问题,不需要把设备拆回来,远程看日志就能判断是网络注册失败、MQTT鉴权失败还是数据格式错误。这个习惯帮我省了无数次现场出差,非常推荐有条件的团队在开发阶段就把日志系统做进去。
另外想提醒的是,合宙不同固件版本的AT指令细节可能会有差异,比如某些版本默认开启回显,某些版本对逗号参数的处理有要求。动手之前先去合宙官方文档中心找到对应固件版本号的AT指令手册,不要拿旧项目的指令集直接套用。我见过不止一位同事因为固件升级后指令行为变了,排查了半天才发现是版本兼容问题。先把手册翻清楚,再开始配参数,这是做AT模组开发最省时间的路线。