OPC UA订阅在C#客户端应用程序中无法触发事件处理程序。

4
我有一个FactoryTalk服务器,上面有一些节点,我需要监控几个属性值。
我创建了一个客户端,成功读写数据,但无法让订阅工作起来。
以下是订阅配置:
subscription = new Subscription(session.DefaultSubscription)
{
    DisplayName = "Test subscription",
    PublishingEnabled = true,
    PublishingInterval = 500,
    LifetimeCount = 0,
};

我的监控项目:
monitoredItems = nodeAttrs
                .Select(nodeId => new MonitoredItem(subscription.DefaultItem)
                {
                    StartNodeId = nodeId,
                    AttributeId = Attributes.Value,
                    QueueSize = 1,
                    SamplingInterval = 500,
                    MonitoringMode = MonitoringMode.Reporting,
                })
                .ToList();

我给它们分配了通知处理程序(这里需要协议对象实例,所以我进行了调整):
MonitoredItemNotificationEventHandler monitoredItemEventHandler = (monitoredItem, e) => AttributeNotification(monitoredItem, e, protocol);

然后我添加事件处理程序:
foreach (var monitoredItem in monitoredItems)
{
    monitoredItem.Notification += monitoredItemEventHandler;
}

我将项目添加到订阅并创建它:
subscription.AddItems(monitoredItems);
session.AddSubscription(subscription);
subscription.Create();

我已经通过控制台检查了一遍,订阅已经被服务器创建并分配了一个ID。我也检查了所有的监视项,CreateMonitoredItems服务调用成功,并且它们也被分配了客户端句柄,NodeId正确解析,没有错误的StatusCode。
我通过一个名为UaExpert的第三方客户端应用程序对属性进行了更改。
然而,我无法触发通知事件处理程序。
我做错了什么吗? 有人能给出如何解决/调试这个问题的建议吗?

你是否正在将事件处理程序函数添加到被监视的项目中?:monitoredItem.Notification += MyItemChangedHandler; - Victor Pieper
你是否正在为被监视的项目添加一个事件处理函数?:monitoredItem.Notification += MyItemChangedHandler; - undefined
是的,抱歉,我忘记添加片段。已更新问题。 - infradude
是的,抱歉我忘记添加代码片段了。已经更新了问题。 - undefined
我不知道这是否有帮助,但这个事件处理程序对我有效:monitoredItem.Notification += MyItemChangedHandler; | public static void MyItemChangedHandler(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs eventArgs) { MonitoredItemNotification? notification = eventArgs.NotificationValue as MonitoredItemNotification; Console.WriteLine("Node: {0} Value: {1}", monitoredItem.StartNodeId, notification.Value.WrappedValue.ToString()); } - Victor Pieper
我不知道这是否有帮助,但这个事件处理程序对我有用:monitoredItem.Notification += MyItemChangedHandler; | public static void MyItemChangedHandler(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs eventArgs) { MonitoredItemNotification? notification = eventArgs.NotificationValue as MonitoredItemNotification; Console.WriteLine("Node: {0} Value: {1}", monitoredItem.StartNodeId, notification.Value.WrappedValue.ToString()); } - undefined
1个回答

1

今天我在同一个地方遇到了困难。UA-.NETStandard的文档不是应该的样子。 最后,我在这个示例中找到了线索:https://github.com/OPCFoundation/UA-.NETStandard/blob/54f7f8aa9b2e07531f73dadd6e4bd933566302ee/Applications/ConsoleReferenceClient/UAClient.cs#L387

要在.NET中向OPCUA订阅添加带通知的监视项,请尝试以下代码。

添加监视项

     /**
     * Add monitored items to Subscription
     */
    public void AddMonitoredItemGroup(List<clsOPCUAElement> nodesToMonitor)
    {
        try
        {
            if(this.Subscription == null) throw new Exception("No subscription present!");
            if (nodesToMonitor.Count == 0) throw new Exception("No items to monitor!");

            foreach (clsOPCUAElement element in nodesToMonitor)
            {
                //Configure MonitoredItem
                MonitoredItem m = new MonitoredItem(this.Subscription.DefaultItem);
                m.StartNodeId = element.NodeID;
                m.AttributeId = Attributes.Value;
                m.DiscardOldest = true;
                m.MonitoringMode = MonitoringMode.Reporting;
                m.QueueSize = 0;
                m.SamplingInterval = 200;
                
                //Add eventhandler
                m.Notification += this.MonitoredItemHandler;        
                
                //Add to subscription
                this.Subscription.AddItem(m);
            }                

            //This is essential! 
            this.Subscription.ApplyChanges();

        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex.ToString());
        }

    }

MonitoredItemHandler - 捕获通知,将其序列化为 clsOPCUAElement,并触发一个新的事件,可以从其他对象订阅。
        public virtual void MonitoredItemHandler(MonitoredItem item, MonitoredItemNotificationEventArgs args)
    {
        try
        {
            Console.WriteLine("MonitoredItemHandler: " + item.StartNodeId.ToString());
            OnMonitoredItemChanged?.Invoke(new clsOPCUAElement(item.StartNodeId.ToString(), item.LastValue, item.LastValue.GetType()));

        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex.ToString());
        }
    }

clsOPCUAElement(它只是一个容器,我们从包含整个变量树的JSON结构中反序列化元素)

    public class clsOPCUAElement
{
    

    /**
     * 
     */
    public clsOPCUAElement(String _NodeID, Object _Value = default, Type _Type = default)
    {
        if (_NodeID.Length == 0) throw new ArgumentException("NodeID mustn't be empty!");
        this.NodeID = _NodeID;
        this.Value = _Value;
        this.Type = _Type;
    }

    public String NodeID;
    public Object Value;
    public Type Type;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接