Search code examples
c#.netopcsiemensopc-da

OPC dll - How to retrieve tags value in bulk


I'm using OPCSiemensDAAutomation dll with C# .NET to retrieve tag's value from OPC Server. I managed to retrieve the values using QueryAvailableProperties() and GetItemProperties(), but the objective is to retrieve 500k tags value per request.

I have tested with 100 tags and the code finished it in 45 seconds, with multi threading resulted in a small improvement of 30 seconds for 100 tags. It'll requires more than 4 hours to achieve the targeted tags volume with current speed. Is there any way that I can retrieve the tags value in bulk with better performance? Thanks.

var opcServer = new OPCSiemensDAAutomation.OPCServer();
opcServer.Connect("PCS7.OPCDAServer.1");
ConcurrentBag<DataRow> myBag = new ConcurrentBag<DataRow>(dt.AsEnumerable().ToList());
Parallel.ForEach(myBag, data =>
{
    if (count <= num)
    {
        int cnt;
        Array propertyIds, descriptions, dataTypes, errors, vals;
        try
        {
            opcServer.QueryAvailableProperties(data[0].ToString(), out cnt, out propertyIds, out descriptions, out dataTypes);
            opcServer.GetItemProperties(data[0].ToString(), cnt, propertyIds, out vals, out errors);
            Tags tag = new Tags();
            tag.Id = data[0].ToString();
            tag.Value = vals.GetValue(2).ToString();
            tags.Add(tag);
            Interlocked.Increment(ref count);
        }
        catch
        { }
    }
});

Solution

  • You can create OPC Groups:

    OPCGroup myGroup = myServer.addGroup(groupName, isActive, isSubscribed, updateRate);
    

    And then you can add tags to your group:

    myGroup.OPCItems.AddItem("FullAddress", ClientHandle) //a unique number inside the group
    

    The FullAddress is composed of the OPCChannel name, the connection name and the complete address, ie: S7:[MyPLCName]DB1.dbx4.

    When you have the group fully populated, you can read all the variables at once.

    int itemCount = myGroup.OPCItems.Count;
    object qualities = null;
    object timeStamps = null;
    object errors = null;
    int serverHandles[itemCount];
    Array values = Array.CreateInstance(TypeOf(object), {itemCount },{1})
    for (int i = 0; i < itemCount; i++){
       serverHandles[i] = myGroup.OPCItems.Item(i + 1).ServerHandle;
       values.SetValue("", i);
    }
    
    myGroup.SyncRead(OPCSiemensDAAutomation.OPCDataSource.OPCDevice, itemCount + 1, ServerHandles, values, errors, qualities, timeStamps);
    

    Then you will have four new arrays related to the first one serverHandles.

    It is wise to check the qualities array before using the data from the values one.