From 9dfe40cefabeec59af307e4de244d60a65b71516 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Thu, 30 Nov 2023 19:27:55 +0100 Subject: [PATCH] Gestione null read con errori e disconnessione --- IOB-UT-NEXT/ToMapo.cs | 5 ++ IOB-WIN-NEXT/IobOpc/OpcUa.cs | 22 ++++- IOB-WIN-NEXT/UAClient.cs | 163 +++++++++-------------------------- 3 files changed, 67 insertions(+), 123 deletions(-) diff --git a/IOB-UT-NEXT/ToMapo.cs b/IOB-UT-NEXT/ToMapo.cs index 776a6063..0e80d735 100644 --- a/IOB-UT-NEXT/ToMapo.cs +++ b/IOB-UT-NEXT/ToMapo.cs @@ -632,6 +632,11 @@ namespace IOB_UT_NEXT /// public bool UseFullId { get; set; } = false; + /// + /// Numero massimo di letture null prima di disconnettere il client + /// + public int maxNullRead { get; set; } = 1000; + /// /// Base del NameSpace usato per le funzionalità di translate (parametri ACT --> SET) /// diff --git a/IOB-WIN-NEXT/IobOpc/OpcUa.cs b/IOB-WIN-NEXT/IobOpc/OpcUa.cs index 7cb11745..a7187c27 100644 --- a/IOB-WIN-NEXT/IobOpc/OpcUa.cs +++ b/IOB-WIN-NEXT/IobOpc/OpcUa.cs @@ -533,7 +533,7 @@ namespace IOB_WIN_NEXT.IobOpc } else { - lgTrace($"checkAndSend ERROR | MonIt: {MonIt.DisplayName} | NotifyValue Null!!!"); + lgError($"checkAndSend ERROR | MonIt: {MonIt.DisplayName} | NotifyValue Null!!!"); } } else @@ -1452,7 +1452,7 @@ namespace IOB_WIN_NEXT.IobOpc lgInfo($"Chiamata UAClient con configurazione standard: {application.ApplicationConfiguration.ApplicationName}"); string userName = opcUaParams == null || opcUaParams.Identity == null ? "" : opcUaParams.Identity.UserName; string passwd = opcUaParams == null || opcUaParams.Identity == null ? "" : opcUaParams.Identity.Passwd; - UA_ref = new UAClient(application.ApplicationConfiguration, cIobConf.codIOB, userName, passwd, isVerboseLog, ClientBase.ValidateResponse); + UA_ref = new UAClient(application.ApplicationConfiguration, cIobConf.codIOB, userName, passwd, isVerboseLog, ClientBase.ValidateResponse, opcUaParams.maxNullRead); lgInfo($"Chiamata apertura OpcUa Client: {cIobConf.cncIpAddr}:{port}"); UA_ref.ServerUrl = $"opc.tcp://{cIobConf.cncIpAddr}:{port}"; @@ -1594,6 +1594,8 @@ namespace IOB_WIN_NEXT.IobOpc } } } + // gestione ricezione null + UA_ref.eh_nullExceed += UA_ref_eh_nullExceed; // gestione eventi change UA_ref.eh_MonItChange += UA_ref_eh_MonItChange; lgInfo("eh_MonItChange event registered"); @@ -1614,7 +1616,7 @@ namespace IOB_WIN_NEXT.IobOpc // controllo read error ed eventuale disconnect if (readErrorCurr > readErrorMax) { - lgError($"Effettuo disconnessione x superamento errori lettura UA_ref.ReadNode, sleetp 15 sec"); + lgError($"Effettuo disconnessione x superamento errori lettura UA_ref.ReadNode, sleep {readErrorSleepTime}msec"); tryDisconnect(); Thread.Sleep(readErrorSleepTime); readErrorCurr = 0; @@ -1622,6 +1624,20 @@ namespace IOB_WIN_NEXT.IobOpc return esitoLink; } + /// + /// Ricevuto troppi null --> disconnetto e traccio + /// + /// + /// + /// + private void UA_ref_eh_nullExceed(object sender, int e) + { + lgError($"Effettuo disconnessione x superamento letture UA_ref.ReadNode a NULL ({e}), sleep {2 * readErrorSleepTime}msec"); + tryDisconnect(); + Thread.Sleep(2 * readErrorSleepTime); + readErrorCurr = 0; + } + /// /// Formatta un dataitem x salvataggio in memoria locale /// diff --git a/IOB-WIN-NEXT/UAClient.cs b/IOB-WIN-NEXT/UAClient.cs index 1d6fc593..2d32b013 100644 --- a/IOB-WIN-NEXT/UAClient.cs +++ b/IOB-WIN-NEXT/UAClient.cs @@ -72,8 +72,17 @@ namespace IOB_WIN_NEXT /// /// Initializes a new instance of the UAClient class. /// - public UAClient(ApplicationConfiguration configuration, string codIOB, string user, string pwd, bool verboseLog, Action validateResponse) + /// + /// + /// + /// + /// + /// + /// Numero massimo di risposte nulle in browsing prima di disconnettersi + public UAClient(ApplicationConfiguration configuration, string codIOB, string user, string pwd, bool verboseLog, Action validateResponse, int maxNullRead) { + currNullReceiv = 0; + maxNullAllowed = maxNullRead; m_validateResponse = validateResponse; currIob = codIOB; lg = LogManager.GetCurrentClassLogger(); @@ -99,6 +108,11 @@ namespace IOB_WIN_NEXT /// public event EventHandler eh_MonItChange; + /// + /// Evento notifica superamento numero letture null + /// + public event EventHandler eh_nullExceed; + #endregion Public Events #region Public Properties @@ -393,8 +407,6 @@ namespace IOB_WIN_NEXT try { - //#region Read a node by calling the Read Service - //// build a list of nodes to be read //ReadValueIdCollection nodesToRead = new ReadValueIdCollection() //{ @@ -427,10 +439,6 @@ namespace IOB_WIN_NEXT // lgInfo("Read Value = {0} , StatusCode = {1}", result.Value, result.StatusCode); //} - //#endregion Read a node by calling the Read Service - - #region Read the Value attribute of a node by calling the Session.ReadValue method - try { DataValue resp = m_session.ReadValue(reqNodeId); @@ -447,8 +455,6 @@ namespace IOB_WIN_NEXT numErrors++; lgTrace($"ReadValue Error | reqNodeId: {reqNodeId} | numErrors: {numErrors}{Environment.NewLine}{exc}"); } - - #endregion Read the Value attribute of a node by calling the Session.ReadValue method } catch (Exception ex) { @@ -466,8 +472,6 @@ namespace IOB_WIN_NEXT return answ; } - protected int maxErrors = 20; - /// /// Read a SINGLE of nodes value (RAW) from Server /// @@ -507,8 +511,6 @@ namespace IOB_WIN_NEXT return answ; } - protected int numErrors = 0; - /// /// Read a list of nodes from Server /// @@ -618,83 +620,6 @@ namespace IOB_WIN_NEXT monItList.Add(currMonIt); } -#if false - MonitoredItem IO_120_00_MonitoredItem = new MonitoredItem(subscription.DefaultItem); - // Int32 Node - Objects\CTT\Scalar\Simulation\Int32 - IO_120_00_MonitoredItem.StartNodeId = new NodeId("ns=4;s=IO_120.00"); - IO_120_00_MonitoredItem.AttributeId = Attributes.Value; - IO_120_00_MonitoredItem.DisplayName = "IO_120 Variable"; - IO_120_00_MonitoredItem.SamplingInterval = 1000; - IO_120_00_MonitoredItem.Notification += OnMonitoredItemNotification; - subscription.AddItem(IO_120_00_MonitoredItem); - - MonitoredItem IO_120_01_MonitoredItem = new MonitoredItem(subscription.DefaultItem); - // Int32 Node - Objects\CTT\Scalar\Simulation\Int32 - IO_120_01_MonitoredItem.StartNodeId = new NodeId("ns=4;s=IO_120.01"); - IO_120_01_MonitoredItem.AttributeId = Attributes.Value; - IO_120_01_MonitoredItem.DisplayName = "IO_120_01 Variable"; - IO_120_01_MonitoredItem.SamplingInterval = 1000; - IO_120_01_MonitoredItem.Notification += OnMonitoredItemNotification; - subscription.AddItem(IO_120_01_MonitoredItem); - - MonitoredItem IO_130_MonitoredItem = new MonitoredItem(subscription.DefaultItem); - // Int32 Node - Objects\CTT\Scalar\Simulation\Int32 - IO_130_MonitoredItem.StartNodeId = new NodeId("ns=4;s=IO_130"); - IO_130_MonitoredItem.AttributeId = Attributes.Value; - IO_130_MonitoredItem.DisplayName = "IO_130 Variable"; - IO_130_MonitoredItem.SamplingInterval = 1000; - IO_130_MonitoredItem.Notification += OnMonitoredItemNotification; - subscription.AddItem(IO_130_MonitoredItem); - - MonitoredItem IO_135_MonitoredItem = new MonitoredItem(subscription.DefaultItem); - // Int32 Node - Objects\CTT\Scalar\Simulation\Int32 - IO_135_MonitoredItem.StartNodeId = new NodeId("ns=4;s=IO_135"); - IO_135_MonitoredItem.AttributeId = Attributes.Value; - IO_135_MonitoredItem.DisplayName = "IO_135 Variable"; - IO_135_MonitoredItem.SamplingInterval = 1000; - IO_135_MonitoredItem.Notification += OnMonitoredItemNotification; - subscription.AddItem(IO_135_MonitoredItem); - - MonitoredItem IO_140_MonitoredItem = new MonitoredItem(subscription.DefaultItem); - // Int32 Node - Objects\CTT\Scalar\Simulation\Int32 - IO_140_MonitoredItem.StartNodeId = new NodeId("ns=4;s=IO_140"); - IO_140_MonitoredItem.AttributeId = Attributes.Value; - IO_140_MonitoredItem.DisplayName = "IO_140 Variable"; - IO_140_MonitoredItem.SamplingInterval = 1000; - IO_140_MonitoredItem.Notification += OnMonitoredItemNotification; - subscription.AddItem(IO_140_MonitoredItem); - - //MonitoredItem intMonitoredItem = new MonitoredItem(subscription.DefaultItem); - //// Int32 Node - Objects\CTT\Scalar\Simulation\Int32 - //intMonitoredItem.StartNodeId = new NodeId("ns=2;s=Scalar_Simulation_Int32"); - //intMonitoredItem.AttributeId = Attributes.Value; - //intMonitoredItem.DisplayName = "Int32 Variable"; - //intMonitoredItem.SamplingInterval = 1000; - //intMonitoredItem.Notification += OnMonitoredItemNotification; - - //subscription.AddItem(intMonitoredItem); - - //MonitoredItem floatMonitoredItem = new MonitoredItem(subscription.DefaultItem); - //// Float Node - Objects\CTT\Scalar\Simulation\Float - //floatMonitoredItem.StartNodeId = new NodeId("ns=2;s=Scalar_Simulation_Float"); - //floatMonitoredItem.AttributeId = Attributes.Value; - //floatMonitoredItem.DisplayName = "Float Variable"; - //floatMonitoredItem.SamplingInterval = 1000; - //floatMonitoredItem.Notification += OnMonitoredItemNotification; - - //subscription.AddItem(floatMonitoredItem); - - //MonitoredItem stringMonitoredItem = new MonitoredItem(subscription.DefaultItem); - //// String Node - Objects\CTT\Scalar\Simulation\String - //stringMonitoredItem.StartNodeId = new NodeId("ns=2;s=Scalar_Simulation_String"); - //stringMonitoredItem.AttributeId = Attributes.Value; - //stringMonitoredItem.DisplayName = "String Variable"; - //stringMonitoredItem.SamplingInterval = 1000; - //stringMonitoredItem.Notification += OnMonitoredItemNotification; - - //subscription.AddItem(stringMonitoredItem); -#endif - // Create the monitored items on Server side subscription.ApplyChanges(); lgInfo($"MonitoredItems created for SubscriptionId = {subscription.Id}"); @@ -707,7 +632,7 @@ namespace IOB_WIN_NEXT } /// - /// Write a list of nodes to the Server + /// Write a list of nodes to the Server /// /// public void WriteNodes(List node2Write) @@ -846,32 +771,6 @@ namespace IOB_WIN_NEXT qtyWriteVal.Value.Value = (int)hhmm + 10; nodesToWrite.Add(qtyWriteVal); -#if false - //// Int32 Node - Objects\CTT\Scalar\Scalar_Static\Int32 - //WriteValue intWriteVal = new WriteValue(); - //intWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_Int32"); - //intWriteVal.AttributeId = Attributes.Value; - //intWriteVal.Value = new DataValue(); - //intWriteVal.Value.Value = (int)100; - //nodesToWrite.Add(intWriteVal); - - //// Float Node - Objects\CTT\Scalar\Scalar_Static\Float - //WriteValue floatWriteVal = new WriteValue(); - //floatWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_Float"); - //floatWriteVal.AttributeId = Attributes.Value; - //floatWriteVal.Value = new DataValue(); - //floatWriteVal.Value.Value = (float)100.5; - //nodesToWrite.Add(floatWriteVal); - - //// String Node - Objects\CTT\Scalar\Scalar_Static\String - //WriteValue stringWriteVal = new WriteValue(); - //stringWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_String"); - //stringWriteVal.AttributeId = Attributes.Value; - //stringWriteVal.Value = new DataValue(); - //stringWriteVal.Value.Value = "String Test"; - //nodesToWrite.Add(stringWriteVal); -#endif - // Write the node attributes StatusCodeCollection results = null; DiagnosticInfoCollection diagnosticInfos; @@ -907,6 +806,10 @@ namespace IOB_WIN_NEXT protected static bool isLogVerbose = false; protected static Logger lg; + protected int currNullReceiv = 0; + protected int maxErrors = 20; + protected int maxNullAllowed = 100; + protected int numErrors = 0; #endregion Protected Fields @@ -1002,12 +905,32 @@ namespace IOB_WIN_NEXT // Log MonitoredItem Notification event MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification; - // sollevo evento notifica vaziazione MonitoredItem - if (eh_MonItChange != null) + // verifico se ricevo null, superata soglia genero eccezione + if ($"{notification.Value}" == "(null)") { - eh_MonItChange(this, new opcUaMonitItemChange(monitoredItem, notification)); + currNullReceiv++; + } + else + { + currNullReceiv--; + currNullReceiv = currNullReceiv > 0 ? currNullReceiv : 0; + // sollevo evento notifica vaziazione MonitoredItem + if (eh_MonItChange != null) + { + eh_MonItChange(this, new opcUaMonitItemChange(monitoredItem, notification)); + } } lgTrace($"Notification Received | Variable: {monitoredItem.DisplayName} | Value: {notification.Value}"); + // se ho ricevuto troppi nul --> disconnetto + if (currNullReceiv > maxNullAllowed) + { + if (eh_nullExceed != null) + { + eh_nullExceed(this, currNullReceiv); + } + // reset + currNullReceiv = 0; + } } catch (Exception ex) {