diff --git a/CVCncLib/CVCncLib.dll b/CVCncLib/CVCncLib.dll
index eb5b8986..fd43c085 100644
Binary files a/CVCncLib/CVCncLib.dll and b/CVCncLib/CVCncLib.dll differ
diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_001.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_001.json
index 8caafeab..433ca0eb 100644
--- a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_001.json
+++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_001.json
@@ -2,10 +2,10 @@
"BrowseFullVal": "ns=4;s=NxController.GlobalVars",
"BrowseNSIndex": 4,
"BrowseValue": 5001,
- "keyPartCount": "PartDone(0)",
- "keyPartReq": "PartToDo(0)",
+ "keyPartCount": "",
+ "keyPartReq": "",
"keyPartId": "",
- "keyProgName": "PartName(0)",
+ "keyProgName": "",
"keyRunMode": "",
"pingAsPowerOn": true,
"Identity": {
diff --git a/IOB-WIN-NEXT/IobOpcUa.cs b/IOB-WIN-NEXT/IobOpcUa.cs
index 44b6e334..9ea373e7 100644
--- a/IOB-WIN-NEXT/IobOpcUa.cs
+++ b/IOB-WIN-NEXT/IobOpcUa.cs
@@ -252,7 +252,7 @@ namespace IOB_WIN_NEXT
///
///
///
- private void checkAndSend(Opc.Ua.Client.MonitoredItem MonIt, string NotifyValue, bool forceSend)
+ internal void checkAndSend(Opc.Ua.Client.MonitoredItem MonIt, string NotifyValue, bool forceSend)
{
if (MonIt != null)
{
@@ -296,6 +296,64 @@ namespace IOB_WIN_NEXT
}
}
+ ///
+ /// Verifica ed invia variazioni DAL FORMATO RAW data (byte[])
+ ///
+ ///
+ ///
+ ///
+ internal virtual void checkAndSendRaw(Opc.Ua.Client.MonitoredItem MonIt, byte[] NotifyValue, bool forceSend)
+ {
+ if (MonIt != null)
+ {
+ if (NotifyValue != null && NotifyValue.Length > 0)
+ {
+ // versione base: il valore è la stringa composta da TUTTI i valori in BYTE espressi come comma-sep-string
+ StringBuilder sb = new StringBuilder();
+ foreach (var bVal in NotifyValue)
+ {
+ sb.Append($"{bVal},");
+ }
+ string currVal = sb.ToString();
+
+ string sVal = "";
+ string descr = "";
+ DateTime locTStamp = DateTime.Now;
+ descr = itemTranslation("OPC", MonIt.DisplayName);
+ sVal = $"Change: {locTStamp.ToString()} | descr: {descr} | Id: {MonIt.StartNodeId} | Val: {currVal}";
+ lgInfo(sVal);
+
+ // verifico se salvare
+ bool changed = checkSaveValue(MonIt, currVal);
+ // cerco se non sia un dato filtrato in FLUXLOG...
+ bool isFiltered = opcUaParams.fluxLogVeto.Contains(MonIt.DisplayName);
+ if (isFiltered)
+ {
+ lgTrace($"NON ACCODATO sample per {MonIt.DisplayName} - trovato VETO in fluxLogVeto", false);
+ }
+ else
+ {
+ if (changed || forceSend)
+ {
+ accodaFLog(sVal, qEncodeFLog(descr, $"{NotifyValue}"));
+ }
+ else
+ {
+ lgTrace($"NON ACCODATO sample per {MonIt.DisplayName} - verifica variazione ha dato esito negativo", false);
+ }
+ }
+ }
+ else
+ {
+ lgError($"checkAndSend ERROR | MonIt: {MonIt.DisplayName} | NotifyValue Null!!!");
+ }
+ }
+ else
+ {
+ lgError("checkAndSend ERROR: MonIt null");
+ }
+ }
+
///
/// Indica se si debba leggere un area di tipo "encoded" (byte raw --> obj)
///
@@ -305,33 +363,6 @@ namespace IOB_WIN_NEXT
///
protected byte[] byteRawData { get; set; } = new byte[1];
-#if false
- ///
- /// Restitusice una versione serializzata delle variabili complesse in formato string
- ///
- ///
- ///
- ///
- protected virtual string bSerString(string dataType, byte[] rawBytes)
- {
- string answ = "";
-
- return answ;
- }
- ///
- /// Restitusice una versione serializzata delle variabili complesse in formato object (generico)
- ///
- ///
- ///
- ///
- protected virtual object bSerObj(string dataType, byte[] rawBytes)
- {
- object answ = null;
-
- return answ;
- }
-#endif
-
///
/// Vera connessione ad OpcUa
///
@@ -461,19 +492,14 @@ namespace IOB_WIN_NEXT
if (rawVal != null)
{
byteRawData = getByteRaw((DataValue)rawVal);
- StringBuilder sb = new StringBuilder();
- foreach (var bVal in byteRawData)
- {
- sb.Append($"{bVal},");
- }
- currVal = sb.ToString();
+ checkAndSendRaw(item, byteRawData, true);
}
}
else
{
currVal = UA_ref.ReadNode(item.StartNodeId);
+ checkAndSend(item, currVal, true);
}
- checkAndSend(item, currVal, true);
}
}
// gestione eventi change
@@ -574,46 +600,35 @@ namespace IOB_WIN_NEXT
utils.callUrlNow($"{urlSaveDataItems}", rawData);
}
- ///
- /// Data ora ultima lettura RAW data (x lettura periodica forzata...)
- ///
- protected DateTime lastRawDataRead { get; set; } = DateTime.Now.AddMinutes(-1);
-
///
/// Periodo massimo (in sec) per letture dati RAW in mancanza di eventi
///
- protected int rawDataReadMaxElapsed { get; set; } = 90;
+ protected int lastCurrentMaxElapsed { get; set; } = 120;
///
/// Evento rilevazione modifica valori --> chiamo checkSend
///
///
///
- private void UA_ref_eh_MonItChange(object sender, opcUaMonitItemChange e)
+ internal virtual void UA_ref_eh_MonItChange(object sender, opcUaMonitItemChange e)
{
string currVal = "";
// da verificare decodifica valore byte...
if (doByteRead)
{
- // aggiorno ultima lettura
- lastRawDataRead = DateTime.Now;
var currNot = e.CurrNotify;
if (currNot != null)
{
byteRawData = getByteRaw((DataValue)currNot.Value);
- StringBuilder sb = new StringBuilder();
- foreach (var bVal in byteRawData)
- {
- sb.Append($"{bVal},");
- }
- currVal = sb.ToString();
+ checkAndSendRaw(e.CurrMonitoredItem, byteRawData, false);
}
}
else
{
currVal = $"{e.CurrNotify.Value}";
+ checkAndSend(e.CurrMonitoredItem, currVal, false);
}
- checkAndSend(e.CurrMonitoredItem, currVal, false);
+ // aggiorno ultima lettura
lastCurrent = DateTime.Now;
}
@@ -706,7 +721,7 @@ namespace IOB_WIN_NEXT
{
if (!string.IsNullOrEmpty(NotifyValue))
{
- lgTrace($"Richiesta checkSaveSample per {dataItem.DisplayName} | id: {dataItem.StartNodeId} | Valore: {NotifyValue}");
+ lgTrace($"Richiesta checkSaveValue per {dataItem.DisplayName} | id: {dataItem.StartNodeId} | Valore: {NotifyValue}");
// verifico in memoria se ho l'oggetto condition ed il suo valore..
string uuid = $"{dataItem.DisplayName}";
DateTime adesso = DateTime.Now;
@@ -757,7 +772,7 @@ namespace IOB_WIN_NEXT
else
{
// registro non trovato da aggiungere...
- lgInfo($"DataItem non trovato in checkSaveSample: {dataItem.DisplayName}");
+ lgInfo($"DataItem non trovato in checkSaveValue: {dataItem.DisplayName}");
// provo a creare oggetto in memoria...
try
{
@@ -836,8 +851,8 @@ namespace IOB_WIN_NEXT
// bit 0 (poweron) imposto a 1 SE pingo + PowerOn=="ON"...
bool powerOnOk = checkPing && hasPowerOn;
- // controllo se sono poweroff e se non ho dati buoni da > 2 minuti --> disconnetto
- if (!powerOnOk && adesso.Subtract(lastCurrent).TotalMinutes > 2)
+ // controllo se sono poweroff e se non ho dati buoni da > lastCurrentMaxElapsed --> disconnetto
+ if (!powerOnOk && adesso.Subtract(lastCurrent).TotalSeconds > lastCurrentMaxElapsed)
{
tryDisconnect();
}
@@ -1093,7 +1108,7 @@ namespace IOB_WIN_NEXT
// verifico SE sia necessario forzare la lettura RAW
if (doByteRead)
{
- if (DateTime.Now.Subtract(lastRawDataRead).TotalSeconds > rawDataReadMaxElapsed)
+ if (DateTime.Now.Subtract(lastCurrent).TotalSeconds > lastCurrentMaxElapsed)
{
// FIXME TODO !!!
foreach (var item in dataItemMem)
@@ -1103,7 +1118,7 @@ namespace IOB_WIN_NEXT
if (rawVal != null)
{
byteRawData = getByteRaw((DataValue)rawVal);
- lastRawDataRead = DateTime.Now;
+ lastCurrent = DateTime.Now;
currReadErrors = 0;
}
else
diff --git a/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs b/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs
index cb93a84d..7fd8a32c 100644
--- a/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs
+++ b/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs
@@ -222,6 +222,9 @@ namespace IOB_WIN_NEXT
#region Public Constructors
+ ///
+ /// Valore corrente dei dati ICOEL (traduzione JIT da byte[])
+ ///
protected DatiMesIcoel currData
{
get
@@ -240,6 +243,16 @@ namespace IOB_WIN_NEXT
}
}
+ ///
+ /// Ultima versione validata delle info x confronto
+ ///
+ protected DatiMesIcoel lastData { get; set; } = new DatiMesIcoel(new byte[115]);
+
+ internal override void UA_ref_eh_MonItChange(object sender, opcUaMonitItemChange e)
+ {
+ base.UA_ref_eh_MonItChange(sender, e);
+ }
+
///
/// Estende l'init della classe base, impiegando il pacchetto Nuget OPC-UA foundation con la gestione specifica per Omron (es ICOEL)
/// https://github.com/OPCFoundation/UA-.NETStandard
@@ -257,30 +270,110 @@ namespace IOB_WIN_NEXT
doByteRead = true;
lgInfo($"Avviato IobOpcUaOmronIcoel | encodeReadData: {doByteRead}");
}
-
-
-#if false
- protected override object bSerObj(string dataType, byte[] rawBytes)
+ ///
+ /// Verifico se salvare e inviare proprietà specificata
+ ///
+ ///
+ protected void testSendProperty(Opc.Ua.Client.MonitoredItem MonIt, string NotifyValue, bool forceSend)
{
- object answ = null;
- // provo a deserializzare l'oggetto
- try
+ DateTime locTStamp = DateTime.Now;
+ string sVal = "";
+ string descr = "";
+ descr = itemTranslation("OPC", MonIt.DisplayName);
+ sVal = $"Change: {locTStamp.ToString()} | descr: {descr} | Id: {MonIt.StartNodeId} | Val: {NotifyValue}";
+ lgInfo($"TSP | {sVal}");
+
+ bool changed = checkSaveValue(MonIt, NotifyValue);
+ // cerco se non sia un dato filtrato in FLUXLOG...
+ bool isFiltered = opcUaParams.fluxLogVeto.Contains(MonIt.DisplayName);
+ if (isFiltered)
{
- if (rawBytes != null)
+ lgTrace($"TSP | NON ACCODATO sample per {MonIt.DisplayName} - trovato VETO in fluxLogVeto", false);
+ }
+ else
+ {
+ if (changed || forceSend)
{
- currData = new DatiMesIcoel(rawBytes);
- answ = currData;
+ accodaFLog(sVal, qEncodeFLog(descr, $"{NotifyValue}"));
}
else
{
- answ = base.bSerObj(dataType, rawBytes);
+ lgTrace($"TSP | NON ACCODATO sample per {MonIt.DisplayName} - verifica variazione ha dato esito negativo", false);
}
}
- catch
- { }
- return answ;
- }
-#endif
+ }
+
+ ///
+ /// effettua verifica del datablock icoel invianod eventualmente i dati variati
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected void testSendDataBlock(NodeId startNodeId, string blockName, MesItemStatus currBlock, MesItemStatus newBlock, bool forceSend)
+ {
+ // verifica globale blocchi old/new...
+ if (!currBlock.Equals(newBlock))
+ {
+ // creo un nuovo monitoredItem se non ci fosse x ogni variabile dell'oggetto...
+ testSendProperty(new Opc.Ua.Client.MonitoredItem() { DisplayName = $"{blockName}_Stato", NodeClass = NodeClass.Variable, StartNodeId = startNodeId }, $"{newBlock.Stato}", forceSend);
+ testSendProperty(new Opc.Ua.Client.MonitoredItem() { DisplayName = $"{blockName}_Velocita", NodeClass = NodeClass.Variable, StartNodeId = startNodeId }, $"{newBlock.Velocita}", forceSend);
+ testSendProperty(new Opc.Ua.Client.MonitoredItem() { DisplayName = $"{blockName}_Termico", NodeClass = NodeClass.Variable, StartNodeId = startNodeId }, $"{newBlock.Termico}", forceSend);
+ testSendProperty(new Opc.Ua.Client.MonitoredItem() { DisplayName = $"{blockName}_MagnetoTermico", NodeClass = NodeClass.Variable, StartNodeId = startNodeId }, $"{newBlock.MagnetoTermico}", forceSend);
+ testSendProperty(new Opc.Ua.Client.MonitoredItem() { DisplayName = $"{blockName}_AvariaInverter", NodeClass = NodeClass.Variable, StartNodeId = startNodeId }, $"{newBlock.AvariaInverter}", forceSend);
+ }
+ }
+
+
+ ///
+ /// Verifica ed invia variazioni DAL FORMATO RAW data (byte[]) --> esplode oggetti e li testa 1:1
+ ///
+ ///
+ ///
+ ///
+ internal override void checkAndSendRaw(Opc.Ua.Client.MonitoredItem MonIt, byte[] NotifyValue, bool forceSend)
+ {
+ if (MonIt != null)
+ {
+ if (NotifyValue != null && NotifyValue.Length > 0)
+ {
+
+ // verifico variazione "globale"
+ if (!lastData.Equals(currData))
+ {
+ // effettuo test/invio x ogni info
+ testSendDataBlock(MonIt.StartNodeId, "Calibratrice_L1", lastData.Calibratrice_L1, currData.Calibratrice_L1, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "Calibratrice_L2", lastData.Calibratrice_L2, currData.Calibratrice_L2, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "Dewatering_L1", lastData.Dewatering_L1, currData.Dewatering_L1, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "Dewatering_L2", lastData.Dewatering_L2, currData.Dewatering_L2, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "Elevatore_L1", lastData.Elevatore_L1, currData.Elevatore_L1, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "Elevatore_L2", lastData.Elevatore_L2, currData.Elevatore_L2, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "ImmergitoreBins_L1", lastData.ImmergitoreBins_L1, currData.ImmergitoreBins_L1, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "ImmergitoreBins_L2", lastData.ImmergitoreBins_L2, currData.ImmergitoreBins_L2, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "ImmergitoreCasse_L1", lastData.ImmergitoreCasse_L1, currData.ImmergitoreCasse_L1, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "ImmergitoreCasse_L2", lastData.ImmergitoreCasse_L2, currData.ImmergitoreCasse_L2, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "NastroTaglierina_L1", lastData.NastroTaglierina_L1, currData.NastroTaglierina_L1, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "NastroTaglierina_L2", lastData.NastroTaglierina_L2, currData.NastroTaglierina_L2, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "Precalibro_L1", lastData.Precalibro_L1, currData.Precalibro_L1, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "Precalibro_L2", lastData.Precalibro_L2, currData.Precalibro_L2, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "Taglierina_L1", lastData.Taglierina_L1, currData.Taglierina_L1, forceSend);
+ testSendDataBlock(MonIt.StartNodeId, "Taglierina_L2", lastData.Taglierina_L2, currData.Taglierina_L2, forceSend);
+ // salvo lastData...
+ lastData = currData;
+ }
+ }
+ else
+ {
+ lgError($"checkAndSend ERROR | MonIt: {MonIt.DisplayName} | NotifyValue Null!!!");
+ }
+ }
+ else
+ {
+ lgError("checkAndSend ERROR: MonIt null");
+ }
+ }
#endregion Public Constructors
@@ -337,7 +430,7 @@ namespace IOB_WIN_NEXT
B_input += (1 << 3);
}
}
-
+
// controllo se sono poweroff e se non ho dati buoni da > 2 minuti --> disconnetto
if (!powerOnOk && adesso.Subtract(lastCurrent).TotalMinutes > 2)
{
diff --git a/IOB-WIN-NEXT/Objects.cs b/IOB-WIN-NEXT/Objects.cs
index 73a803c1..5304b21f 100644
--- a/IOB-WIN-NEXT/Objects.cs
+++ b/IOB-WIN-NEXT/Objects.cs
@@ -101,6 +101,11 @@ namespace IOB_WIN_NEXT
///
public string value { get; set; } = "";
+ ///
+ /// Valore Registrato in formato byte array
+ ///
+ public byte[] rawByte { get; set; } = new byte[1];
+
///
/// Timestamp data-ora evento registrato
///