爱印云打印平台设备通讯协议规范
This content is not available in your language yet.
文档版本: v1.0
最后更新: 2026-06-03
适用对象: 设备固件开发者、第三方硬件集成商
📝 协议更新日志
Section titled “📝 协议更新日志”| 日期 | 更新内容 |
|---|---|
| 2026-05-15 | 1. 【ASR-对齐】ASR 客户端接入改为基于 /ws/asr 查询参数规范:token 必填,支持 model/language/hotwordCacheId/asrServiceType → ASR 服务 API 文档2. 【ASR-字段】首帧配置由 hotword_id 调整为网关协议字段 hotwords(可选)与 svs_lang(可选),并补充参数回退/纠正规则 → ASR 服务 API 文档3. 【ASR-回包】补充 connected/result/error 回包字段(asr_service_type/model/language 等)以匹配网关行为 → ASR 服务 API 文档 |
| 2026-05-14 | 1. 【下发-细分】Pull type=text_to_image 错误码从通用 2005 细分为场景化错误码:2006(提示词审核处理失败)/2007(提示词审核不通过)/2008(文生图生成失败)/2009(图片审核失败)→ 业务错误码(errCode)2. 【下发-补充】新增 text_to_image Pull Ack 细分错误示例,便于设备按错误类型执行重试或提示策略 → 下行消息:Pull 响应(Pull Ack)3. 【ASR-调整】使用 ASR 时不再要求先拉取 type=device_params,设备可沿用 Bootstrap 返回的 asrAddress(单 URL)直接连接;hotword_id 改为可选透传字段 → ASR 服务 API 文档 |
| 2026-05-13 | 1. 【下发-变更】type=device_params 响应移除热词内容下发,改为下发 hotwordId(热词ID)→ 下行消息:Pull 响应(Pull Ack)2. 【ASR-新增】新增 ASR 传输协议说明,设备在 ASR 首帧配置中增加 hotword_id 字段(来源于 device_params.hotwordId)→ ASR 服务 API 文档3. 【ASR-补充】新增按首帧配置计算音频分片与二进制发送示例(实时流式/离线文件)→ ASR 服务 API 文档 |
| 2026-05-12 | 1. 【上报-新增】Pull 新增 type=device_params(设备参数拉取)请求类型,用于主动获取设备设置参数 → 上行消息:任务拉取请求(Pull)2. 【下发-新增】Pull Ack 新增 type=device_params 响应,返回设备扩展配置中的 language/timezone 以及按语言匹配的型号热词 hotWords → 下行消息:Pull 响应(Pull Ack)3. 【文档-更新】补充 device_params 的请求示例、字段定义、响应逻辑与 FAQ 拉取策略说明 |
| 2026-05-09 | 1. 【上报-新增】Pull 新增 type=text_to_label(文本生成标签)请求类型,客户端仅上报 prompt(可选 bizId/fileType/prnProtocol),标签匹配与生成由云端处理 → 上行消息:任务拉取请求(Pull)2. 【下发-明确】 text_to_label 生成结果统一通过 devices/{tenantCode}/{userName}/{sn}/down/print 下发,按 resources[].fileType 区分 prn/image,prn 时使用 resources[].prnProtocol(当前 esc) → 下行消息:打印任务下发3. 【下发-新增】补充 text_to_label 请求异常时的 Pull Ack 返回示例(type/errCode/msg) → 下行消息:Pull 响应(Pull Ack) |
| 2026-04-29 | 1. 【上报-新增】打印回执新增 jobIds(批量任务单回执)与 queueStatus(本地队列状态);Pull 上报新增 type + params 结构,支持 print/text_to_image/feature_list/firmware → 上行消息:打印任务回执、上行消息:任务拉取请求(Pull)2. 【上报-删除】打印回执移除基于资源序号的 seqs 回执模型;Pull 上报移除旧版以 jobId + seq 为核心的拉取语义 → 上行消息:打印任务回执、上行消息:任务拉取请求(Pull)3. 【下发-新增】Pull Ack 升级为统一响应通道,新增 type/errCode/msg/params,支持功能列表与资源请求失败回包;打印下发新增 resources[].fileType、resources[].prnProtocol 以支持图片与 PRN 协议分流 → 下行消息:Pull 响应(Pull Ack)、下行消息:打印任务下发4. 【下发-删除】Pull Ack 移除旧版 code + message=no_task 单一无任务响应模型;打印下发移除顶层 jobId/totalFileNumber 与 resources[].seq 结构 → 下行消息:Pull 响应(Pull Ack)、下行消息:打印任务下发5. 【上报/下发-修改】主题路径由 devices/{sn}/... 统一升级为 devices/{tenantCode}/{userName}/{sn}/...,用于租户与用户维度隔离 → 主题命名规范 |
- Step 1: Bootstrap API - 获取连接参数
- Step 2: 连接 MQTT Broker
- Step 3: 订阅下行主题
- Step 4: 上报设备状态
- Step 5: 主动拉取任务
- Step 6: 处理平台下发的任务
- 主题命名规范
- 通用消息格式
- 上行消息:设备状态上报
- 上行消息:打印任务回执
- 上行消息:固件升级回执
- 上行消息:设备控制指令回执
- 上行消息:设备事件上报
- 上行消息:任务拉取请求(Pull)
- 下行消息:Pull 响应(Pull Ack)
- ASR 接入说明(独立文档)
- 下行消息:打印任务下发
- 下行消息:固件升级任务
- 下行消息:设备控制指令
- Q1: 设备时间不准确怎么办?
- Q2: 如何处理网络波动导致的消息丢失?
- Q3: 打印任务太大,如何优化下载速度?
- Q4: 固件升级失败后如何回滚?
- Q5: 如何判断是否需要主动拉取任务?
- Q6: 设备 SN 和 Secret 如何获取?
- Q7: 如何调试 MQTT 连接问题?
🚀 快速开始
Section titled “🚀 快速开始”- 设备已向平台注册,获得
SN(序列号)和Secret(密钥) - 设备支持 HTTPS 和 MQTT 协议
- 设备具备基本的文件下载和哈希校验能力
- 建议设备时间与 NTP 服务器同步,误差不超过 5 分钟
- 设备上电 → 调用 Bootstrap API 获取连接参数
- 使用返回的参数连接 MQTT Broker
- 订阅下行主题(接收平台命令和 Pull 响应/Pull Ack)
- 上报设备状态
- 主动拉取固件升级任务(通过 Pull 主题请求固件更新)
- 主动拉取打印任务(通过 Pull 主题请求打印资源)
- 处理平台下发的打印/升级/控制任务
设备引导与连接时序
Section titled “设备引导与连接时序”sequenceDiagram
autonumber
participant Dev as 设备
participant API as Bootstrap API
participant MQTT as EMQX Broker
Note over Dev,MQTT: 1. 设备引导
Dev->>API: POST /api/v1/bootstrap {sn, ts, sign}
API->>API: 验证签名和时间戳
API-->>Dev: 返回 MQTT 参数和主题配置
Note over Dev,MQTT: 2. MQTT 连接
Dev->>MQTT: CONNECT (clientId, username, password)
MQTT->>MQTT: 验证 JWT Token
MQTT-->>Dev: CONNACK (连接成功)
Note over Dev,MQTT: 3. 订阅主题
Dev->>MQTT: SUBSCRIBE devices/{tenantCode}/{userName}/{sn}/down/print (QoS 2)
Dev->>MQTT: SUBSCRIBE devices/{tenantCode}/{userName}/{sn}/down/upgrade (QoS 2)
Dev->>MQTT: SUBSCRIBE devices/{tenantCode}/{userName}/{sn}/down/control (QoS 2)
Dev->>MQTT: SUBSCRIBE devices/{tenantCode}/{userName}/{sn}/down/pull/ack (QoS 1)
MQTT-->>Dev: SUBACK
Note over Dev,MQTT: 4. 上报状态
Dev->>MQTT: PUBLISH devices/{tenantCode}/{userName}/{sn}/up/state {状态数据}
MQTT-->>Dev: PUBACK
Note over Dev,MQTT: 5. 主动拉取任务
Dev->>MQTT: PUBLISH devices/{tenantCode}/{userName}/{sn}/up/pull {type:"firmware", params:{hardware:{...}, firmware:[...]}}
MQTT-->>Dev: PUBACK
Dev->>MQTT: PUBLISH devices/{tenantCode}/{userName}/{sn}/up/pull {type:"print"}
MQTT-->>Dev: PUBACK
打印任务完整流程
Section titled “打印任务完整流程”sequenceDiagram
autonumber
participant Platform as 平台
participant MQTT as EMQX Broker
participant Dev as 设备
Note over Dev,Platform: 1. 设备主动拉取任务
Dev->>MQTT: PUBLISH up/pull {type:"print"}
MQTT->>Platform: 转发拉取请求
alt 有打印任务
Platform->>MQTT: PUBLISH down/print {打印任务批次(resources=[...])}
MQTT->>Dev: 转发打印任务
Note over Dev: 2. 立即确认收到的任务单
Dev->>MQTT: PUBLISH up/print/ack {status:confirm, jobIds:[...], queueStatus:"good"}
Note right of Dev: 本次下发的 jobIds 必须在10秒内发送 confirm
MQTT->>Platform: 转发确认回执
Note over Dev: 3. 下载并打印
Dev->>Dev: 下载 resources[i].url
Dev->>Dev: 校验 hash
Note over Dev: 4. 打印进度
Dev->>MQTT: PUBLISH up/print/ack {status:printing, jobIds:["..."]}
MQTT->>Platform: 转发进度回执
Note over Dev: 5. 完成当前任务单
Dev->>MQTT: PUBLISH up/print/ack {status:success, jobIds:["..."]}
MQTT->>Platform: 转发完成回执
Note over Dev: 6. 打印完本批次后继续拉取
Dev->>MQTT: PUBLISH up/pull {type:"print"}
MQTT->>Platform: 请求下一批任务
alt 无可用任务
Platform->>MQTT: PUBLISH down/pull/ack {type:"print", errCode:[]}
MQTT->>Dev: 回复无可用任务
end
else 无可用任务
Platform->>MQTT: PUBLISH down/pull/ack {type:"print", errCode:[]}
MQTT->>Dev: 回复无可用任务
end
固件升级流程
Section titled “固件升级流程”sequenceDiagram
autonumber
participant Platform as 平台
participant MQTT as EMQX Broker
participant Dev as 设备
Note over Dev,Platform: 1. 设备主动拉取任务
Dev->>MQTT: PUBLISH up/pull {type:"firmware", params:{hardware:{...}, firmware:[...]}}
MQTT->>Platform: 转发拉取请求
Platform->>Platform: 检查固件版本,发现有升级任务
Note over Platform,Dev: 2. 升级任务下发
Platform->>MQTT: PUBLISH devices/{tenantCode}/{userName}/{sn}/down/upgrade {升级任务}
MQTT->>Dev: 转发升级任务
Note over Dev: 3. 立即确认
Dev->>MQTT: PUBLISH up/upgrade/ack {status:confirm}
MQTT->>Platform: 转发确认回执
Note over Dev: 4. 下载固件
Dev->>Dev: 下载固件文件
Dev->>MQTT: PUBLISH up/upgrade/ack {status:downloading}
MQTT->>Platform: 转发下载进度
Note over Dev: 5. 校验哈希
Dev->>Dev: 验证 SHA256 hash
Note over Dev: 6. 执行升级
Dev->>MQTT: PUBLISH up/upgrade/ack {status:upgrading}
MQTT->>Platform: 转发升级状态
Dev->>Dev: 应用新固件
Dev->>Dev: 重启设备
Note over Dev: 7. 重启后上报
Dev->>MQTT: PUBLISH up/upgrade/ack {status:success}
MQTT->>Platform: 转发成功回执
Dev->>MQTT: PUBLISH up/state {新固件版本}
MQTT->>Platform: 同步设备状态
Note over Dev: 8. 拉取打印任务
Dev->>MQTT: PUBLISH up/pull {type:"print"}
MQTT->>Platform: 请求打印任务
设备控制指令流程
Section titled “设备控制指令流程”sequenceDiagram
autonumber
participant Platform as 平台
participant MQTT as EMQX Broker
participant Dev as 设备
Note over Platform,Dev: 1. 控制指令下发
Platform->>MQTT: PUBLISH devices/{tenantCode}/{userName}/{sn}/down/control {控制指令}
MQTT->>Dev: 转发控制指令
Note over Dev: 2. 立即确认
Dev->>MQTT: PUBLISH up/control/ack {status:confirm}
MQTT->>Platform: 转发确认回执
Note over Dev: 3. 完成操作
Dev->>MQTT: PUBLISH up/control/ack {status:success}
MQTT->>Platform: 转发完成回执
alt 需要重启的操作
Note over Dev: 4. 设备重启
Dev->>Dev: 执行重启
Note over Dev: 5. 重启后上报
Dev->>MQTT: PUBLISH up/state {设备状态}
MQTT->>Platform: 同步设备状态
end
📖 协议概述
Section titled “📖 协议概述”设备 <--HTTPS--> Bootstrap API (获取连接参数)设备 <--MQTT--> EMQX Broker <--Bridge--> Kafka <--> 平台应用- 双向通信: 设备可上报状态,平台可下发任务
- QoS 保证: 上行 QoS1,下行 QoS2(可协商降级到 QoS1)
- 消息幂等: 基于
msgId和jobId实现幂等去重 - TLS 加密: 生产环境强制使用 TLS 1.2+
📚 术语定义
Section titled “📚 术语定义”| 术语 | 说明 | 示例/备注 |
|---|---|---|
| Device(设备) | 物联网打印机或相关硬件设备 | - |
| SN(序列号) | 设备的全局唯一标识符 | SN-XYZ-001,禁止包含 | . / \ 等特殊字符 |
| Secret(密钥) | 平台为设备分配的密钥,用于签名验证 | 32-64字节随机字符串,设备端需安全存储 |
| msgId(消息ID) | 消息的唯一标识符,32字符长度 | 建议使用 UUID v4 去掉连字符,如 a1b2c3d4e5f6789012345678901234ab |
| ProtocolVersion | 协议版本号 | 当前为 1.0 |
| 术语 | 说明 |
|---|---|
| MQTT | 消息队列遥测传输协议,轻量级发布/订阅模式 |
| Topic(主题) | MQTT 消息的分类路径,格式如 devices/{tenantCode}/{userName}/{sn}/up/state |
| Upstream(上行) | 设备 → 平台的消息流 |
| Downstream(下行) | 平台 → 设备的消息流 |
| QoS | 消息传输质量等级:QoS0(最多一次)、QoS1(至少一次)、QoS2(恰好一次) |
| ACL | 访问控制列表,限制设备只能访问自己的主题 |
| 术语 | 说明 |
|---|---|
| jobId | 打印任务的唯一标识符 |
| deviceUpgradeId | 设备升级任务的唯一标识符 |
| firmwareType | 固件类型:cloud(云端)、printer(打印机)、bluetooth(蓝牙) |
| seq | 资源序号,从 1 开始递增 |
| 字段 | 单位 | 说明 |
|---|---|---|
| ts | 毫秒 | Unix 时间戳(13位毫秒级),设备上报的当前时间,如 1724040060000 |
| dateTime | 毫秒 | Unix 时间戳(13位毫秒级),服务器时间,如 1724846400000 |
提示: Bootstrap API 仅校验时间戳长度为13位,不校验时间窗口,设备可在引导成功后根据响应中的
serverTime进行时间校准。
⚠️ 错误码定义
Section titled “⚠️ 错误码定义”HTTP 状态码
Section titled “HTTP 状态码”| 状态码 | 说明 | 处理建议 |
|---|---|---|
| 200 | 成功 | - |
| 401 | 签名无效或已过期 | 检查签名算法和时间戳 |
| 404 | 设备未注册 | 联系平台管理员注册设备 |
| 423 | 设备已被禁用 | 设备被停用,无法继续使用 |
| 429 | 请求频率超限 | 实施指数退避策略 |
| 500 | 服务器内部错误 | 重试或联系技术支持 |
业务错误码(errCode)
Section titled “业务错误码(errCode)”约定:凡字段名为
errCode(数组)时,空数组[]表示无错误/正常;当存在错误时,数组内元素为一个或多个错误码,取值参考本章节错误码定义。
| 错误码 | 说明 |
|---|---|
| 0 | 操作成功 |
认证相关 (1000-1099)
Section titled “认证相关 (1000-1099)”| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 1001 | 签名非法 | 检查签名算法,确认 Secret 正确 |
| 1002 | 令牌过期或无效 | 重新调用 Bootstrap API 获取新令牌 |
| 1003 | 设备未授权 | 检查设备是否已注册并启用 |
网络通讯 (2000-2099)
Section titled “网络通讯 (2000-2099)”| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 2001 | 主题访问被拒绝(ACL) | 检查主题路径是否正确 |
| 2002 | 消息格式错误 | 检查 JSON 格式和必填字段 |
| 2003 | 消息体过大 | 单条消息不得超过 256KB |
| 2004 | 资源请求类型不支持 | 检查 Pull 请求 type 是否在协议支持范围内 |
| 2005 | 资源请求处理失败 | 检查 msg 字段错误详情并按提示修正请求或稍后重试 |
| 2006 | 文生图提示词审核处理失败 | 检查提示词审核服务状态与配置,建议稍后重试 |
| 2007 | 文生图提示词审核不通过 | 提示用户调整提示词内容后重新发起请求 |
| 2008 | 文生图生成失败 | 检查生图引擎状态/参数合法性,必要时重试 |
| 2009 | 文生图图片审核失败 | 图片结果未通过审核或审核流程异常,建议调整提示词或稍后重试 |
打印相关 (3000-3099)
Section titled “打印相关 (3000-3099)”| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 3001 | 打印失败(设备硬件故障) | 检查打印机状态,上报详细错误信息 |
| 3002 | 打印超时 | 检查网络和设备性能 |
| 3003 | 打印内容下载失败 | 检查网络连接,支持断点续传 |
| 3004 | 打印内容校验失败 | 重新下载文件,检查 hash 算法 |
| 3005 | 存储空间不足 | 重启机器或者联系工程师排查情况处理 |
固件升级 (4000-4099)
Section titled “固件升级 (4000-4099)”| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 4001 | 升级包校验失败 | 检查 SHA256 哈希值 |
| 4002 | 升级失败/回滚 | 保留旧固件,支持回滚机制 |
| 4003 | 升级包下载失败 | 检查网络,支持断点续传 |
| 4004 | 固件版本不兼容 | 检查设备型号和固件版本匹配 |
| 4005 | 存储空间不足 | 清理临时文件或提示用户 |
| 4006 | 升级超时 | 设备升级超时且达到最大重试次数,平台标记失败 |
设备控制 (5000-5099)
Section titled “设备控制 (5000-5099)”| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 5001 | 不支持的控制指令 | 检查指令是否在支持列表中 |
| 5002 | 控制指令参数错误 | 检查参数格式和取值范围 |
| 5003 | 控制指令执行失败 | 检查设备状态和硬件功能 |
| 5004 | 控制指令超时 | 检查设备响应能力 |
设备状态 (6000-6099)
Section titled “设备状态 (6000-6099)”| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 6001 | 打印机缺纸 | 提示用户添加纸张 |
| 6002 | 打印机卡纸 | 提示用户清除卡纸 |
| 6003 | 打印机过热 | 暂停打印,等待降温 |
| 6004 | 电池电量低 | 提示用户充电 |
| 6005 | 存储空间不足 | 清理缓存文件 |
| 6006 | 盖子未关 | 重新把盖子关上 |
| 6007 | 盖子未关且卡纸 | 重新打开盖子整理下纸张再关好盖子 |
| 6008 | 盖子未关且过热 | 通风散热后再重新关盖打印 |
| 6009 | 卡纸且过热 | 通风散热后打开盖子调整纸张后再重新关盖打印 |
| 6010 | 盖子未关且卡纸且过热 | 通风散热后打开盖子调整纸张后再重新关盖打印 |
| 6011 | 硬件错误 | 联系工程师处理 |
| 6012 | 设备忙 | 等待设备正常后再执行后续打印操作 |
| 6013 | 纸张类型错误 | 检查纸张类型是否与任务要求匹配 |
🔌 接入流程
Section titled “🔌 接入流程”Step 1: Bootstrap API - 获取连接参数
Section titled “Step 1: Bootstrap API - 获取连接参数”设备上电后,首先通过 HTTPS 调用 Bootstrap API 获取 MQTT 连接参数和主题配置。
环境地址
| 环境 | API 基础地址 | 前端地址 | Bootstrap 完整地址 |
|---|---|---|---|
| 测试环境 | https://cprint-api-stg.iprtapp.com | https://cprint-stg.iprtapp.com | https://cprint-api-stg.iprtapp.com/api/v1/bootstrap |
| 正式环境 | https://cprint-api.iprtapp.com | https://cprint.iprtapp.com | https://cprint-api.iprtapp.com/api/v1/bootstrap |
接口地址
POST https://cprint-api-stg.iprtapp.com/api/v1/bootstrap请求头
请求体结构
{ "sn": "SN-XYZ-001", // 必填:设备序列号 "protocolVersion": "1.0", // 必填:协议版本 "ts": 1724040000000, // 必填:当前时间戳(13位毫秒),误差不超过±5分钟 "sign": "abc123def456..." // 必填:签名,见下方算法说明}请求字段说明
Section titled “请求字段说明”| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
sn | string | ✅ | 设备序列号,全局唯一标识符 |
protocolVersion | string | ✅ | 协议版本号,当前为 1.0 |
ts | int64 | ✅ | 当前时间戳(13位毫秒),仅需确保为13位长度即可 |
sign | string | ✅ | HMAC-SHA256签名,计算方式见下方算法说明 |
签名算法详解
Section titled “签名算法详解”算法: HMAC-SHA256
步骤:
- 拼接明文字符串:
plaintext = sn + ts- 示例:
"SN-XYZ-001" + "1724040000000"→"SN-XYZ-0011724040000000"
- 示例:
- 使用 Secret 作为密钥,对明文进行 HMAC-SHA256 计算,例如明文
SN-XYZ-0011724040000000使用密钥password进行HMAC-SHA256加密后的结果为5776e385eb1e6a652e71dd3cb37b98a7f459d186ec630a3da5274fa97f429743 - 将计算结果转换为十六进制小写字符串
成功响应(HTTP 200)
{ "code": 0, "message": "OK", "data": { "device": { "sn": "SN-TEST-001", "model": "A40w-4G" }, "mqtt": { "host": "mqtt.byteone.com", "port": 8883, // TLS端口,测试环境可能为1883 "clientId": "SN-TEST-001|1.0", // 格式:{sn}|{protocolVersion} "username": "SN-TEST-001", "password": "eyJhbGciOiJIUzI1NiIs...", // JWT短期令牌 "qosUp": 1, // 上行消息QoS等级 "qosDown": 2, // 下行消息QoS等级 "tokenTtlSec": 3600, // 令牌有效期(秒) "keepalive": 60, // MQTT心跳时间(秒),设备应按此间隔发送心跳包 "cleanSession": false, // 是否清洁会话,false表示保持会话以恢复离线消息 "tls": { "enabled": true, // 生产环境必须为true "caCertPem": "-----BEGIN CERTIFICATE-----\n..." // TLS根证书 } }, "topics": { "upState": "devices/TENANT-TEST-001/USER-TEST-001/SN-TEST-001/up/state", "upPrintAck": "devices/TENANT-TEST-001/USER-TEST-001/SN-TEST-001/up/print/ack", "upUpgradeAck": "devices/TENANT-TEST-001/USER-TEST-001/SN-TEST-001/up/upgrade/ack", "upControlAck": "devices/TENANT-TEST-001/USER-TEST-001/SN-TEST-001/up/control/ack", "upEvent": "devices/TENANT-TEST-001/USER-TEST-001/SN-TEST-001/up/event", "upPull": "devices/TENANT-TEST-001/USER-TEST-001/SN-TEST-001/up/pull", "downPrint": "devices/TENANT-TEST-001/USER-TEST-001/SN-TEST-001/down/print", "downUpgrade": "devices/TENANT-TEST-001/USER-TEST-001/SN-TEST-001/down/upgrade", "downControl": "devices/TENANT-TEST-001/USER-TEST-001/SN-TEST-001/down/control", "downPullAck": "devices/TENANT-TEST-001/USER-TEST-001/SN-TEST-001/down/pull/ack" }, "stateReportInterval": 1800, // 设备状态上报周期(秒),默认1800秒(30分钟) "serverTime": 1759991021, // 服务器当前时间戳,用于时间校准 "asrAddress": "wss://asr.iprtapp.com/ws/asr?asrServiceType={引导接口下发的ASR服务类型}&hotwordCacheId={引导接口下发的热词缓存ID,可选}&language={引导接口下发或设备确认的识别语言,如zh-CN}&model={引导接口下发的识别模型,如SenseVoiceSmall}&token={引导接口下发的ASR访问令牌}" // ASR完整连接地址示例,实际使用时必须以引导接口返回值为准 }}失败响应示例
{ "code": 1001, "message": "签名验证失败", "data": null}响应字段说明
Section titled “响应字段说明”| 字段路径 | 类型 | 说明 |
|---|---|---|
code | int | 业务错误码,0表示成功 |
message | string | 响应消息描述 |
data.device.sn | string | 设备序列号 |
data.device.model | string | 设备型号 |
data.mqtt.host | string | MQTT服务器地址 |
data.mqtt.port | int | MQTT服务器端口,8883(TLS)或1883(非TLS) |
data.mqtt.clientId | string | MQTT客户端ID,格式固定为 {sn}|{protocolVersion} |
data.mqtt.username | string | MQTT连接用户名,通常为设备SN |
data.mqtt.password | string | JWT短期令牌,有效期由 tokenTtlSec 指定 |
data.mqtt.qosUp | int | 上行消息QoS等级(通常为1) |
data.mqtt.qosDown | int | 下行消息QoS等级(通常为2) |
data.mqtt.tokenTtlSec | int | JWT令牌有效期(秒),默认为3600秒(1小时) |
data.mqtt.keepalive | int | MQTT心跳时间(秒),设备应按此间隔发送心跳包保持连接,默认60秒 |
data.mqtt.cleanSession | bool | 是否清洁会话,true表示不保留离线消息,false表示保持会话以便恢复离线消息 |
data.mqtt.tls.enabled | bool | 是否启用TLS,生产环境必须为true |
data.mqtt.tls.caCertPem | string | TLS根证书(PEM格式),用于验证服务器身份,目前使用验证过的公钥,所以当前字段默认为空,由设备端自行通过证书库认证 |
data.topics.upState | string | 设备状态上行主题 |
data.topics.upPrintAck | string | 打印任务回执上行主题 |
data.topics.upUpgradeAck | string | 固件升级回执上行主题 |
data.topics.upControlAck | string | 控制指令回执上行主题 |
data.topics.upEvent | string | 设备事件上行主题,用于设备上报事件通知 |
data.topics.upPull | string | 任务拉取上行主题,设备主动拉取打印资源、文生图资源、文本生成标签资源、功能列表或固件更新 |
data.topics.downPrint | string | 打印任务下行主题 |
data.topics.downUpgrade | string | 设备固件升级下行主题 |
data.topics.downControl | string | 控制指令下行主题,接收平台控制命令 |
data.topics.downPullAck | string | Pull响应下行主题,用于回复无可用任务、功能列表响应或资源请求错误信息 |
data.stateReportInterval | int | 设备状态上报周期(秒),设备应按此间隔定期上报设备状态,默认1800秒(30分钟) |
data.serverTime | int64 | 服务器当前时间戳(秒级,13位),设备可用于时间校准 |
data.asrAddress | string | ASR WebSocket 完整连接地址。设备必须直接使用引导接口下发的值,不要写死域名、路径或查询参数;详细接入方式见 ASR 服务 API 文档 |
- 参数有效期: Bootstrap 返回的 MQTT 连接参数长期有效,除非平台更新配置
- 令牌续期: JWT 令牌有效期为
tokenTtlSec秒(通常为3600秒),令牌接近过期(剩余5分钟)时,应重新调用 Bootstrap API 获取新令牌 - 时间同步: 如果设备时间与
serverTime差异过大,应使用serverTime进行校准 - TLS证书: 生产环境必须启用 TLS
- ASR连接: 设备必须使用 Bootstrap 返回的
asrAddress原样发起 WebSocket 连接;如返回值已包含token/asrServiceType/hotwordCacheId/language/model等查询参数,设备端无需自行拼接或替换,详细参数与时序见 ASR 服务 API 文档
Step 2: 连接 MQTT Broker
Section titled “Step 2: 连接 MQTT Broker”使用 Bootstrap API 返回的参数连接 MQTT Broker。
TLS 配置(生产环境必选)
Section titled “TLS 配置(生产环境必选)”Step 3: 订阅下行主题
Section titled “Step 3: 订阅下行主题”连接成功后,立即订阅平台下发命令的主题。需订阅以下主题:
devices/{tenantCode}/{userName}/{sn}/down/print- 打印任务下发devices/{tenantCode}/{userName}/{sn}/down/upgrade- 固件升级任务下发devices/{tenantCode}/{userName}/{sn}/down/control- 控制指令下发devices/{tenantCode}/{userName}/{sn}/down/pull/ack- Pull 响应(无任务/无更新/功能列表/设备参数/资源请求错误)
Step 4: 上报设备状态
Section titled “Step 4: 上报设备状态”订阅成功后,立即上报一次设备状态。
Step 5: 主动拉取任务
Section titled “Step 5: 主动拉取任务”上报状态后,设备应主动通过 Pull 主题拉取可用资源,推荐使用 type + params 结构:
// 发送到 devices/{tenantCode}/{userName}/{sn}/up/pull{ "msgId": "xxx", "type": "print", // print/text_to_image/text_to_label/feature_list/device_params/firmware "params": {}, "ts": 1724044088000}当设备需要主动检查固件更新时,发送 type=firmware并在 params 中携带硬件参数与当前固件版本信息。
注意: 设备端需自行判断本地是否存在阻塞性错误(如缺纸、卡纸),存在错误时不应发送 Pull 请求。云端在收到 Pull 时不再判断设备错误状态。
Step 6: 处理平台下发的任务
Section titled “Step 6: 处理平台下发的任务”监听消息事件,处理打印和升级任务。
📡 消息协议
Section titled “📡 消息协议”主题命名规范
Section titled “主题命名规范”| 方向 | 主题模式 | 说明 |
|---|---|---|
| 上行 | devices/{tenantCode}/{userName}/{sn}/up/{message_type} | 设备上报消息到平台 |
| 下行 | devices/{tenantCode}/{userName}/{sn}/down/{message_type} | 平台下发命令或资源到设备 |
命名约束:
- 主题路径仅允许字符:
[a-z0-9-_/] tenantCode、userName建议使用A-Z0-9-_字符组合- SN 建议使用
A-Z0-9-字符组合 - 主题路径最大长度:256 字符
通用消息格式
Section titled “通用消息格式”所有 MQTT 消息载荷均为 JSON UTF-8 编码格式。
通用字段:
{ "msgId": "32字符唯一ID", // 必填:消息唯一标识符,用于去重 "ts": 1724040060000, // 必填:消息时间戳(13位毫秒) // ... 其他业务字段}msgId 生成规范:
- 长度:32 字符
- 格式:建议使用 UUID v4 去掉连字符(例:
a1b2c3d4e5f6789012345678901234ab) - 唯一性:全局唯一,用于消息去重和链路追踪
- 生成示例:
上行消息:设备状态上报
Section titled “上行消息:设备状态上报”主题: devices/{tenantCode}/{userName}/{sn}/up/state
QoS: 1
用途: 上报设备实时状态,包括网络、电量、固件版本等信息
{ "msgId": "a1b2c3d4e5f6789012345678901234ab", "ts": 1724040060000, "rssi": -58, // WiFi 信号强度(dBm) "battery": 90, // 电池电量百分比(0~100) "paper": 1, // 纸张状态:0=无纸,1=有纸 "paperType": "roll", // 纸张类型:fold/roll/gap/hole/tattoo "errCode": [], // 错误码数组:空数组表示正常,可同时上报多个错误码 "temperature": 35.2, // 可选:设备温度(摄氏度) "humidity": 45, // 可选:设备湿度(0~100) "ipAddress": "192.168.1.25", // 可选:设备IP地址 "bluetoothMac": "00:1A:7D:DA:71:13", // 可选:蓝牙MAC地址 "imei": "865123456789012", // 可选:4G模块IMEI号(15位数字) "iccid": "89860123456789012345", // 可选:SIM卡ICCID号(18-22位数字) "signalStrength": -75, // 可选:4G信号强度(dBm) "networkType": "4G", // 可选:网络类型(2G/3G/4G/5G) "printCount": 12345, // 可选:累计打印张数 "avgLatency": 150, // 可选:平均延时(毫秒) "packetLossRate": 2, // 可选:丢包率(0~100,如2表示2%) "charging": false, // 可选:是否正在充电 "sleepTime": 10, // 可选:休眠时间(分钟) "firmware": [ { "firmwareType": "cloud", // 固件类型 "firmwareVersion": "1.2.3", // 固件版本号 "nn": "NN-001" // 模组NN号 }, { "firmwareType": "printer", "firmwareVersion": "3.4.5", "nn": "NN-002" // 打印机NN号 }, { "firmwareType": "bluetooth", "firmwareVersion": "0.9.8" } ]}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | ✅ | 消息唯一ID,32字符 |
ts | int64 | ✅ | 消息时间戳(13位毫秒) |
rssi | int | ❌ | WiFi信号强度,单位dBm,通常为负数 |
battery | float | ❌ | 电量百分比,范围0~1 |
paper | int | ✅ | 纸张状态,0=缺纸,1=正常 |
paperType | string | ❌ | 纸张类型:fold(折叠纸)/roll(卷纸)/gap(标签纸)/hole(孔型纸)/tattoo(纹身纸) |
errCode | int[] | ✅ | 设备错误码数组,[] 表示正常,其他见错误码表,可同时上报多个错误码 |
temperature | float | ❌ | 设备温度(摄氏度) |
humidity | float | ❌ | 设备湿度(0~1) |
ipAddress | string | ❌ | 设备当前IP地址 |
bluetoothMac | string | ❌ | 蓝牙MAC地址 |
imei | string | ❌ | 4G模块IMEI号(15位数字),用于识别4G模块 |
iccid | string | ❌ | SIM卡ICCID号(18-22位数字),用于识别SIM卡 |
signalStrength | int | ❌ | 4G信号强度(dBm),通常为负数 |
networkType | string | ❌ | 网络类型:2G/3G/4G/5G |
printCount | int | ❌ | 累计打印张数 |
avgLatency | int | ❌ | 平均延时(毫秒),用于监控设备网络质量 |
packetLossRate | int | ❌ | 丢包率(0~100),如2表示2%丢包率 |
charging | bool | ❌ | 是否正在充电,true 表示充电中 |
sleepTime | int | ❌ | 休眠时间(分钟) |
firmware | array | ✅ | 固件版本列表 |
firmware[].firmwareType | string | ✅ | 固件类型:cloud/printer/bluetooth |
firmware[].firmwareVersion | string | ✅ | 固件版本号 |
firmware[].nn | string | ❌ | 设备当前 NN 号,建议在 firmwareType=cloud 的固件项中上报;非空时云端将更新设备记录中的 NN 号 |
| 场景 | 上报时机 |
|---|---|
| 开机上报 | 设备启动完成,各状态正常,MQTT 连接成功后立即上报 |
| 周期上报 | 可选,建议每 30 分钟上报一次 |
| 变化上报 | 重要状态变更时立即上报(缺纸、电量低、过热等) |
| 频率限制 | 每分钟不超过 100 条(突发异常除外) |
上行消息:打印任务回执
Section titled “上行消息:打印任务回执”主题: devices/{tenantCode}/{userName}/{sn}/up/print/ack
QoS: 1
用途: 向平台回复打印任务的执行状态和进度
{ "msgId": "b2c3d4e5f67890a1b2c3d4e5f67890a1", "jobIds": [ "92ef08872ff906876071478274eec57b", "24ef08872ff906876071478274eec5aa" ], "ackOriginalMsgId": "a1b2c3d4e5f6789012345678901234ab", "status": "confirm", "queueStatus": "good", "errCode": [], "msg": "ok", "ts": 1724040088000}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | ✅ | 消息唯一ID,32字符 |
jobIds | string[] | ✅ | 打印任务单ID数组,与下发任务的 resources[].jobId 对应 |
ackOriginalMsgId | string | ✅ | 原始下发消息的msgId,用于消息关联 |
status | string | ✅ | 任务状态:confirm/printing/success/failed |
queueStatus | string | ❌ | 本地打印任务队列状态:good/congested/full,仅 status=confirm 时建议上报 |
errCode | int[] | ✅ | 错误码数组,[] 表示成功,其他见错误码表,可同时返回多个错误码 |
msg | string | ✅ | 错误描述信息或状态说明 |
ts | int64 | ✅ | 消息时间戳(13位毫秒) |
状态字段详解
Section titled “状态字段详解”| status 值 | 含义 | 是否必传 | 说明 |
|---|---|---|---|
| confirm | 收到任务确认 | ✅ 必传 | 设备收到下发消息后立即回复,10秒内必须发送。jobIds 可携带多个确认接收的任务单ID;建议同时上报 queueStatus |
| printing | 打印中 | ✅ 建议 | 打印进度上报,jobIds 上报当前正在处理的任务单ID数组(通常 1 个) |
| success | 打印成功 | ✅ 必传 | 打印完成,jobIds 上报已完成的任务单ID数组(通常 1 个) |
| failed | 打印失败 | ✅ 必传 | 打印失败,jobIds 上报失败的任务单ID数组(通常 1 个) |
queueStatus 说明(仅 confirm)
Section titled “queueStatus 说明(仅 confirm)”good:云端可继续下发新的任务单congested:云端不再继续下发新任务单(避免进一步堆积)full:云端不再继续下发新任务单;本次已下发但设备因队满无法入队/处理的任务单,云端应在设备后续重新 Pull 时重新下发
注意: 拉取新的打印任务或固件升级任务请使用独立的 Pull 主题(
devices/{tenantCode}/{userName}/{sn}/up/pull)。
掉电恢复流程
Section titled “掉电恢复流程”- 设备打印中突然断电
- 设备重启: 设备重启后完成自检、MQTT 连接,上报设备状态
- 主动拉取任务: 设备通过 Pull 主题(
devices/{tenantCode}/{userName}/{sn}/up/pull)发起type=print请求,云端根据历史回执自主判断下发未完成的任务单 - 续打任务下发: 平台下发未完成/未打印的任务单批次
- 恢复打印: 设备继续打印
上行消息:固件升级回执
Section titled “上行消息:固件升级回执”主题: devices/{tenantCode}/{userName}/{sn}/up/upgrade/ack
QoS: 1
用途: 向平台回复固件升级任务的执行状态
{ "msgId": "d4e5f6789012a3b4c5d6e7f89012a3b4", "deviceUpgradeId": "92ef08872ff906876071478274eec57b", // 设备升级任务ID "ackOriginalMsgId": "原始下发消息的msgId", "status": "upgrading", // 升级状态 "errCode": [], // 错误码数组,空数组表示成功 "msg": "ok", // 错误描述 "ts": 1724041088000}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | ✅ | 消息唯一ID,32字符 |
deviceUpgradeId | string | ✅ | 设备升级任务ID,与下发任务的deviceUpgradeId对应 |
ackOriginalMsgId | string | ✅ | 原始下发消息的msgId,用于消息关联 |
status | string | ✅ | 升级状态:confirm/downloading/upgrading/success/failed |
errCode | int[] | ✅ | 错误码数组,[] 表示成功,其他见错误码表,可同时返回多个错误码 |
msg | string | ✅ | 错误描述信息或状态说明 |
ts | int64 | ✅ | 消息时间戳(13位毫秒) |
| status 值 | 含义 | 是否必传 | 说明 |
|---|---|---|---|
| confirm | 收到任务确认 | ✅ 必传 | 设备收到升级任务后立即回复 |
| downloading | 下载中 | ❌ 可选 | 固件下载进度上报 |
| upgrading | 升级中 | ❌ 可选 | 正在执行升级 |
| success | 升级成功 | ✅ 必传 | 升级完成并重启后发送 |
| failed | 升级失败 | ✅ 必传 | 升级过程中出现错误 |
上行消息:设备控制指令回执
Section titled “上行消息:设备控制指令回执”主题: devices/{tenantCode}/{userName}/{sn}/up/control/ack
QoS: 1
用途: 向平台回复设备控制指令的执行状态
{ "msgId": "g5h6i7j890k1l2m3n4o5p6q789r0s1t2", "controlId": "a351eff1b614d0c1f64227d0c4b28c99", // 控制指令ID "ackOriginalMsgId": "原始下发消息的msgId", "status": "confirm", // 执行状态 "errCode": [], // 错误码数组,空数组表示成功 "msg": "ok", // 错误描述 "ts": 1724042088000}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | ✅ | 消息唯一ID,32字符 |
controlId | string | ✅ | 控制指令ID,与下发指令的controlId对应 |
ackOriginalMsgId | string | ✅ | 原始下发消息的msgId,用于消息关联 |
status | string | ✅ | 执行状态:confirm/success/failed |
errCode | int[] | ✅ | 错误码数组,[] 表示成功,其他见错误码表,可同时返回多个错误码 |
msg | string | ✅ | 错误描述信息或状态说明 |
ts | int64 | ✅ | 消息时间戳(13位毫秒) |
| status 值 | 含义 | 是否必传 | 说明 |
|---|---|---|---|
| confirm | 收到指令确认 | ✅ 必传 | 设备收到控制指令后立即回复 |
| success | 执行成功 | ✅ 必传 | 控制操作完成 |
| failed | 执行失败 | ✅ 必传 | 控制操作失败 |
上行消息:设备事件上报
Section titled “上行消息:设备事件上报”主题: devices/{tenantCode}/{userName}/{sn}/up/event
QoS: 1
用途: 设备向平台上报事件通知,用于触发云端特定业务逻辑
{ "msgId": "h7i8j9k012l3m4n5o6p7q8r901s2t3u4", "eventType": "stop_print", // 事件类型 "eventParams": { // 事件参数(可选) "reason": "user_action" // 事件原因或其他参数 }, "ts": 1724043088000}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | ✅ | 消息唯一ID,32字符 |
eventType | string | ✅ | 事件类型,见下方事件类型表 |
eventParams | object | ❌ | 事件参数,JSON对象,不同事件类型有不同参数 |
ts | int64 | ✅ | 消息时间戳(13位毫秒) |
支持的事件类型
Section titled “支持的事件类型”| eventType 值 | 含义 | eventParams 参数 | 云端处理逻辑 |
|---|---|---|---|
| stop_print | 停止打印事件 | reason: 停止原因(可选) | 云端收到后会清除该设备的打印队列中所有待打印任务 |
停止打印事件说明
Section titled “停止打印事件说明”当设备需要停止打印时(如用户按下停止按钮),设备应发送此事件通知云端。
消息示例:
{ "msgId": "i8j9k012l3m4n5o6p7q8r901s2t3u4v5", "eventType": "stop_print", "eventParams": { "reason": "user_button" }, "ts": 1724043188000}云端响应:
- 收到
stop_print事件后,云端会立即清除该设备打印队列中所有可被打印的任务
上行消息:任务拉取请求(Pull)
Section titled “上行消息:任务拉取请求(Pull)”主题: devices/{tenantCode}/{userName}/{sn}/up/pull
QoS: 1
用途: 设备主动拉取资源,当前支持普通打印资源、文生图资源、文本生成标签资源、功能列表、设备参数与固件更新拉取
消息结构(推荐)
Section titled “消息结构(推荐)”{ "msgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6", "type": "print", // print/text_to_image/text_to_label/feature_list/device_params/firmware,空则按 print 处理 "params": {}, "ts": 1724044088000}固件更新拉取示例
Section titled “固件更新拉取示例”{ "msgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z7", "type": "firmware", "params": { "hardware": { "deviceModel": "P5802" }, "firmware": [ {"firmwareType": "cloud", "firmwareVersion": "1.2.3", "nn": "NN-001"}, {"firmwareType": "printer", "firmwareVersion": "3.4.5"} ] }, "ts": 1724044088000}文本生成标签拉取示例
Section titled “文本生成标签拉取示例”{ "msgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z8", "type": "text_to_label", "params": { "prompt": "开封贴,牛排", "timezone": "Asia/Shanghai", "language": "zh-CN", "width": 40, "height": 15 }, "ts": 1724044088000}设备参数拉取示例
Section titled “设备参数拉取示例”{ "msgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z9", "type": "device_params", "params": {}, "ts": 1724044088000}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | ✅ | 消息唯一ID,32字符 |
type | string | ❌ | 资源类型:print/text_to_image/text_to_label/feature_list/device_params/firmware |
params | object | ❌ | 类型参数对象,不同 type 字段不同。type 为空时可不传并走旧结构;type=feature_list/device_params 时通常传 {} 或 null |
params.hardware | object | ❌ | type=firmware时建议上报。硬件参数 |
params.hardware.deviceModel | string | ❌ | 设备型号(示例:P5802) |
params.firmware | array | ❌ | type=firmware 时建议上报。设备当前固件版本列表 |
params.firmware[].firmwareType | string | ❌ | 固件类型:cloud/printer/bluetooth |
params.firmware[].firmwareVersion | string | ❌ | 固件版本号 |
params.firmware[].nn | string | ❌ | 模组或打印机 NN 号 |
params.bizId | string | ❌ | type=text_to_image/text_to_label 时可选。业务ID,不传时由云端按默认策略处理 |
params.width | int | 条件必填 | type=text_to_image 时必填,表示图片宽度(像素);type=text_to_label 时可选,表示标签宽度(mm) |
params.height | int | 条件必填 | type=text_to_image 时必填,表示图片高度(像素);type=text_to_label 时可选,表示标签高度(mm) |
params.prompt | string | ✅ | type=text_to_image/text_to_label 时必填。用户输入提示词 |
params.timezone | string | ❌ | type=text_to_label 时可选。设备时区;未传时云端读取设备扩展配置 timezone |
params.language | string | ❌ | type=text_to_label 时可选。设备语言;未传时云端读取设备扩展配置 language |
params.fileType | string | ❌ | type=text_to_image/text_to_label 时可选。下发文件类型:image 或 prn;默认:text_to_image=image,text_to_label=prn |
params.prnProtocol | string | ❌ | type=text_to_image/text_to_label 且 params.fileType=prn 时可选。PRN 协议类型,当前仅支持 esc(默认 esc) |
ts | int64 | ✅ | 消息时间戳(13位毫秒) |
云端响应逻辑
Section titled “云端响应逻辑”type=text_to_image:- 云端根据
params.width/height/prompt处理文生图请求,params.bizId可选用于指定业务 - 当
params.fileType=image(默认)时,处理完成后通过devices/{tenantCode}/{userName}/{sn}/down/print下发图片资源,resources[].fileType=image - 当
params.fileType=prn时,云端将文生图结果转换为 PRN 打印数据后下发,resources[].fileType=prn,并在resources[].prnProtocol中返回协议类型(当前仅esc)
- 云端根据
type=text_to_label:- 客户端必须上报
params.prompt,可选上报params.timezone/language/width/height/bizId/fileType/prnProtocol - 当未上报
params.timezone/language/width/height时,云端读取设备扩展配置中的timezone/language/width/height - 生成结果统一通过
devices/{tenantCode}/{userName}/{sn}/down/print下发 - 当
params.fileType=prn(默认)时,resources[].fileType=prn,并返回resources[].prnProtocol(当前仅esc) - 当
params.fileType=image时,resources[].fileType=image
- 客户端必须上报
type=feature_list:- 仅特定机型在需要动态同步功能列表时发起
- 云端通过
devices/{tenantCode}/{userName}/{sn}/down/pull/ack返回功能列表响应(type=feature_list)
type=device_params:- 设备用于主动拉取设备设置参数
- 云端通过
devices/{tenantCode}/{userName}/{sn}/down/pull/ack返回type=device_params响应 - 返回
params.language、params.timezone、params.width、params.height(来自设备配置扩展参数)和params.hotwordId(热词ID,可按需用于 ASR 连接参数hotwordCacheId)
type=firmware:- 云端判断设备是否存在可用的固件升级任务
- 若有可用升级:通过
devices/{tenantCode}/{userName}/{sn}/down/upgrade下发固件升级任务 - 若无可用升级:通过
devices/{tenantCode}/{userName}/{sn}/down/pull/ack返回type=firmware且errCode=[]的响应
- 任务筛选条件(打印任务):
- 任务在有效期内
- 任务状态不为”取消”或”完成”
- 失败状态的任务如仍在设备配置的有效期内,可重新下发
type=print参数约束:type=print请求不应携带固件参数(如params.hardware/params.firmware),仅用于拉取打印任务type=text_to_label参数约束:客户端需提交params.prompt,可选提交params.timezone/language/width/height/bizId/fileType/prnProtocol;不应上传标签模板匹配结果与生成内容type=device_params参数约束:请求体params通常为空对象,设备不需要上报语言、时区、尺寸与热词筛选参数;云端返回设备当前配置对应的timezone/language/width/height/hotwordId。hotwordId可用于 ASR 连接参数hotwordCacheId,但不作为 ASR 连接前置条件type=firmware兼容性约束:仅支持firmware,不再兼容firmware_upgrade、upgrade作为 Pull 类型- 设备端职责:设备在发送 Pull 请求前应自行判断本地是否存在阻塞性错误(如缺纸、卡纸等)。存在阻塞性错误时不应发送 Pull 请求
- 云端职责:云端在收到 Pull 请求时不再判断设备错误状态,直接按上述逻辑响应。云端仅在以下场景判断设备错误:
- 用户创建新任务时
- 有队列任务需要由云端主动触发下发时
下行消息:Pull 响应(Pull Ack)
Section titled “下行消息:Pull 响应(Pull Ack)”主题: devices/{tenantCode}/{userName}/{sn}/down/pull/ack
QoS: 1
用途: 云端对 Pull 请求的统一响应通道:
type=print:当云端当前没有新的打印任务单且没有新的固件升级任务时返回errCode=[]的响应(不返回默认参数)type=firmware:当云端当前没有可用固件升级任务时返回errCode=[]的响应type=feature_list:返回功能列表type=device_params:返回设备设置参数(语言、时区、标签宽高)与热词ID(hotwordId)type=text_to_label:当请求参数非法或生成失败时返回errCode与msg- 资源请求失败:返回
errCode与msg
{ "msgId": "m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8", "ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6", "type": "print", "errCode": [], "msg": "", "dateTime": 1724044188000}固件更新拉取无可用更新响应示例
Section titled “固件更新拉取无可用更新响应示例”{ "msgId": "m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b9", "ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z7", "type": "firmware", "errCode": [], "msg": "", "dateTime": 1724044188000}功能列表响应示例
Section titled “功能列表响应示例”{ "msgId": "r1s2t3u4v5w6x7y8z9a0b1c2d3e4f5g6", "ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6", "type": "feature_list", "errCode": [], "msg": "", "params": { "features": [ { "featureCode": "print_basic", "featureName": "普通打印", "featureType": "normal" }, { "featureCode": "ai_text_to_image", "featureName": "文生图打印", "featureType": "ai", "bizCode": "ai_doodle_swarmui_marker", "bizName": "文生图" }, { "featureCode": "ai_text_to_label", "featureName": "文本生成标签", "featureType": "ai", "bizCode": "ai_text_label", "bizName": "文本生成标签" } ] }, "dateTime": 1724044288000}设备参数响应示例
Section titled “设备参数响应示例”{ "msgId": "r1s2t3u4v5w6x7y8z9a0b1c2d3e4f5ga", "ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z9", "type": "device_params", "errCode": [], "msg": "", "params": { "language": "zh-CN", "timezone": "Asia/Shanghai", "width": 40, "height": 15, "hotwordId": "hotword_label_daily_v1" }, "dateTime": 1724044288500}资源请求失败响应示例
Section titled “资源请求失败响应示例”{ "msgId": "r1s2t3u4v5w6x7y8z9a0b1c2d3e4f5g7", "ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z7", "type": "text_to_image", "errCode": [2002], "msg": "text_to_image缺少prompt", "params": {}, "dateTime": 1724044289000}{ "msgId": "r1s2t3u4v5w6x7y8z9a0b1c2d3e4f5g8", "ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z8", "type": "text_to_label", "errCode": [2002], "msg": "text_to_label缺少prompt", "params": {}, "dateTime": 1724044290000}{ "msgId": "r1s2t3u4v5w6x7y8z9a0b1c2d3e4f5g9a", "ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z9a", "type": "text_to_image", "errCode": [2007], "msg": "提示词审核不通过:涉及违规内容,请调整后重试", "params": {}, "dateTime": 1724044290500}{ "msgId": "r1s2t3u4v5w6x7y8z9a0b1c2d3e4f5g9", "ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z9", "type": "text_to_label", "errCode": [2005], "msg": "text_to_label生成失败,请稍后重试", "params": {}, "dateTime": 1724044291000}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | ✅ | 消息唯一ID,32字符 |
ackOriginalMsgId | string | ✅ | 对应 Pull 请求的 msgId |
type | string | ✅ | Pull 响应类型:print/text_to_image/text_to_label/feature_list/device_params/firmware |
errCode | int[] | ✅ | 错误码数组,[] 表示成功;非空表示请求失败,错误码定义见错误码章节 |
msg | string | ❌ | 错误消息内容(errCode 非空时必填);无错误时可不传或传空字符串 |
params | object | ❌ | 参数详情。type=feature_list/type=device_params 时返回;其他类型可省略 |
params.features | array | ❌ | 功能列表(type=feature_list 时返回) |
params.features[].featureCode | string | ✅ | 功能 code |
params.features[].featureName | string | ✅ | 功能名称 |
params.features[].featureType | string | ✅ | 功能类型:normal(普通功能)/ai(AI功能) |
params.features[].bizCode | string | ❌ | 当 featureType=ai 时必填,表示 AI 业务 code |
params.features[].bizName | string | ❌ | 当 featureType=ai 时必填,表示 AI 业务名称 |
params.language | string | ❌ | 设备语言配置(type=device_params 时返回),来源于设备配置扩展参数 |
params.timezone | string | ❌ | 设备时区配置(type=device_params 时返回),来源于设备配置扩展参数 |
params.width | int | ❌ | 设备标签宽度(mm,type=device_params 时返回),来源于设备配置扩展参数 |
params.height | int | ❌ | 设备标签高度(mm,type=device_params 时返回),来源于设备配置扩展参数 |
params.hotwordId | string | ❌ | 热词ID(type=device_params 时返回),设备可按需映射为 ASR 连接参数 hotwordCacheId |
dateTime | int64 | ✅ | 服务器时间(13位毫秒时间戳) |
- 当有可用的打印任务时,云端通过
devices/{tenantCode}/{userName}/{sn}/down/print主题下发,不使用 Pull Ack 承载任务数据 - 当有可用的固件升级任务时,云端通过
devices/{tenantCode}/{userName}/{sn}/down/upgrade主题下发,不使用 Pull Ack 承载任务数据 - 当
type=print且errCode=[]且未返回params时,表示云端当前没有新的打印任务单,且没有新的固件升级任务 - 设备发起
type=feature_listPull 时,云端应返回type=feature_list的 Pull Ack 响应 - 设备发起
type=device_paramsPull 时,云端应返回type=device_params的 Pull Ack 响应,并返回language/timezone/width/height/hotwordId - 设备发起
type=text_to_labelPull 成功后,云端通过普通打印主题devices/{tenantCode}/{userName}/{sn}/down/print下发生成结果(fileType=prn或image) - 当资源请求处理失败时,云端应返回
errCode(非空)与msg(错误信息)供设备侧展示与重试策略判断
ASR 接入说明(独立文档)
Section titled “ASR 接入说明(独立文档)”设备协议文档不再内嵌 ASR 传输细节。
ASR 连接参数、首帧字段、二进制音频发送规则、回包格式、错误处理与服务端配置,请统一参考:
在本协议中仅保留以下约定:
- Bootstrap 返回
data.asrAddress作为设备实际使用的 ASR WebSocket 完整连接地址,设备必须以该返回值为准; - 文档中的 ASR 地址仅作格式示例,例如:
wss://asr.iprtapp.com/ws/asr?asrServiceType={引导接口下发的ASR服务类型}&hotwordCacheId={引导接口下发的热词缓存ID,可选}&language={引导接口下发或设备确认的识别语言,如zh-CN}&model={引导接口下发的识别模型,如SenseVoiceSmall}&token={引导接口下发的ASR访问令牌}; - 设备按 ASR 独立文档完成 Token、连接、识别与会话关闭流程;
- 若本页面与 ASR 页面出现冲突,以 ASR 页面为准。
下行消息:打印任务下发
Section titled “下行消息:打印任务下发”主题: devices/{tenantCode}/{userName}/{sn}/down/print
QoS: 2(可协商降级到 QoS 1)
用途: 平台向设备下发打印任务
{ "msgId": "e5f6789012a3b4c5d6e7f89012a3b4c5", "resources": [ { "jobId": "j-202408-0001", "url": "https://obj.example.com/prints/j-202408-0001-part1.data", "hash": "sha256:ab12cd34ef56...", "size": 102400, "fileType": "prn", "prnProtocol": "esc", "compression": "gzip" }, { "jobId": "j-202408-0002", "url": "https://obj.example.com/prints/j-202408-0002-part1.data", "hash": "sha256:cd34ef56ab78...", "size": 102400, "fileType": "prn", "prnProtocol": "esc", "compression": "none" } ], "dateTime": 1724846400000}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | ✅ | 消息唯一ID |
resources | array | ✅ | 打印资源列表,单次下发最多100个 |
resources[].jobId | string | ✅ | 打印任务单ID。云端单个任务单只会包含一个文件;单次下发可包含多个任务单 |
resources[].url | string | ✅ | 文件下载URL |
resources[].hash | string | ✅ | SHA256哈希值,格式:sha256:十六进制字符串 |
resources[].size | int | ✅ | 文件大小(字节) |
resources[].fileType | string | ✅ | 文件类型:prn(原有打印逻辑)、image(AI图片打印逻辑) |
resources[].prnProtocol | string | ❌ | 当 resources[].fileType=prn 时返回。PRN协议类型,当前仅 esc |
resources[].compression | string | ✅ | 压缩方式:none(不压缩)、gzip(gzip压缩)。设备下载后需根据此字段决定是否解压 |
dateTime | int64 | ✅ | 服务器时间(13位毫秒时间戳) |
- 接收任务: 收到消息后立即发送
status=confirm回执(10秒内),jobIds填写本次确认接收的任务单ID数组,并在queueStatus中上报本地队列状态 - 幂等检查: 以
jobId为粒度做去重;重复任务单可直接返回上次结果(success/failed) - 下载资源: 逐条下载
resources[]文件,支持断点续传 - 校验哈希: 下载完成后验证 SHA256 哈希值
- 解压资源: 检查
compression字段,若为gzip则进行 gzip 解压,若为none则跳过解压 - 执行打印:
resources[].fileType=prn:按resources[].prnProtocol指定协议解析并打印(当前仅支持esc)resources[].fileType=image:走 AI 图片打印逻辑- 开始打印时发送
status=printing(建议)
- 完成回执: 每个任务单打印完成后发送对应
jobId的status=success或status=failed
下行消息:固件升级任务
Section titled “下行消息:固件升级任务”主题: devices/{tenantCode}/{userName}/{sn}/down/upgrade
QoS: 2(可协商降级到 QoS 1)
用途: 平台向设备下发固件升级任务
{ "msgId": "f6789012a3b4c5d6e7f89012a3b4c5d6", "deviceUpgradeId": "u-202408-0001", // 设备升级任务ID "firmwareType": "cloud", // 固件类型 "firmwareVersion": "1.2.4", // 固件版本号 "url": "https://obj.example.com/fw/p5802-1.2.4.bin", "hash": "sha256:cd34ef56ab78...", // SHA256哈希值 "size": 5242880, // 文件大小(字节) "compression": "gzip", // 压缩方式:none-不压缩,gzip-gzip压缩 "dateTime": 1724846400000 // 服务器时间(13位毫秒时间戳)}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | ✅ | 消息唯一ID,32字符 |
deviceUpgradeId | string | ✅ | 设备升级任务唯一标识,用于幂等去重 |
firmwareType | string | ✅ | 固件类型:cloud(云端固件)、printer(打印机固件)、bluetooth(蓝牙固件) |
firmwareVersion | string | ✅ | 固件版本号 |
url | string | ✅ | 固件下载URL |
hash | string | ✅ | SHA256哈希值,格式:sha256:十六进制字符串 |
size | int | ✅ | 文件大小(字节) |
compression | string | ✅ | 压缩方式:none(不压缩)、gzip(gzip压缩)。设备下载后需根据此字段决定是否解压 |
dateTime | int64 | ✅ | 服务器时间(13位毫秒时间戳) |
- 接收任务: 收到消息后立即发送
status=confirm回执 - 下载固件:
- 支持断点续传
- 定期发送
status=downloading进度(可选)
- 校验哈希: 下载完成后验证 SHA256 哈希值,失败则立即报错
- 解压固件: 检查
compression字段,若为gzip则进行 gzip 解压,若为none则跳过解压 - 执行升级:
- 发送
status=upgrading状态 - 应用新固件
- 发送
- 重启设备: 升级完成后重启
- 上报结果:
- 重启后发送
status=success回执 - 上报新的固件版本(通过设备状态消息)
- 重启后发送
下行消息:设备控制指令
Section titled “下行消息:设备控制指令”主题: devices/{tenantCode}/{userName}/{sn}/down/control
QoS: 2(可协商降级到 QoS 1)
用途: 平台向设备下发控制指令,用于远程控制设备行为
{ "msgId": "h6i7j890k1l2m3n4o5p6q789r0s1t2u3", "controlId": "a351eff1b614d0c1f64227d0c4b28c99", // 控制指令唯一ID "command": "reboot", // 控制指令类型 "params": {}, // 可选:指令参数 预留字段 "dateTime": 1724846400000 // 服务器时间(13位毫秒时间戳)}支持的控制指令
Section titled “支持的控制指令”| 指令 (command) | 说明 | 参数 (params) | 预期行为 |
|---|---|---|---|
| shutdown | 关机 | 无 | 设备执行安全关机,保存状态后关闭电源 |
| reboot | 重启 | 无 | 设备执行安全重启,保存状态后重启系统 |
| beep | 发声/蜂鸣 | 无 | 发出蜂鸣声 |
| reset_wifi | 重置WiFi | 无 | 清除WiFi配置,恢复到待配网状态 |
| reset_bluetooth | 重置蓝牙 | 无 | 清除蓝牙配对记录,恢复到待配对状态 |
| factory_reset | 恢复出厂设置 | 无 | 清除所有配置,恢复出厂状态。keep_network为true时保留网络配置 |
| clear_cache | 清理缓存 | 无 | 清理临时文件和打印缓存 |
| set_params | 设置设备参数 | - | 设置设备运行参数;设备收到后更新本地配置并回执 |
说明:测试页打印不再通过控制指令下发。平台如需打印测试页,应由云端自行拼接测试页内容并按普通打印任务流程下发。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | ✅ | 消息唯一ID |
controlId | string | ✅ | 控制指令唯一标识,用于幂等去重 |
command | string | ✅ | 控制指令类型,见上表 |
params | object | ❌ | 指令参数,不同指令参数不同 |
dateTime | int64 | ✅ | 服务器时间(13位毫秒时间戳) |
- 接收指令: 收到消息后立即发送
status=confirm回执 - 幂等检查: 根据
controlId判断是否为重复指令 - 参数验证: 检查
command是否支持,params是否合法 - 完成回执:
- 成功:发送
status=success - 失败:发送
status=failed,携带错误信息
- 成功:发送
- 重启类操作: 重启后上报设备状态
示例 : 重启设备
{ "msgId": "a1b2c3d4e5f6789012345678901234ab", "controlId": "a351eff1b614d0c1f64227d0c4b28c99", "command": "reboot", "dateTime": 1724846400000}设备应针对不同错误场景返回相应错误码:
| 错误场景 | errCode | msg 示例 |
|---|---|---|
| 不支持的指令 | [5001] | “不支持的控制指令: xxx” |
| 参数错误 | [5002] | “参数错误: duration必须为正整数” |
| 设备忙碌 | [6012] | “设备正在打印,无法执行控制操作” |
| 执行失败 | [5003] | “WiFi重置失败: 网络模块错误” |
安全注意事项
Section titled “安全注意事项”- 危险操作确认: factory_reset 等危险操作建议设备端二次确认(如通过指示灯闪烁或按键确认)
- 幂等性: 基于
controlId实现幂等,避免重复执行
🔒 安全机制
Section titled “🔒 安全机制”TLS 要求
Section titled “TLS 要求”| 环境 | TLS | 端口 | 说明 |
|---|---|---|---|
| 生产环境 | ✅ 必须 | 8883 | 强制使用 TLS 1.2+ |
| 测试环境 | ❌ 可选 | 1883 / 8883 | 建议启用 TLS |
TLS 配置:
- 服务器证书验证: 设备必须验证服务器证书的有效性
- 证书链: 使用 Bootstrap API 返回的
caCertPem验证整个证书链 - 证书过期: 设备应定期检查并更新 CA 证书
阶段 1: HTTP Bootstrap 认证
- 算法: HMAC-SHA256
- 输入:
sn + ts - 密钥: 设备 Secret
- 输出: 十六进制签名字符串
- 有效期: ±5 分钟时间窗口
阶段 2: MQTT 连接认证
- 用户名: 设备 SN
- 密码: JWT 短期令牌(来自 Bootstrap 响应)
- 令牌有效期: 通常 3600 秒/1小时(由
tokenTtlSec指定)
令牌续期策略
Section titled “令牌续期策略”访问控制(ACL)
Section titled “访问控制(ACL)”ACL 规则
Section titled “ACL 规则”设备仅允许访问自己的主题,禁止跨设备访问。
| 操作 | 允许的主题模式 |
|---|---|
| 发布(PUBLISH) | devices/{tenantCode}/{userName}/{自己的sn}/up/* |
| 订阅(SUBSCRIBE) | devices/{tenantCode}/{userName}/{自己的sn}/down/* |
违规示例:
敏感信息保护
Section titled “敏感信息保护”| 信息类型 | 存储要求 | 说明 |
|---|---|---|
| SN(序列号) | 明文存储 | 设备唯一标识,无需加密 |
| Secret(密钥) | 加密存储 | 使用设备硬件密钥加密,禁止明文存储 |
| JWT Token | 内存存储 | 不持久化,重启后重新获取 |
| CA 证书 | 明文存储 | 公开信息,可明文存储 |
虽然 TLS 已提供传输层加密,但关键业务消息建议额外签名:
🔧 错误处理
Section titled “🔧 错误处理”常见连接错误
Section titled “常见连接错误”| 错误 | 原因 | 解决方案 |
|---|---|---|
| Connection refused | 网络不可达 | 检查网络连接,使用指数退避重试 |
| Authentication failed | 令牌无效或过期 | 重新调用 Bootstrap API 获取新令牌 |
| Certificate verify failed | TLS 证书验证失败 | 检查 CA 证书是否正确 |
| Keep alive timeout | 网络不稳定 | 降低 keepalive 间隔 |
❓ FAQ 常见问题
Section titled “❓ FAQ 常见问题”Q1: 设备时间不准确怎么办?
Section titled “Q1: 设备时间不准确怎么办?”A: 设备应该实现以下时间同步机制:
- NTP 同步: 定期与 NTP 服务器同步时间
- Bootstrap 校准: 使用 Bootstrap API 返回的
serverTime校准本地时间 - 误差检测: 如果时间误差超过 5 分钟,拒绝签名验证并提示用户
Q2: 如何处理网络波动导致的消息丢失?
Section titled “Q2: 如何处理网络波动导致的消息丢失?”A: 采用以下策略:
- 使用 QoS 1 或 QoS 2: 保证消息至少送达一次
- 消息缓存: 离线时缓存消息,连接恢复后重发
- 幂等设计: 基于
jobId和msgId实现幂等去重 - 超时重试: 设置合理的超时时间和重试机制
Q3: 打印任务太大,如何优化下载速度?
Section titled “Q3: 打印任务太大,如何优化下载速度?”A: 建议采用以下优化措施:
- 并发下载: 同时下载多个
resources资源(限制并发数为 3-5) - 断点续传: 使用 HTTP Range 请求支持断点续传
- 预加载: 打印前几个资源时,提前拉取后续资源
- 压缩传输: 资源文件支持 gzip 压缩,设备根据
resources[].compression字段判断是否需要解压。当compression为gzip时,下载完成并校验哈希后需进行 gzip 解压
Q4: 固件升级失败后如何回滚?
Section titled “Q4: 固件升级失败后如何回滚?”A: 设备应该实现以下机制:
- 双分区设计: 保留旧固件分区,升级失败时自动切换
- 升级标记: 记录升级状态,重启后检查是否成功
- 回滚逻辑: 升级失败自动回滚到旧版本
- 上报失败: 通过
up/upgrade/ack上报失败原因
Q5: 如何判断是否需要主动拉取任务?
Section titled “Q5: 如何判断是否需要主动拉取任务?”可以采用以下策略:
- 拉取打印资源: 设备上电、MQTT连接成功、上报状态后,通过 Pull 主题发起
type=print请求 - 持续拉取更多任务单: 在本地队列不足时,通过 Pull 主题继续发起
type=print请求,在设备确认打印任务的时候,云端也会继续下推新的任务,设备根据本地队列上报队列状态,云端根据队列结果下发和缓存任务。当本地打印到最后一个打印任务的时候,需要主动pull打印任务,防止云端缓存没下发情况 - 文生图资源请求: 当设备需要 AI 文生图时,发送
type=text_to_image,并在params中携带width/height/prompt,可选bizId、fileType(image/prn)和prnProtocol(当前仅esc) - 文本生成标签请求: 当设备需要 AI 文本生成标签时,发送
type=text_to_label,params需携带prompt,可选timezone/language/width/height/bizId/fileType/prnProtocol;未携带timezone/language/width/height时云端读取设备扩展配置。标签匹配和生成在云端完成。云端通过普通打印主题下发,fileType=prn时返回prnProtocol - 获取功能列表(按需): 仅特定机型在需要动态同步可用功能时,发送
type=feature_list,params通常为空对象即可 - 获取设备设置参数(按需): 当设备需要同步云端设备设置参数时,发送
type=device_params;云端返回设备扩展参数中的language/timezone/width/height,以及可选热词IDhotwordId。该步骤不是 ASR 连接前置条件 - 主动检查固件更新: 当设备在开机后以及其他需要检查固件更新时,发送
type=firmware并在params中携带硬件参数与当前固件版本信息;若云端无可用更新,将返回type=firmware且errCode=[]的 Pull Ack(不兼容firmware_upgrade/upgrade) - 设备端错误判断: 设备在发送 Pull 请求前应自行判断本地是否存在阻塞性错误(如缺纸、卡纸),存在阻塞性错误时不应发送 Pull
重要: 云端在收到 Pull 请求时不再判断设备错误状态,设备端需自行负责错误状态的判断。
Q6: 设备 SN 和 Secret 如何获取?
Section titled “Q6: 设备 SN 和 Secret 如何获取?”A: 设备侧必须具备 SN 和 Secret(用于 Bootstrap 签名与 MQTT 连接认证),通常来源如下:
- 设备注册: 平台侧为设备创建设备记录,生成 SN 与 Secret
- 生产烧录: 在生产环节将 SN 与 Secret 烧录到设备(Secret 必须加密存储)
- App 侧绑定(不同型号流程不同):
- WiFi 版本:App 通过连接设备本体蓝牙,与设备握手后可获取 SN/设备秘钥等信息,再完成配网与绑定
- 4G 版本:App 通过扫描/输入 SN 发起验证码请求;设备在线时打印验证码,App 输入/识别验证码后完成绑定(App 不直接持有 Secret)
注意:以上为“设备入网/绑定”的业务流程说明;协议层仍以设备本地持有 SN/Secret 为前提完成引导与认证。
Q7: 如何调试 MQTT 连接问题?
Section titled “Q7: 如何调试 MQTT 连接问题?”A: 建议使用以下工具和方法:
-
MQTT 客户端工具:
- MQTTX: 图形化 MQTT 客户端
- mosquitto_sub/pub: 命令行工具
-
抓包分析:
-
日志调试:
- 启用 MQTT 库的详细日志
- 记录连接参数、认证信息(脱敏)
-
测试环境:
- 先在测试环境验证(使用 1883 明文端口)
- 确认无误后切换到生产环境(8883 TLS 端口)
消息桥接架构
Section titled “消息桥接架构”平台采用分离式消息架构,通过 Messaging Bridge 组件实现 MQTT 和 Kafka 之间的双向消息转发:
设备 <--MQTT--> EMQX <--Messaging Bridge--> Kafka <--> 平台应用设备到平台 (EMQX → Kafka):
devices/{tenantCode}/{userName}/{sn}/up/state→ Kafka Topic:iot-messages(type: device_state)devices/{tenantCode}/{userName}/{sn}/up/print/ack→ Kafka Topic:iot-messages(type: print_ack)devices/{tenantCode}/{userName}/{sn}/up/upgrade/ack→ Kafka Topic:iot-messages(type: upgrade_ack)devices/{tenantCode}/{userName}/{sn}/up/control/ack→ Kafka Topic:iot-messages(type: control_ack)devices/{tenantCode}/{userName}/{sn}/up/event→ Kafka Topic:iot-messages(type: device_event)devices/{tenantCode}/{userName}/{sn}/up/pull→ Kafka Topic:iot-messages(type: pull_request)
平台到设备 (Kafka → EMQX):
- Kafka Topic:
device-commands(type: print_command) →devices/{tenantCode}/{userName}/{sn}/down/print - Kafka Topic:
upgrade-commands(type: upgrade_command) →devices/{tenantCode}/{userName}/{sn}/down/upgrade - Kafka Topic:
control-commands(type: control_command) →devices/{tenantCode}/{userName}/{sn}/down/control - Kafka Topic:
pull-ack-commands(type: pull_ack) →devices/{tenantCode}/{userName}/{sn}/down/pull/ack
| 项目 | 限制 | 说明 |
|---|---|---|
| 单条消息大小 | 256 KB | 打印内容应通过 URL 下载,不直接放在消息体 |
| resources 数组大小 | 100 个元素 | 单次下发最多 100 个打印资源 |
| 状态上报频率 | 10 条/分钟 | 突发异常场景除外 |
| 主题路径长度 | 256 字符 | 包含完整路径 |
| msgId 长度 | 32 字符 | UUID v4 去掉连字符 |
| jobId 长度 | 32 字符 | UUID v4 去掉连字符 |
| Bootstrap 连接参数有效期 | 长期有效 | 仅 JWT Token 需定期续期 |
| JWT Token 有效期 | 1 小时 | 由 tokenTtlSec 指定 |
协议版本历史
Section titled “协议版本历史”| 版本 | 日期 | 变更说明 |
|---|---|---|
| v1.0 | 2026-04-29 | 定义基础通信协议 |
文档维护: 爱印科技-应用技术部-方江琛
最后更新: 2026-06-03