Vegard H
Vegard H

Reputation: 1

OPC UA Client capture the lost item values from the UA server after a disconnect/connection error?

I am building a OPC UA Client using OPC Foundation SDK. I am able to create a subscription containing some Monitoreditems.

On the OPC UA server these monitored items change value constantly (every second or so).

I want to disconnect the client (simulate a connection broken ), keep the subcription alive and wait for a while. Then I reconnect having my subscriptions back, but I also want all the monitored Item values queued up during the disconnect. Right now I only get the last server value on reconnect.

I am setting a queuesize:

monitoredItem.QueueSize = 100;

To kind of simulate a connection error I have set the "delete subscription" to false on ClosesSession: m_session.CloseSession(new RequestHeader(), false);

My question is how to capture the content of the queue after a disconnect/connection error???

Should the ‘lost values’ be “new MonitoredItem_Notification” automatically when the client reconnect?

Should the SubscriptionId be the same as before the connection was broken?

Should the sessionId be the same or will a new SessionId let med keep the existing subscriptions? What is the best way to simulate a connection error?

Many questions :-)

A sample from the code where I create the subscription containing some MonitoredItems and the MonitoredItem_Notification event method.

Any OPC UA Guru out there??

if (node.Displayname == "node to monitor")
{
   MonitoredItem mon = CreateMonitoredItem((NodeId)node.reference.NodeId, node.Displayname);
   m_subscription.AddItem(mon);
   m_subscription.ApplyChanges();
}
private MonitoredItem CreateMonitoredItem(NodeId nodeId, string displayName)
{
    if (m_subscription == null)
    {

        m_subscription = new Subscription(m_session.DefaultSubscription);

        m_subscription.PublishingEnabled = true;
        m_subscription.PublishingInterval = 3000;//1000;
        m_subscription.KeepAliveCount = 10;
        m_subscription.LifetimeCount = 10;
        m_subscription.MaxNotificationsPerPublish = 1000;
        m_subscription.Priority = 100;
        bool cache = m_subscription.DisableMonitoredItemCache;

        m_session.AddSubscription(m_subscription);

        m_subscription.Create();
    }

        // add the new monitored item.
        MonitoredItem monitoredItem = new MonitoredItem(m_subscription.DefaultItem);
        //Each time a monitored item is sampled, the server evaluates the sample using a filter defined for each monitoreditem.
        //The server uses the filter to determine if the sample should be reported. The type of filter is dependent on the type of item.
        //DataChangeFilter for Variable, Eventfilter when monitoring Events. etc
        //MonitoringFilter f = new MonitoringFilter();
        //DataChangeFilter f = new DataChangeFilter();
        //f.DeadbandValue

        monitoredItem.StartNodeId = nodeId;
        monitoredItem.AttributeId = Attributes.Value;
        monitoredItem.DisplayName = displayName;
        //Disabled, Sampling, (Report (includes sampling))
        monitoredItem.MonitoringMode = MonitoringMode.Reporting;
        //How often the Client wish to check for new values on the server. Must be 0 if item is an event.
        //If a negative number the SamplingInterval is set equal to the PublishingInterval (inherited)
        //The Subscriptions KeepAliveCount should always be longer than the SamplingInterval/PublishingInterval
        monitoredItem.SamplingInterval = 500;
        //Number of samples stored on the server between each reporting
        monitoredItem.QueueSize = 100;
        monitoredItem.DiscardOldest = true;//Discard oldest values when full
        monitoredItem.CacheQueueSize = 100;

        monitoredItem.Notification += m_MonitoredItem_Notification;

        if (ServiceResult.IsBad(monitoredItem.Status.Error))
        {
            return null;
        }

        return monitoredItem;
    }



    private void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new MonitoredItemNotificationEventHandler(MonitoredItem_Notification), monitoredItem, e);
            return;
        }

    try
        {
            if (m_session == null)
            {
                return;
            }

        MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;

        if (notification == null)
        {
            return;
        }


            string sess = m_session.SessionId.Identifier.ToString();
            string s = string.Format(" MonitoredItem: {0}\t Value: {1}\t Status: {2}\t SourceTimeStamp: {3}", monitoredItem.DisplayName, (notification.Value.WrappedValue.ToString().Length == 1) ? notification.Value.WrappedValue.ToString()  : notification.Value.WrappedValue.ToString(), notification.Value.StatusCode.ToString(), notification.Value.SourceTimestamp.ToLocalTime().ToString("HH:mm:ss.fff"));
            richTextBox1.AppendText(s + "SessionId: " + sess);
        }
        catch (Exception exception)
        {
            ClientUtils.HandleException(this.Text, exception);
        }
    }e here

Upvotes: 0

Views: 1801

Answers (1)

Kevin Herron
Kevin Herron

Reputation: 7005

I don't know how much of this, if any, the SDK you're using does for you, but the approach when reconnecting is generally:

  1. try to resume (re-activate) your old session. If this is successful your subscriptions will already exist and all you need to do is send more PublishRequests. Since you're trying to test by closing the session this probably won't work.

  2. create a new session and then call the TransferSubscription service to transfer the previous subscriptions to your new session. You can then start sending PublishRequests and you'll get the queued notifications.

Again, depending on the stack/SDK/toolkit you're using some or none of this may be handled for you.

Upvotes: 1

Related Questions