MES + 工业打印机:让每一件产品“自动生成身份证”,从生产到追溯真正闭环
在传统注塑工厂,MES记录生产、打印机打印标签,两套系统各自独立运行,人工重复录入容易出错。本文以实际工业场景为例,介绍如何构建 MES + 工业打印机自动打印网关:MES作为生产数据唯一来源,通过MQTT触发打印,打印网关自动拉取设备与生产数据并转换为打印协议,经TCP下发工业打印机完成产品标识,并把打印结果纳入追溯体系,真正实现“生产—打印—追溯”闭环。
在传统注塑工厂里,MES负责记录生产,打印机负责打印标签,两套系统往往各自独立运行。
生产人员需要先在MES中查询生产信息,再手动输入打印软件;设备编号、产品规格、颜色、重量、生产批次等信息也可能需要人工录入。
这种方式看似简单,但一旦产线数量增加,就容易出现:
- 打印错设备编号
- 产品规格录入错误
- 批次与实际生产不一致
- 操作员信息无法追溯
- 白班/夜班标识错误
- 打印数据与MES生产数据脱节
- 出现异常后无法快速定位问题
真正的智能制造,并不是简单地"给MES增加一个打印按钮",而是让MES成为生产数据唯一来源,让打印机成为MES数据的最终执行终端。
本文以实际工业场景为例,介绍如何构建一套 MES + 工业打印机自动打印网关。
一、MES与打印机为什么需要打通?
在注塑、滴灌带、包装、食品、电子装配等生产行业中,产品通常需要打印:
设备编号 + 产品规格 + 产品颜色 + 重量 + 生产编号 + 操作员 + 检验员 + 班次
这些信息实际上都已经存在于MES中。
例如生产现场有一台设备:
LA#ST-02
MES中可以维护:
设备名称:LA生产线2号设备
设备编号:LA#ST-02
产品规格:φ16-30cm
产品颜色:黑色
产品重量:10Kg
生产编号:XXXXXX
操作员:冉阳
检验员:XXXX
如果打印机还需要操作员重新输入这些信息,就产生了一个非常明显的问题:
MES已经有数据,为什么还要人工再输入一次?
因此,更合理的架构应该是:
生产设备
↓
MES生产数据
↓
打印网关
↓
工业打印机
↓
产品标签
打印机不再负责"产生生产数据",而只负责:
执行MES下发的打印任务。
二、整体系统架构
整个系统可以设计成四层。
┌──────────────────────────────────────────┐
│ ERP / MES │
│ │
│ 设备管理 生产订单 产品规格 人员管理 │
│ 生产批次 检验信息 产品颜色 重量信息 │
└───────────────────┬──────────────────────┘
│ HTTP API
▼
┌──────────────────────────────────────────┐
│ MES Printer Gateway │
│ │
│ MQTT监听 │
│ ↓ │
│ 获取设备数据 │
│ ↓ │
│ 生成打印数据 │
│ ↓ │
│ TCP发送 │
└───────────────┬──────────────────────────┘
│ TCP/IP
▼
┌──────────────────────────────────────────┐
│ Industrial Printer │
│ │
│ TCP : 9100 │
│ │
│ 接收打印指令 │
│ ↓ │
│ 自动打印 │
└──────────────────────────────────────────┘
这套架构最大的特点是:
打印机不需要直接连接MES数据库。
打印网关负责中间转换。
三、为什么采用 MQTT + HTTP + TCP?
这套方案实际上采用了三种通信方式,每一种负责不同的事情。
- MQTT:负责"通知打印"
MQTT不负责传输完整生产数据。
它只发送:
{
"device_no": "LA#ST-02"
}
意思就是:
LA#ST-02设备发生打印请求。
例如MES生产完成后:
MES
↓
MQTT
↓
/mes/Lines/Print
↓
{"device_no":"LA#ST-02"}
打印网关收到消息后,再去MES查询完整数据。
这样做有一个非常重要的好处:
MQTT消息非常小。
即使未来增加到几十台、几百台设备,也非常容易管理。
四、ERPNext作为MES数据中心
当前项目采用ERPNext作为MES基础平台。
打印网关通过ERPNext REST API查询:
Machine Equipment
例如:
GET
/api/resource/Machine%20Equipment/LA%23ST-02
这里有一个非常容易忽略的问题。
设备编号:
LA#ST-02
里面包含:
#
而#属于URL特殊字符,因此不能直接拼接URL。
需要进行URL编码:
from urllib.parse import quote
encoded_dev = quote(device_no, safe="")
url = f"{ERP_URL}/api/resource/{encoded_doctype}/{encoded_dev}"
最终:
LA#ST-02
会转换成:
LA%23ST-02
这也是工业MES开发中非常典型的细节。
五、ERPNext API Key + API Secret
打印网关不需要模拟网页登录ERPNext。
而是使用:
API Key
+
API Secret
通过Token方式访问。
HTTP Header:
headers = {
"Authorization": f"token {API_KEY}:{API_SECRET}",
"Content-Type": "application/json",
"Accept": "application/json"
}
然后:
response = requests.get(
url,
headers=headers,
timeout=10
)
这样打印网关就可以独立运行。
例如:
MES服务器
192.168.20.200
↑
│ HTTP API
│
↓
Printer Gateway
│
│ TCP
↓
打印机
192.168.17.45:9100
需要注意的是,API Secret 属于敏感凭据,实际部署时应放入配置文件或环境变量,并避免写入Git仓库。
六、设备编号自动转换
工业现场经常存在多个设备之间的关联。
例如:
LA#ST-02
代表生产线设备。
而实际对应的注塑机可能是:
LA#IM-02
视觉检测设备可能是:
LA#IV-02
因此打印网关可以根据设备编号自动转换。
例如:
def convert_device_number(device_no, target_type):
if not device_no:
return ""
parts = device_no.split("#")
if len(parts) != 2:
return device_no
line = parts[0]
machine = parts[1]
if "-" not in machine:
return device_no
number = machine.split("-", 1)[1]
return f"{line}#{target_type}-{number}"
调用:
convert_device_number(
"LA#ST-02",
"IM"
)
得到:
LA#IM-02
调用:
convert_device_number(
"LA#ST-02",
"IV"
)
得到:
LA#IV-02
这样MES只需要维护一个生产设备编号,系统即可自动关联生产设备和检测设备。
七、班次信息也可以自动生成
打印标签经常需要区分:
白班
夜班
如果依靠人工选择,就容易出现错误。
可以直接根据系统时间判断。
例如项目要求:
09:00~21:00 = 白班
21:00~次日09:00 = 夜班
代码:
from datetime import datetime
def get_shift_text():
now = datetime.now()
current_minutes = now.hour * 60 + now.minute
day_start = 9 * 60
night_start = 21 * 60
if day_start <= current_minutes < night_start:
return "✔", ""
return "", "✔"
这样打印机接收到的就是已经处理好的结果。
例如:
09:30
↓
白班
↓
✔
或者:
23:20
↓
夜班
↓
✔
生产人员无需再选择。
八、打印数据最终如何组成?
当前打印协议采用:
Header
+
字段
+
Tail
其中字段使用:
;
分隔。
例如:
dtbzbq.zpl;
9;
LA#ST-02;
产品规格;
10Kg;
✔;
;
生产编号;
检验员;
操作工;
黑色
最终转换为TCP数据:
1B 1C 74 70 6C
...
0D 0A
其中:
1B 1C 74 70 6C
是打印协议头。
0D 0A
是结束符。
因此打印网关本质上就是一个:
MES数据 → 打印协议
转换器。
九、打印网关的核心工作流程
完整流程可以设计成:
MES
│
│ 生产完成
▼
发布MQTT打印消息
│
▼
/mes/Lines/Print
│
▼
Printer Gateway
│
│ 获取device_no
▼
查询Machine Equipment
│
▼
获取生产数据
│
┌──────┴──────┐
│ │
▼ ▼
设备信息 产品信息
│ │
└──────┬──────┘
▼
生成打印字段
│
▼
生成TCP数据包
│
▼
连接打印机9100
│
▼
发送 0D 0A
│
100ms
│
▼
发送主打印数据
│
▼
等待打印机响应
│
最长3秒
│
▼
记录返回数据
│
▼
关闭TCP连接
这个流程比简单的:
MQTT → 打印机
可靠得多。
十、为什么发送打印前还要发送 0D 0A?
当前项目的打印机通信流程不是直接发送主数据。
而是:
TCP连接
↓
发送 0D 0A
↓
等待100ms
↓
发送主打印数据
↓
等待返回
↓
关闭TCP
也就是说:
prepare_data = bytes([0x0D, 0x0A])
sock.sendall(prepare_data)
time.sleep(0.1)
sock.sendall(packet)
这个设计相当于在正式打印之前给打印机发送一个初始化/分隔数据。
对于工业设备通信来说,这种"小协议细节"非常重要。
不要认为TCP连接成功就代表打印机一定已经准备好。
十一、打印机返回数据必须记录
很多工业项目只做:
sock.sendall(packet)
然后:
sock.close()
这实际上是不完整的。
因为打印机可能会返回:
ACK
状态码
错误码
设备信息
异常信息
因此当前方案增加了:
sock.settimeout(3)
然后:
response_data = b""
while True:
try:
chunk = sock.recv(4096)
if not chunk:
break
response_data += chunk
logger.info(
"收到HEX:%s",
chunk.hex(" ")
)
except socket.timeout:
logger.warning(
"等待打印机返回超时"
)
break
最终日志可以看到:
打印机TCP连接成功
发送初始化数据:0D 0A
等待0.100秒后发送主打印数据
发送主打印数据,长度:xxx bytes
主数据HEX:
1b 1c 74 70 6c ...
等待打印机返回,超时:3秒
收到打印机数据:
...
收到HEX:
...
打印机TCP连接已关闭
这对于现场调试尤其重要。
十二、3秒没有响应,是不是打印失败?
这里需要特别注意。
TCP发送成功
和:
打印机返回成功
是两个不同概念。
例如:
发送成功
↓
打印机已经收到
↓
打印机开始处理
↓
打印机没有返回数据
↓
3秒超时
这时候不能简单判断:
打印失败
更合理的是把状态拆成:
SEND_SUCCESS
RESPONSE_RECEIVED
RESPONSE_TIMEOUT
SEND_FAILED
CONNECT_FAILED
以后MES可以进一步实现:
打印任务
↓
发送
↓
等待
↓
打印机响应
↓
成功 / 超时 / 失败
这样才能真正形成打印任务闭环。
十三、打印网关为什么不直接写进MES?
这是系统架构中非常重要的一点。
如果直接把打印机TCP代码写进MES后台:
MES
├── ERP
├── 生产
├── 设备
├── 质量
└── 打印机
随着打印机数量增加,后台会越来越复杂。
而采用独立打印网关:
MES
│
├── MQTT
│
▼
Printer Gateway
│
├── Printer 01
├── Printer 02
├── Printer 03
├── Printer 04
└── ...
可以实现打印机层独立扩展。
以后增加:
ZPL打印机
热转印打印机
喷码机
激光打标机
标签打印机
只需要增加对应驱动。
MES本身不需要修改核心业务逻辑。
十四、从一台打印机扩展到整座工厂
单台设备:
MES
│
▼
Printer Gateway
│
▼
Printer
扩展到一条产线:
MES
│
MQTT
│
┌────┴────┐
│ │
Printer Printer
Gateway Gateway
│ │
┌────┼────┐ ┌────┼────┐
▼ ▼ ▼ ▼ ▼ ▼
P01 P02 P03 P04 P05 P06
进一步扩展到整个工厂:
MES
│
MQTT / HTTP API
│
┌──────┼──────┐
│ │ │
LA LB LC
│ │ │
打印网关 打印网关 打印网关
│ │ │
多台打印机 多台打印机 多台打印机
最终形成:
MES统一管理,打印网关统一执行,打印机分布式部署。
十五、最终形成"生产—打印—追溯"闭环
真正有价值的不是"自动打印"本身。
而是打印完成后,这个标签可以成为产品的数字身份。
例如:
产品
↓
生产设备
↓
生产批次
↓
生产时间
↓
操作员
↓
检验员
↓
产品规格
↓
产品颜色
↓
重量
↓
打印标签
↓
二维码
↓
MES追溯
客户拿到产品以后,通过二维码扫描:
产品二维码
↓
MES
↓
查询生产记录
↓
生产设备
↓
生产时间
↓
操作员
↓
检验记录
↓
质量数据
这时候打印机就不再只是一个"打印设备"。
而成为:
MES数字化追溯体系中的最后一个执行节点。
十六、未来可以继续升级哪些功能?
这套架构还可以继续扩展。
① 打印任务队列
MES
↓
MQTT
↓
打印任务队列
↓
Printer
防止瞬间大量任务造成打印机压力。
② 打印任务ID
例如:
PRINT-20260902-000001
MES可以完整记录:
任务ID
设备
打印时间
打印内容
发送状态
响应状态
异常信息
③ 自动重试
例如:
第一次失败
↓
等待1秒
↓
第二次
↓
仍失败
↓
第三次
↓
报警
④ 打印机心跳
持续监控:
在线
离线
忙碌
缺纸
故障
⑤ 打印内容防错
打印前自动检查:
设备编号 ✓
产品规格 ✓
生产批次 ✓
操作员 ✓
检验员 ✓
任何关键字段为空:
禁止打印
⑥ 打印结果回写MES
最终形成:
MES
↓
打印请求
↓
Printer Gateway
↓
打印机
↓
打印结果
↓
MES
这才是真正意义上的:
MES + 打印设备闭环控制
十七、总结
传统生产模式是:
MES记录数据
+
人工操作打印机
智能制造模式则是:
MES产生生产数据
↓
MQTT触发打印
↓
打印网关读取MES
↓
自动生成打印协议
↓
TCP发送工业打印机
↓
等待打印机响应
↓
记录打印结果
↓
回写MES
最终实现:
生产数据从MES产生,经过打印网关自动转换,最终驱动工业打印机完成产品标识,并将打印过程纳入MES追溯体系。
这不是简单的"MES连接打印机",而是把生产数据、设备数据、人员数据、质量数据和产品标签真正连接起来。
对于注塑工厂而言,下一步还可以把它扩展成:
注塑机
↓
MES
↓
生产订单
↓
产品参数
↓
视觉检测
↓
称重
↓
自动打印
↓
二维码
↓
包装
↓
入库
↓
全流程追溯
最终形成一套真正面向智能工厂的**"生产—检测—打印—包装—入库—追溯"数字化闭环系统**。
