Skip to content

5.5 消息格式规范(payload 与数据点的映射规则) ​

本节说明 MQTT payload 与数据点的映射规则。设备 publish 一条消息后,服务器会按一套固定规则把 payload 拆开写进实时数据库。规则不复杂,但不了解会产生意料之外的数据点。

5.5.1 两条基本前提 ​

  1. 主题名就是数据点名。发布到主题 temperature,等于把值写进数据点 temperature。不需要、也不支持 {用户名}/data/{点名} 这种三段式主题:身份由 CONNECT 报文的用户名密码提供,不出现在主题里。
  2. publish 一定会落库。只要 QoS0/QoS1 消息到达服务器就立刻写实时数据库(QoS2 在收到 PUBREL 后写)。同时 Broker 正常执行转发,两者互不影响。

5.5.2 四条映射规则 ​

一条 MQTT 消息会变成哪些数据点:四条映射规则与同时生效的坑

服务器先尝试把 payload 当 JSON 解析。只有解析成功且是 JSON 对象才走 JSON 分支,否则整个 payload 当一个值。

规则一:payload 不是 JSON 对象 → 数据点 = 主题名,值 = 整个 payload

topic:   temperature
payload: 25.6
结果:    temperature = 25.6

这是推荐用法:一个主题对应一个点,payload 就是裸值。数字、字符串、true/false 都可以,服务器统一按字符串存。

注意:JSON 数组(如 [1,2,3])不是对象,也走这条规则,整个 [1,2,3] 会被当成 temperature 的值存进去。

规则二:JSON 对象里的 value 字段 → 数据点 = 主题名

topic:   temperature
payload: {"value":25.6}
结果:    temperature = 25.6

value 是唯一被特殊对待的字段名,它的值直接写到主题同名的数据点上,不会变成 temperature/value。

规则三:JSON 对象里的其它字段 → 数据点 = 主题名/字段名

topic:   motor
payload: {"speed":1450,"current":3.2}
结果:    motor/speed   = 1450
         motor/current = 3.2

一条消息批量上报多个点就靠这条规则。等价于分别发布到 motor/speed 和 motor/current。

规则四:主题为空 + JSON 对象 → 数据点 = 字段名本身

topic:   (空)
payload: {"temperature":25.6,"humidity":60}
结果:    temperature = 25.6
         humidity    = 60

适合一次上报一批互不相关的点,不想让它们共享主题前缀。

5.5.3 规则会同时生效 ​

同一条 JSON 里的不同字段各走各的规则。这是最容易被误解的地方:

topic:   temperature
payload: {"value":25.6,"timestamp":1705312200,"quality":"good"}

结果:    temperature           = 25.6          ← value 走规则二
         temperature/timestamp = 1705312200    ← 走规则三
         temperature/quality   = good          ← 走规则三

请勿直接套用其它平台的 JSON 格式

{value, timestamp, quality} 是很多平台的标准上报格式,但在这里 timestamp 和 quality 不会被当成元数据,而是各自变成一个真实的数据点写进数据库。数据点列表里会多出一堆 xxx/timestamp、xxx/quality,还会各自占用存盘配额。

服务器的时间戳由服务器自己打,不需要设备上报。只想上报一个值,直接把 payload 设成裸值(规则一)最稳妥。

5.5.4 值的类型 ​

所有值最终都按字符串存入数据库。JSON 里的 25.6、"25.6"、true 存进去分别是 25.6、25.6、true。

云组态和事件触发在做数值比较时会把字符串转成数字,所以上报数字型数据时不用特意加引号,但要保证内容能被解析成数字(不要带单位,25.6℃ 会导致比较失败)。

嵌套的 JSON(字段值本身又是对象或数组)不会被递归展开,只有第一层字段名会被用来拼数据点名。需要多层结构时应把主题拆开分别发布。

5.5.5 命名建议 ​

  • 用 / 分层,和数据点子键规则天然一致:车间1/1号机/温度
  • 主题名支持中文(服务器按 UTF-8 处理),云组态里绑定的就是同一个名字
  • 避免用 $ 开头:$ 是 MQTT 系统主题的保留前缀,不参与通配符匹配
  • 一个点一个主题。把大量字段塞进一条 JSON 虽然可用,但数据点名难以维护

5.5.6 下发(服务器 → 设备) ​

服务器不预定义 command / alarm 这类固定路由。控制类语义由业务侧自行约定主题名和 payload。

实时数据库的值变化时,服务器会把变化推到 MQTT 侧,默认格式是 QoS0 + retain,payload 为 {"value":值}。设备订阅对应主题即可收到下发。

因为默认下发格式是 {"value":值},而规则二正好把 value 映射回主题同名点,所以上下行是自洽的:设备收到什么格式,原样发回去也能被正确解析。

5.5.7 需要完全自定义格式怎么办 ​

上面四条是系统默认规则。如果对接的第三方设备的格式固定无法修改(比如必须用 {"d":{"t":25.6}} 这种私有结构),可以在服务器端写 Lua 策略函数接管解析:

  • mqtt_to_databus(topic, payload, len, qos, retain, client_id, is_utf8):上行接管,由脚本决定拆成哪些数据点
  • databus_to_mqtt(点名, 点值):下行接管,由脚本决定发什么主题和 payload

两个函数返回 false 时系统按默认规则接管,返回 true 表示已由脚本处理完成。这样既能兼容私有格式,也不影响其它设备走默认规则。


LPPLC 工业物联网云平台 · 软硬件与云平台全栈自研