前言
工业现场的设备越来越杂,协议越来越多,每次接新项目最头疼的就是通讯对接和界面开发。OPC UA 这个东西说了很多年,确实能统一不少麻烦,但真要用起来还是有一堆细节要处理。再加上组态界面、变量管理、报警历史这些功能,每个项目都得从头搞一遍,实在不划算。
本文分享一个基于 WPF + MVVM 开发的 OPC UA 组态平台原型,把通讯、变量管理、拖拽设计器、运行态隔离这些东西都集成到一起了。目前已经从一个原型演示推进到了更接近正式工业上位机界面的状态,适合用来做设备上位机原型验证、客户 Demo 演示,或者作为二次开发的参考。
项目介绍
一个以 OPC UA 为核心的工业上位机 / HMI 组态平台。说白了就是一套拿来就能跑的上位机框架,支持通过 OPC UA 读写 PLC 变量,还带了一个拖拽式的组态设计器。你可以像用触摸屏组态软件一样,拖几个控件上去,绑定变量,就能做出一个监控页面。
当前版本已经具备了从通讯到界面再到数据持久化的完整链路。设计态和运行态做了隔离,运行时界面不能乱改,这一点比较贴近实际工程的需求。整体界面风格也从早期的演示页进化到了更正式的状态卡片化布局。
项目功能
功能模块 | 具体内容 |
OPC UA 通讯 | IP/端口/Endpoint 可配置;支持匿名和用户名密码连接;支持变量读写;同时支持订阅优先和轮询兜底两种数据刷新策略 |
变量系统 | CSV 变量表批量导入;支持自定义变量新增;变量可设置分类、分组、方向、报警属性、读写权限 |
事件绑定 | 变量与事件关联;支持触发条件、事件名、目标对象、执行参数;报警类事件支持触发、恢复和计数统计 |
组态设计器 | 左侧工具箱、中间画布、右侧属性编辑器;支持拖拽添加控件、位置调整、复制粘贴删除;支持页面模板应用;运行态下禁止编辑 |
运行态页面 | 运行总览、手动画面、参数设定、报警画面四个核心页面;支持登录权限控制 |
工业模块 | Motor、Cylinder、Axis、Robot、Stopper、Indicator、ValueDisplay、AlarmBanner、PageButton 等常用工业图形化组件 |
手动画面与设备控制 | 电机启停与故障复位、气缸伸缩与到位反馈、挡停升降、机械手启停/暂停/复位、轴使能/报警复位/Jog+/-/定位移动/回零 |
参数与报警 | 参数分页展示;行级权限只读控制;参数持久化到 JSON 文件;报警确认/复位/恢复记录/次数统计/历史持久化 |
权限控制 | 操作员、工程师、管理员三级角色;工程师默认密码 123456,管理员默认密码 admin888 |
项目特点
1、通讯层用的是 OPC UA 标准协议,不再需要为不同品牌的 PLC 分别适配驱动,这一点比传统 Modbus 方案省心不少。OPC UA 本身支持加密通信和丰富的安全策略,在工业场景里也更可靠 。
2、设计态和运行态做了严格隔离。运行时不能拖拽修改界面,这个设计很实用——现场误操作导致界面被改乱的情况在实际项目中并不少见。
3、变量管理做得比较细致。支持从 CSV 表批量导入变量,也可以直接在系统里新增自定义变量,每个变量都可以配置分类、分组、读写方向、报警属性,方便后期维护。
4、参数行级权限控制。不同的用户角色登录后,能看到和修改的参数不一样。比如操作员只能看不能改,工程师可以改一部分,管理员有全部权限。
5、报警系统有完整的生命周期。从触发、确认、复位到恢复,每一步都有记录,还能统计报警次数和持久化到文件。重启程序后历史报警不会丢。
6、代码结构清晰,按 Models、Services、ViewModels、Converters、Behaviors 分层,接手的人能快速找到对应的代码位置。
项目技术
技术项 | 说明 |
开发语言 | C# |
UI 框架 | WPF + MVVM 模式 |
通讯协议 | OPC UA(支持匿名和用户名密码认证) |
数据持久化 | System.Text.Json(参数、报警历史、组态工程均存为 JSON 文件) |
异步编程 | async / await |
数据绑定 | ObservableCollection + INotifyPropertyChanged |
配置存储 | config/ 目录下多个 JSON 文件分离管理 |
项目代码
1、OPC UA 通讯服务
通讯层核心是 OPC UA 客户端封装。支持通过配置 Endpoint URL 连接服务器,可以选匿名或用户名密码方式认证。读写变量走的是标准 OPC UA 服务接口,数据刷新同时支持订阅和轮询两种模式——正常情况下走订阅,断线或异常时自动切到轮询兜底。这种双保险策略在工业现场比较实用。
2、变量系统
变量表支持从 CSV 文件批量导入,字段包括变量名、分类、分组、数据类型、读写方向、报警上下限等。系统内部维护一个变量池,所有需要展示或控制的工业数据都从这里取。新加变量也不用改代码,直接在界面里新增或者重新导入 CSV 就行。
3、组态设计器
设计器是这套系统比较有特色的部分。左边是工具箱,中间是画布,右边是属性面板。从工具箱拖一个控件到画布上,右侧就能显示这个控件的所有可配置属性——位置、大小、绑定的变量、颜色、文字等等。支持控件复制粘贴删除,也支持保存成页面模板方便复用。在运行态下设计器会被锁住,防止误操作。
4、运行态与设计态隔离
系统里通过一个状态标志区分当前是设计模式还是运行模式。设计模式下可以拖拽调整控件布局、修改属性、增删页面。切换到运行模式后,所有组态编辑功能被禁用,界面只负责展示数据和响应操作。这个设计保证了现场运行时的界面稳定性。
5、配置持久化
所有配置都存成 JSON 文件,放在项目目录的 config/ 下面:
designer-layout.json:页面布局信息
designer-project.json:组态工程
alarm-history.json:报警历史记录
这样做的好处是配置文件可以直接复制到别的机器上,迁移很方便。
项目效果
运行起来之后,主界面包含几个核心页面:
运行总览:以卡片形式展示关键设备的状态和数据,整体布局比较规整
手动画面:按设备单元划分,电机、气缸、机械手、轴的操控入口都在这里
参数设定:参数分页展示,不同角色登录后能看到不同的行级权限
报警画面:显示当前报警列表,支持确认、复位,底部有报警次数统计和未确认计数
用不同角色登录后,界面上能看到的变化主要体现在参数页——工程师和管理员可以修改,操作员只能看。
设备控制这一块,当前已经支持了电机启停和故障复位占位输出、气缸伸缩及到位状态反馈、挡停升降、机械手启停/暂停/复位、轴的使能/报警复位/Jog+/Jog-/定位移动/回零等操作入口。虽然部分功能还是占位状态,但框架已经搭好了,后续补充具体逻辑即可。
报警系统的状态流转做得比较完整——触发一条报警后,它会在当前报警列表里出现,可以点击确认,也可以复位。恢复时会有恢复记录,历史报警会持久化到 alarm-history.json 文件里,重启程序也能查看到之前的记录。
项目源码
项目结构大致如下:
├── Models/ 数据模型│ ├── Variable.cs 变量定义│ ├── Alarm.cs 报警记录│ ├── Parameter.cs 参数定义│ └── ...├── Services/ 服务层│ ├── OpcUaService.cs OPC UA 通讯封装│ ├── VariableService.cs 变量管理│ ├── AlarmService.cs 报警管理│ └── ...├── ViewModels/ 视图模型│ ├── MainViewModel.cs│ ├── DesignerViewModel.cs│ ├── RuntimeViewModel.cs│ └── ...├── Converters/ 值转换器├── Behaviors/ XAML 行为├── config/ 配置文件目录│ ├── appsettings.json│ ├── designer-layout.json│ ├── designer-project.json│ ├── parameters.json│ └── alarm-history.json├── sample-tags.csv 示例变量表├── MainWindow.xaml├── MainWindow.xaml.cs└── PlcOpcUaHmi.csproj需要 Windows 系统 + .NET 8 SDK。
为了防止丢失,可以在评论区留言关键字「HMI组态」,即可获取完整源码地址。
总结
这套组态平台原型从实际项目需求出发,把 OPC UA 通讯、变量管理、拖拽设计器、运行态隔离、报警历史、权限控制这些功能都集成到了一起。
如果想继续往下走,还有几个方向可以深入:接入 SQLite 做历史数据存储、增加趋势曲线和配方管理、把权限系统改成可配置的用户管理、做好项目发布与运行时打包、以及把设备控制和报警模型做得更参数化。这套框架已经搭好了底子,上面的东西可以根据实际项目需要慢慢往上加。
关键词
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号[DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
作者:小码编匠
出处:gitee.com/smallcore/DotNetCore
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!
觉得有收获?不妨分享让更多人受益
关注「DotNet技术匠」,共同提升技术实力
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!