项目概览

PVD 上下料 MES 桥接与追溯系统是一套已经投入生产使用的 Windows 工业软件。它部署在设备侧,在 PLC 与外部 MES 之间承担业务桥接:持续读取设备状态和待执行命令,把上料、下料、查询与解绑动作编排成可验证的 MES 调用链,并将处理结果写回 PLC,同时在本地保留可追溯的会话、关系、命令与接口事务。

这类系统的难点并不在于完成一次 Modbus 读取或 HTTP 请求,而在于两个状态系统之间没有天然事务。PLC 关心指令是否被接收和执行,MES 关心物料、载具和工序关系是否符合业务约束;网络超时、设备重发、应用重启或多步骤调用部分成功,都可能让两侧状态产生分歧。因此,系统需要显式保存流程上下文、活动关系、TraceId、响应结果和接口事务,使异常能够被定位和人工恢复。

本文以已经确认的生产版本为基线:主应用标签和 Windows x64 安装包版本均为 1.0.6,对应源码提交 46a7649。当前工作区存在后续开发内容,本文不会把这些未提交修改描述为生产能力。

匿名化与公开边界

本文会说明 PVD 上下料、料盘、目标工装、排产、扣料、绑定、过站和解绑等通用业务概念,但不会公开:

  • 客户、公司、产品、产线和设备厂商名称;
  • 设备型号、工位编码、现场拓扑和安装位置;
  • 网络地址、端口、寄存器地址、命令值和响应编码;
  • MES 接口地址、字段名称、请求或响应样本;
  • 产品 SN、Token、账号、密码、连接字符串和配置值;
  • 数据库内容、日志样本、导出文件和现场截图;
  • 本地绝对路径、安装路径和发布目录;
  • 产量、节拍、良率、停机时间和未经记录的稳定性指标。

下文的架构图和流程使用抽象名称,只用于说明工程设计,不能还原真实设备或协议。

项目目标

系统围绕“可靠桥接、状态可解释、生产可追溯”建立以下目标:

  1. 稳定轮询 PLC 设备状态和业务命令,并串行化同一通信通道上的访问;
  2. 将上料、下料、查询和解绑命令转换为明确的 MES 业务步骤;
  3. 在执行前校验来源、目标和当前活动关系,降低错误绑定与重复操作风险;
  4. 将成功或失败结果及时写回 PLC,形成设备侧可识别的命令闭环;
  5. 保存载具会话、活动关系、绑定历史、命令记录和 MES 事务;
  6. 通过 TraceId 把一次设备命令关联到本地记录和外部请求;
  7. 为操作人员提供设备监控、历史时间线、事务筛选、导出和配置维护界面;
  8. 支持 Windows x64 安装交付、数据库迁移、日志诊断和离线 Mock 联调。

技术栈与职责

层次 技术与组件 主要职责
桌面界面 .NET 8、WPF、CommunityToolkit.Mvvm 设备监控、事务查询、历史时间线、导出和配置维护
应用宿主 Generic Host、依赖注入、Options 生命周期、配置、日志、后台服务和应用服务装配
设备接入 Modbus TCP、轮询服务、字节序适配 状态读取、命令读取、参数读取和响应写回
业务编排 命令处理器、工作流引擎 上料、下料、查询、解绑和流程上下文管理
外部集成 HttpClient、JSON、Token、重试处理器 排产、来源/目标、SN、扣料、绑定、过站和解绑调用
追溯模型 会话、活动关系、绑定/解绑、命令记录 设备动作、业务关系和异常结果的本地证据链
数据访问 EF Core、SQLite、迁移 运行数据持久化、查询、筛选和历史时间线
状态通知 MVVM Messaging 连接状态、设备状态和界面刷新消息
可观测性 NLog、MES 事务、请求耗时 运行日志、外部调用结果和故障定位
验证与交付 xUnit、Mock、Inno Setup 开发验证、无现场系统联调和 Windows x64 安装

Generic Host 统一管理配置、日志、依赖注入和后台服务。WPF ViewModel 只消费应用服务和消息,设备通信与外部 MES 适配位于基础设施层,工作流负责组织业务步骤,EF Core 仓储保存可恢复的本地状态。

总体架构

┌────────────────────────── 现场设备层 ──────────────────────────┐
│ PLC:设备状态、业务命令、参数与处理响应                         │
└──────────────────────────────┬─────────────────────────────────┘
                               │ 受控工业网络 / Modbus TCP
                               ▼
┌────────────────────────────────────────────────────────────────┐
│ .NET 8 / Generic Host                                          │
│                                                                │
│ 状态轮询服务 ───────────────→ 运行状态 / MVVM Messaging         │
│ 命令轮询服务 → 命令分发器 → 上料 / 下料 / 查询 / 解绑处理器      │
│                    │                         │                  │
│                    ▼                         ▼                  │
│              工作流上下文             EF Core / SQLite         │
│                    │            会话 / 关系 / 命令 / MES 事务   │
│                    ▼                                            │
│             HTTP MES 适配器 / 重试 / Mock                       │
└──────────────────────────────┬─────────────────────────────────┘
                               │ HTTP / JSON
                               ▼
                     ┌───────────────────┐
                     │ 外部 MES          │
                     └───────────────────┘

系统把“设备事实”“业务事实”和“操作界面”分开:PLC 读写由单一客户端串行完成,工作流负责业务顺序,SQLite 保存追溯证据,界面通过消息和查询展示状态。这样能够避免 WPF 页面直接持有现场通信资源,也让设备掉线或界面切换不至于破坏业务对象的生命周期。

启动与运行生命周期

应用启动时先加载 JSON 配置和 NLog,创建 Generic Host,注册 PLC、MES、工作流、仓储与消息组件,随后执行 EF Core 迁移。数据库准备完成后,状态轮询和命令轮询后台服务开始运行,WPF 主窗口展示设备与 MES 状态。

启动进程
  → 加载配置与日志
  → 构建 Generic Host / 依赖注入
  → 执行 EF Core 数据库迁移
  → 启动 PLC 状态与命令轮询
  → 显示 WPF 监控界面
  → 停止时取消后台任务并释放资源

启动顺序保证数据库早于业务轮询就绪。配置中的一部分通过 Options 监视机制读取更新,但数据库、日志路径和已经实例化的客户端参数仍属于启动时边界,不能把整个应用描述为完全热重载。

PLC 状态轮询与串行访问

状态后台服务按固定周期读取自动/手动、运行和报警等设备状态,并把结果发布为运行状态消息,同时保存必要的设备快照。命令后台服务轮询多个业务命令组,只对非空闲命令进行分发。

Modbus TCP 客户端通过异步锁串行化连接、读取和写入,避免状态轮询与命令处理同时操作同一连接。数值和字符串分别支持可配置字节序,以兼容不同 PLC 数据布局。连接、读写和 HTTP 调用都有独立超时,取消信号会贯穿后台服务和业务处理器。

状态轮询 ─┐
          ├─→ 异步锁 → Modbus TCP 连接 → PLC
命令轮询 ─┘

当前重连延时配置没有形成真正的退避策略。故障期间,后台服务仍可能按照轮询周期反复尝试并持续写日志,属于需要收敛的运行风险。

命令分发与响应闭环

命令处理链按照“识别命令、读取参数、执行业务、写回响应、保存记录”的方向推进。为避免 PLC 持续保持命令值造成重复触发,处理器会在进入业务步骤前清理当前指令,再读取并校验参数。

发现非空闲命令
  → 清理当前命令
  → 读取并校验参数
  → 创建 TraceId 与执行上下文
  → 调用对应工作流
  → 写回成功或失败响应
  → 保存命令执行记录

该链路具有清晰的诊断步骤,但 PLC 指令清理、外部业务调用、响应写回和本地执行记录不是单一原子操作。进程在中间退出时,仍需要结合 PLC 当前状态、MES 事务和历史记录判断是否可以安全重试。

料盘到 PVD 的上料流程

上料工作流先获取外部 MES 访问上下文,再读取当天排产和来源载具状态,校验来源与目标是否匹配当前业务。校验通过后,系统依次完成产品标识生成、物料扣减、载具绑定和工序过站,并在本地建立活动关系和会话记录。

料盘 → PVD
  → 获取 MES 访问上下文
  → 查询当日排产
  → 查询并校验来源载具
  → 查询并校验目标载具
  → 生成产品 SN
  → 扣减物料
  → 建立载具绑定
  → 完成工序过站
  → 保存会话、活动关系和绑定记录

公开流程只表达步骤顺序,不展示实际接口字段、产品编码规则、工装身份、请求载荷或结果码。每一步的外部调用都会记录成功状态、耗时和经过限制的错误信息,供现场排障使用。

PVD 到目标工装的下料流程

下料方向以 PVD 侧的当前产品和活动关系为起点,查询目标工装状态并校验是否允许转移。工作流完成对应的 MES 业务步骤后,关闭旧关系、建立或结束目标侧关系,并保存下料会话与解绑记录。

PVD → 目标工装
  → 查询 PVD 当前上下文
  → 查询并校验目标工装
  → 执行下料业务步骤
  → 更新或关闭活动关系
  → 保存解绑记录和会话结果
  → 向 PLC 写回处理状态

上下料不是两个互不相关的接口调用:它们共享载具关系和产品上下文。只有持续维护当前活动关系,才能解释“某个产品从哪里来、当前在哪里、经过了什么动作”。

查询命令与流程预加载

PLC 在正式发起上料或下料前,可以通过查询命令预加载业务上下文。查询处理器读取当前载具关系、外部 MES 信息和本地会话,把经过校验的上下文保存到工作流状态中,后续命令可以复用同一组关键数据。

这种设计减少正式动作执行时的重复查询,也可以更早发现来源、目标或关系冲突。但预加载结果存在时效性,正式业务仍应对关键状态做最终校验,不能把一次查询当作长期锁定。

会话、活动关系与重复绑定防护

追溯模型由多个相互关联的记录组成:

记录 作用
载具转移会话 表示一次上料或下料流程的开始、结束和最终状态
活动关系 表示产品与载具当前仍有效的关联
绑定/解绑记录 保存关系建立和关闭的历史事实
命令执行记录 保存 PLC 命令、处理结果、错误摘要和耗时
MES 事务 保存外部调用方向、状态、耗时和关联 TraceId
设备状态快照 保存必要的设备运行状态变化

业务处理前会检查当前活动关系:相同关系的重复请求可以按已有状态处理,冲突关系会被拒绝,降低设备重发造成重复绑定的风险。所有记录通过 TraceId 串联,使一次 PLC 指令可以追踪到业务会话和外部调用。

当前活动关系检查主要依赖应用层查询,没有对应的数据库唯一约束。跨线程竞争或未来多实例运行时,两个请求仍可能同时通过检查,因此后续需要把业务唯一性下沉到数据库约束,并对冲突设计明确的幂等返回。

外部 MES 适配、重试与 Mock

外部适配器使用 HttpClient 和 JSON 调用 MES,区分超时、主动取消、HTTP 失败、空响应和解析失败。Token 与请求超时由配置提供,调用结果会转换为有限的业务结果,避免工作流直接依赖外部响应的全部结构。

重试处理器对超时、限流、服务器错误和瞬时网络异常使用固定间隔重试。它能够缓解短时抖动,但多步骤工作流没有跨系统事务或补偿机制,对非幂等 POST 自动重试还可能产生重复副作用。正式改进方向应是为每个业务动作提供幂等键、可查询状态和补偿策略,而不是无限增加重试次数。

开发环境可以切换到 Mock MES,在没有现场接口时验证 PLC 轮询、命令分发、工作流和 WPF 状态展示。Mock 是开发工具,不代表真实 MES 的认证、并发、限流和失败语义,也不能替代现场联调。

SQLite 追溯与数据展示

EF Core 与 SQLite 保存命令、会话、活动关系、绑定/解绑、设备快照和 MES 事务。应用启动时执行迁移,仓储为各业务操作提供独立数据库上下文。WPF 界面围绕这些记录提供:

  • 设备监控:连接状态、运行模式、报警和最近命令;
  • MES 事务:按时间、方向和结果筛选外部调用,并查看请求耗时;
  • 历史追溯:从载具会话展开绑定、解绑和 MES 事务时间线;
  • 数据导出:导出经过筛选的运行记录,用于受控排障;
  • 配置维护:校验并保存 PLC、MES、轮询、日志和数据库相关设置。

SQLite 适合当前单机部署,但设备快照和 MES 事务当前缺少自动清理与分级保留。数据库备份、异机副本和实际恢复演练也尚未固化,必须作为后续运维工作处理。

配置、日志与消息通知

JSON 配置用于保存连接、超时、轮询、字节序和运行路径等参数。保存配置后,部分 Options 消费者可以接收变化;需要重建客户端或在启动时绑定的参数仍应通过重启生效,并在界面中明确提示。

NLog 记录启动、连接、命令和异常。MVVM Messaging 把 PLC 连接状态、设备状态与业务结果从后台服务传递到界面,降低后台线程与窗口对象的直接耦合。

生产数据治理仍有明显边界:MES Token、请求和响应、产品码以及 PLC 参数可能进入 SQLite、界面导出或调试日志。当前没有统一的字段级脱敏和保留策略,排障便利性不能替代最小化记录、访问控制和到期清理。

Windows 安装与现场交付

应用面向 Windows x64,通过 Inno Setup 生成版本化安装程序。当前现场确认使用 1.0.6,安装包包含应用文件和初始配置,支持桌面应用的标准安装与卸载流程。

确认源码标签与依赖
  → Release 构建
  → 发布 Windows x64
  → 生成 Inno Setup 安装包
  → 备份现场数据库与配置
  → 安装或升级
  → 验证 PLC、MES、上下料与追溯

现有安装工程仍依赖开发机绝对发布路径,并可能覆盖现场配置;聚合仓库 Gitlink、源码标签、测试仓库和安装包也没有通过统一 manifest 对齐。因此当前交付可以使用,但尚未形成完全可复现、可审计和可自动回滚的发布链路。

版本与验证基线

本案例严格区分生产标签和正在开发的工作区:

验证项 结果与边界
生产主应用 标签 1.0.6,源码提交 46a7649,已确认用于现场生产
Windows x64 安装包 版本 1.0.6,已确认用于现场生产
生产标签 Release 构建 通过临时只读导出单独验证:2 个项目,0 error、0 warning
当前开发工作区 0 error、0 warning;包含未提交的后续修改,不属于生产标签
当前开发测试快照 36 项通过;测试依赖未提交修改,不能作为 1.0.6 的测试认证
发布版本追溯 测试仓库缺少与生产标签严格对应的发布标记,也没有统一版本 manifest
源码仓库 CI 当前没有持续集成工作流

标签构建使用独立临时导出完成,没有 stash、checkout、清理或改写当前工作区。未提交的 MES 接口测试界面、Token 刷新修正及相关测试属于后续开发内容,本文不将其写成生产能力。

生产使用结果

根据已经确认的现场事实,可以做出以下定性描述:

  • 主应用和安装包 1.0.6 已投入生产使用;
  • PLC 状态、命令轮询和响应写回形成了设备侧闭环;
  • 料盘到 PVD、PVD 到目标工装的业务步骤已接入外部 MES;
  • 会话、活动关系、绑定/解绑、命令和接口事务形成了本地追溯链;
  • 设备监控、历史时间线、事务筛选和配置维护为现场排障提供了入口;
  • Mock MES 支持脱离现场接口的开发与演示。

本文不披露客户或现场数据,也不虚构节拍、产量、良率、成功率和长期稳定性指标。生产确认覆盖系统整体使用,不表示每个源码分支或开发中的界面都已部署到现场。

已知边界与风险

版本与发布治理

  • 聚合仓库 Gitlink、源码标签、测试仓库和安装包尚未通过统一 manifest 对齐;
  • 测试仓库没有与 1.0.6 严格对应的发布标记,36 项测试只能代表当前开发快照;
  • 安装脚本依赖开发机绝对发布路径,构建过程难以在干净环境中复现;
  • 升级可能覆盖现场配置,缺少配置 schema 迁移、安装前备份和自动回滚;
  • 源码仓库没有持续集成工作流,发布质量依赖人工步骤。

跨系统一致性

  • MES 多步骤调用没有分布式事务或补偿机制,部分成功后可能留下中间状态;
  • 对非幂等 POST 的自动重试可能造成重复扣料、绑定或过站副作用;
  • 活动关系缺少数据库唯一约束,跨线程或多实例并发仍可能竞争;
  • PLC 指令清零、业务处理、响应写回和执行记录不是单一原子操作;
  • 查询预加载与正式执行之间存在状态变化窗口,需要最终校验和幂等键。

认证、Token 与数据安全

  • 1.0.6 对持久化 Token 的有效期和刷新处理不完整;
  • MES Token、请求、响应、产品码和 PLC 参数可能进入数据库、界面导出和调试日志;
  • 当前没有统一日志脱敏、数据分级、导出审批和保留策略;
  • 桌面端没有登录、RBAC 或操作审计,配置维护依赖主机与现场权限;
  • PLC 通信没有加密或应用层鉴权,只适合受控工业网络。

运行与恢复

  • PLC 重连延时没有形成真正退避,故障期间可能高频重试并持续写日志;
  • 设备快照和 MES 事务缺少自动清理,长期运行需要监控数据库和磁盘增长;
  • SQLite 备份、异机复制和恢复演练尚未固化;
  • 普通单元测试与 Mock 不能替代真实 PLC、外部 MES、断网和硬件在环验收;
  • 单机 SQLite 与桌面进程构成当前运行边界,多实例部署需要重新设计并发控制。

后续路线

  1. 为扣料、绑定、过站和解绑设计跨系统幂等键、状态查询与补偿流程;
  2. 在数据库中增加活动关系唯一约束,并定义并发冲突的幂等响应;
  3. 完成 Token 有效期、刷新、失效重试和安全存储的完整生命周期;
  4. 对请求、响应、产品码、PLC 参数和导出数据实施字段级脱敏与分级保留;
  5. 增加本地登录、细粒度 RBAC、配置变更审计和高风险操作确认;
  6. 实现指数退避、抖动、熔断和可观测的 PLC/MES 重连策略;
  7. 建立设备快照与事务数据保留策略、SQLite 热备份、异机副本和恢复演练;
  8. 建立 CI,固定 SDK 与依赖,执行 Release 构建、测试、静态分析和安装包验证;
  9. 用发布 manifest 关联源码、测试、数据库迁移、安装包、配置 schema 和现场验收;
  10. 改造可复现安装工程,支持配置迁移、安装前备份、健康检查和版本回滚;
  11. 建立 PLC 仿真、外部 MES 沙箱、网络故障和真实硬件在环的分层回归。

项目复盘

这个项目的核心价值,是把一次看似简单的“PLC 命令”转换为可以解释和追踪的跨系统业务链:

  • 设备状态和命令通过串行 Modbus 通道稳定读取;
  • 上下料动作在执行前获得排产、来源、目标和关系上下文;
  • 每个外部步骤都有 TraceId、耗时、结果和本地事务记录;
  • 活动关系描述产品与载具的当前事实,绑定/解绑记录保留历史;
  • PLC 收到明确响应,操作人员可以从界面还原处理过程;
  • Mock 与测试提升开发效率,生产标签和开发快照则保持清晰边界。

生产运行说明该设计已经能够承担实际上下料业务,但也暴露出工业桥接系统最关键的工程债务:跨系统幂等与补偿、发布可追溯、Token 与日志安全、数据保留以及可恢复交付。下一阶段应优先补齐这些边界,而不是继续增加更多未经治理的接口步骤。