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?
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With