
云打印机 MQTT 直连实战完整字段表、JSON / XML 排版与防重打设计附 Python 示例大多数商用云打印机只有「设备 → 厂商云 → 你的系统」一条路数据必须经过厂商。本文给出一条可私有化的路径设备直连你自有的 MQTT Broker打印内容全程不落厂商云。含官方通信协议v2025-11-10的完整下行字段表、XML 与 JSON 两套排版示例、14 项上报状态码、id防重打设计以及 Broker 选型与接入要点。一、为什么需要「直连」市面上商用云打印机的默认架构是云中转打印机 ←→ 厂商云 ←→ 你的 SaaS / ERP这条链路的问题不在功能在合规与自主权金融 / 医疗 / 政务客户的打印内容单据、处方、凭条不得落到第三方服务器你的业务系统里设备是厂商的资产—— 换供应商等于换掉全部设备厂商云故障 你的全部门店停摆。MQTT 直连把中间那一跳去掉打印机 ←→ 你自有的 MQTT Broker设备只认 Broker 地址与凭证打印内容不出你的服务器。协议规范MQTT 直连 / HTTP / 自定义指令计划于 2026-10 以 Apache 2.0 开放届时你可以自行实现 Broker 端也可以在多家供应商之间迁移而不必换设备。云中转与直连不是二选一 —— 成熟的方案两套都支持按客户合规等级切换。该直连方案目前已有国内与海外用户商用运行。二、协议全貌三条约定 一种配置方式官方《云打印机对接第三方 MQTT 服务器通信协议》只约束三件事其余交给部署方项约定可接入的服务器类型阿里云 MQTT、腾讯云 MQTT、自建 MQTT、电信云等有定制需求可另行对接QoS订阅主题与发布主题一律 QoS 1Clean Session设备默认清除会话若希望设备接收离线期间的消息需在 PC 配置工具写入参数时选择「不清除 Session」参数写入方式设备开机后通过USB 数据线连接 PC用《云打印设备配置工具》写入 Broker 地址与凭证设备侧覆盖热敏打印机、标签打印机、打印云盒三类形态。这里有一个容易误解的点协议不定义「设备如何知道自己该连哪个 Broker」—— 因为它不是协议行为而是出厂 / 现场配置行为参数经 USB 写入设备。所以部署流程里必然有一步「批量写入参数」这步用官方 PC 工具即可完成不需要自己改固件。三、Topic 主题规范约定「方向」不固化「字符串」协议只约定主题的角色不约定具体字符串订阅主题接收打印任务、语音播报消息、命令消息 —— QoS 1发布主题上报设备状态与打印结果 —— QoS 1也就是说sw/xxx/task/down这类字符串不属于协议定义范围而由部署方自定义。下面给一套推荐命名方案工程建议非协议强制好处是便于通配符订阅与分环境隔离推荐 Topic方向QoS用途{product}/{ver}/{sn}/task下行1打印任务{product}/{ver}/{sn}/voice下行1语音播报{product}/{ver}/{sn}/cmd下行1配置管理命令{product}/{ver}/{sn}/status上行1设备状态与打印结果平台侧用通配符订阅避免为每台设备单独建订阅{product}/{ver}//status落地时请把主题字符串写进你的部署文档 —— 因为协议不强制跨供应商迁移时这部分要重新约定这是直连方案需要提前规划的一点。四、下行打印与语音消息字段表服务器推送到设备的消息为 UTF-8 JSON。完整字段如下官方 v2025-11-10 规范关键字类型必填说明iduint32是打印任务 ID服务端确保不重复用于防重复打印。设备上报结果以此 ID 标识任务。取值范围0 – 4294967295typeint是打印数据排版类型打印语言见下表contentsString / Array / Object是打印内容数据格式与type保持一致pWidthint否打印纸张宽度 mm58 / 80 / 110默认 58pCopyint否打印份数默认 1pTypeint否纸张类型默认 1纸张为标签时必传vTypeint否播报类型vMessagestring否语音播报文本TTS 合成或音频下载 URLvModeint否播报排队策略默认 0messagestring否预留 HTTP 下载类型的打印内容与contents二选一优先取contentsgatewaystring否仅打印云盒usb发往 USB 打印机192.168.2.11发往指定局域网 IP 打印机type取值值含义contents形态1ESCBASE64 编码后数据字符串2CPCL字符串3TSPL字符串4XMLUTF-8字符串5JSONUTF-8Array小票/ Object标签6PNGURL 链接或 base64 内容字符串99打印设备配置管理Object其中type4的 XML 又分两种设计基础 XML兼容市面各运打印平台矢量打印 XML是专为全球语言打印设计的排版框架。XML 与 JSON 的完整排版定义见官网文档中心https://www.sw-aiot.com/doc.html。pType取值1 连续纸默认2 标签纸3 黑标纸4 穿孔纸8 连续纸用标签指令打印小票vType取值-1 无播报0 定制语音配合vMessage1 播报「你有新的订单」10000 指定语音链接下载播报vMode取值0 按队列顺序播报任务先插入队列默认1 立即播报2 立即播报并清空待播报队列五、下行示例均取自官方规范5.1 XML 排版type4—— 58mm 小票{id:12345678,type:4,pType:1,pWidth:58,pCopy:1,vType:0,vMessage:测试语音,contents:CB收款小票/CBBR商户存根 请妥善保管BR--------------------------------BR商户名称 小熊每日鲜水果店BR商户编号 1005800029BR交易时间 2020-12-11 10:23:30BR交易订单号 1005800012112007217BR支付单号 202012112200140385141256912BR优惠金额 5.00BR备注 测试小票BR交易状态 收款成功BR支付方式 支付宝-公众号支付BR交易金额 126.50 元BRBRQR10058001200047217/QRBR--------------------------------BR打印时间 2020-11-12 11:02:36 签名BR}常用 XML 标签BR换行CB居中放大B放大一倍C居中L字体变高一倍W字体变宽一倍BOLD加粗RIGHT右对齐CUT切纸PLUGIN钱箱或外置音响IMGPNG 图片 URLQR二维码单个订单最多打印一个BC128_A/BC128/BC128_C条码A 为数字 大写字母混合58mm 最多 14 位C 为纯数字5.2 JSON 排版 · 小票type5contents为 Array{id:12345678,vType:0,vMessage:这是测试语音,pType:1,pWidth:58,pCopy:1,type:5,contents:[{cont:云打印 JSON 排版,type:title},{thead:{名称:40%,单价:25%,数量:15%,金额:20%},tbody:[[云打印机4G/WiFi,100,1,100],[4G 音箱摄像头,999.44,1,999.44]]},{cont:合计:2009.1 元,size:11,align:left},{both_sides:[收款金额,258.00]},{both_sides:[支付方式,微信支付]},{cont:1234567890,type:qrcode,align:center,size:60},{cont:1,type:cut}]}小票元素typetitle居中放大标题text文本行cont可为字符串或数组png图片最大 60Kbmp图片最大 6Kqrcode最大 512 字节bc128默认 CODE128A/bc128a/bc128cdiv_line-分割线支持居中插字div_star*分割线cutcont为0全切 /1半切plugin开钱箱通用属性alignleft 默认 / center / rightboldtrue / falsesize两位数字ABA 为倍宽、B 为倍高各取 0–7both_sides第一个字符串左对齐、第二个右对齐theadtbody多列表格thead可传对象映射列宽占比也可传数组只给占比5.3 JSON 排版 · 标签type5contents为 Object{id:12345678,pType:2,type:5,contents:{SIZE:[60,40],DIRECTION:0,DENSITY:7,SOUND:3,label:[{type:TEXT,x:10,y:20,font:2,w:2,h:2,r:0,cont:放大 1 倍},{type:QRCODE,x:10,y:70,e:M,w:5,cont:12345678},{type:BC128,x:240,y:70,h:30,show:0,r:0,narrow:1,wide:1,cont:1234567889},{type:BAR,x:10,y:300,w:420,h:4},{type:BITMAP,x:10,y:200,cont:data:image/bmp;base64,...}]}}标签顶层参数SIZE[宽, 高] mmDIRECTIONDENSITYSOUNDlabel元素数组。标签元素类型TEXTx/y/font/w/h/r/contQRCODEe纠错等级、w尺寸BC128h高度、show是否显示可读字符、narrow/wide条宽比BARw/h画线BITMAPbase64 BMP同一份 JSON 载荷在HTTP 推送与MQTT 直连两条通路上完全通用 —— 你可以先用 HTTP 跑通原型量上来后切 MQTT业务侧序列化代码一行不用改。六、下行远程配置管理type99设备支持云端远程设置音量、重启、切换默认指令模式{id:12345678,type:99,contents:{cmd:volume,value:1}}命令载荷说明volume{cmd:volume,value:1}音量0 静音 / 1 低音量 / 2 中音量 / 3 大音量 / 4 最大reboot{cmd:reboot}系统重启label_cmd{cmd:label_cmd,print:tspl}默认标签指令可选tspl/cpcl/zpl默认 tsplprint_cmd{cmd:print_cmd,cmd:tspl}设置打印机默认语言可选tspl/cpcl/esc七、上行状态与打印结果上报设备通过发布主题上报UTF-8 JSON关键字类型说明devicenamestring云打印设备 SN机器码与三元组的 DeviceName 或 ClientID 一致iduint32打印任务 ID与服务器下发的任务 ID 一致上报设备状态时不带此字段注意区分codeint结果码code状态码code含义0打印成功 / 打印机正常100未知错误通讯异常101打印机缺纸102打印机开盖103打印机过热201没有id202没有type203无效type参数未在定义范围204没有 msg205无效 msg如链接非标准 HTTP206下载错误重复下载 6 次207任务长度超出设备缓冲区208内容格式错误209重复任务不执行打印根据 ID 判断三类上报样例// 4G 机型开机连上 MQTT 服务后上报一次imei 为 15 位数字iccid 为 20 位卡号{devicename:dev1,imei:123456789012345,iccid:12345678901234567890}// 设备状态上报缺纸不带 id{devicename:dev1,code:101}// 打印结果上报任务 123456789 打印成功{devicename:dev1,id:123456789,code:0}带扫码功能的产品另有一路上报{devicename:dev1,scan_content:abcd1234}。八、防重打设备是最后一道闸自建链路最容易踩的坑是同一张单子打两遍。这套协议把防线放在两层服务端id由服务端保证不重复下发前登记落库唯一索引。设备端内置防重打 ——同一id在不断电情况下只打印一次重复推送时直接回报code 209重复任务不执行打印。# 服务端下发前登记落库唯一索引列名对应协议里的 id# CREATE UNIQUE INDEX uk_mqtt_id ON print_tasks(mqtt_id);# 设备端命中已执行表 → 不打印回报 {devicename:...,id:id,code:209}配套工程约定设备只在打印完成后上报结果回报体里的id与下发一致服务端收到该id且code 0才把任务置为「已完成」未收到回报的任务超时后重新入队并复用同一个id不要新建 ID—— 即使重复到达设备侧防重打会自动跳过。⚠️id是uint32上限 4294967295。若沿用雪花 ID 之类的 64 位方案务必先截断或做映射否则溢出后防重打逻辑会失效。九、鉴权与部署要点等级方案适用L1 基础Username 设备 TokenPassword 可空内网 / 测试L2 增强Password HMAC-SHA256(device_secret, {ts}\n{nonce}\n{device_sn})公网生产L3 强安全mTLS 客户端证书CN{device_sn}, O{customer_id}金融 / 医疗 / 政企生产环境必须 TLS8883这条没有妥协余地。其余建议值端口1883TCP仅限内网/ 8883TLS生产必须Keep Alive 60sClientID 建议使用设备 SN —— 规范要求devicename与三元组的 DeviceName 或 ClientID 一致用随机 ClientID 会与设备侧会话互相踢下线单条载荷做上限控制JSON 票据里png≤ 60K、bmp≤ 6K、qrcode≤ 512 字节超限会命中code 207超缓冲区或208格式错误。大图请走type6传 URL。最小可运行示例Python Pahoimportjsonimportpaho.mqtt.clientasmqtt BROKER,PORTbroker.example.com,8883DEVICE_SNSW-03DW-ABC123TOPIC_TASKfswprint/v1/{DEVICE_SN}/task# 下行设备订阅TOPIC_STATUSfswprint/v1/{DEVICE_SN}/status# 上行设备发布clientmqtt.Client(client_idDEVICE_SN)client.username_pw_set(sw_dev_abc123def456,)client.tls_set(ca_certs/path/to/ca.crt)defon_connect(c,userdata,flags,rc):ifrc!0:returnc.subscribe(TOPIC_TASK,qos1)# 接收打印任务 / 语音 / 命令task{id:100001,type:5,pType:1,pWidth:58,pCopy:1,contents:[{cont:深圳商为,type:title},{cont:Hello PB-03DW,type:text,bold:True},{cont:https://sw-aiot.com,type:qrcode,align:center,size:04},],}c.publish(TOPIC_TASK,json.dumps(task,ensure_asciiFalse),qos1)defon_message(c,userdata,msg):# 设备侧上报{devicename:...,id:100001,code:0}print(msg.topic,msg.payload.decode(utf-8))client.on_connecton_connect client.on_messageon_message client.connect(BROKER,PORT,keepalive60)client.loop_forever()Node.js 侧同理mqtt包mqtts://协议 ca证书。Go 用 Eclipse Paho注意SetClientID(device_sn)与SetUsername(token)。十、Broker 选型官方支持三类服务器协议对 Broker 无绑定官方明确支持接入阿里云 MQTT、腾讯云 MQTT、自建 MQTT、电信云。自建一条命令即可起一个 EMQX# docker-compose.ymlservices:emqx:image:emqx/emqx:5.6ports:-1883:1883# MQTT-8883:8883# MQTT over TLS-18083:18083# Dashboardvolumes:-./data:/opt/emqx/datadocker compose up -d即可。Mosquitto / HiveMQ / AWS IoT Core 同样适用。十一、几个常见坑ClientID 用随机值→ 与设备侧会话互相踢下线。规范要求devicename与 DeviceName / ClientID 一致ClientID 请用设备 SN。id用 64 位自增→ 超出 uint32 上限4294967295后溢出防重打逻辑失效。把 Topic 字符串当成协议标准→ 换 Broker 或换供应商时发现对不上。协议不固化主题落地时务必写进部署文档。图片 base64 塞进 JSON 票据→ 超过 60K 会报207/208。大图用type6的 URL 模式。Clean Session 设成 false 却没做会话恢复→ 重连后收到一堆历史消息。初期保持默认清除会话。生产用 1883 明文→ 数据裸奔。相关能力本文协议内容以商为《云打印机对接第三方 MQTT 通信协议》v2025-11-10 为准HTTP 侧 v1.0。该 MQTT 直连方案已有国内与海外用户商用运行协议规范计划 2026-10 以 Apache 2.0 开放。XML / JSON 完整排版定义见官网文档中心https://www.sw-aiot.com/doc.html