设备通讯协议(v1.0-ws)
This content is not available in your language yet.
文档版本: v1.0-ws
最后更新: 2026-06-24
适用对象: 设备固件开发者、第三方硬件集成商
协议更新日志
Section titled “协议更新日志”| 日期 | 更新内容 |
|---|---|
| 2026-06-24 | 1. 【下发-新增】文件打印 params.resources[] 新增 sourceType 字段,用于标识任务来源:print、text_to_image、text_to_label,取值与 Pull 请求 params.type 保持一致 → 打印任务下发 |
| 2026-06-11 | 1. 【状态-补充】设备状态上报补充 Wi-Fi RSSI 与 4G LTE RSRP 的 dBm 口径、RSRP 索引换算和 4 格信号转换公式 → 设备状态上报 2. 【控制-新增】设备控制指令新增 report_state,平台可要求设备立即通过 /up/state 上报一次设备状态 → 设备控制指令 |
| 2026-06-05 | 1. 【协议-新增】发布单 WebSocket 通道设备协议,设备通过 protocolVersion=1.0-ws 接入,状态、Pull、打印、语音生成、固件升级、控制与心跳均复用同一 WebSocket 连接 → 协议范围2. 【固件-补充】固件升级下发说明补齐 compression 最新处理要求,明确设备按实际下发的 url/hash/size/compression 处理文件 → 固件升级任务下发 |
1. 协议范围
Section titled “1. 协议范围”本文档定义设备通过单个 WebSocket 长连接接入云打印平台时使用的消息格式、连接流程、任务处理时序和回执规则。
设备接入后,以下业务均通过同一个设备 WebSocket 通道传输:
| 业务 | 上行消息 | 下行消息 | 关联章节 |
|---|---|---|---|
| 心跳保活 | /up/heartbeat | /down/heartbeat | 心跳协议 |
| 状态上报 | /up/state | - | 设备状态上报 |
| 任务拉取 | /up/pull | /down/pull/ack、/down/print、/down/upgrade | 任务拉取请求 |
| 打印任务 | /up/print/ack | /down/print | 打印任务下发 |
| 语音生成 | /up/voice_generate + Binary | /down/print、/down/voice_text | 语音生成任务 |
| 固件升级 | /up/upgrade/ack | /down/upgrade | 固件升级任务下发 |
| 设备控制 | /up/control/ack | /down/control | 设备控制指令 |
| 设备事件 | /up/event | - | 设备事件上报 |
ASR 不需要设备单独连接 ASR 网关。设备在本协议的 WebSocket 通道内发送 /up/voice_generate 文本帧和音频 Binary 帧,云端完成识别后按 generateType 返回文本或打印任务。
2. 接入链路
Section titled “2. 接入链路”| 链路 | 协议 | 帧类型 | 使用时机 |
|---|---|---|---|
| 设备 -> Bootstrap API | HTTPS / HTTP/1.1 | JSON | 设备开机后、Token 过期前重新获取接入参数 |
| 设备 <-> 云端设备网关 | WebSocket (ws/wss) | Text JSON | 发送通用信封消息,例如心跳、状态、任务、回执 |
| 设备 -> 云端设备网关 | WebSocket | Binary | /up/voice_generate 会话开始后发送音频字节 |
| 云端设备网关 -> 设备 | WebSocket | Binary | /down/print 且 deliverType=stream 时下发打印数据 |
设备侧实现至少需要保存以下 Bootstrap 返回值:
| 参数 | 来源字段 | 使用位置 |
|---|---|---|
| WebSocket 地址 | data.websocket.url | 建立设备 WebSocket 连接 |
| 连接鉴权 | data.websocket.authorization | WebSocket 握手请求头 Authorization |
| Token 有效期 | data.websocket.tokenTtlSec | 到期前重新 Bootstrap 并重连 |
| 心跳周期 | data.websocket.keepalive | /up/heartbeat 发送周期 |
| 消息类型映射 | data.messageTypes.* | 组装 messageType |
| ASR 首帧参数 | data.asr | /up/voice_generate 的 funasrStart 默认值 |
| 状态上报周期 | data.stateReportInterval | 定时发送 /up/state |
| 服务端时间 | data.serverTime | 校准设备时间或计算时间偏移 |
3. 设备开机上线时序
Section titled “3. 设备开机上线时序”设备每次开机、网络恢复或 Token 失效后,按以下顺序接入:
- 初始化网络、读取设备 SN、固件版本、硬件型号、耗材和错误状态。
- 调用 Bootstrap,提交
sn、protocolVersion、ts、sign。 - 使用 Bootstrap 返回的
data.websocket.url建立 WebSocket 连接。 - WebSocket 握手时在请求头加入
Authorization: {data.websocket.authorization}。 - 连接成功后立即发送
/up/state,上报当前errCode、warnCode、firmware。 - 发送
/up/pull,params.type=firmware,检查固件升级任务。 - 发送
/up/pull,params.type=print,拉取待打印任务。 - 按
data.websocket.keepalive周期发送/up/heartbeat。 - 按
data.stateReportInterval周期发送/up/state;状态变化时立即补发/up/state。 - 持续监听
/down/print、/down/upgrade、/down/control、/down/heartbeat和/down/voice_text。
sequenceDiagram
autonumber
participant Dev as 设备
participant API as Bootstrap API
participant Srv as 云端设备网关
Dev->>Dev: 初始化网络、读取 SN、固件和设备状态
Dev->>API: POST /api/v1/bootstrap
API-->>Dev: WebSocket 地址、Authorization、消息类型、心跳、ASR 参数
Dev->>Srv: WebSocket Connect + Authorization
Srv-->>Dev: 连接建立
Dev->>Srv: /up/state
Dev->>Srv: /up/pull type=firmware
Srv-->>Dev: /down/upgrade 或 /down/pull/ack
Dev->>Srv: /up/pull type=print
Srv-->>Dev: /down/print 或 /down/pull/ack
loop keepalive 周期
Dev->>Srv: /up/heartbeat
Srv-->>Dev: /down/heartbeat
end
连接断开后,设备按以下顺序恢复:
- 关闭本地旧 WebSocket 连接和未完成的 Binary 发送状态。
- 判断
authorization是否仍在有效期内。 - 未过期时,使用原 WebSocket 参数重连。
- 已过期或连续重连失败时,重新调用 Bootstrap。
- 重连成功后发送
/up/state。 - 如断开前存在未完成任务,根据任务类型发送最终回执或重新拉取任务。
4. HTTP Bootstrap
Section titled “4. HTTP Bootstrap”4.1 请求
Section titled “4.1 请求”POST https://cprint-api-stg.iprtapp.com/api/v1/bootstrap{ "sn": "SN-XYZ-001", "protocolVersion": "1.0-ws", "ts": 1724040000000, "sign": "abc123def456..."}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
sn | string | 是 | 设备序列号 |
protocolVersion | string | 是 | WebSocket 协议版本,固定使用 1.0-ws |
ts | int64 | 是 | 13 位毫秒时间戳 |
sign | string | 是 | HMAC-SHA256 签名,明文为 sn + ts |
4.2 响应
Section titled “4.2 响应”{ "code": 0, "message": "OK", "data": { "device": { "sn": "SN-TEST-001", "model": "A40w-4G" }, "websocket": { "url": "wss://iot.byteone.com/ws/device", "authorization": "Bearer eyJhbGciOiJIUzI1NiIs...", "tokenTtlSec": 3600, "keepalive": 60 }, "messageTypes": { "upPull": "/up/pull", "upVoiceGenerate": "/up/voice_generate", "upPrintAck": "/up/print/ack", "upUpgradeAck": "/up/upgrade/ack", "upControlAck": "/up/control/ack", "upState": "/up/state", "upEvent": "/up/event", "upHeartbeat": "/up/heartbeat", "downPullAck": "/down/pull/ack", "downPrint": "/down/print", "downUpgrade": "/down/upgrade", "downControl": "/down/control", "downHeartbeat": "/down/heartbeat", "downVoiceText": "/down/voice_text" }, "asr": { "model": "SenseVoiceSmall", "language": "zh-CN", "hotwordCacheId": "hotword_label_daily_v1", "mode": "2pass", "wav_format": "pcm", "audio_fs": 16000, "chunk_size": [5, 10, 5], "chunk_interval": 10, "itn": true }, "stateReportInterval": 1800, "serverTime": 1759991021000 }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
code | int | 是 | 0 表示获取成功 |
message | string | 是 | 接口返回描述 |
data.device.sn | string | 是 | 设备本次接入的 SN |
data.device.model | string | 否 | 固件升级拉取和状态上报中的设备型号 |
data.websocket.url | string | 是 | WebSocket 连接地址 |
data.websocket.authorization | string | 是 | WebSocket 握手请求头 Authorization |
data.websocket.tokenTtlSec | int | 是 | Token 有效期,单位秒 |
data.websocket.keepalive | int | 是 | /up/heartbeat 发送周期,单位秒 |
data.messageTypes.* | string | 是 | 设备组装 messageType 时使用 |
data.asr | object | 否 | /up/voice_generate 开始帧默认参数 |
data.stateReportInterval | int | 否 | /up/state 定时上报周期,单位秒 |
data.serverTime | int64 | 否 | 服务端 13 位毫秒时间 |
5. WebSocket 消息格式
Section titled “5. WebSocket 消息格式”5.1 通用信封
Section titled “5.1 通用信封”除 Binary 帧外,所有 WebSocket Text 消息均使用以下 JSON 信封:
{ "msgId": "32字符唯一ID", "messageType": "/up/pull", "ts": 1724044088000, "params": {}}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgId | string | 是 | 消息唯一标识,使用 UUID v4 去连字符或等价唯一 ID;回执通过 ackOriginalMsgId 关联 |
messageType | string | 是 | 消息类型路径,优先使用 Bootstrap 返回的 data.messageTypes |
ts | int64 | 是 | 13 位毫秒时间戳 |
params | object | 否 | 业务参数对象 |
5.2 Binary 帧使用范围
Section titled “5.2 Binary 帧使用范围”| 方向 | 前置消息 | Binary 内容 | 结束消息 |
|---|---|---|---|
| 设备 -> 云端 | /up/voice_generate,streamStage=start | 音频字节 | /up/voice_generate,streamStage=end |
| 云端 -> 设备 | /down/print,deliverType=stream,streamStage=start | 打印数据字节 | /down/print,streamStage=end |
设备收到或发送 Binary 帧时,需要根据当前会话状态区分音频数据和打印数据。不存在已开始的语音或流式打印会话时,忽略该 Binary 帧并上报设备事件或错误状态。
5.3 MQTT 字段对应关系
Section titled “5.3 MQTT 字段对应关系”WebSocket 协议复用 MQTT 协议的业务字段名,业务载荷统一放入 WebSocket params 内:
| MQTT 字段/语义 | WebSocket 字段路径 | 说明 |
|---|---|---|
msgId | msgId | 字段名一致 |
ts | ts | 字段名一致 |
| MQTT 主题路径 | messageType | 例如 MQTT up/pull 对应 WebSocket /up/pull |
| MQTT 业务顶层字段 | params.* | 例如 MQTT resources 对应 WebSocket params.resources |
Pull type | params.type | 例如 print、text_to_label、firmware |
Pull params | params.params | Pull 的业务参数对象保留 params 字段名 |
Control params | params.params | 控制指令参数对象保留 params 字段名 |
Event eventType/eventParams | params.eventType / params.eventParams | 事件字段名保持一致 |
6. 上行消息
Section titled “6. 上行消息”6.1 任务拉取请求
Section titled “6.1 任务拉取请求”messageType: /up/pull
设备在以下时机发送 Pull:
| 时机 | params.type | params.params |
|---|---|---|
| 开机上线后检查固件 | firmware | 当前硬件型号和固件版本 |
| 开机上线后拉取打印任务 | print | {} |
| 设备空闲时主动取任务 | print | {} |
| 文本生成图片 | text_to_image | width、height、prompt 等生成参数 |
| 文本生成标签 | text_to_label | prompt、标签尺寸、语言、时区等生成参数 |
| 获取能力列表 | feature_list | {} 或 null |
| 获取设备参数 | device_params | {} 或 null |
普通打印任务拉取:
{ "msgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6", "messageType": "/up/pull", "ts": 1724044088000, "params": { "type": "print", "params": {} }}固件更新拉取:
{ "msgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z7", "messageType": "/up/pull", "ts": 1724044088000, "params": { "type": "firmware", "params": { "hardware": { "deviceModel": "P5802" }, "firmware": [ { "firmwareType": "cloud", "firmwareVersion": "1.2.3", "nn": "NN-001" }, { "firmwareType": "printer", "firmwareVersion": "3.4.5" } ] } }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.type | string | 否 | 任务类型;为空时按 print 处理 |
params.params | object | 否 | 当前任务类型的业务参数 |
params.params.hardware | object | 否 | type=firmware 时上报硬件信息 |
params.params.hardware.deviceModel | string | 否 | type=firmware 时填写设备型号 |
params.params.firmware | object[] | 否 | type=firmware 时填写当前固件列表 |
params.params.firmware[].firmwareType | string | 否 | cloud/printer/bluetooth |
params.params.firmware[].firmwareVersion | string | 否 | 当前固件版本 |
params.params.firmware[].nn | string | 否 | 对应固件类型的 NN 号 |
params.params.bizId | string | 否 | type=text_to_image 或 text_to_label 时填写业务 ID |
params.params.width | int | 条件必填 | type=text_to_image 时为图片宽度(像素);type=text_to_label 时为标签宽度(mm) |
params.params.height | int | 条件必填 | type=text_to_image 时为图片高度(像素);type=text_to_label 时为标签高度(mm) |
params.params.prompt | string | 条件必填 | type=text_to_image 或 text_to_label 时填写用户输入文本 |
params.params.timezone | string | 否 | type=text_to_label 时填写设备时区 |
params.params.language | string | 否 | type=text_to_label 时填写设备语言 |
params.params.fileType | string | 否 | image 或 prn |
params.params.prnProtocol | string | 条件必填 | fileType=prn 时填写,当前支持 esc |
云端响应:
- 有普通打印任务时,下发
/down/print。 - 有固件升级任务时,下发
/down/upgrade。 - 无可用任务或返回功能/参数结果时,下发
/down/pull/ack。
6.2 语音生成任务
Section titled “6.2 语音生成任务”messageType: /up/voice_generate
设备通过 /up/voice_generate 发起语音生成会话。会话由一个开始帧、若干 Binary 音频帧和一个停止帧组成。
sequenceDiagram
autonumber
participant Dev as 设备
participant Srv as 云端设备网关
Dev->>Srv: /up/voice_generate streamStage=start
loop 录音过程中
Dev->>Srv: Binary 音频 chunk
end
Dev->>Srv: /up/voice_generate streamStage=end
alt generateType=text
Srv-->>Dev: /down/voice_text
else generateType=label 或 image
Srv-->>Dev: /down/print
Dev->>Srv: /up/print/ack status=confirm
Dev->>Srv: /up/print/ack status=printing
Dev->>Srv: /up/print/ack status=success 或 failed
end
语音会话处理步骤:
- 从 Bootstrap
data.asr读取 ASR 默认参数。 - 用户触发录音后发送开始帧,
params.streamStage=start。 - 将录音数据按 Binary frame 发送到同一个 WebSocket 通道。
- 录音结束后发送停止帧,
params.streamStage=end,params.is_speaking=false。 - 停止帧中携带本次音频的
crc32和audioBytes。 generateType=text时,等待/down/voice_text。generateType=label或image时,等待/down/print并按打印任务流程回执。
开始帧:
{ "msgId": "v-start-0001", "messageType": "/up/voice_generate", "ts": 1724045000000, "params": { "streamStage": "start", "generateType": "label", "bizId": "voice_print_label", "deliverType": "file", "fileType": "image", "model": "SenseVoiceSmall", "language": "zh-CN", "hotwordCacheId": "hotword_label_daily_v1", "funasrStart": { "mode": "2pass", "wav_name": "SN-TEST-001-1724045000000", "wav_format": "pcm", "audio_fs": 16000, "chunk_size": [5, 10, 5], "chunk_interval": 10, "is_speaking": true, "itn": true, "hotwords": "", "language": "zh-CN", "retain_asr_record": false } }}生成 PRN 文件时,开始帧使用:
{ "params": { "streamStage": "start", "generateType": "label", "deliverType": "file", "fileType": "prn", "prnProtocol": "esc" }}Binary 音频帧:
funasrStart.wav_format | Binary 内容 |
|---|---|
pcm | 裸 PCM 字节,不带文件头 |
wav | WAV 文件字节 |
mp3 | MP3 文件字节 |
mp4 | MP4 文件字节 |
flac | FLAC 文件字节 |
停止帧:
{ "msgId": "v-end-0001", "messageType": "/up/voice_generate", "ts": 1724045003000, "params": { "streamStage": "end", "is_speaking": false, "crc32": "1a2b3c4d", "audioBytes": 128000, "errCode": [], "msg": "" }}设备本地录音异常时,在停止帧携带 errCode 和 msg:
{ "msgId": "v-end-0002", "messageType": "/up/voice_generate", "ts": 1724045003000, "params": { "streamStage": "end", "is_speaking": false, "crc32": "1a2b3c4d", "audioBytes": 124000, "errCode": [2012], "msg": "device memory pressure, dropped 4000 bytes before upload" }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.streamStage | string | 是 | start 或 end |
params.generateType | string | start 时必填 | label 生成标签并下发打印任务;image 生成图片并下发打印任务;text 返回识别文本 |
params.bizId | string | start 时可选 | 语音生成业务 ID |
params.deliverType | string | start 时可选 | file 或 stream,默认 file |
params.fileType | string | start 时可选 | image 或 prn;generateType=label/image 时生效 |
params.prnProtocol | string | 条件必填 | fileType=prn 时填写,当前支持 esc |
params.model | string | 是 | ASR 模型,当前内置 CPU 部署支持 Fun-ASR-MLT-Nano-GGUF 与 SenseVoiceSmall;配置 Azure 上游后也可使用 MicrosoftAzureSpeech |
params.language | string | 否 | 语言偏好,例如 zh-CN;支持语言见 ASR 服务 API 文档 |
params.hotwordCacheId | string | 否 | 热词缓存 ID |
params.funasrStart.mode | string | start 时填写 | 必须匹配所选 ASR 模型支持的模式;Fun-ASR-MLT-Nano-GGUF 仅支持 offline,SenseVoiceSmall 与 MicrosoftAzureSpeech 支持 offline、online、2pass |
params.funasrStart.wav_name | string | start 时填写 | 音频会话名 |
params.funasrStart.wav_format | string | start 时填写 | pcm、wav、mp3、mp4、flac |
params.funasrStart.audio_fs | int | start 时填写 | 采样率,常用 16000 |
params.funasrStart.chunk_size | int[] | start 时填写 | 分块参数,默认 [5,10,5] |
params.funasrStart.chunk_interval | int | start 时填写 | 分块间隔,默认 10 |
params.funasrStart.is_speaking | bool | start 时填写 | 开始帧填写 true |
params.funasrStart.itn | bool | 否 | 文本归一化,默认 true |
params.funasrStart.hotwords | string | 否 | 热词 JSON 字符串;未传时可使用 hotwordCacheId |
params.funasrStart.language | string | 否 | 标准语言码;未传时使用 params.language |
params.funasrStart.retain_asr_record | bool | 否 | 是否保留本次识别记录 |
params.is_speaking | bool | end 时必填 | 停止帧填写 false |
params.crc32 | string | 否 | 本次会话全部原始音频字节 CRC32 十六进制字符串;兼容 crc、crcCheckCode、audioCrc32、crs |
params.audioBytes | int | 否 | 本次会话全部原始音频字节长度;兼容 audioLength、rawAudioLength、rawAudioBytes |
params.errCode | int/int[] | 否 | 设备上报的 ASR 错误码 |
params.msg | string | 否 | 设备上报的 ASR 错误描述 |
ASR 校验规则:
- 停止帧存在
crc32时,云端用已收到的音频字节计算 CRC32;不一致时记录错误码2010。 - 停止帧存在
audioBytes时,云端用已收到的音频字节长度比对;不一致时记录错误码2011。 - 设备出现本地内存不足并丢弃录音字节时,停止帧上报
errCode:[2012],后续/up/state上报warnCode:[2012]。 - 语音会话未发送停止帧即异常结束时,后续
/up/state上报warnCode:[2013]。
6.3 打印结果回执
Section titled “6.3 打印结果回执”messageType: /up/print/ack
收到 /down/print 后,设备按任务阶段发送回执:
| 阶段 | params.status | 发送时机 |
|---|---|---|
| 接收确认 | confirm | 收到 /down/print 并完成任务幂等检查后 |
| 打印开始 | printing | 文件下载、校验、解压完成并开始打印时 |
| 打印成功 | success | 设备完成打印并确认出纸状态后 |
| 打印失败 | failed | 下载、校验、解压、打印或设备状态不满足时 |
{ "msgId": "b2c3d4e5f67890a1b2c3d4e5f67890a1", "messageType": "/up/print/ack", "ts": 1724040088000, "params": { "jobIds": ["92ef08872ff906876071478274eec57b"], "ackOriginalMsgId": "e5f6789012a3b4c5d6e7f89012a3b4c5", "status": "confirm", "queueStatus": "good", "errCode": [], "msg": "ok" }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.jobIds | string[] | 是 | 打印任务单 ID 数组;文件打印取 resources[].jobId,流式打印取 jobId |
params.ackOriginalMsgId | string | 是 | 对应 /down/print 的 msgId |
params.status | string | 是 | confirm、printing、success、failed |
params.queueStatus | string | 否 | confirm 时填写队列状态:good、congested、full |
params.errCode | int[] | 是 | 错误码数组,[] 表示成功 |
params.msg | string | 是 | 结果描述 |
6.4 固件升级回执
Section titled “6.4 固件升级回执”messageType: /up/upgrade/ack
收到 /down/upgrade 后,设备按升级阶段发送回执:
| 阶段 | params.status | 发送时机 |
|---|---|---|
| 接收确认 | confirm | 收到升级任务并完成 deviceUpgradeId 幂等检查后 |
| 下载中 | downloading | 开始下载固件文件后,可按进度间隔上报 |
| 升级中 | upgrading | 固件文件校验完成并进入升级流程前 |
| 升级成功 | success | 升级完成并重启上线后 |
| 升级失败 | failed | 下载、校验、解压、写入或重启校验失败时 |
{ "msgId": "d4e5f6789012a3b4c5d6e7f89012a3b4", "messageType": "/up/upgrade/ack", "ts": 1724041088000, "params": { "deviceUpgradeId": "92ef08872ff906876071478274eec57b", "ackOriginalMsgId": "f6789012a3b4c5d6e7f89012a3b4c5d6", "status": "upgrading", "errCode": [], "msg": "ok" }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.deviceUpgradeId | string | 是 | 对应 /down/upgrade 的 deviceUpgradeId |
params.ackOriginalMsgId | string | 是 | 对应 /down/upgrade 的 msgId |
params.status | string | 是 | confirm、downloading、upgrading、success、failed |
params.errCode | int[] | 是 | 错误码数组,[] 表示成功 |
params.msg | string | 是 | 结果描述 |
6.5 设备控制指令回执
Section titled “6.5 设备控制指令回执”messageType: /up/control/ack
收到 /down/control 后,设备按以下顺序处理:
- 使用
controlId做幂等检查。 - 发送
status=confirm回执。 - 执行
command。 - 执行成功后发送
status=success。 - 执行失败或参数不支持时发送
status=failed,并携带errCode与msg。
{ "msgId": "g5h6i7j890k1l2m3n4o5p6q789r0s1t2", "messageType": "/up/control/ack", "ts": 1724042088000, "params": { "controlId": "a351eff1b614d0c1f64227d0c4b28c99", "ackOriginalMsgId": "h6i7j890k1l2m3n4o5p6q789r0s1t2u3", "status": "confirm", "errCode": [], "msg": "ok" }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.controlId | string | 是 | 对应 /down/control 的 controlId |
params.ackOriginalMsgId | string | 是 | 对应 /down/control 的 msgId |
params.status | string | 是 | confirm、success、failed |
params.errCode | int[] | 是 | 错误码数组,[] 表示成功 |
params.msg | string | 是 | 结果描述 |
6.6 设备状态上报
Section titled “6.6 设备状态上报”messageType: /up/state
设备在以下时机发送状态:
| 时机 | 上报内容 |
|---|---|
| WebSocket 连接成功后 | 当前设备状态、固件版本、错误码、警告码 |
stateReportInterval 周期到达 | 当前设备状态 |
| 设备错误或警告变化 | 最新 errCode、warnCode |
| 打印任务完成后 | 耗材、错误码、计数等变化字段 |
| 固件升级重启上线后 | 新固件版本 |
| ASR 异常后 | warnCode:[2012] 或 warnCode:[2013] |
{ "msgId": "a1b2c3d4e5f6789012345678901234ab", "messageType": "/up/state", "ts": 1724040060000, "params": { "rssi": -58, "battery": 90, "paper": 1, "paperType": "roll", "errCode": [], "warnCode": [2013], "temperature": 35.2, "humidity": 45, "ipAddress": "192.168.1.25", "bluetoothMac": "00:1A:7D:DA:71:13", "imei": "865123456789012", "iccid": "89860123456789012345", "signalStrength": -75, "networkType": "4G", "printCount": 12345, "avgLatency": 150, "packetLossRate": 2, "charging": false, "sleepTime": 10, "firmware": [ { "firmwareType": "cloud", "firmwareVersion": "1.2.3", "nn": "NN-001" }, { "firmwareType": "printer", "firmwareVersion": "3.4.5", "nn": "NN-002" } ] }}| 字段路径 | 类型 | 必填 | 说明 |
|---|---|---|---|
params.rssi | int | 否 | Wi-Fi RSSI,单位 dBm,通常为负数,数值越接近 0 信号越强 |
params.signalStrength | int | 否 | 4G LTE RSRP,单位 dBm,通常为负数;不要上报 RSRP 原始索引值 |
params.networkType | string | 否 | 网络类型:WiFi、4G、5G 等 |
params.errCode | int[] | 是 | 阻塞性错误码,[] 表示无错误 |
params.warnCode | int[] | 否 | 非阻塞警告码,[] 表示无警告 |
params.firmware | object[] | 是 | 当前固件列表 |
params.firmware[].firmwareType | string | 是 | cloud、printer、bluetooth |
params.firmware[].firmwareVersion | string | 是 | 当前固件版本 |
params.firmware[].nn | string | 否 | 对应固件类型的 NN 号 |
信号强度说明
Section titled “信号强度说明”params.rssi 与 params.signalStrength 都使用 dBm。Wi-Fi 信号上报 ESP32/ESP-IDF 的 RSSI dBm 值,参考 Espressif ESP-IDF Wi-Fi API 中 RSSI threshold 的 rssi 参数说明:阈值单位为 dBm,常见范围约为 -100 到 10,极强信号可能出现轻微正值。
params.signalStrength 上报 4G LTE RSRP dBm 值。若模组只提供 LTE RSRP 报告值,应先按 3GPP TS 36.133 v14.5.0 Table 9.1.4-1 的 RSRP measurement report mapping 转成 dBm 后再上报:
| RSRP 报告值 | RSRP dBm 区间 |
|---|---|
value <= -17 | rsrp < -156 dBm |
-16 <= value <= -1 | (value - 140) dBm <= rsrp < (value - 139) dBm |
value = 0 | rsrp < -140 dBm |
1 <= value <= 96 | (value - 141) dBm <= rsrp < (value - 140) dBm |
97 <= value <= 126 | -44 dBm <= rsrp |
value = 127 | 无效值,不上报 params.signalStrength 或按未知处理 |
4 格信号展示可按以下公式从 dBm 转换。缺失或无效值应显示为未知,不参与公式计算。
wifiBars = min(4, max(0, floor((rssiDbm + 95) / 10)))lteBars = min(4, max(0, floor((rsrpDbm + 125) / 10)))对应阈值为:Wi-Fi < -85 为 0 格,[-85,-76] 为 1 格,[-75,-66] 为 2 格,[-65,-56] 为 3 格,>= -55 为 4 格;4G RSRP < -115 为 0 格,[-115,-106] 为 1 格,[-105,-96] 为 2 格,[-95,-86] 为 3 格,>= -85 为 4 格。
6.7 设备事件上报
Section titled “6.7 设备事件上报”messageType: /up/event
设备在发生用户操作、任务中断、设备本地事件时发送事件。
{ "msgId": "h7i8j9k012l3m4n5o6p7q8r901s2t3u4", "messageType": "/up/event", "ts": 1724043088000, "params": { "eventType": "stop_print", "eventParams": { "reason": "user_button" } }}| 字段路径 | 类型 | 必填 | 说明 |
|---|---|---|---|
params.eventType | string | 是 | 事件类型,例如 stop_print |
params.eventParams | object | 否 | 事件参数 |
7. 下行消息
Section titled “7. 下行消息”7.1 Pull 响应
Section titled “7.1 Pull 响应”messageType: /down/pull/ack
云端在 Pull 请求无直接任务下发、返回功能列表或返回设备参数时发送该消息。
{ "msgId": "pull-ack-0001", "messageType": "/down/pull/ack", "ts": 1724044089000, "params": { "ackOriginalMsgId": "k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6", "type": "print", "errCode": [], "msg": "no task", "dateTime": 1724044089000 }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.ackOriginalMsgId | string | 是 | 对应 /up/pull 的 msgId |
params.type | string | 是 | 对应 /up/pull 的 params.type |
params.errCode | int[] | 是 | 错误码数组,[] 表示请求成功 |
params.msg | string | 是 | 响应描述 |
params.params | object | 否 | 功能列表或设备参数等响应数据 |
params.dateTime | int64 | 否 | 服务端时间 |
7.2 打印任务下发
Section titled “7.2 打印任务下发”messageType: /down/print
设备收到 /down/print 后,先发送 /up/print/ack status=confirm,再按 deliverType 处理打印数据。
7.2.1 文件打印
Section titled “7.2.1 文件打印”文件打印处理步骤:
- 读取
resources。 - 使用每个
resources[].jobId做幂等检查。 - 发送
/up/print/ack,status=confirm。 - 下载
resources[].url。 - 校验下载文件大小和
hash。 compression=gzip时先解压。- 根据
fileType处理文件;prn直接进入打印协议,image进入设备图像打印流程。 - 开始打印时发送
status=printing。 - 打印成功发送
status=success;失败发送status=failed。
{ "msgId": "e5f6789012a3b4c5d6e7f89012a3b4c5", "messageType": "/down/print", "ts": 1724846400000, "params": { "deliverType": "file", "resources": [ { "jobId": "j-202408-0001", "url": "https://obj.example.com/prints/j-202408-0001.data", "hash": "sha256:ab12cd34ef56...", "size": 102400, "fileType": "prn", "prnProtocol": "esc", "sourceType": "print", "compression": "gzip" } ], "dateTime": 1724846400000 }}7.2.2 流式打印
Section titled “7.2.2 流式打印”流式打印处理步骤:
- 收到
deliverType=stream、streamStage=start的/down/print。 - 使用
jobId做幂等检查。 - 发送
/up/print/ack,status=confirm。 - 接收后续 WebSocket Binary frame,并写入打印缓冲。
- 开始输出时发送
/up/print/ack,status=printing。 - 收到
streamStage=end后校验crc32和dataBytes。 - 打印成功发送
status=success;校验或打印失败发送status=failed。
开始帧:
{ "msgId": "p-start-0001", "messageType": "/down/print", "ts": 1724045010000, "params": { "deliverType": "stream", "streamStage": "start", "ackOriginalMsgId": "v-end-0001", "jobId": "j-voice-0001", "fileType": "prn", "prnProtocol": "esc", "dateTime": 1724045010000 }}结束帧:
{ "msgId": "p-end-0001", "messageType": "/down/print", "ts": 1724045015000, "params": { "deliverType": "stream", "streamStage": "end", "jobId": "j-voice-0001", "crc32": "0f1e2d3c", "dataBytes": 204800, "errCode": [], "msg": "ok", "dateTime": 1724045015000 }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.deliverType | string | 是 | file 或 stream |
params.resources | object[] | 条件必填 | deliverType=file 时填写打印资源列表 |
params.resources[].jobId | string | 是 | 打印任务单 ID,用于 /up/print/ack.params.jobIds |
params.resources[].url | string | 是 | 文件下载 URL |
params.resources[].hash | string | 是 | SHA256 哈希,格式 sha256:十六进制字符串 |
params.resources[].size | int | 是 | 文件大小,单位字节 |
params.resources[].fileType | string | 是 | prn 或 image |
params.resources[].prnProtocol | string | 否 | fileType=prn 时返回,当前支持 esc |
params.resources[].sourceType | string | 是 | 任务来源类型,取值与 Pull 请求 params.type 保持一致:print、text_to_image、text_to_label |
params.resources[].compression | string | 是 | none 或 gzip |
params.streamStage | string | 条件必填 | deliverType=stream 时填写 start 或 end |
params.ackOriginalMsgId | string | 否 | 流式打印关联的原始上行消息 ID,例如语音停止帧 msgId |
params.jobId | string | 条件必填 | deliverType=stream 时的打印任务单 ID |
params.crc32 | string | end 时必填 | 流式打印全部 Binary 字节 CRC32 十六进制字符串 |
params.dataBytes | int | end 时必填 | 流式打印全部 Binary 字节长度;设备可兼容读取 bytes |
params.errCode | int[] | 否 | 流结束状态错误码,[] 表示成功 |
params.msg | string | 否 | 流结束状态描述 |
params.dateTime | int64 | 是 | 服务端时间 |
7.3 语音识别文本结果下发
Section titled “7.3 语音识别文本结果下发”messageType: /down/voice_text
仅当 /up/voice_generate 开始帧中 params.generateType=text 时使用。设备收到后使用 ackOriginalMsgId 关联语音会话。
{ "msgId": "voice-text-0001", "messageType": "/down/voice_text", "ts": 1724045010000, "params": { "ackOriginalMsgId": "v-end-0001", "generateType": "text", "text": "打印一张开封特产标签", "errCode": [], "msg": "", "dateTime": 1724045010000 }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.ackOriginalMsgId | string | 是 | 对应 /up/voice_generate 停止帧 msgId |
params.generateType | string | 是 | 固定为 text |
params.text | string | 是 | 最终语音识别文本 |
params.errCode | int[] | 是 | 错误码数组,[] 表示成功 |
params.msg | string | 是 | 结果描述 |
params.dateTime | int64 | 是 | 服务端时间 |
7.4 固件升级任务下发
Section titled “7.4 固件升级任务下发”messageType: /down/upgrade
设备收到 /down/upgrade 后,按 deviceUpgradeId 做幂等处理。已处理成功的升级任务不重复执行;正在处理的任务可继续上报当前阶段。
sequenceDiagram autonumber participant Srv as 云端设备网关 participant Dev as 设备 Srv-->>Dev: /down/upgrade Dev->>Srv: /up/upgrade/ack status=confirm Dev->>Dev: 下载固件文件 Dev->>Srv: /up/upgrade/ack status=downloading Dev->>Dev: 校验 hash 和 size Dev->>Dev: 按 compression 解压 Dev->>Srv: /up/upgrade/ack status=upgrading Dev->>Dev: 写入固件并重启 Dev->>Srv: /up/upgrade/ack status=success 或 failed Dev->>Srv: /up/state firmware=新版本
{ "msgId": "f6789012a3b4c5d6e7f89012a3b4c5d6", "messageType": "/down/upgrade", "ts": 1724846400000, "params": { "deviceUpgradeId": "u-202408-0001", "firmwareType": "cloud", "firmwareVersion": "1.2.4", "url": "https://obj.example.com/fw/p5802-1.2.4.bin.gz", "hash": "sha256:cd34ef56ab78...", "size": 5242880, "compression": "gzip", "dateTime": 1724846400000 }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.deviceUpgradeId | string | 是 | 升级任务唯一标识,用于幂等去重和 /up/upgrade/ack |
params.firmwareType | string | 是 | cloud、printer、bluetooth |
params.firmwareVersion | string | 是 | 目标固件版本 |
params.url | string | 是 | 固件下载 URL |
params.hash | string | 是 | 下发文件 SHA256,格式 sha256:十六进制字符串 |
params.size | int | 是 | 下发文件大小,单位字节 |
params.compression | string | 是 | none 或 gzip;gzip 表示下载文件校验后需要解压 |
params.dateTime | int64 | 是 | 服务端时间 |
固件升级处理步骤:
- 收到任务后发送
/up/upgrade/ack,status=confirm。 - 下载固件文件;下载过程中可发送
status=downloading。 - 按
size和hash校验下载文件。 compression=gzip时解压下载文件。- 进入升级写入前发送
status=upgrading。 - 升级完成并重启上线后发送
status=success。 - 发送
/up/state,在firmware中上报新版本。 - 任一步骤失败时发送
status=failed,携带errCode与msg。
7.5 设备控制指令
Section titled “7.5 设备控制指令”messageType: /down/control
{ "msgId": "h6i7j890k1l2m3n4o5p6q789r0s1t2u3", "messageType": "/down/control", "ts": 1724846400000, "params": { "controlId": "a351eff1b614d0c1f64227d0c4b28c99", "command": "reboot", "params": {}, "dateTime": 1724846400000 }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.controlId | string | 是 | 控制指令 ID,用于幂等去重和 /up/control/ack |
params.command | string | 是 | 控制命令 |
params.params | object | 否 | 控制命令参数 |
params.dateTime | int64 | 是 | 服务端时间 |
支持的 command:
| 命令 | 设备动作 |
|---|---|
shutdown | 关机 |
reboot | 重启 |
beep | 蜂鸣 |
reset_wifi | 重置 Wi-Fi |
reset_bluetooth | 重置蓝牙 |
factory_reset | 恢复出厂设置 |
clear_cache | 清理缓存 |
set_params | 设置设备参数,参数从 params.params 读取 |
report_state | 立即上报当前设备状态;设备确认收到后发送 /up/state,完成后回 success |
report_state 用于平台主动刷新设备状态。该控制指令不携带超时参数;设备收到后立即上报当前状态即可。管理端 HTTP 刷新接口默认等待 10 秒;等待期间设备通过 /up/state 上报状态后,平台会立即把最新状态返回给 HTTP 客户端,超时则返回当前缓存状态并标记超时。
8. 心跳协议
Section titled “8. 心跳协议”设备按 Bootstrap 返回的 data.websocket.keepalive 周期发送心跳。云端返回 /down/heartbeat 时,设备用 ackOriginalMsgId 关联本次心跳。
连续多个周期未收到 /down/heartbeat 或 WebSocket 连接异常时,设备进入重连流程。
上行心跳:
{ "msgId": "hb-up-0001", "messageType": "/up/heartbeat", "ts": 1724040005000}下行心跳:
{ "msgId": "hb-down-0001", "messageType": "/down/heartbeat", "ts": 1724040005001, "params": { "ackOriginalMsgId": "hb-up-0001" }}| 字段路径 | 类型 | 必填 | 使用位置 |
|---|---|---|---|
params.ackOriginalMsgId | string | 是 | 对应 /up/heartbeat 的 msgId |
9. 任务处理总时序
Section titled “9. 任务处理总时序”9.1 普通打印任务
Section titled “9.1 普通打印任务”sequenceDiagram autonumber participant Srv as 云端设备网关 participant Dev as 设备 Srv-->>Dev: /down/print deliverType=file Dev->>Srv: /up/print/ack status=confirm Dev->>Dev: 下载、校验、解压资源 Dev->>Srv: /up/print/ack status=printing Dev->>Dev: 打印 Dev->>Srv: /up/print/ack status=success 或 failed Dev->>Srv: /up/state
9.2 语音生成打印任务
Section titled “9.2 语音生成打印任务”sequenceDiagram autonumber participant Dev as 设备 participant Srv as 云端设备网关 Dev->>Srv: /up/voice_generate streamStage=start Dev->>Srv: Binary 音频 Dev->>Srv: /up/voice_generate streamStage=end Srv-->>Dev: /down/print deliverType=file 或 stream Dev->>Srv: /up/print/ack status=confirm Dev->>Srv: /up/print/ack status=printing Dev->>Srv: /up/print/ack status=success 或 failed
9.3 设备控制任务
Section titled “9.3 设备控制任务”sequenceDiagram
autonumber
participant Srv as 云端设备网关
participant Dev as 设备
Srv-->>Dev: /down/control
Dev->>Srv: /up/control/ack status=confirm
Dev->>Dev: 执行 command
opt command=report_state
Dev->>Srv: /up/state
end
Dev->>Srv: /up/control/ack status=success 或 failed
10. 错误码
Section titled “10. 错误码”| 错误码 | 含义 | 上报位置 |
|---|---|---|
2010 | ASR 录音 CRC 校验不一致 | 云端记录;设备检查停止帧 crc32 |
2011 | ASR 录音长度不一致 | 云端记录;设备检查停止帧 audioBytes |
2012 | ASR 本地内存不足丢弃录音字节 | /up/voice_generate 停止帧 errCode,/up/state.warnCode |
2013 | ASR 会话异常结束 | /up/state.warnCode |
4001 | 固件下载失败 | /up/upgrade/ack.errCode |
4002 | 升级失败或回滚 | /up/upgrade/ack.errCode |
4003 | 固件校验失败 | /up/upgrade/ack.errCode |
4004 | 固件版本不兼容 | /up/upgrade/ack.errCode |
11. 实现检查表
Section titled “11. 实现检查表”设备固件接入完成前,按以下项目核对:
- 开机后先调用 Bootstrap,再建立 WebSocket。
- WebSocket 握手请求头携带 Bootstrap 返回的
Authorization。 - 所有 Text 消息包含
msgId、messageType、ts。 - 回执消息通过
ackOriginalMsgId关联下行msgId。 - 连接成功后立即上报
/up/state。 - 上线后先拉取
firmware,再拉取print。 - 心跳周期使用 Bootstrap 返回的
keepalive。 - 语音生成按 start、Binary、end 顺序发送。
- 语音停止帧携带
is_speaking=false,并可携带crc32、audioBytes。 - 收到
/down/print后先回confirm,再处理下载或流式数据。 - 收到
/down/upgrade后按confirm、downloading、upgrading、success/failed回执。 - 收到
/down/control后按confirm、success/failed回执;其中report_state需要在成功回执前立即补发/up/state。 - 固件升级成功重启后发送
/up/state上报新版本。 - Token 到期前重新 Bootstrap 并重连。
文档维护: 爱印科技-应用技术部-方江琛
最后更新: 2026-06-11