消息透传与数据解析
推荐阅读:
- 《设备接入(概述)》 — 了解 IotDeviceMessage 消息格式
- 《设备接入(MQTT 协议)》 — 下文的快速体验使用 MQTT 协议
- 《阿里云物联网平台 —— JavaScript 数据解析脚本模板和示例》 (opens new window)
- 《阿里云物联网平台 —— 编写数据解析脚本解析设备透传数据》 (opens new window)
很多设备不会发送标准的 JSON 消息,只会收发自定义的二进制帧(例如 AA 01 00 FA 3C)。消息透传与数据解析,用来接入这类设备:
- 消息透传(raw):设备把原始字节发到网关的透传入口,平台原样保存;平台也可以把原始字节原样下发给设备
- 数据解析:为产品配置一段 JavaScript 脚本,
decode把上行的原始字节解析为标准消息,encode把下行的属性设置、服务调用编码为字节
例如:
- 温湿度传感器上报 5 个字节,解析为
thing.property.post属性上报,之后与标准设备一样保存属性、触发场景联动 - 管理后台对设备「属性设置」,由脚本编码为设备能识别的控制帧
- 还没写好脚本时,先透传接入,在「设备消息」中查看设备实际发送的原始帧(HEX)
整体流程如下:
上行:设备 ──原始字节──▶ 网关透传入口 ──decode(ctx)──▶ 一条标准消息(带原始帧)──▶ 平台
└─ 未启用脚本 / 返回 null ──▶ thing.raw.post(只带原始帧)
下行:thing.property.set、thing.service.invoke ──encode(ctx)──▶ {bytes} 透传写出 / {standard: true} 按原格式下发
thing.raw.push(管理后台透传下发) ─────────────────────▶ 原样写出,不经过脚本
脚本由 yudao-module-iot-gateway 网关模块执行;脚本的保存、调试由 yudao-module-iot-biz 模块提供,两者共用 yudao-module-iot-core 中的 IotScriptUtils 脚本契约(入参构造、输出校验)。
# 1. 功能概述
# 1.1 透传方法
| method | 方向 | 说明 |
|---|---|---|
thing.raw.post | 上行 | 透传上报:没有解析为业务消息的原始帧。只能由网关的透传入口生成,设备不能通过标准 JSON 发送,管理后台也不能模拟 |
thing.raw.push | 下行 | 透传下发:管理后台「模拟设备 → 透传下发」发送,原样写出给设备,不经过 encode |
两者的原始字节都保存在消息的 raw 字段(Base64),「设备消息」中按 HEX 展示。解析成功的业务消息,同样带有 raw 字段。
# 1.2 哪些消息会执行脚本
不是所有消息都经过脚本,只有下表中「执行」的几种情况:
| 场景 | 是否执行脚本 |
|---|---|
| 设备通过透传入口上报的原始字节(见「6. 各协议的透传入口」) | 执行 decode |
平台下发的 thing.property.set、thing.service.invoke 请求 | 执行 encode |
Modbus 设备对 encode 编码下发的指令的响应 | 执行 decode(带 ctx.request) |
| 设备通过标准主题、路径上报的 JSON 消息 | 不执行,保持原有处理 |
thing.raw.push 透传下发 | 不执行,原样写出;Modbus 设备的响应直接记录为回复 |
其它下行:各类 _reply 回复、配置推送、OTA、设备影子、拓扑等 | 不执行,按原协议的标准格式下发 |
| 连接认证、动态注册等 | 不执行 |
因此,使用脚本的设备如需 OTA、设备影子 等功能,仍按该协议原有的标准消息格式收发,能否使用取决于该协议原有的支持能力。
# 1.3 上行的处理结果
每次透传上报,最多投递一条消息:
| 情况 | 结果 |
|---|---|
| 网关的脚本开关关闭(默认),或产品脚本停用、未配置 | 投递一条 thing.raw.post,只带原始帧 |
decode 返回一条消息 | 投递这条业务消息,raw 字段带上原始帧 |
decode 返回 null、undefined,或脚本没有定义 decode | 投递一条 thing.raw.post,只带原始帧 |
| 脚本执行出错、超时、繁忙或已熔断、输出不合法 | 不投递任何消息,只在网关日志中记录(HTTP、CoAP 在响应中返回错误码) |
注意:透传上报解析出的消息,平台不会自动回复 _reply(例如 thing.property.post_reply)。
# 1.4 下行的处理结果
thing.property.set、thing.service.invoke 下行时,网关按产品脚本的 encode 决定如何下发:
| 情况 | 结果 |
|---|---|
| 网关的脚本开关关闭,或产品脚本停用、未配置 | 按原协议的标准格式下发 |
encode 返回 { bytes: [...] } | 按协议透传写出这些字节 |
encode 返回 { standard: true } | 按原协议的标准格式下发 |
encode 返回 null、undefined,或没有定义 encode | 不下发,只在网关日志中记录(不会改为按标准格式下发) |
| 脚本执行出错、超时、输出不合法 | 不下发,只在网关日志中记录 |
网关脚本开关开启时,同一设备的指令按收到的顺序依次处理,每个设备最多排队 256 条,超出的指令丢弃并记录日志。
传输确认 ≠ 业务结果
- 管理后台「属性设置」「透传下发」提示成功,只表示平台已把指令交给网关,不代表设备已收到;网关写出成功,也只表示已写入设备连接(MQTT 为 publish 已提交)。
- MQTT 透传上报的 PUBACK,只表示网关已处理完本次上报,不代表脚本解析成功。
- HTTP、CoAP 透传上报的最终响应,是网关对本次解析、投递的反馈:成功时
code为0、data.messageId为投递的消息编号,失败时返回错误码(见「6.1 协议差异」),可据此排查。CoAP 的 CON 请求先收到的空 ACK 只是传输确认,结果以之后的分离响应为准。 - 以上都不代表平台已处理完这条消息,也不代表设备已执行完成。设备的执行结果,需要设备回执:
decode返回带code的回执(见「3.1 decode」),或 Modbus 的实际响应,才会出现在「设备消息」中。网关判定的失败(设备离线、写出失败、Modbus 超时或断线等)只记录网关日志,不会生成失败回复。
# 2. 配置
# 2.1 开启网关的脚本开关
在网关的 application.yaml 中开启,默认关闭:
yudao:
iot:
gateway:
script:
enabled: true # 是否开启数据解析脚本,默认 false
deadline: 2s # 截止时间,默认 2s
exec-budget: 500ms # 单次脚本执行的时间预算,默认 500ms
max-instructions: 1000000 # 单次脚本执行的指令上限,默认 1000000
max-pending-commands-per-device: 256 # 每个设备最多排队的下行指令数,默认 256
对应 IotGatewayProperties.ScriptProperties 配置类,一般只需修改 enabled。
① deadline:只作用于透传上报和脚本的处理,标准 JSON 消息、thing.raw.push 不受影响:
- 透传上报:从网关收到开始计算,覆盖排队、执行
decode;投递前已超过时不投递(开关关闭时也会核对排队时间)。HTTP、CoAP 也在这个时间内应答 encode:从网关收到下行指令开始计算,覆盖按设备排队、执行encode;写出前已超过时不下发,之后的网络写出不受它限制- Modbus 设备响应的
decode:从收到响应开始计算;超过时不记录回复
截止时间只在投递、写出之前检查,已经开始的投递或写出不会撤销。因此 HTTP、CoAP 返回超时后,消息仍可能已投递,有副作用的操作不宜盲目重试。
② exec-budget:单次脚本的执行时间,与 deadline 剩余的时间取较早者。
③ 开关关闭时:透传上报只记录 thing.raw.post,下行指令按标准格式下发,thing.raw.push 照常原样写出。
④ 管理后台的脚本保存、调试,在平台(yudao-module-iot-biz)执行,不受这个网关开关影响。
# 2.2 数据存储
产品的数据解析脚本,保存在 iot_product 表;网关随设备信息缓存使用:
| 字段 | 类型 | 说明 |
|---|---|---|
script_content | TEXT | 数据解析脚本,JavaScript ES5,UTF-8 不超过 32KB |
script_enabled | BIT(1) | 是否启用,默认关闭 |
设备消息的原始帧,保存在时序库设备消息表 device_message 的 raw 列(原始字节的 Base64),由对应的 Mapper 建表:
- TDengine:
raw VARCHAR(8192),见 IotDeviceMessageMapper.xml 的createSTable - IoTDB:
raw STRING FIELD,见 IotDeviceMessageIoTDBMapper.xml 的createTable
# 3. 编写脚本
脚本使用 JavaScript ES5 语法,定义 decode(ctx)、encode(ctx) 两个函数,可以只定义其中一个。函数名与入参和阿里云不同,不能直接复制阿里云的脚本。
# 3.1 decode(ctx)
上行时调用,ctx 的字段如下:
| 字段 | 说明 |
|---|---|
direction | 固定为 decode |
protocol | 协议类型,例如 mqtt、tcp、modbus_tcp_client |
productKey | 产品标识 |
deviceName | 设备名称(脚本调试时固定为 debug-device) |
receivedAt | 接收时间,毫秒时间戳 |
bytes | 原始字节,无符号整数数组,每个元素 0~255 |
hex | 原始字节的 HEX 字符串,大写、无空格 |
request | 仅 Modbus 透传事务的响应才有:原请求的 { method, requestId, params },普通上行没有该字段 |
返回值为一条标准消息对象(不要再包一层 messages、result),或者 null:
| 字段 | 说明 |
|---|---|
method | 必填。上报只能是 thing.property.post、thing.event.post |
params | 上报时必填,必须是对象。属性上报为 { 标识符: 值 },事件上报为 { identifier, value, time? } |
requestId | 可选,不超过 50 个字符;不填时由平台生成 |
code | 可选,整数。有值时表示回执:method 只能是 thing.property.set、thing.service.invoke,且必须带 requestId |
msg | 可选,回执的说明,不超过 256 个字符 |
data | 可选,回执的数据 |
① 不能返回 id、deviceId、raw 等其它字段,消息编号、时间、设备身份、原始帧都由平台设置。
② params、data 序列化后各不超过 8192 字节(UTF-8),事件的 identifier 为 1~100 个字符。
③ 如果设备会回执下行指令,可以在 decode 中返回回执,例如 { method: 'thing.property.set', requestId: '...', code: 0 }。requestId 需与下发的请求一致(可在 encode 时把 ctx.message.requestId 编进帧里),「设备消息」中的请求才能与回执配对。
# 3.2 encode(ctx)
下发 thing.property.set、thing.service.invoke 请求时调用,ctx 的字段如下:
| 字段 | 说明 |
|---|---|
direction | 固定为 encode |
protocol | 协议类型 |
productKey | 产品标识 |
deviceName | 设备名称 |
message | 下行指令 { method, requestId, params }。属性设置的 params 为 { 标识符: 值 },服务调用为 { identifier, inputParams } |
返回值三选一:
{ bytes: [...] }:透传写出的字节,每个元素为 0~255 的整数。Modbus 协议必须是合法的请求 PDU(见「6.2 Modbus」),其它协议为 1~4096 字节{ standard: true }:这条指令按原协议的标准格式下发null:不下发
bytes 和 standard 只能返回一个,也不能带其它字段。
# 3.3 完整示例
假设设备使用如下的帧格式:
| 方向 | 帧 | 说明 |
|---|---|---|
| 上行 | AA 01 + 温度(2 字节)+ 湿度(1 字节) | 属性上报。温度为 int16 大端,单位 0.1℃;湿度为 uint8,单位 % |
| 上行 | AA 02 + 告警级别(1 字节) | 告警事件 |
| 下行 | AA 81 + 开关(1 字节) | 设置开关:00 关、01 开 |
对应的产品物模型有:属性 temperature(float)、humidity(int)、power(bool,读写),事件 alarm(输出参数 level,int)。脚本如下:
/**
* 上行:原始字节 → 一条标准消息;返回 null 表示没有业务消息(记录为 thing.raw.post)
*/
function decode(ctx) {
var b = ctx.bytes; // 无符号字节数组,每个元素 0~255
if (b.length < 2 || b[0] !== 0xAA) {
return null;
}
// AA 01:属性上报
if (b[1] === 0x01 && b.length >= 5) {
var t = (b[2] << 8) | b[3];
if (t > 0x7FFF) {
t -= 0x10000; // int16 负数
}
return {
method: 'thing.property.post',
params: {
temperature: t / 10,
humidity: b[4]
}
};
}
// AA 02:告警事件
if (b[1] === 0x02 && b.length >= 3) {
return {
method: 'thing.event.post',
params: {
identifier: 'alarm',
value: { level: b[2] },
time: ctx.receivedAt
}
};
}
return null;
}
/**
* 下行:thing.property.set、thing.service.invoke → 下发的字节
*/
function encode(ctx) {
var msg = ctx.message;
if (msg.method === 'thing.property.set' && msg.params && msg.params.power !== undefined) {
return { bytes: [0xAA, 0x81, Number(msg.params.power) ? 1 : 0] };
}
// 其它指令,按原协议的标准格式下发
return { standard: true };
}
例如,上行 AA 01 00 FA 3C 解析为:
{
"method": "thing.property.post",
"params": {
"temperature": 25,
"humidity": 60
}
}
下行属性设置 { "power": 1 },编码为 AA 81 01。
# 3.4 运行约束
① 语法:ES5(Rhino 引擎)。不要使用箭头函数、class、模板字符串等 ES6+ 语法;没有 console、Buffer、TextDecoder、setTimeout 等宿主对象,也不能访问任何 Java 类。
② 无状态:每次调用都在新的作用域中重新执行脚本的顶层代码,调用之间不能保存状态;Array.prototype 等标准对象不能修改。
③ 大小:脚本 UTF-8 不超过 32KB;透传上报的原始字节 1~4096 字节;脚本返回值序列化后不超过 65536 个字符。
④ 执行预算:单次执行不超过 500ms(exec-budget)、100 万条指令(max-instructions),递归深度不超过 64 层,超过按超时或出错处理。
⑤ 熔断:同一脚本(按内容区分)在一个网关节点 1 分钟内超时 3 次,该节点之后的调用直接拒绝。修改脚本内容、或重启网关后恢复。
⑥ 脚本与网关运行在同一个 JVM 中,以上约束只限制执行时间和调用方式,不是进程级的资源隔离。
# 4. 管理后台
本节截图均为示例:使用「3.3 完整示例」的脚本和示例数据。
# 4.1 产品数据解析
对应 [IoT 物联网 -> 设备接入 -> 产品管理] 菜单,进入产品详情的「数据解析」Tab。对应前端项目的文件:
- Vue3:
src/views/iot/product/product/detail/ProductDetailsScript.vue - Vben Antd / Ele:
apps/web-antd、apps/web-ele下的src/views/iot/product/product/detail/modules/script.vue - Admin Uniapp:
src/pages-iot/product/product/components/script-section.vue

① 保存并生效:只保存脚本内容,不改变启用状态。保存时检查长度和语法(只编译,不执行),有语法错误时提示行号。
② 启用 / 停用:只修改启用状态,启用的是已保存的内容。启用时脚本内容不能为空;清空脚本内容,需要先停用。
③ 恢复为已保存内容:放弃编辑区未保存的修改。脚本没有草稿、历史版本,未保存的修改只保留在当前页面。
④ 已保存内容:展示已保存内容的 SHA-256 前 12 位,与网关熔断日志中的 hash(...) 对应,便于确认是哪一版脚本。
生效时间
保存、启用、停用后,不是立即对设备生效:网关按设备在本地缓存设备信息(包括产品的脚本),缓存写入 1 分钟后,下一次访问时才异步刷新,刷新完成前仍使用旧的脚本。测试时,可以重启网关立即生效。
# 4.2 脚本调试
「数据解析」Tab 右侧的调试面板,执行当前编辑区的内容(未保存也可以)。调试不保存脚本、不发送给设备、不修改属性,使用与网关相同的运行约束和输出校验。

① 上行解码:输入原始字节的 HEX(允许空格,1~4096 字节),展示解析出的消息。返回 null 时提示「无业务消息」,实际上报时记录为 thing.raw.post。
② 下行编码:输入下行指令 JSON,method 只能是 thing.property.set、thing.service.invoke,展示下发方式及输出的 HEX。返回 null 时提示 ENCODE_EMPTY。
③ 失败类型:ERROR 脚本出错(带行号)、TIMEOUT 超时、REJECTED 调试繁忙或已熔断、OUTPUT_INVALID 输出不合法、ENCODE_EMPTY 未生成下行数据。
调试时 ctx.deviceName 固定为 debug-device,ctx.protocol 为产品的协议类型。
# 4.3 透传下发
进入设备详情的「模拟设备」Tab,切换到「透传下发」,输入载荷 HEX 后发送,下发 thing.raw.push。对应 Vue3 的 DeviceDetailsSimulator.vue 文件。

① 字节原样写出给设备,不经过 encode,也不受网关脚本开关影响。
② HTTP、CoAP 协议的产品不支持透传下发。
③ 普通协议为 1~4096 字节;Modbus 协议填写 PDU(功能码 + 数据,不含从站地址、CRC、MBAP),5~253 字节,写操作会二次确认功能码和地址。
④ 「模拟设备」不提供透传上报的模拟。验证 decode,请使用「4.2 脚本调试」,或参考「5. 快速体验」用真实客户端上报。
# 4.4 设备消息
进入设备详情的「设备消息」Tab,「原始帧(HEX)」列展示消息的 raw 字段,可以复制;支持按「有原始帧」「无原始帧」筛选。对应 Vue3 的 DeviceDetailsMessage.vue 文件。

| 消息 | 原始帧 |
|---|---|
透传上报解析出的业务消息、thing.raw.post | 设备上报的原始字节 |
thing.raw.push 透传下发 | 下发的字节 |
| Modbus 透传事务的回复 | 设备响应的 PDU |
encode 编码下发的属性设置、服务调用 | 无:记录的是平台下发的标准指令,不含编码后的字节 |
# 4.5 接口
| 接口 | 说明 | 权限 |
|---|---|---|
PUT /iot/product/update-script | 更新数据解析脚本(只修改提交的 scriptContent、scriptEnabled) | iot:product:update |
POST /iot/product/debug-script | 调试数据解析脚本 | iot:product:update |
POST /iot/device/message/send | 发送消息;method 为 thing.raw.push 时,params 为 { "payload": "Base64" } | iot:device:message-send,透传下发另需 iot:device:message-raw-send |
GET /iot/device/message/page | 设备消息分页;raw=true 只看有原始帧的消息 | iot:device:message-query |
# 5. 快速体验(MQTT)
下面以 MQTT 协议的直连设备为例,使用 MQTTX (opens new window) 模拟设备,跑通「透传上报 → 解析 → 属性设置编码 → 透传下发」。
请将主题中的
{productKey}、{deviceName}替换为实际值。
① 准备物模型:在 MQTT 产品的「物模型(功能定义)」中,新增「3.3 完整示例」中的属性 temperature、humidity、power(事件 alarm 可选)。也可以把脚本中的标识符,改为产品已有的属性。
② 开启网关开关:按「2.1 开启网关的脚本开关」设置 enabled: true,重启网关。
③ 配置脚本:进入产品详情的「数据解析」Tab,粘贴「3.3 完整示例」的脚本,点击「保存并生效」,再点击「启用」。
④ 调试脚本:在右侧调试面板中验证:
- 上行解码,输入
AA 01 00 FA 3C,解析出temperature为25、humidity为60的属性上报 - 下行编码,输入
{"method": "thing.property.set", "requestId": "debug-1", "params": {"power": 1}},输出 HEX 为AA8101
⑤ 连接设备:按 《设备接入(MQTT 协议)》 的「4.1 连接认证」连接设备,并订阅 /sys/{productKey}/{deviceName}/thing/raw/push 主题。如果网关在 ③ 之前已经访问过该设备,等待约 1 分钟让网关刷新缓存,或重启网关。
⑥ 透传上报:发布到 /sys/{productKey}/{deviceName}/thing/raw/post 主题,Payload 格式选择 Hex,内容为 AA0100FA3C。
- 「设备消息」中出现一条
thing.property.post,原始帧为AA 01 00 FA 3C - 「物模型数据」中,
temperature为 25、humidity为 60
再发布一个脚本不认识的帧,例如 AA09,「设备消息」中出现一条只带原始帧的 thing.raw.post。
⑦ 属性设置:在「模拟设备 → 下行指令调试 → 属性设置」中,设置 power 为 1,MQTTX 在 raw/push 主题收到字节 AA 81 01(按 Hex 查看)。
⑧ 透传下发:在「模拟设备 → 透传下发」中,输入 AA 7F 发送,MQTTX 在 raw/push 主题收到原样的 AA 7F。「设备消息」中出现一条带原始帧的 thing.raw.push。
# 6. 各协议的透传入口
透传入口与标准消息的入口相互独立:设备通过标准主题、路径发送的 JSON 消息,处理方式不变;标准路径也不接受 thing.raw.post、thing.raw.push 方法。
# 6.1 协议差异
| 协议 | 透传上报 | 透传下行 | 设备侧的应答 |
|---|---|---|---|
| MQTT | 发布到 /sys/{productKey}/{deviceName}/thing/raw/post | 发布到 /sys/{productKey}/{deviceName}/thing/raw/push,QoS 1 | 处理完成后回 PUBACK,与解析是否成功无关 |
| EMQX | 同 MQTT 主题,经 EMQX 转发给网关 | 同 MQTT,经 EMQX 发布 | 由 EMQX 应答;多条透传上报并行处理,不保证顺序 |
| HTTP | POST /topic/sys/{productKey}/{deviceName}/thing/raw/post,Content-Type: application/octet-stream,Authorization 携带 Token | 不支持 | 同一请求内响应:成功返回 data.messageId,失败返回错误码 |
| CoAP | POST /topic/sys/{productKey}/{deviceName}/thing/raw/post,Content-Format 为 42(application/octet-stream),Option 2088 携带 Token | 不支持 | CON 请求先回空 ACK,再分离响应结果;超过截止时间返回超时错误码 |
| TCP | 认证时 params.mode 传 raw,之后该连接的每一帧(仍按配置的拆包器切分)都是原始字节 | 按拆包器加帧后写出;非透传连接不支持 | 无 |
| UDP | 报文 49 52 01 + Token 长度(2 字节大端)+ Token(UTF-8)+ 原始字节 | 报文 49 52 01 00 00 + 原始字节,发往设备会话的地址 | 无 |
| WebSocket | text 帧认证后,binary 帧为原始字节 | binary 帧 | 无 |
| Modbus | 无透传上报,轮询按原有点位配置处理 | 写出 PDU,网关负责封装帧 | 设备的实际响应,见「6.2 Modbus」 |
① HTTP、CoAP 透传上报失败时返回的错误码,例如 1051003101 处理超时、1051003102 脚本繁忙或已熔断、1051003103 输出不合法、1051003100 执行失败。
② TCP 认证消息示例(仍使用 JSON 序列化),其它字段见 《设备接入(TCP 协议)》:
{
"method": "auth",
"params": {
"clientId": "...",
"username": "...",
"password": "...",
"mode": "raw"
}
}
透传连接建议使用 length_field 或 fixed_length 拆包器,避免原始字节中出现分隔符。
③ 各协议的连接认证、Token 获取等,参见对应的协议文档:HTTP、MQTT、EMQX、TCP、UDP、WebSocket、CoAP、Modbus Client、Modbus Server。
# 6.2 Modbus
Modbus Client、Modbus Server 的透传下行,内容都是 PDU(功能码 + 数据),不带从站地址、CRC、MBAP,由网关按设备配置封装。
① PDU 规则:5~253 字节,功能码只能是 01、02、03、04、05、06、0F、10,并校验数量、字节数(例如读寄存器数量 1~125)。透传下发、encode 的输出都按这个规则校验。
② 事务:每个连接最多 32 个透传请求在途或排队;超时沿用原有配置(Modbus Client 为设备连接配置的超时时间,Modbus Server 为 request-timeout)。
③ 设备响应:
thing.raw.push:直接把设备响应的 PDU 作为回复,异常响应(功能码最高位为 1)的回复带错误码encode下发的指令:用 encode 时的脚本执行decode,ctx.request为原请求,必须返回method、requestId与原请求一致的回执,否则不记录回复- 超时、断线、写出失败等网关判定的失败,只记录网关日志
例如,用「写单个寄存器」设置开关,并解析响应:
function encode(ctx) {
var msg = ctx.message;
if (msg.method === 'thing.property.set' && msg.params && msg.params.power !== undefined) {
// 06:写单个寄存器,地址 0x0001,值 0 / 1
return { bytes: [0x06, 0x00, 0x01, 0x00, Number(msg.params.power) ? 1 : 0] };
}
return { standard: true }; // 其它指令,按点位配置下发
}
function decode(ctx) {
if (!ctx.request) {
return null;
}
var ok = (ctx.bytes[0] & 0x80) === 0; // 功能码最高位为 1 表示异常响应
return {
method: ctx.request.method,
requestId: ctx.request.requestId,
code: ok ? 0 : 500,
msg: ok ? '成功' : 'Modbus 异常码 ' + ctx.bytes[1]
};
}
# 7. 常见问题
| 现象 | 排查 |
|---|---|
透传上报只看到 thing.raw.post | 网关脚本开关未开启;产品脚本未启用;decode 返回了 null;网关缓存还没刷新(见「4.1」的生效时间) |
| 透传上报后,设备消息中什么都没有 | 脚本出错、超时、输出不合法或已熔断,查看网关日志中的 [sendRawMessage];HTTP、CoAP 查看响应中的错误码 |
| 属性设置提示成功,设备没有收到 | encode 返回 null 或出错、设备离线、TCP 连接不是透传连接,查看网关日志中的 [encodeDownstreamCommand]、[writeRawMessage] |
| 设备收到的是 JSON,不是字节 | 网关脚本开关未开启、产品脚本未启用,或 encode 返回了 { standard: true } |
设备收不到 property/post_reply | 透传上报解析出的消息,平台不自动回复 |
| Modbus 透传下发提示 PDU 不合法 | 只填写 PDU(功能码 + 数据),不要带从站地址、CRC、MBAP |
| 保存、调试提示繁忙或已熔断 | 平台的调试执行器繁忙(同时最多执行 2 个、排队 4 个)或已熔断,稍后重试;仍然失败时,修改脚本内容或重启平台 |
| 网关日志提示脚本熔断 | 脚本 1 分钟内超时 3 次,检查是否有死循环、大循环,修改脚本内容后恢复 |