跳转到内容

爱印云打印平台设备通讯协议规范

文档版本: v1.0
最后更新: 2026-06-03
适用对象: 设备固件开发者、第三方硬件集成商


日期更新内容
2026-05-151. 【ASR-对齐】ASR 客户端接入改为基于 /ws/asr 查询参数规范:token 必填,支持 model/language/hotwordCacheId/asrServiceTypeASR 服务 API 文档
2. 【ASR-字段】首帧配置由 hotword_id 调整为网关协议字段 hotwords(可选)与 svs_lang(可选),并补充参数回退/纠正规则 → ASR 服务 API 文档
3. 【ASR-回包】补充 connected/result/error 回包字段(asr_service_type/model/language 等)以匹配网关行为 → ASR 服务 API 文档
2026-05-141. 【下发-细分】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-131. 【下发-变更】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-121. 【上报-新增】Pull 新增 type=device_params(设备参数拉取)请求类型,用于主动获取设备设置参数 → 上行消息:任务拉取请求(Pull)
2. 【下发-新增】Pull Ack 新增 type=device_params 响应,返回设备扩展配置中的 language/timezone 以及按语言匹配的型号热词 hotWords下行消息:Pull 响应(Pull Ack)
3. 【文档-更新】补充 device_params 的请求示例、字段定义、响应逻辑与 FAQ 拉取策略说明
2026-05-091. 【上报-新增】Pull 新增 type=text_to_label(文本生成标签)请求类型,客户端仅上报 prompt(可选 bizId/fileType/prnProtocol),标签匹配与生成由云端处理 → 上行消息:任务拉取请求(Pull)
2. 【下发-明确】text_to_label 生成结果统一通过 devices/{tenantCode}/{userName}/{sn}/down/print 下发,按 resources[].fileType 区分 prn/imageprn 时使用 resources[].prnProtocol(当前 esc) → 下行消息:打印任务下发
3. 【下发-新增】补充 text_to_label 请求异常时的 Pull Ack 返回示例(type/errCode/msg) → 下行消息:Pull 响应(Pull Ack)
2026-04-291. 【上报-新增】打印回执新增 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[].fileTyperesources[].prnProtocol 以支持图片与 PRN 协议分流 → 下行消息:Pull 响应(Pull Ack)下行消息:打印任务下发
4. 【下发-删除】Pull Ack 移除旧版 code + message=no_task 单一无任务响应模型;打印下发移除顶层 jobId/totalFileNumberresources[].seq 结构 → 下行消息:Pull 响应(Pull Ack)下行消息:打印任务下发
5. 【上报/下发-修改】主题路径由 devices/{sn}/... 统一升级为 devices/{tenantCode}/{userName}/{sn}/...,用于租户与用户维度隔离 → 主题命名规范


  • 设备已向平台注册,获得 SN(序列号)和 Secret(密钥)
  • 设备支持 HTTPS 和 MQTT 协议
  • 设备具备基本的文件下载和哈希校验能力
  • 建议设备时间与 NTP 服务器同步,误差不超过 5 分钟
  1. 设备上电 → 调用 Bootstrap API 获取连接参数
  2. 使用返回的参数连接 MQTT Broker
  3. 订阅下行主题(接收平台命令和 Pull 响应/Pull Ack)
  4. 上报设备状态
  5. 主动拉取固件升级任务(通过 Pull 主题请求固件更新)
  6. 主动拉取打印任务(通过 Pull 主题请求打印资源)
  7. 处理平台下发的打印/升级/控制任务
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
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
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: 请求打印任务
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

设备 <--HTTPS--> Bootstrap API (获取连接参数)
设备 <--MQTT--> EMQX Broker <--Bridge--> Kafka <--> 平台应用
  • 双向通信: 设备可上报状态,平台可下发任务
  • QoS 保证: 上行 QoS1,下行 QoS2(可协商降级到 QoS1)
  • 消息幂等: 基于 msgIdjobId 实现幂等去重
  • TLS 加密: 生产环境强制使用 TLS 1.2+

术语说明示例/备注
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 进行时间校准。


状态码说明处理建议
200成功-
401签名无效或已过期检查签名算法和时间戳
404设备未注册联系平台管理员注册设备
423设备已被禁用设备被停用,无法继续使用
429请求频率超限实施指数退避策略
500服务器内部错误重试或联系技术支持

约定:凡字段名为 errCode(数组)时,空数组 [] 表示无错误/正常;当存在错误时,数组内元素为一个或多个错误码,取值参考本章节错误码定义。

错误码说明
0操作成功
错误码说明处理建议
1001签名非法检查签名算法,确认 Secret 正确
1002令牌过期或无效重新调用 Bootstrap API 获取新令牌
1003设备未授权检查设备是否已注册并启用
错误码说明处理建议
2001主题访问被拒绝(ACL)检查主题路径是否正确
2002消息格式错误检查 JSON 格式和必填字段
2003消息体过大单条消息不得超过 256KB
2004资源请求类型不支持检查 Pull 请求 type 是否在协议支持范围内
2005资源请求处理失败检查 msg 字段错误详情并按提示修正请求或稍后重试
2006文生图提示词审核处理失败检查提示词审核服务状态与配置,建议稍后重试
2007文生图提示词审核不通过提示用户调整提示词内容后重新发起请求
2008文生图生成失败检查生图引擎状态/参数合法性,必要时重试
2009文生图图片审核失败图片结果未通过审核或审核流程异常,建议调整提示词或稍后重试
错误码说明处理建议
3001打印失败(设备硬件故障)检查打印机状态,上报详细错误信息
3002打印超时检查网络和设备性能
3003打印内容下载失败检查网络连接,支持断点续传
3004打印内容校验失败重新下载文件,检查 hash 算法
3005存储空间不足重启机器或者联系工程师排查情况处理
错误码说明处理建议
4001升级包校验失败检查 SHA256 哈希值
4002升级失败/回滚保留旧固件,支持回滚机制
4003升级包下载失败检查网络,支持断点续传
4004固件版本不兼容检查设备型号和固件版本匹配
4005存储空间不足清理临时文件或提示用户
4006升级超时设备升级超时且达到最大重试次数,平台标记失败
错误码说明处理建议
5001不支持的控制指令检查指令是否在支持列表中
5002控制指令参数错误检查参数格式和取值范围
5003控制指令执行失败检查设备状态和硬件功能
5004控制指令超时检查设备响应能力
错误码说明处理建议
6001打印机缺纸提示用户添加纸张
6002打印机卡纸提示用户清除卡纸
6003打印机过热暂停打印,等待降温
6004电池电量低提示用户充电
6005存储空间不足清理缓存文件
6006盖子未关重新把盖子关上
6007盖子未关且卡纸重新打开盖子整理下纸张再关好盖子
6008盖子未关且过热通风散热后再重新关盖打印
6009卡纸且过热通风散热后打开盖子调整纸张后再重新关盖打印
6010盖子未关且卡纸且过热通风散热后打开盖子调整纸张后再重新关盖打印
6011硬件错误联系工程师处理
6012设备忙等待设备正常后再执行后续打印操作
6013纸张类型错误检查纸张类型是否与任务要求匹配

Step 1: Bootstrap API - 获取连接参数

Section titled “Step 1: Bootstrap API - 获取连接参数”

设备上电后,首先通过 HTTPS 调用 Bootstrap API 获取 MQTT 连接参数和主题配置。

环境地址

环境API 基础地址前端地址Bootstrap 完整地址
测试环境https://cprint-api-stg.iprtapp.comhttps://cprint-stg.iprtapp.comhttps://cprint-api-stg.iprtapp.com/api/v1/bootstrap
正式环境https://cprint-api.iprtapp.comhttps://cprint.iprtapp.comhttps://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..." // 必填:签名,见下方算法说明
}
字段类型必填说明
snstring设备序列号,全局唯一标识符
protocolVersionstring协议版本号,当前为 1.0
tsint64当前时间戳(13位毫秒),仅需确保为13位长度即可
signstringHMAC-SHA256签名,计算方式见下方算法说明

算法: HMAC-SHA256

步骤:

  1. 拼接明文字符串:plaintext = sn + ts
    • 示例:"SN-XYZ-001" + "1724040000000""SN-XYZ-0011724040000000"
  2. 使用 Secret 作为密钥,对明文进行 HMAC-SHA256 计算,例如明文SN-XYZ-0011724040000000使用密钥password进行HMAC-SHA256加密后的结果为5776e385eb1e6a652e71dd3cb37b98a7f459d186ec630a3da5274fa97f429743
  3. 将计算结果转换为十六进制小写字符串

成功响应(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
}
字段路径类型说明
codeint业务错误码,0表示成功
messagestring响应消息描述
data.device.snstring设备序列号
data.device.modelstring设备型号
data.mqtt.hoststringMQTT服务器地址
data.mqtt.portintMQTT服务器端口,8883(TLS)或1883(非TLS)
data.mqtt.clientIdstringMQTT客户端ID,格式固定为 {sn}|{protocolVersion}
data.mqtt.usernamestringMQTT连接用户名,通常为设备SN
data.mqtt.passwordstringJWT短期令牌,有效期由 tokenTtlSec 指定
data.mqtt.qosUpint上行消息QoS等级(通常为1)
data.mqtt.qosDownint下行消息QoS等级(通常为2)
data.mqtt.tokenTtlSecintJWT令牌有效期(秒),默认为3600秒(1小时)
data.mqtt.keepaliveintMQTT心跳时间(秒),设备应按此间隔发送心跳包保持连接,默认60秒
data.mqtt.cleanSessionbool是否清洁会话,true表示不保留离线消息,false表示保持会话以便恢复离线消息
data.mqtt.tls.enabledbool是否启用TLS,生产环境必须为true
data.mqtt.tls.caCertPemstringTLS根证书(PEM格式),用于验证服务器身份,目前使用验证过的公钥,所以当前字段默认为空,由设备端自行通过证书库认证
data.topics.upStatestring设备状态上行主题
data.topics.upPrintAckstring打印任务回执上行主题
data.topics.upUpgradeAckstring固件升级回执上行主题
data.topics.upControlAckstring控制指令回执上行主题
data.topics.upEventstring设备事件上行主题,用于设备上报事件通知
data.topics.upPullstring任务拉取上行主题,设备主动拉取打印资源、文生图资源、文本生成标签资源、功能列表或固件更新
data.topics.downPrintstring打印任务下行主题
data.topics.downUpgradestring设备固件升级下行主题
data.topics.downControlstring控制指令下行主题,接收平台控制命令
data.topics.downPullAckstringPull响应下行主题,用于回复无可用任务、功能列表响应或资源请求错误信息
data.stateReportIntervalint设备状态上报周期(秒),设备应按此间隔定期上报设备状态,默认1800秒(30分钟)
data.serverTimeint64服务器当前时间戳(秒级,13位),设备可用于时间校准
data.asrAddressstringASR WebSocket 完整连接地址。设备必须直接使用引导接口下发的值,不要写死域名、路径或查询参数;详细接入方式见 ASR 服务 API 文档
  1. 参数有效期: Bootstrap 返回的 MQTT 连接参数长期有效,除非平台更新配置
  2. 令牌续期: JWT 令牌有效期为 tokenTtlSec 秒(通常为3600秒),令牌接近过期(剩余5分钟)时,应重新调用 Bootstrap API 获取新令牌
  3. 时间同步: 如果设备时间与 serverTime 差异过大,应使用 serverTime 进行校准
  4. TLS证书: 生产环境必须启用 TLS
  5. ASR连接: 设备必须使用 Bootstrap 返回的 asrAddress 原样发起 WebSocket 连接;如返回值已包含 token/asrServiceType/hotwordCacheId/language/model 等查询参数,设备端无需自行拼接或替换,详细参数与时序见 ASR 服务 API 文档

使用 Bootstrap API 返回的参数连接 MQTT Broker。


连接成功后,立即订阅平台下发命令的主题。需订阅以下主题:

  • 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 响应(无任务/无更新/功能列表/设备参数/资源请求错误)

订阅成功后,立即上报一次设备状态。


上报状态后,设备应主动通过 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 时不再判断设备错误状态。


监听消息事件,处理打印和升级任务。


方向主题模式说明
上行devices/{tenantCode}/{userName}/{sn}/up/{message_type}设备上报消息到平台
下行devices/{tenantCode}/{userName}/{sn}/down/{message_type}平台下发命令或资源到设备

命名约束:

  • 主题路径仅允许字符:[a-z0-9-_/]
  • tenantCodeuserName 建议使用 A-Z0-9-_ 字符组合
  • SN 建议使用 A-Z0-9- 字符组合
  • 主题路径最大长度:256 字符

所有 MQTT 消息载荷均为 JSON UTF-8 编码格式。

通用字段:

{
"msgId": "32字符唯一ID", // 必填:消息唯一标识符,用于去重
"ts": 1724040060000, // 必填:消息时间戳(13位毫秒)
// ... 其他业务字段
}

msgId 生成规范:

  • 长度:32 字符
  • 格式:建议使用 UUID v4 去掉连字符(例:a1b2c3d4e5f6789012345678901234ab
  • 唯一性:全局唯一,用于消息去重和链路追踪
  • 生成示例:

主题: 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"
}
]
}
字段类型必填说明
msgIdstring消息唯一ID,32字符
tsint64消息时间戳(13位毫秒)
rssiintWiFi信号强度,单位dBm,通常为负数
batteryfloat电量百分比,范围0~1
paperint纸张状态,0=缺纸,1=正常
paperTypestring纸张类型:fold(折叠纸)/roll(卷纸)/gap(标签纸)/hole(孔型纸)/tattoo(纹身纸)
errCodeint[]设备错误码数组,[] 表示正常,其他见错误码表,可同时上报多个错误码
temperaturefloat设备温度(摄氏度)
humidityfloat设备湿度(0~1)
ipAddressstring设备当前IP地址
bluetoothMacstring蓝牙MAC地址
imeistring4G模块IMEI号(15位数字),用于识别4G模块
iccidstringSIM卡ICCID号(18-22位数字),用于识别SIM卡
signalStrengthint4G信号强度(dBm),通常为负数
networkTypestring网络类型:2G/3G/4G/5G
printCountint累计打印张数
avgLatencyint平均延时(毫秒),用于监控设备网络质量
packetLossRateint丢包率(0~100),如2表示2%丢包率
chargingbool是否正在充电,true 表示充电中
sleepTimeint休眠时间(分钟)
firmwarearray固件版本列表
firmware[].firmwareTypestring固件类型:cloud/printer/bluetooth
firmware[].firmwareVersionstring固件版本号
firmware[].nnstring设备当前 NN 号,建议在 firmwareType=cloud 的固件项中上报;非空时云端将更新设备记录中的 NN 号
场景上报时机
开机上报设备启动完成,各状态正常,MQTT 连接成功后立即上报
周期上报可选,建议每 30 分钟上报一次
变化上报重要状态变更时立即上报(缺纸、电量低、过热等)
频率限制每分钟不超过 100 条(突发异常除外)

主题: 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
}
字段类型必填说明
msgIdstring消息唯一ID,32字符
jobIdsstring[]打印任务单ID数组,与下发任务的 resources[].jobId 对应
ackOriginalMsgIdstring原始下发消息的msgId,用于消息关联
statusstring任务状态:confirm/printing/success/failed
queueStatusstring本地打印任务队列状态:good/congested/full,仅 status=confirm 时建议上报
errCodeint[]错误码数组,[] 表示成功,其他见错误码表,可同时返回多个错误码
msgstring错误描述信息或状态说明
tsint64消息时间戳(13位毫秒)
status 值含义是否必传说明
confirm收到任务确认✅ 必传设备收到下发消息后立即回复,10秒内必须发送。jobIds 可携带多个确认接收的任务单ID;建议同时上报 queueStatus
printing打印中✅ 建议打印进度上报,jobIds 上报当前正在处理的任务单ID数组(通常 1 个)
success打印成功✅ 必传打印完成,jobIds 上报已完成的任务单ID数组(通常 1 个)
failed打印失败✅ 必传打印失败,jobIds 上报失败的任务单ID数组(通常 1 个)
  • good:云端可继续下发新的任务单
  • congested:云端不再继续下发新任务单(避免进一步堆积)
  • full:云端不再继续下发新任务单;本次已下发但设备因队满无法入队/处理的任务单,云端应在设备后续重新 Pull 时重新下发

注意: 拉取新的打印任务或固件升级任务请使用独立的 Pull 主题(devices/{tenantCode}/{userName}/{sn}/up/pull)。

  1. 设备打印中突然断电
  2. 设备重启: 设备重启后完成自检、MQTT 连接,上报设备状态
  3. 主动拉取任务: 设备通过 Pull 主题(devices/{tenantCode}/{userName}/{sn}/up/pull)发起 type=print 请求,云端根据历史回执自主判断下发未完成的任务单
  4. 续打任务下发: 平台下发未完成/未打印的任务单批次
  5. 恢复打印: 设备继续打印

主题: devices/{tenantCode}/{userName}/{sn}/up/upgrade/ack
QoS: 1
用途: 向平台回复固件升级任务的执行状态

{
"msgId": "d4e5f6789012a3b4c5d6e7f89012a3b4",
"deviceUpgradeId": "92ef08872ff906876071478274eec57b", // 设备升级任务ID
"ackOriginalMsgId": "原始下发消息的msgId",
"status": "upgrading", // 升级状态
"errCode": [], // 错误码数组,空数组表示成功
"msg": "ok", // 错误描述
"ts": 1724041088000
}
字段类型必填说明
msgIdstring消息唯一ID,32字符
deviceUpgradeIdstring设备升级任务ID,与下发任务的deviceUpgradeId对应
ackOriginalMsgIdstring原始下发消息的msgId,用于消息关联
statusstring升级状态:confirm/downloading/upgrading/success/failed
errCodeint[]错误码数组,[] 表示成功,其他见错误码表,可同时返回多个错误码
msgstring错误描述信息或状态说明
tsint64消息时间戳(13位毫秒)
status 值含义是否必传说明
confirm收到任务确认✅ 必传设备收到升级任务后立即回复
downloading下载中❌ 可选固件下载进度上报
upgrading升级中❌ 可选正在执行升级
success升级成功✅ 必传升级完成并重启后发送
failed升级失败✅ 必传升级过程中出现错误

主题: devices/{tenantCode}/{userName}/{sn}/up/control/ack
QoS: 1
用途: 向平台回复设备控制指令的执行状态

{
"msgId": "g5h6i7j890k1l2m3n4o5p6q789r0s1t2",
"controlId": "a351eff1b614d0c1f64227d0c4b28c99", // 控制指令ID
"ackOriginalMsgId": "原始下发消息的msgId",
"status": "confirm", // 执行状态
"errCode": [], // 错误码数组,空数组表示成功
"msg": "ok", // 错误描述
"ts": 1724042088000
}
字段类型必填说明
msgIdstring消息唯一ID,32字符
controlIdstring控制指令ID,与下发指令的controlId对应
ackOriginalMsgIdstring原始下发消息的msgId,用于消息关联
statusstring执行状态:confirm/success/failed
errCodeint[]错误码数组,[] 表示成功,其他见错误码表,可同时返回多个错误码
msgstring错误描述信息或状态说明
tsint64消息时间戳(13位毫秒)
status 值含义是否必传说明
confirm收到指令确认✅ 必传设备收到控制指令后立即回复
success执行成功✅ 必传控制操作完成
failed执行失败✅ 必传控制操作失败

主题: devices/{tenantCode}/{userName}/{sn}/up/event
QoS: 1
用途: 设备向平台上报事件通知,用于触发云端特定业务逻辑

{
"msgId": "h7i8j9k012l3m4n5o6p7q8r901s2t3u4",
"eventType": "stop_print", // 事件类型
"eventParams": { // 事件参数(可选)
"reason": "user_action" // 事件原因或其他参数
},
"ts": 1724043088000
}
字段类型必填说明
msgIdstring消息唯一ID,32字符
eventTypestring事件类型,见下方事件类型表
eventParamsobject事件参数,JSON对象,不同事件类型有不同参数
tsint64消息时间戳(13位毫秒)
eventType 值含义eventParams 参数云端处理逻辑
stop_print停止打印事件reason: 停止原因(可选)云端收到后会清除该设备的打印队列中所有待打印任务

当设备需要停止打印时(如用户按下停止按钮),设备应发送此事件通知云端。

消息示例:

{
"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
用途: 设备主动拉取资源,当前支持普通打印资源、文生图资源、文本生成标签资源、功能列表、设备参数与固件更新拉取

{
"msgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6",
"type": "print", // print/text_to_image/text_to_label/feature_list/device_params/firmware,空则按 print 处理
"params": {},
"ts": 1724044088000
}
{
"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
}
{
"msgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z8",
"type": "text_to_label",
"params": {
"prompt": "开封贴,牛排",
"timezone": "Asia/Shanghai",
"language": "zh-CN",
"width": 40,
"height": 15
},
"ts": 1724044088000
}
{
"msgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z9",
"type": "device_params",
"params": {},
"ts": 1724044088000
}
字段类型必填说明
msgIdstring消息唯一ID,32字符
typestring资源类型:print/text_to_image/text_to_label/feature_list/device_params/firmware
paramsobject类型参数对象,不同 type 字段不同。type 为空时可不传并走旧结构;type=feature_list/device_params 时通常传 {}null
params.hardwareobjecttype=firmware时建议上报。硬件参数
params.hardware.deviceModelstring设备型号(示例:P5802
params.firmwarearraytype=firmware 时建议上报。设备当前固件版本列表
params.firmware[].firmwareTypestring固件类型:cloud/printer/bluetooth
params.firmware[].firmwareVersionstring固件版本号
params.firmware[].nnstring模组或打印机 NN 号
params.bizIdstringtype=text_to_image/text_to_label 时可选。业务ID,不传时由云端按默认策略处理
params.widthint条件必填type=text_to_image 时必填,表示图片宽度(像素);type=text_to_label 时可选,表示标签宽度(mm)
params.heightint条件必填type=text_to_image 时必填,表示图片高度(像素);type=text_to_label 时可选,表示标签高度(mm)
params.promptstringtype=text_to_image/text_to_label 时必填。用户输入提示词
params.timezonestringtype=text_to_label 时可选。设备时区;未传时云端读取设备扩展配置 timezone
params.languagestringtype=text_to_label 时可选。设备语言;未传时云端读取设备扩展配置 language
params.fileTypestringtype=text_to_image/text_to_label 时可选。下发文件类型:imageprn;默认:text_to_image=imagetext_to_label=prn
params.prnProtocolstringtype=text_to_image/text_to_labelparams.fileType=prn 时可选。PRN 协议类型,当前仅支持 esc(默认 esc
tsint64消息时间戳(13位毫秒)
  1. 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
  2. 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
  3. type=feature_list:
    • 仅特定机型在需要动态同步功能列表时发起
    • 云端通过 devices/{tenantCode}/{userName}/{sn}/down/pull/ack 返回功能列表响应(type=feature_list
  4. type=device_params:
    • 设备用于主动拉取设备设置参数
    • 云端通过 devices/{tenantCode}/{userName}/{sn}/down/pull/ack 返回 type=device_params 响应
    • 返回 params.languageparams.timezoneparams.widthparams.height(来自设备配置扩展参数)和 params.hotwordId(热词ID,可按需用于 ASR 连接参数 hotwordCacheId
  5. type=firmware:
    • 云端判断设备是否存在可用的固件升级任务
    • 若有可用升级:通过 devices/{tenantCode}/{userName}/{sn}/down/upgrade 下发固件升级任务
    • 若无可用升级:通过 devices/{tenantCode}/{userName}/{sn}/down/pull/ack 返回 type=firmwareerrCode=[] 的响应
  6. 任务筛选条件(打印任务):
    • 任务在有效期内
    • 任务状态不为”取消”或”完成”
    • 失败状态的任务如仍在设备配置的有效期内,可重新下发
  • 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/hotwordIdhotwordId 可用于 ASR 连接参数 hotwordCacheId,但不作为 ASR 连接前置条件
  • type=firmware 兼容性约束:仅支持 firmware,不再兼容 firmware_upgradeupgrade 作为 Pull 类型
  • 设备端职责:设备在发送 Pull 请求前应自行判断本地是否存在阻塞性错误(如缺纸、卡纸等)。存在阻塞性错误时不应发送 Pull 请求
  • 云端职责:云端在收到 Pull 请求时不再判断设备错误状态,直接按上述逻辑响应。云端仅在以下场景判断设备错误:
    • 用户创建新任务时
    • 有队列任务需要由云端主动触发下发时

主题: 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:当请求参数非法或生成失败时返回 errCodemsg
  • 资源请求失败:返回 errCodemsg
{
"msgId": "m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8",
"ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6",
"type": "print",
"errCode": [],
"msg": "",
"dateTime": 1724044188000
}

固件更新拉取无可用更新响应示例

Section titled “固件更新拉取无可用更新响应示例”
{
"msgId": "m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b9",
"ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z7",
"type": "firmware",
"errCode": [],
"msg": "",
"dateTime": 1724044188000
}
{
"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
}
{
"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
}
{
"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
}
字段类型必填说明
msgIdstring消息唯一ID,32字符
ackOriginalMsgIdstring对应 Pull 请求的 msgId
typestringPull 响应类型:print/text_to_image/text_to_label/feature_list/device_params/firmware
errCodeint[]错误码数组,[] 表示成功;非空表示请求失败,错误码定义见错误码章节
msgstring错误消息内容(errCode 非空时必填);无错误时可不传或传空字符串
paramsobject参数详情。type=feature_list/type=device_params 时返回;其他类型可省略
params.featuresarray功能列表(type=feature_list 时返回)
params.features[].featureCodestring功能 code
params.features[].featureNamestring功能名称
params.features[].featureTypestring功能类型:normal(普通功能)/ai(AI功能)
params.features[].bizCodestringfeatureType=ai 时必填,表示 AI 业务 code
params.features[].bizNamestringfeatureType=ai 时必填,表示 AI 业务名称
params.languagestring设备语言配置(type=device_params 时返回),来源于设备配置扩展参数
params.timezonestring设备时区配置(type=device_params 时返回),来源于设备配置扩展参数
params.widthint设备标签宽度(mm,type=device_params 时返回),来源于设备配置扩展参数
params.heightint设备标签高度(mm,type=device_params 时返回),来源于设备配置扩展参数
params.hotwordIdstring热词ID(type=device_params 时返回),设备可按需映射为 ASR 连接参数 hotwordCacheId
dateTimeint64服务器时间(13位毫秒时间戳)
  • 当有可用的打印任务时,云端通过 devices/{tenantCode}/{userName}/{sn}/down/print 主题下发,不使用 Pull Ack 承载任务数据
  • 当有可用的固件升级任务时,云端通过 devices/{tenantCode}/{userName}/{sn}/down/upgrade 主题下发,不使用 Pull Ack 承载任务数据
  • type=printerrCode=[] 且未返回 params 时,表示云端当前没有新的打印任务单,且没有新的固件升级任务
  • 设备发起 type=feature_list Pull 时,云端应返回 type=feature_list 的 Pull Ack 响应
  • 设备发起 type=device_params Pull 时,云端应返回 type=device_params 的 Pull Ack 响应,并返回 language/timezone/width/height/hotwordId
  • 设备发起 type=text_to_label Pull 成功后,云端通过普通打印主题 devices/{tenantCode}/{userName}/{sn}/down/print 下发生成结果(fileType=prnimage
  • 当资源请求处理失败时,云端应返回 errCode(非空)与 msg(错误信息)供设备侧展示与重试策略判断

设备协议文档不再内嵌 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 页面为准。

主题: 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
}
字段类型必填说明
msgIdstring消息唯一ID
resourcesarray打印资源列表,单次下发最多100个
resources[].jobIdstring打印任务单ID。云端单个任务单只会包含一个文件;单次下发可包含多个任务单
resources[].urlstring文件下载URL
resources[].hashstringSHA256哈希值,格式:sha256:十六进制字符串
resources[].sizeint文件大小(字节)
resources[].fileTypestring文件类型:prn(原有打印逻辑)、image(AI图片打印逻辑)
resources[].prnProtocolstringresources[].fileType=prn 时返回。PRN协议类型,当前仅 esc
resources[].compressionstring压缩方式:none(不压缩)、gzip(gzip压缩)。设备下载后需根据此字段决定是否解压
dateTimeint64服务器时间(13位毫秒时间戳)
  1. 接收任务: 收到消息后立即发送 status=confirm 回执(10秒内),jobIds 填写本次确认接收的任务单ID数组,并在 queueStatus 中上报本地队列状态
  2. 幂等检查: 以 jobId 为粒度做去重;重复任务单可直接返回上次结果(success/failed
  3. 下载资源: 逐条下载 resources[] 文件,支持断点续传
  4. 校验哈希: 下载完成后验证 SHA256 哈希值
  5. 解压资源: 检查 compression 字段,若为 gzip 则进行 gzip 解压,若为 none 则跳过解压
  6. 执行打印:
    • resources[].fileType=prn:按 resources[].prnProtocol 指定协议解析并打印(当前仅支持 esc
    • resources[].fileType=image:走 AI 图片打印逻辑
    • 开始打印时发送 status=printing(建议)
  7. 完成回执: 每个任务单打印完成后发送对应 jobIdstatus=successstatus=failed

主题: 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位毫秒时间戳)
}
字段类型必填说明
msgIdstring消息唯一ID,32字符
deviceUpgradeIdstring设备升级任务唯一标识,用于幂等去重
firmwareTypestring固件类型:cloud(云端固件)、printer(打印机固件)、bluetooth(蓝牙固件)
firmwareVersionstring固件版本号
urlstring固件下载URL
hashstringSHA256哈希值,格式:sha256:十六进制字符串
sizeint文件大小(字节)
compressionstring压缩方式:none(不压缩)、gzip(gzip压缩)。设备下载后需根据此字段决定是否解压
dateTimeint64服务器时间(13位毫秒时间戳)
  1. 接收任务: 收到消息后立即发送 status=confirm 回执
  2. 下载固件:
    • 支持断点续传
    • 定期发送 status=downloading 进度(可选)
  3. 校验哈希: 下载完成后验证 SHA256 哈希值,失败则立即报错
  4. 解压固件: 检查 compression 字段,若为 gzip 则进行 gzip 解压,若为 none 则跳过解压
  5. 执行升级:
    • 发送 status=upgrading 状态
    • 应用新固件
  6. 重启设备: 升级完成后重启
  7. 上报结果:
    • 重启后发送 status=success 回执
    • 上报新的固件版本(通过设备状态消息)

主题: devices/{tenantCode}/{userName}/{sn}/down/control
QoS: 2(可协商降级到 QoS 1)
用途: 平台向设备下发控制指令,用于远程控制设备行为

{
"msgId": "h6i7j890k1l2m3n4o5p6q789r0s1t2u3",
"controlId": "a351eff1b614d0c1f64227d0c4b28c99", // 控制指令唯一ID
"command": "reboot", // 控制指令类型
"params": {}, // 可选:指令参数 预留字段
"dateTime": 1724846400000 // 服务器时间(13位毫秒时间戳)
}
指令 (command)说明参数 (params)预期行为
shutdown关机设备执行安全关机,保存状态后关闭电源
reboot重启设备执行安全重启,保存状态后重启系统
beep发声/蜂鸣发出蜂鸣声
reset_wifi重置WiFi清除WiFi配置,恢复到待配网状态
reset_bluetooth重置蓝牙清除蓝牙配对记录,恢复到待配对状态
factory_reset恢复出厂设置清除所有配置,恢复出厂状态。keep_network为true时保留网络配置
clear_cache清理缓存清理临时文件和打印缓存
set_params设置设备参数-设置设备运行参数;设备收到后更新本地配置并回执

说明:测试页打印不再通过控制指令下发。平台如需打印测试页,应由云端自行拼接测试页内容并按普通打印任务流程下发。

字段类型必填说明
msgIdstring消息唯一ID
controlIdstring控制指令唯一标识,用于幂等去重
commandstring控制指令类型,见上表
paramsobject指令参数,不同指令参数不同
dateTimeint64服务器时间(13位毫秒时间戳)
  1. 接收指令: 收到消息后立即发送 status=confirm 回执
  2. 幂等检查: 根据 controlId 判断是否为重复指令
  3. 参数验证: 检查 command 是否支持,params 是否合法
  4. 完成回执:
    • 成功:发送 status=success
    • 失败:发送 status=failed,携带错误信息
  5. 重启类操作: 重启后上报设备状态

示例 : 重启设备

{
"msgId": "a1b2c3d4e5f6789012345678901234ab",
"controlId": "a351eff1b614d0c1f64227d0c4b28c99",
"command": "reboot",
"dateTime": 1724846400000
}

设备应针对不同错误场景返回相应错误码:

错误场景errCodemsg 示例
不支持的指令[5001]“不支持的控制指令: xxx”
参数错误[5002]“参数错误: duration必须为正整数”
设备忙碌[6012]“设备正在打印,无法执行控制操作”
执行失败[5003]“WiFi重置失败: 网络模块错误”
  1. 危险操作确认: factory_reset 等危险操作建议设备端二次确认(如通过指示灯闪烁或按键确认)
  2. 幂等性: 基于 controlId 实现幂等,避免重复执行

环境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 指定)

设备仅允许访问自己的主题,禁止跨设备访问。

操作允许的主题模式
发布(PUBLISH)devices/{tenantCode}/{userName}/{自己的sn}/up/*
订阅(SUBSCRIBE)devices/{tenantCode}/{userName}/{自己的sn}/down/*

违规示例:


信息类型存储要求说明
SN(序列号)明文存储设备唯一标识,无需加密
Secret(密钥)加密存储使用设备硬件密钥加密,禁止明文存储
JWT Token内存存储不持久化,重启后重新获取
CA 证书明文存储公开信息,可明文存储

虽然 TLS 已提供传输层加密,但关键业务消息建议额外签名:


错误原因解决方案
Connection refused网络不可达检查网络连接,使用指数退避重试
Authentication failed令牌无效或过期重新调用 Bootstrap API 获取新令牌
Certificate verify failedTLS 证书验证失败检查 CA 证书是否正确
Keep alive timeout网络不稳定降低 keepalive 间隔

A: 设备应该实现以下时间同步机制:

  1. NTP 同步: 定期与 NTP 服务器同步时间
  2. Bootstrap 校准: 使用 Bootstrap API 返回的 serverTime 校准本地时间
  3. 误差检测: 如果时间误差超过 5 分钟,拒绝签名验证并提示用户

Q2: 如何处理网络波动导致的消息丢失?

Section titled “Q2: 如何处理网络波动导致的消息丢失?”

A: 采用以下策略:

  1. 使用 QoS 1 或 QoS 2: 保证消息至少送达一次
  2. 消息缓存: 离线时缓存消息,连接恢复后重发
  3. 幂等设计: 基于 jobIdmsgId 实现幂等去重
  4. 超时重试: 设置合理的超时时间和重试机制

Q3: 打印任务太大,如何优化下载速度?

Section titled “Q3: 打印任务太大,如何优化下载速度?”

A: 建议采用以下优化措施:

  1. 并发下载: 同时下载多个 resources 资源(限制并发数为 3-5)
  2. 断点续传: 使用 HTTP Range 请求支持断点续传
  3. 预加载: 打印前几个资源时,提前拉取后续资源
  4. 压缩传输: 资源文件支持 gzip 压缩,设备根据 resources[].compression 字段判断是否需要解压。当 compressiongzip 时,下载完成并校验哈希后需进行 gzip 解压

A: 设备应该实现以下机制:

  1. 双分区设计: 保留旧固件分区,升级失败时自动切换
  2. 升级标记: 记录升级状态,重启后检查是否成功
  3. 回滚逻辑: 升级失败自动回滚到旧版本
  4. 上报失败: 通过 up/upgrade/ack 上报失败原因

Q5: 如何判断是否需要主动拉取任务?

Section titled “Q5: 如何判断是否需要主动拉取任务?”

可以采用以下策略:

  1. 拉取打印资源: 设备上电、MQTT连接成功、上报状态后,通过 Pull 主题发起 type=print请求
  2. 持续拉取更多任务单: 在本地队列不足时,通过 Pull 主题继续发起 type=print 请求,在设备确认打印任务的时候,云端也会继续下推新的任务,设备根据本地队列上报队列状态,云端根据队列结果下发和缓存任务。当本地打印到最后一个打印任务的时候,需要主动pull打印任务,防止云端缓存没下发情况
  3. 文生图资源请求: 当设备需要 AI 文生图时,发送 type=text_to_image,并在 params 中携带 width/height/prompt,可选 bizIdfileTypeimage/prn)和 prnProtocol(当前仅 esc
  4. 文本生成标签请求: 当设备需要 AI 文本生成标签时,发送 type=text_to_labelparams 需携带 prompt,可选 timezone/language/width/height/bizId/fileType/prnProtocol;未携带 timezone/language/width/height 时云端读取设备扩展配置。标签匹配和生成在云端完成。云端通过普通打印主题下发,fileType=prn 时返回 prnProtocol
  5. 获取功能列表(按需): 仅特定机型在需要动态同步可用功能时,发送 type=feature_listparams 通常为空对象即可
  6. 获取设备设置参数(按需): 当设备需要同步云端设备设置参数时,发送 type=device_params;云端返回设备扩展参数中的 language/timezone/width/height,以及可选热词ID hotwordId。该步骤不是 ASR 连接前置条件
  7. 主动检查固件更新: 当设备在开机后以及其他需要检查固件更新时,发送 type=firmware并在 params 中携带硬件参数与当前固件版本信息;若云端无可用更新,将返回 type=firmwareerrCode=[] 的 Pull Ack(不兼容 firmware_upgrade/upgrade
  8. 设备端错误判断: 设备在发送 Pull 请求前应自行判断本地是否存在阻塞性错误(如缺纸、卡纸),存在阻塞性错误时不应发送 Pull

重要: 云端在收到 Pull 请求时不再判断设备错误状态,设备端需自行负责错误状态的判断。


A: 设备侧必须具备 SN 和 Secret(用于 Bootstrap 签名与 MQTT 连接认证),通常来源如下:

  1. 设备注册: 平台侧为设备创建设备记录,生成 SN 与 Secret
  2. 生产烧录: 在生产环节将 SN 与 Secret 烧录到设备(Secret 必须加密存储)
  3. App 侧绑定(不同型号流程不同):
  • WiFi 版本:App 通过连接设备本体蓝牙,与设备握手后可获取 SN/设备秘钥等信息,再完成配网与绑定
  • 4G 版本:App 通过扫描/输入 SN 发起验证码请求;设备在线时打印验证码,App 输入/识别验证码后完成绑定(App 不直接持有 Secret)

注意:以上为“设备入网/绑定”的业务流程说明;协议层仍以设备本地持有 SN/Secret 为前提完成引导与认证。


A: 建议使用以下工具和方法:

  1. MQTT 客户端工具:

  2. 抓包分析:

  3. 日志调试:

    • 启用 MQTT 库的详细日志
    • 记录连接参数、认证信息(脱敏)
  4. 测试环境:

    • 先在测试环境验证(使用 1883 明文端口)
    • 确认无误后切换到生产环境(8883 TLS 端口)

平台采用分离式消息架构,通过 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 指定

版本日期变更说明
v1.02026-04-29定义基础通信协议

文档维护: 爱印科技-应用技术部-方江琛
最后更新: 2026-06-03