COmpletata review Giacovelli's ICOEL OPC-UA

This commit is contained in:
Samuele Locatelli
2022-05-12 17:08:07 +02:00
parent 615e0d99bb
commit cfd95b00d3
5 changed files with 190 additions and 77 deletions
Binary file not shown.
+3 -3
View File
@@ -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": {
+72 -57
View File
@@ -252,7 +252,7 @@ namespace IOB_WIN_NEXT
/// <param name="MonIt"></param>
/// <param name="NotifyValue"></param>
/// <param name="forceSend"></param>
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
}
}
/// <summary>
/// Verifica ed invia variazioni DAL FORMATO RAW data (byte[])
/// </summary>
/// <param name="MonIt"></param>
/// <param name="NotifyValue"></param>
/// <param name="forceSend"></param>
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");
}
}
/// <summary>
/// Indica se si debba leggere un area di tipo "encoded" (byte raw --> obj)
/// </summary>
@@ -305,33 +363,6 @@ namespace IOB_WIN_NEXT
/// </summary>
protected byte[] byteRawData { get; set; } = new byte[1];
#if false
/// <summary>
/// Restitusice una versione serializzata delle variabili complesse in formato string
/// </summary>
/// <param name="dataType"></param>
/// <param name="rawBytes"></param>
/// <returns></returns>
protected virtual string bSerString(string dataType, byte[] rawBytes)
{
string answ = "";
return answ;
}
/// <summary>
/// Restitusice una versione serializzata delle variabili complesse in formato object (generico)
/// </summary>
/// <param name="dataType"></param>
/// <param name="rawBytes"></param>
/// <returns></returns>
protected virtual object bSerObj(string dataType, byte[] rawBytes)
{
object answ = null;
return answ;
}
#endif
/// <summary>
/// Vera connessione ad OpcUa
/// </summary>
@@ -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);
}
/// <summary>
/// Data ora ultima lettura RAW data (x lettura periodica forzata...)
/// </summary>
protected DateTime lastRawDataRead { get; set; } = DateTime.Now.AddMinutes(-1);
/// <summary>
/// Periodo massimo (in sec) per letture dati RAW in mancanza di eventi
/// </summary>
protected int rawDataReadMaxElapsed { get; set; } = 90;
protected int lastCurrentMaxElapsed { get; set; } = 120;
/// <summary>
/// Evento rilevazione modifica valori --> chiamo checkSend
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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
+110 -17
View File
@@ -222,6 +222,9 @@ namespace IOB_WIN_NEXT
#region Public Constructors
/// <summary>
/// Valore corrente dei dati ICOEL (traduzione JIT da byte[])
/// </summary>
protected DatiMesIcoel currData
{
get
@@ -240,6 +243,16 @@ namespace IOB_WIN_NEXT
}
}
/// <summary>
/// Ultima versione validata delle info x confronto
/// </summary>
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);
}
/// <summary>
/// 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)
/// <summary>
/// Verifico se salvare e inviare proprietà specificata
/// </summary>
/// <param name="MonIt"></param>
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
}
/// <summary>
/// effettua verifica del datablock icoel invianod eventualmente i dati variati
/// </summary>
/// <param name="startNodeId"></param>
/// <param name="blockName"></param>
/// <param name="currBlock"></param>
/// <param name="newBlock"></param>
/// <param name="forceSend"></param>
/// <returns></returns>
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);
}
}
/// <summary>
/// Verifica ed invia variazioni DAL FORMATO RAW data (byte[]) --> esplode oggetti e li testa 1:1
/// </summary>
/// <param name="MonIt"></param>
/// <param name="NotifyValue"></param>
/// <param name="forceSend"></param>
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)
{
+5
View File
@@ -101,6 +101,11 @@ namespace IOB_WIN_NEXT
/// </summary>
public string value { get; set; } = "";
/// <summary>
/// Valore Registrato in formato byte array
/// </summary>
public byte[] rawByte { get; set; } = new byte[1];
/// <summary>
/// Timestamp data-ora evento registrato
/// </summary>