COmpletata review Giacovelli's ICOEL OPC-UA
This commit is contained in:
Binary file not shown.
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user