Windows service, writes to OPC takes long time to write to the OPC-object

47 views Asked by At

I have a windows service which has in function

  1. call API service and get location data and Timestamp off vehicles
  2. write the timestamp and the location name to OPC-objects in the same server using OpcDA

The service is running with 15-secunds interval. it's about 7 objects that the service is looping over and write the timestamp and the location into it.

Problem: The problem is that the update of the OPC-objects takes long time, The cycle it self run with 15 seconds interval men the objects got updated within 3,4 and 8 minutes interval.

here is my code

    public  void OnTimer(object sender, ElapsedEventArgs args)
    {
        ConnectToOpc();
        Task.Run(RunCoreFunction);            
        Task.Run(ImportData);
        
    }

   private  async Task RunCoreFunction()
    {
       
        keepRunning = true;
        try
        {
           await PopulateDevices();
              _ = PopulateParalellOpcAsync();
            Heartbeat();
        }
      
        catch (Exception ex)
        {
            _logger.Log(ex.Message + ex.StackTrace.ToString(), "RunCoreFunction", LogType.Error);
        }
    } 

// Bings location name and timestamp from external API and but it inside a list of objects called currCallsResult 
  private async Task PopulateDevices()
    {
        try
        {

            string _restApiUrl = restApiUrl; 
            currCallsResult = await APIProcessor.LoadDeviceInfoFromPBE(_restApiUrl);

            foreach (PBEResult obj in currCallsResult)
            {
                int result = GetMacInMacArray(obj.SystemId);
                if (result == -1)
                {
                    obj.location = null;
                }
                else
                {
                    _logger.Log("Updated entries on " + obj.SystemId + " that is on index: " + result, functionName, LogType.Vehicle);
                }
            }
        }
        catch (Exception ex)
        {
            BreakCoreFunction(ex.Message + " Something wrong with the REST-API");
            _logger.Log(ex.Message + " " + ex.InnerException + " " + ex.StackTrace.ToString(), functionName, LogType.Error);
        }
        _logger.Log("PopluateDevices Finished, Fetch vehicleData from API", functionName, LogType.Main);
    }


 private async Task PopulateParalellOpcAsync()
    {
        ConnectToOpc(); // Connects to the OPC
        _logger.Log(" PopulateParalellOpcAsync Begins", "PopulateParalellOpcAsync", LogType.Main);

        if (currCallsResult != null && currCallsResult.Count > 0)
        {
            var nrOfItems = macArray.Count(x => x != null && x != "EMPTY");  
            if (nrOfItems > 0)
            {

                List<Task> tasks = new List<Task>();
                foreach (PBEResult _obj in currCallsResult)
                {
                    if (_obj.SystemId != null)
                    {
                        //Write data into OPC Object
                        tasks.Add(Task.Run(() => PopulateOpc(_obj)));
                    }
                }
                await Task.WhenAll(tasks);
            }
        }
        else
        {
            _logger.Log(" Can't populate OPC, currCallsResult from the API is empty", "PopulateParalellOpcAsync", LogType.Main);
        }
}


 private async Task<string> PopulateOpc(PBEResult obj) // Writes to the objects.
    {
        int assetID = 0;
        string _checkTag2 = "";           
        if (obj.SystemId != null)
        {                    
                assetID = GetMacInMacArray(obj.SystemId);                  
                if (assetID > 0)
                {
                    try
                    {
                        ConnectToOpc();                           
                        _checkTag2 = await opcMngr.ReadTagAsync(opcTag + assetID + ".LocationData" + ".MacAddress");                           

                        if (!(String.IsNullOrEmpty(_checkTag2)))
                        {
                           
                            opcMngr.WriteStringTagAsync(opcTag + assetID + ".LocationData" + ".Timestamp", obj.TimeStamp.ToString());
                            opcMngr.WriteStringTagAsync(opcTag + assetID + ".LocationData" + ".LocationName", obj.location);
                            _logger.Log(" OPC Tags Updated AssetName: " + obj.AssetName, functionName, LogType.Main);
                        }
                        else
                        {
                            _logger.Log("Error, Look att Error log file  ", functionName, LogType.Main);                                
                    }
                    catch (Exception e)
                    {
                        _logger.Log("Error, Look att Error log file  ", functionName, LogType.Main);
                    }
                }                
        }
        else
        {               
            _logger.Log(", SystemId is null " + obj.AssetName, functionName, LogType.Main);
        }
        return null;
    } 

  private void ConnectToOpc()
    {  
                if ((opcMngr == null) || (opcMngr.Status != "Connected")) // Checks if opcMngr exist and/or is connected
                {
                    _logger.Log("Connecting to OPC", "ConnectToOPC", LogType.Main);
                    opcMngr = new OpcManager(opcUri);
                    _logger.Log("Connected!", "ConnectToOPC", LogType.Main);
                }                
      }
1

There are 1 answers

0
rotabor On
  1. You don't need connecting every timer tick. Keep the connection open while the service is running. Otherwise disconnect respectively.
  2. You ConnectToOpc many times in: OnTimer, PopulateParalellOpcAsync, and PopulateOpc - it can be the reason.
  3. Did you write a value manually using any tool like Matrikon OPC Explorer? Was it successful and fast? If no, check your network connectivity, especially if you have multiple network connections.
  4. How is the server referenced in opcUri? As a local server or using the network path?