项目概览
MES 数据采集与追溯系统是一套已经投入生产使用的 Windows 工业软件,部署在生产现场,连接 PLC 与外部 MES。它负责接收设备侧生产指令,把 RFID、产品身份和工序结果组织成可查询的本地记录,并在外部系统可用时完成校验、状态查询和结果上报。
现场数据链路并不只是“收到一条报文后转发”。一件产品从首次绑定开始,会经历校验、激光加工、清洗、视觉检测、查询和解绑等操作;设备可能重复发送同一动作,网络可能临时中断,外部接口也可能超时。系统必须同时处理身份关联、幂等、追溯、离线缓冲、重试和人工恢复,才能让设备动作与业务记录保持可解释。
本文依据当前现场版本整理:外层交付仓库基线为 c12e508,应用源码基线为 68137a6,Windows x64 安装包版本为 1.6.6。这些版本已经确认用于生产,但本文只公开通用业务和软件架构,不公开现场拓扑、客户信息或接口细节。
匿名化与公开边界
本文会说明 RFID 绑定、校验、激光、清洗、视觉检测和人工补站等通用业务,但不会公开:
- 客户、公司、产品和设备厂商名称;
- 真实工位编码、产品编号、RFID 数据和生产记录;
- PLC 型号、网络地址、端口和现场连接拓扑;
- 报文字段、完整命令格式、接口地址、请求或响应样本;
- API Key、账号、密码、连接字符串和数据库内容;
- 安装目录、备份目录、日志样本和现场配置;
- 产量、节拍、良率、停机时间和未经记录的稳定性指标。
下文中的架构图、表格和流程均使用抽象名称,目的是解释工程设计,不能用于还原真实产线。
项目目标
系统围绕“现场连续生产、数据可追溯、外部系统可恢复”建立以下目标:
- 以稳定的 TCP 服务接收多台 PLC 的数据采集与状态查询请求;
- 建立 RFID 与产品身份的有效绑定关系,并正确处理重复绑定和换码;
- 把每个工序结果写入本地数据库,形成从产品到工位和时间的追溯链;
- 在外部 MES 暂时不可用时保留待上传数据,不阻塞本地证据记录;
- 为操作人员提供实时监控、追溯查询、报表和异常补录界面;
- 通过本地用户认证、管理员能力和日志降低误操作风险;
- 支持 Windows 现场安装、配置保留、数据库迁移和定时备份;
- 用单元测试与集成测试覆盖协议、处理器、持久化和外部接口适配。
技术栈与职责
| 层次 | 技术与组件 | 主要职责 |
|---|---|---|
| 桌面界面 | .NET 8、WPF、CommunityToolkit.Mvvm | 登录、导航、实时监控、追溯、报表、配置和人工补站 |
| 应用编排 | Generic Host、依赖注入、命令处理器 | 生命周期、作用域管理、命令分发和业务用例编排 |
| 设备通信 | TCP、会话管理、协议解析 | 连接接入、报文分帧、请求解析、顺序处理和回复 |
| 业务模型 | 绑定、生产记录、校验状态、上传队列 | 产品身份、工序证据、换码、查询和外部同步状态 |
| 数据访问 | EF Core、SQLite、Repository | 本地持久化、索引、迁移、WAL 和查询 |
| 外部集成 | HttpClient、JSON、API Key | 外部 MES 校验、结果上报和动态信息查询 |
| 后台任务 | BackgroundService | 队列重试、磁盘保护、数据库热备份和过期备份清理 |
| 可观测性 | NLog、通信日志、运行状态 | 通信诊断、业务错误、接口调用和磁盘状态 |
| 验证与交付 | xUnit、Moq、FluentAssertions、Inno Setup | 单元/集成测试、Windows x64 安装和升级 |
应用使用 Generic Host 统一管理配置、日志、依赖注入和后台服务。界面通过 ViewModel 调用应用服务,设备通信和外部接口实现放在基础设施层,业务处理器只依赖仓储与适配器接口。
总体架构
┌────────────────────────── 现场设备层 ──────────────────────────┐
│ PLC / RFID / 工序设备 │
└──────────────────────────────┬─────────────────────────────────┘
│ 受控工业网络 / TCP
▼
┌────────────────────────────────────────────────────────────────┐
│ .NET 8 应用 │
│ │
│ TcpServer → ClientSession → ProtocolParser → CommandDispatcher │
│ │ │
│ ┌──────────────────────────────┼──────────────┐ │
│ ▼ ▼ ▼ │
│ 绑定/解绑处理器 校验/查询处理器 工序处理器 │
│ │ │ │ │
│ └──────────────────────────────┼──────────────┘ │
│ ▼ │
│ EF Core Repository / SQLite │
│ │ │
│ ┌───────────────────────┴──────────────┐ │
│ ▼ ▼ │
│ 外部上传队列与重试服务 WPF/MVVM 界面 │
└──────────────────────────────┬─────────────────────────────────┘
│ HTTP / JSON
▼
┌───────────────────┐
│ 外部 MES │
└───────────────────┘
现场控制与业务集成保持分层:TCP 链路面向设备,SQLite 保存本地生产事实,HTTP 适配器负责外部系统交互,WPF 界面负责人工查看和维护。外部 MES 不可用时,本地记录和待上传队列仍然保留,避免把短时网络故障直接等同于本地数据丢失。
启动与运行生命周期
应用启动时先建立单实例保护,避免同一台主机重复打开多个采集进程。随后加载配置和日志,初始化 SQLite 数据库并执行迁移,再显示本地登录窗口。只有登录成功后,Generic Host 才启动 TCP 服务、上传重试和备份等后台任务,并显示主窗口。
启动进程
→ 获取单实例锁
→ 加载配置与日志
→ 数据库迁移 / WAL 初始化
→ 本地用户登录
→ 启动 Generic Host
→ 启动 TCP、重试与备份后台服务
→ 显示生产监控界面
退出时 Host 会在限定时间内停止后台服务并释放网络、数据库和依赖注入资源。该顺序让数据库准备早于设备请求,也避免未完成登录时提前开放业务处理链路。
TCP 会话与报文边界
TCP 是字节流,不天然保留消息边界。系统同时兼容传统分隔符报文和长度前缀报文,并可在兼容模式下自动识别当前连接使用的分帧方式。会话读取器负责处理粘包、拆包、无效前缀和缓冲区恢复,再把完整载荷交给协议解析器。
关键保护包括:
- 可配置的最大连接数和最大帧长度;
- 空闲连接超时,避免失效连接长期占用会话;
- 长度前缀残帧超时与兼容处理;
- 无效帧丢弃、重新同步和标准失败回复;
- 多个客户端会话并发运行;
- 同一会话中的完整消息依次处理并依次回复;
- TCP KeepAlive 与优雅停止。
每个连接拥有独立会话,但同一连接中的消息不会并行穿过处理器。这降低了同一 PLC 连续命令乱序回复的风险,同时允许不同设备独立推进。
指令分发与业务能力
协议解析器把报文转换为包含来源、序号、命令类型和参数的命令对象。分发器根据命令类型创建对应作用域和处理器,使每个请求获得独立的仓储上下文。
| 能力 | 业务含义 | 主要结果 |
|---|---|---|
| 绑定 | 建立 RFID 与产品身份的当前关联 | 有效绑定、工序顺序和本地生产记录 |
| 校验 | 向外部 MES 确认产品是否允许继续 | 保存最近一次有效校验状态 |
| 查询 | 汇总绑定、工序、颜色和校验信息 | 返回当前产品状态快照 |
| 解绑 | 结束 RFID 的当前产品关联 | 关闭有效绑定并保留历史 |
| 激光 | 记录激光工序位置和结果 | 产品工序追溯记录与待上传项 |
| 清洗 | 记录清洗工序位置和结果 | 产品工序追溯记录与待上传项 |
| 视觉检测 | 记录检测位置与判定 | 质量结果、追溯记录与待上传项 |
公开案例只说明命令职责,不展示实际命令名称、字段顺序、结果编码或报文样本。
RFID 绑定、换码与幂等
绑定处理器以数据库唯一约束作为并发冲突的最终防线。新 RFID 首次进入时创建有效绑定;同一个 RFID 重复绑定到同一产品时返回成功,避免设备重发造成重复业务;如果已经绑定到另一个产品,则关闭旧绑定、建立新绑定并记录换码结果。
收到绑定请求
→ 校验必要参数
→ 尝试创建有效绑定
├─ 创建成功:记录绑定结果并准备外部上报
└─ 唯一约束冲突
├─ 当前产品相同:按幂等成功处理
└─ 当前产品不同:关闭旧绑定 → 新建绑定 → 记录换码
解绑同样具有幂等语义:没有有效绑定时可直接视为已完成;存在绑定时还会核对产品身份,防止错误请求结束其他产品的关系。
产品绑定还保存头尾顺序和加工顺序,使后续查询能够恢复设备继续生产所需的业务上下文。本文不展示这些字段的现场取值和编码规则。
校验、查询与状态持久化
校验处理器根据当前用户和产品上下文生成外部请求,并把成功、拒绝或通信失败映射为有限的本地结果。最新校验状态会写入产品记录,后续查询不依赖内存中的临时变量,因此应用重启后仍能返回已经持久化的最近状态。
查询处理器围绕有效绑定聚合:
- 产品与 RFID 关联;
- 激光和清洗的最近有效位置;
- 视觉检测位置与判定;
- 头尾顺序和加工顺序;
- 按需从外部 MES 查询的动态信息;
- 最近一次有效校验结果。
查询结果来自本地记录与外部动态信息的组合。外部查询失败时使用明确的未知状态,而不是把网络异常伪装成业务通过。
工序数据与人工补站
激光、清洗和视觉检测处理器把工位、产品、时间、位置和结果写入统一的生产记录模型。界面上的产品追溯页可以按产品查看绑定与工序历史,报表页对生产记录进行时间和结果维度的聚合,实时监控页展示设备连接与采集状态。
对于经过现场确认的补录或返修场景,系统提供人工补站入口。补站服务会复用业务校验、载荷生成和持久化能力,并记录执行结果。它用于处理受控异常,不应绕过现场审批,也不能用来批量修改原始生产证据。
设备工序请求
→ 参数与当前绑定校验
→ 写入本地 ProductionRecord
→ 按配置创建外部上传队列记录
→ 回复设备
人工补站
→ 登录用户确认
→ 输入产品与工序上下文
→ 应用服务校验并执行
→ 记录本地结果和外部调用状态
外部 MES 适配与失败重试
外部适配器使用 HttpClient 发送 JSON 请求,支持结果上报、产品校验和动态信息查询。接口地址、认证信息和超时由配置提供,运行时可读取更新后的外部 MES 设置。适配器区分 HTTP 失败、超时、主动取消、空响应和无法解析的响应,并返回有限的业务结果。
需要异步上报的数据先写入 SQLite 上传队列。后台服务定期按创建时间读取待处理或仍可重试的失败项,调用外部适配器,并根据结果更新状态、重试次数、最近重试时间和错误信息。失败项使用指数退避,避免外部系统故障时持续高频请求;磁盘空间低于保护阈值时暂停处理,避免数据库和日志继续放大磁盘风险。
本地工序记录
→ 创建 Pending 上传项
→ 后台服务轮询
→ 调用外部 MES
├─ 成功:标记 Succeeded
└─ 失败:记录原因和次数
→ 指数退避
→ 未超过上限时再次处理
这套机制提供了离线缓冲和基本重试,但当前实现不是严格的事务型 Outbox,相关一致性风险会在“已知边界”中单独说明。
WPF 运维与追溯界面
桌面端使用 WPF、MVVM 和依赖注入组织页面。页面在加载时创建自己的作用域,卸载时释放 ViewModel 和数据库资源,避免长生命周期界面持有已经失效的上下文。
主要界面包括:
- 实时监控:设备连接、采集状态和最近活动;
- 产品追溯:绑定历史、工序记录和综合状态;
- 生产报表:按时间、结果和工序聚合,并通过 LiveCharts 展示;
- 产品补站:执行经过授权的异常补录;
- 系统配置:维护 TCP、外部 MES、监控设备和日志相关设置;
- 用户管理:创建、启停和维护本地用户;
- 运行诊断:查看通信日志、接口异常和磁盘状态。
界面是生产数据的查看和维护入口,但数据库记录与设备消息才是业务事实来源。监控页不会因为界面显示“已发送”就推断外部系统已经接受数据。
本地认证与用户管理
应用启动后要求本地账户登录。密码使用随机盐和 PBKDF2-SHA256 保存,并通过固定时间比较验证,不在数据库中保存明文。用户记录包含启用状态、管理员标识、创建时间和最后登录时间,管理员可以维护现场账户。
本地登录保护的是桌面操作入口,并不为 PLC TCP 连接提供身份认证。管理员标识也只是当前应用内的权限边界,不等同于具有模块、动作和数据范围控制的完整 RBAC。账号停用、密码轮换、失败锁定和现场交接仍需要配套管理制度。
SQLite、迁移与备份
系统以 SQLite 保存绑定、生产记录、通信日志、上传队列和用户数据。EF Core 迁移在后台服务启动前执行,WAL 模式改善界面查询、设备写入和后台任务并行时的使用体验。仓储通过 IDbContextFactory 为操作创建独立上下文,减少长生命周期上下文带来的并发和跟踪问题。
备份后台服务按小时使用 SQLite 原生热备份能力创建一致性副本,并清理超过本地保留期的旧文件。备份过程中不需要停止正常读写,但当前备份仍位于本机;主机级故障、磁盘损坏和勒索风险需要通过异机副本与实际恢复演练解决。
Windows 安装与现场交付
应用面向 Windows x64,通过 Inno Setup 生成版本化安装程序。安装工程包含主程序、运行依赖和默认配置,并在升级时保留现场已有的应用配置,避免覆盖已经验收的网络与外部系统参数。
确认源码与依赖版本
→ Release 构建
→ 运行单元测试和集成测试
→ 发布 Windows x64 应用
→ 生成 Inno Setup 安装包
→ 备份现场配置和数据库
→ 安装或升级
→ 验证登录、PLC 通信、追溯和外部 MES
配置保留可以降低升级风险,但也可能让旧配置缺少新字段。因此安装包版本、配置 schema、数据库迁移和现场验收记录需要通过统一发布清单关联。
构建与测试基线
本案例编写前在当前现场源码版本上重新执行了 Release 构建和测试:
| 验证项 | 结果 |
|---|---|
| 外层交付仓库 | c12e508,工作区干净 |
| 应用源码仓库 | 68137a6,工作区干净 |
| Windows x64 安装包 | 1.6.6,确认为当前现场版本 |
| .NET Release 构建 | 0 error、0 warning |
| 自动化测试 | 两个测试项目,192 项通过、0 项失败 |
| 源码仓库 CI | 当前没有持续集成工作流 |
测试覆盖协议解析、命令处理器、绑定幂等、外部接口适配、SQLite 仓储、用户认证、界面 ViewModel 和 TCP 集成场景。测试全绿说明当前验证范围内的行为一致,不代表真实 PLC、现场网络和外部 MES 可以省略联调。
生产使用结果
根据已经确认的现场事实,可以做出以下定性描述:
- 当前源码与安装包版本已经投入生产使用;
- PLC 数据采集、RFID 产品绑定和工序追溯形成了完整本地链路;
- 校验、查询、激光、清洗和视觉结果能够进入统一业务模型;
- 外部 MES 同步失败时可以通过本地队列保留并重试;
- 操作人员可以在桌面端监控、查询、报表分析和执行受控补站;
- Windows 安装工程用于现场安装、升级和配置保留。
本文不披露客户和产品,也不虚构产量、节拍、良率、接口可用率或长期稳定性指标。源码中存在某项能力,并不表示所有工位都启用了该能力。
已知边界与风险
通信安全
- PLC TCP 通道当前没有 TLS、应用层鉴权或消息签名,必须运行在隔离、受控的工业网络中;
- 本地用户登录只保护 WPF 操作入口,不能识别 PLC 连接方身份;
- 协议会记录原始通信内容用于排障,日志权限和保留周期必须按生产数据管理;
- 后续应收敛监听地址、限制来源,并在协议兼容允许时增加网关认证或加密层。
数据一致性与上传队列
- 绑定、生产记录和上传队列通过多个仓储分别保存,不在同一个数据库事务中;
- 中间步骤失败可能出现“绑定成功但追溯或上传项未写入”的部分完成状态;
- 队列没有处理租约,多个应用实例同时运行时可能重复处理同一记录;
- 外部上报成功但本地状态更新失败时,后续重试可能形成重复提交;
- 当前没有专门的死信状态、人工重放界面或完整队列服务测试。
日志与配置安全
- 外部 MES 适配器当前可能记录完整接口地址、请求载荷和响应正文,其中可能包含产品身份和业务数据;
- 外部接口凭据由现场配置提供,配置文件和安装备份需要限制访问;
- 应优先实施结构化脱敏,只保留调用标识、耗时、状态和经过筛选的错误摘要;
- 升级时保留旧配置,需要校验新增字段、默认值和密钥轮换状态。
认证与权限
- 当前管理员标识不等同于细粒度 RBAC,模块、动作和数据范围尚未形成统一策略;
- 密码最小规则较基础,登录失败锁定、会话超时和强制轮换仍需加强;
- 初始账户、管理员授予和离职停用需要纳入现场交付与审计清单。
运行、验证与恢复
- 系统依赖 Windows、SQLite、现场 PLC 网络和外部 MES,跨平台部署不在当前范围;
- 自动化测试不能替代真实 PLC、异常断网、外部接口限流和硬件在环验证;
- 源码仓库目前没有自动构建、测试和安装包验证工作流;
- 备份位于本机且按时间保留,异机复制、恢复时间和恢复点验收仍待固化;
- SQLite 适合当前单机部署,但需要持续监控文件增长、锁竞争、磁盘空间和备份可恢复性。
后续路线
- 将绑定、生产记录和上传队列改造为同一事务内写入的事务型 Outbox;
- 为上传队列增加处理租约、幂等键、死信状态、人工重放和积压监控;
- 对外部 MES 请求、响应和终端通信日志实施字段级脱敏与分级保留;
- 把接口凭据迁移到受控密钥存储,并建立配置 schema 与轮换流程;
- 收敛 TCP 监听与来源范围,评估网关认证、TLS 或消息签名的兼容方案;
- 将本地管理员模型扩展为可审计的 RBAC,并增加登录限流、锁定和密码策略;
- 建立包含 Release 构建、192 项测试、静态分析和安装包验证的 CI;
- 用发布 manifest 关联源码、安装包、数据库迁移、配置版本和验收记录;
- 增加 PLC 仿真、断网重试、重复消息和硬件在环分层回归;
- 建立异机备份、定期恢复演练、磁盘告警和版本回退流程。
项目复盘
这个项目的核心价值不是把 TCP、SQLite 和 HTTP 拼接起来,而是为每条现场消息建立一条可解释的数据路径:
- 设备请求先被正确分帧和顺序处理;
- RFID 与产品身份通过有效绑定建立生命周期;
- 工序结果先成为本地生产事实,再进入外部同步链路;
- 重复请求通过幂等规则处理,换码和解绑保留历史;
- 外部 MES 故障不会直接抹掉本地追溯证据;
- 操作界面提供监控和恢复入口,但不替代数据库事实;
- 自动化测试验证软件契约,现场验收验证真实系统边界。
生产使用证明了这套链路能够承担实际业务,但也让一致性、安全和运维债务更加具体。下一阶段的重点应是事务型 Outbox、日志脱敏、通信边界、持续集成和可恢复发布,而不是继续堆叠命令数量。