You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何构建基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 00:30:03