如何构建基于C#的OPC UA客户端采集西门子设备告警并存储至SQL Server
基于C#实现OPC UA告警采集并存储到SQL Server的方案
一、绕开源码编译坑:用官方NuGet包快速搭建基础
直接编译OPC Foundation的GitHub仓库容易碰到依赖缺失问题,换用官方维护的NuGet包能省不少麻烦:
- 新建C#控制台/Windows Forms项目(按需选择)
- 在NuGet包管理器中搜索并安装
OPCFoundation.NetStandard.Opc.Ua,这个包自带所有必要依赖DLL,不用手动找文件
二、实现OPC UA告警订阅核心逻辑
OPC UA的告警属于事件类数据,需要通过订阅EventMonitoredItem获取,核心代码示例如下:
using Opc.Ua; using Opc.Ua.Client; using System; namespace CNCAlarmCollector { class Program { static Session _session; static void Main(string[] args) { // 1. 配置客户端参数 var config = new ApplicationConfiguration { ApplicationName = "CNCAlarmCollector", ApplicationType = ApplicationType.Client, SecurityConfiguration = new SecurityConfiguration { AutoAcceptUntrustedCertificates = true // 测试环境临时用,生产环境需配置合法证书 } }; config.Validate(ApplicationType.Client).Wait(); // 2. 连接OPC UA服务器 var endpoint = new EndpointDescription("opc.tcp://[你的OPC UA服务器地址]:[端口]/[路径]"); _session = Session.Create(config, new ConfiguredEndpoint(null, endpoint, EndpointConfiguration.Create(config)), false, "", 60000, null, null).Result; Console.WriteLine("已连接到OPC UA服务器"); // 3. 创建告警订阅 var subscription = new Subscription(_session.DefaultSubscription) { PublishingInterval = 1000, // 每秒轮询一次 Enabled = true }; _session.AddSubscription(subscription); // 订阅服务器级告警节点(如果是单台机床,替换为对应机床的节点ID) var monitoredItem = new EventMonitoredItem(subscription.DefaultItem) { StartNodeId = ObjectIds.Server, EventFilter = EventFilter.CreateSimpleFilter( new SimpleAttributeOperand[] { new SimpleAttributeOperand { TypeDefinitionId = ObjectIds.BaseEventType, BrowsePath = new QualifiedName[] { BrowseNames.Message } }, new SimpleAttributeOperand { TypeDefinitionId = ObjectIds.BaseEventType, BrowsePath = new QualifiedName[] { BrowseNames.SourceName } }, new SimpleAttributeOperand { TypeDefinitionId = ObjectIds.BaseEventType, BrowsePath = new QualifiedName[] { BrowseNames.Time } }, new SimpleAttributeOperand { TypeDefinitionId = ObjectIds.BaseEventType, BrowsePath = new QualifiedName[] { BrowseNames.Severity } } }) }; monitoredItem.Notification += OnAlarmReceived; subscription.AddItem(monitoredItem); subscription.ApplyChanges(); Console.WriteLine("告警订阅已启动,按任意键退出"); Console.ReadKey(); // 清理资源 subscription.Delete(); _session.Close(); } static void OnAlarmReceived(object sender, NotificationEventArgs e) { foreach (var notification in e.Notifications) { if (notification is EventNotificationList eventList) { foreach (var fieldList in eventList.Events) { // 解析告警数据 string alarmMsg = fieldList.Fields[0].Value?.ToString(); string source = fieldList.Fields[1].Value?.ToString(); DateTime alarmTime = fieldList.Fields[2].Value as DateTime? ?? DateTime.Now; int severity = fieldList.Fields[3].Value as int? ?? 0; // 写入SQL Server SaveAlarmToSql(alarmMsg, source, alarmTime, severity); } } } } } }
三、实现SQL Server存储逻辑
首先在SQL Server中创建告警存储表:
CREATE TABLE CNCAlarms ( AlarmId INT IDENTITY(1,1) PRIMARY KEY, AlarmMessage NVARCHAR(500), SourceName NVARCHAR(100), AlarmTime DATETIME, Severity INT, CreateTime DATETIME DEFAULT GETDATE() )
然后在C#中实现写入方法:
using System.Data.SqlClient; static void SaveAlarmToSql(string msg, string source, DateTime time, int severity) { // 替换为你的SQL Server连接字符串 string connStr = "Server=[你的SQL服务器地址];Database=[数据库名];User Id=[用户名];Password=[密码];"; using (var conn = new SqlConnection(connStr)) { conn.Open(); string sql = "INSERT INTO CNCAlarms (AlarmMessage, SourceName, AlarmTime, Severity) VALUES (@Msg, @Source, @Time, @Severity)"; using (var cmd = new SqlCommand(sql, conn)) { cmd.Parameters.AddWithValue("@Msg", msg ?? DBNull.Value); cmd.Parameters.AddWithValue("@Source", source ?? DBNull.Value); cmd.Parameters.AddWithValue("@Time", time); cmd.Parameters.AddWithValue("@Severity", severity); cmd.ExecuteNonQuery(); } } }
四、关键注意事项
- 节点ID替换:如果单台CNC机床有独立的告警节点,用OPC UA Expert免费版浏览节点获取ID,替换代码中的
StartNodeId - 证书配置:生产环境禁用
AutoAcceptUntrustedCertificates = true,配置合法的客户端证书 - 异常处理:给连接、订阅、数据库操作加try-catch,避免程序意外崩溃
- 重连机制:添加会话状态检测,断开时自动重连
- 批量插入优化:告警量较大时,攒一批数据再批量写入,减少数据库IO开销
内容的提问来源于stack exchange,提问作者Rishi Verma
相关产品推荐
相关产品推荐

