convertersystems / opc-ua-client

Visualize and control your enterprise using OPC Unified Architecture (OPC UA) and Visual Studio.
MIT License
395 stars 112 forks source link

Missing Notifications #192

Closed bkohlmaier closed 3 years ago

bkohlmaier commented 3 years ago

We have a big application, with 13 PLCs and approx. 1500 OPC tags with DataChange notifications. At startup everything is working, but after some time we are missing some data changes. After that point, NO more changes are received for these Tags (other tags are still working).

I dont know, why the "subscription is broken." The ex=> path is not triggered in my channel.Subscribe. The response to CreateMonitoredItemsAsync is checked - Every StatusCode is good. How do i get a clue what is going on ?

Is there a "best practice" for using this amount of notifications ? Is it better to create one CreateSubscriptionRequest with 1500 ItemsToCreate, or better 1500 CreateSubscriptionRequest with each 1 ItemsToCreate ? Is there a maximum amount of ItemsToCreate for one CreateSubscriptionRequest ?

Thanx in advance,

awcullen commented 3 years ago

Hi, The best practice is to create fewer Subscriptions, with each Subscription containing the maximum number of MonitoredItems that the PLC vendor will support.

PLC vendors limit the number of Subscriptions and the number of MonitoredItems in a Subscription. For example, the Siemens S7 1500 and 1200 limits are listed below. https://support.industry.siemens.com/cs/document/109755846/what-are-the-system-limits-of-the-opc-ua-server-with-s7-1500-and-s7-1200-?dti=0&pnid=13616&lc=en-US

bkohlmaier commented 3 years ago

Now i have changed my code for one subscription per PLC each with max 250 items. But i am still missing notifications. What can i do to find out what is going wrong? Is it a good idea, to create one channel per PLC? Or maybe i have a problem with multithreading? (I am writing some tags from different theads). I also noticed, when debugging my application in single stepping, i "block" the App and the communication. When doing this, i reach the point where i miss notifications very fast. So i changed the Code to parse the notifications in a separate Task to NOT block the Code. But this didnt solve my problem. I really need help urgent... Thanx.

awcullen commented 3 years ago

You should create one channel per PLC. Could you share some of your code? There are a number of timeouts and other settings that you can adjust to improve the performance.

awcullen commented 3 years ago

I would start with these settings:

MonitoredItem: SamplingInterval: 1000 ms QueueSize: 1 DiscardOldest: true

Subscription: PublishingInterval: 1000 ms KeepAliveCount: 20 LifetimeCount: 60

bkohlmaier commented 3 years ago

I forgot to mention: we have one OPC Server installed on the LinePC where the Application runs. The OPC Server has configured the 15 PLCs. Therefore i have made only one channel to communicate with the OPC Server.

A SamplingInterval of 1000ms will be too slow for us, because we send commands to the PLC and await a response after the execution. So for this interaction: the faster the better. 50ms is the fastest the PLC supports - this is the RevisedSamplingInterval the PLC reports. But this leads to a CPU load of constantly (at least) 25% of the OPC Server. So currently we are using 100ms.

Sample code snippets are attached. opc-ua-client-snippets.zip

One quick question: Do i have to manually send a new PublishRequests before the LifeTimeCount expires ? Or is this handled by the library ?

Thanx in advance.

djonasdev commented 3 years ago

@bkohlmaier

I can give you the following information and tips from my side (My largest project currently comprises 18 PLCs, exclusively Simatic 1500 and 1200 CPUs):

CreateSubscriptionRequest

var subscriptionRequest = new CreateSubscriptionRequest
{
    RequestedPublishingInterval = publishingInterval,
    RequestedMaxKeepAliveCount = 30,
    RequestedLifetimeCount = 30 * 3,
    PublishingEnabled = true
};

MonitoredItemCreateRequest

new MonitoredItemCreateRequest
{
    ItemToMonitor = new ReadValueId
    {
        NodeId = fooNodeId, AttributeId = AttributeIds.Value
    },
    MonitoringMode = MonitoringMode.Reporting,
    RequestedParameters = new MonitoringParameters
    {
        ClientHandle = fooClientHandle, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true
    }
}

avoid using Thread.Sleep(xxx)! Always use await Task.Delay(xxx) if possible.

I've uploaded my SubscriptionManager class to show you my way of managing subscriptions. In order to use them you will have to make some adjustments, as I am using some self-written classes. However, these are easy to replace.

Link: https://gist.github.com/dojo90/a660b5181d980c2a070b1b730aba733c

djonasdev commented 3 years ago

@bkohlmaier is there any news about this?

bkohlmaier commented 3 years ago

I had not the chance to test this at the application where the problem exists. Due to customer decision, we had to change to OPC-DA (which is slower - but stable here).

I made all your suggested changes in an other application - which is a little bit smaller. This application is stable running (but is was also before the changes)

So i can't give you reliable feedback right now. I hope i will get the chance to test it at the original application ... then i will give you feedback.

awcullen commented 3 years ago

Thanks for the update.