3

I have a FactoryTalk server with some nodes and I need to monitor several attribute values.

I made a client which reads and writes data succesfully, but I can't get the subscription to work.

Here's the subscription configuration:

subscription = new Subscription(session.DefaultSubscription)
{
    DisplayName = "Test subscription",
    PublishingEnabled = true,
    PublishingInterval = 500,
    LifetimeCount = 0,
};

My monitored items:

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

And I assign them the notification handler (I need the protocol object instance here, so I tweaked it):

MonitoredItemNotificationEventHandler monitoredItemEventHandler = (monitoredItem, e) => AttributeNotification(monitoredItem, e, protocol);

Then I add the event handlers:

foreach (var monitoredItem in monitoredItems)
{
    monitoredItem.Notification += monitoredItemEventHandler;
}

And I add the items to the subscription and create it:

subscription.AddItems(monitoredItems);
session.AddSubscription(subscription);
subscription.Create();

I've checked through the console and the subscription gets created and assigned an ID by the server. I check all the monitored items as well, CreateMonitoredItems service call succeeds, and they also get client handles assigned, NodeId's are correctly resolved, with no error StatusCodes.

I make changes to the attributes via a 3rd party client application called UaExpert.

Yet I can't get the notification event handler to fire off.

Did I do something wrong? Does anyone have advice on how to resolve/debug this?

infradude
  • 31
  • 4
  • Are you adding an Eventhandler function to the monitored items?: `monitoredItem.Notification += MyItemChangedHandler;` – Victor Pieper Jun 20 '23 at 09:51
  • Yes, sorry I forgot to add the snippet. Updated the question. – infradude Jun 20 '23 at 14:00
  • I don't know if it will help but this this eventhandler works for me: `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 Jun 20 '23 at 14:08

1 Answers1

0

Today I struggled at the same point. The documentation of the UA-.NETStandard is not, what it should be. After all I found the clue in this example: https://github.com/OPCFoundation/UA-.NETStandard/blob/54f7f8aa9b2e07531f73dadd6e4bd933566302ee/Applications/ConsoleReferenceClient/UAClient.cs#L387

To Add a monitoredItem with Notification to an OPCUA Subscription in .NET try the following code.

Add monitored Item

     /**
     * 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 - picks up the notification, serialize it to clsOPCUAElement and fire a new Event, wich can be subscribed from other objects

        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 (it's just a container, we deserialize the elements from a json structure containing the whole variable tree)

    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;
}
Robin
  • 1
  • 2