Warning: Attempt to read property "post_author" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/opengraph/class-facebook.php on line 325

Warning: Attempt to read property "post_author" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/opengraph/class-facebook.php on line 330

Warning: Attempt to read property "post_date" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/opengraph/class-facebook.php on line 311

Warning: Attempt to read property "post_modified" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/opengraph/class-facebook.php on line 312

Warning: Attempt to read property "ID" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/class-opengraph.php on line 67

Warning: Attempt to read property "ID" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/class-opengraph.php on line 77

Warning: Attempt to read property "ID" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/class-jsonld.php on line 139

Warning: Attempt to read property "post_modified" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/class-jsonld.php on line 757

Warning: Attempt to read property "post_date" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/class-jsonld.php on line 758

Warning: Attempt to read property "post_type" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/class-jsonld.php on line 766

Warning: Attempt to read property "post_author" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/class-jsonld.php on line 772

Warning: Attempt to read property "post_modified" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/class-jsonld.php on line 775

Warning: Attempt to read property "post_date" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/class-jsonld.php on line 775

Warning: Attempt to read property "post_content" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/blocks/class-block-parser.php on line 73

Warning: Attempt to read property "ID" on null in /usr/local/lighthouse/softwares/wordpress/wp-content/plugins/seo-by-rank-math/includes/modules/schema/class-frontend.php on line 71
技术笔记

一个物联网平台同时接 MQTT 联网设备和 485 串口老设备,我们是怎么做的

一个平台要同时接 MQTT 联网设备和只有 485 串口的老设备。本文讲我们怎么把两类设备收口到同一套模型,以及什么情况下应该直接换设备,而不是硬做协议适配。

2026 年 9 月 26 日 · 技术笔记

文中客户一律用描述性别名,不出现客户名称、项目全称与地点。

做物联网平台,最容易在需求阶段被一句话带过去:「设备都能联网吧?」

真实情况往往是:一批设备是近年的,自带 MQTT,开机就上报;另一批是几年前甚至更早的,只留了一根 RS-485 或 RS-232,连网口都没有。甲方想要的是一个平台看到全部设备,而不是两套系统、两个大屏。

这篇文章讲的,就是我们在一个智能设备的中央管理平台项目里,怎么把这两类设备塞进同一套模型。

一、先承认现实:老设备不会因为你建了平台就联网

那次项目的设备侧是分裂的:

  • 新设备走 MQTT,有稳定的心跳、状态上报和下行指令通道;
  • 老设备只有串口(RS-232 / RS-485 一类),靠一台工控机或网关做本地采集,采集程序是 Java 的,通过串口库读写数据。

市面上大多数通用 IoT 平台只支持其中一类——通常是 MQTT。于是常见的处理方式是:把老设备全换掉,或者给老设备单独做一个小系统,数据再同步到大平台。前者的成本甲方不一定接受,后者最后一定演变成两套口径、两套运维。

我们要做的是第三条路:在同一个后台里,把两种协议做成两个平行的适配层,上面用同一套模型收口。

二、两条通道,各管一段

实现上,这条链路分成两条互不干扰的通道:

第一条:MQTT 通道。 平台侧维护连接配置、消息收发服务与数据处理服务三个角色——连接配置负责 broker 地址、认证与重连策略;收发服务负责订阅主题、下发消息;处理服务负责把上行报文解析成平台内部的设备状态。

第二条:串口通道。 这一侧要自己处理串口参数的枚举与配置(波特率、数据位、校验位、停止位),管理串口的打开、读取与释放,并把读到的字节流按设备协议解析。我们在项目里用的是 Java 的串口库,把参数管理和串口管理拆成两个类,前者描述「怎么连」,后者负责「怎么读写」。

关键点在于:这两条通道的实现代码是分开的,但对上层暴露的能力是同一套——设备上线/离线、状态上报、指令下发、异常告警。上层业务不知道自己面对的是 MQTT 设备还是串口设备。

三、收口到「场景—设备—指令」模型

两条通道之上,我们统一成了三层模型:

  • 设备:唯一标识、类型、所属位置、当前状态、最近心跳。不管底下是 MQTT 还是串口,设备对象长一样。
  • 指令:把「下发」抽象成一个表单模型——指令类型、目标设备、参数、超时与重试。MQTT 设备直接把指令报文发出去;串口设备则由采集侧转换成对应的串口帧。
  • 场景:把「某个条件下触发一组设备的某个动作」定义成场景,场景里引用的设备可以混合 MQTT 与串口设备。

这个模型的意义在于:加设备的时候不用改上层。新增一台 MQTT 设备,只是多一个连接;新增一台串口设备,只是多一条串口配置。业务侧的联动逻辑完全不用动。

四、老设备值得救吗:一个判断方法

我们通常会让甲方算三笔账:

  1. 替换成本:设备本身 + 施工 + 停机损失。工业现场停机往往比设备贵。
  2. 数据价值:这台设备上的数据,是每天看一次就够,还是要做秒级监控?如果只是抄表级需求,串口采集足够。
  3. 剩余寿命:如果这批设备三年内本来就要淘汰,做协议适配的投入就很难收回;如果还要用八年,适配层就是划算的。

多数情况下结论是混合方案:关键设备联网直采,边缘设备走网关 + 串口汇聚。这也是我们在平台侧坚持同时保留两条通道的原因——不让甲方为了上一套平台而被迫换设备。

五、数据落哪:为什么要考虑时序库

设备数据有个显著特征:写入密集、按时间查询、几乎不更新。用传统关系表存,几百万条以后查询就会开始难受。

我们在设备数据侧采用过时序库的方案——把设备数据表建成时序超表,并针对时间维度做分区与压缩优化。带来的直接好处是:按时间范围查某台设备的历史曲线,响应稳定;同时保留与既有业务库(MySQL / PostgreSQL 等)的联表能力。

选型上我们的建议是:如果你的设备点位在几百以内、采样间隔是分钟级,关系库完全够用;一旦到了几千点位、秒级采样,就应该在设计阶段就引入时序库,事后迁移的代价远大于一开始多用一张表。

六、什么情况下我们建议直接换设备

说了这么多适配层的好处,也要说清楚它的边界。下面三种情况,我们一般不建议做协议适配:

  • 设备本身已经无法稳定通信:串口时断时续、校验错误率高,再好的适配层也救不回数据质量。
  • 需要的功能硬件不支持:比如要做远程固件升级、要读设备内部寄存器之外的参数,硬件层面就不支持。
  • 安全要求不允许:某些场景下老设备没有认证能力,接入后反而成了内网的薄弱点,这时候应该先解决网络隔离与接入认证,而不是急着上平台。

七、一条可复用的经验

回过头看,这个项目最值钱的不是 MQTT 或串口本身,而是把「协议适配」和「业务模型」彻底分开这件事。

分开之后,我们后来在其他场景里也复用了同一套结构:充电设施的数据采集与监测、工业设备的状态与可靠性管理、现场作业类 App 的数据回传,底层协议各不相同,但上层都是「设备—指令—场景」这一套。

对甲方来说,这意味着一件事:你不需要在立项时就把所有设备的通信方式确定死。先把模型定下来,协议可以后面加。


如果你手上的项目也面临新旧设备混用、不知道该换设备还是做适配,可以先做一次设备清单与通信方式的梳理,再决定平台怎么建。

了解更多:AIoT 应用开发 · 数据集成 · 数据大屏与数字孪生 · 技术咨询

需要一份写清范围的清单?把你的业务说一遍,几秒生成需求清单。