Windows 服务,写入 OPC 需要很长时间才能写入 OPC 对象

问题描述 投票:0回答:1

我有一个正在运行的 Windows 服务

  1. 调用API服务并获取车辆的位置数据和时间戳
  2. 使用 OpcDA 将时间戳和位置名称写入同一服务器中的 OPC 对象

服务以 15 秒的间隔运行。 服务循环遍历大约 7 个对象,并将时间戳和位置写入其中。

问题: 问题是OPC对象的更新需要很长时间, 它以 15 秒的间隔自行运行循环,对象在 3,4 和 8 分钟的间隔内更新。

这是我的代码

    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);
                }                
      }
c# windows-services opc opc-da
1个回答
0
投票
  1. 您不需要连接每个计时器滴答声。服务运行时保持连接打开。
  2. 您在 OnTimer、PopulateParalellOpcAsync 和 PopulateOpc 中多次 ConnectToOpc - 这可能就是原因。
  3. 您是否使用 Matrikon OPC Explorer 等工具手动写入值?是否成功且快速?如果没有,请检查您的网络连接,尤其是当您有多个网络连接时。
  4. opcUri 中服务器如何引用?作为本地服务器还是使用网络路径?
© www.soinside.com 2019 - 2024. All rights reserved.