Files

1343 lines
52 KiB
C#

using Microsoft.Extensions.Configuration;
using MP.MONO.Core;
using MP.MONO.Core.CONF;
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MP.MONO.ADAPTER
{
/// <summary>
/// Classe di comunicazione OPC-UA
/// </summary>
public class IobOpcUa : IobGeneric
{
private Logger Log = LogManager.GetCurrentClassLogger();
/// <summary>
/// Avvia un oggetto IOB in grado di comunicare con server OPC-UA
/// Impiega il pacchetto Nuget OPC-UA foundation https://github.com/OPCFoundation/UA-.NETStandard
/// </summary>
/// <param name="confPath"></param>
public IobOpcUa(string confPath, IConfigurationRoot? config) : base(confPath , config)
{
// gestione data filtering...
if (!string.IsNullOrEmpty(config.GetValue<string>("ENABLE_DATA_FILTER")))
{
bool.TryParse(config.GetValue<string>("ENABLE_DATA_FILTER"), out enableDataFilter);
}
// gestione restart OpcUa client...
if (!string.IsNullOrEmpty(config.GetValue<string>("ENABLE_CLI_RESTART")))
{
bool.TryParse(config.GetValue<string>("ENABLE_CLI_RESTART"), out enableCliRestart);
}
// init datetime counters
DateTime adesso = DateTime.Now;
lastCurrent = adesso;
// ora leggo il file di conf specifico....
string jsonFileName = config.GetValue<string>("OPC_PARAM_CONF");
if (!string.IsNullOrEmpty(jsonFileName))
{
// leggo il file...
loadOpcUaConf(jsonFileName);
}
}
//#region Public Methods
/// <summary>
/// Processo i task richiesti e li elimino dalla coda 1:1
/// </summary>
/// <param name="task2exe"></param>
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
{
// uso metodo base x ora
return base.executeTasks(task2exe);
}
///// <summary>
///// Recupera uno specifico dataItem
///// </summary>
///// <param name="diKey"></param>
///// <returns></returns>
//public string getDataItemValue(string diKey)
//{
// string answ = "";
// if (string.IsNullOrEmpty(diKey))
// {
// lgError($"Attenzione: richiesta chiave vuota in getDataItemValue{Environment.NewLine}StackTrace: {Environment.StackTrace}");
// }
// else
// {
// DateTime adesso = DateTime.Now;
// if (dataItemMem.Count == 0)
// {
// numErroriCheck++;
// if (vetoCheckStatus < adesso)
// {
// lgError($"Errore in getDataItemValue per {diKey} | dataItemMem NON contiene valori");
// // imposto veto per vetoSeconds...
// vetoCheckStatus = adesso.AddSeconds(vetoSeconds * 2);
// }
// }
// else
// {
// if (!dataItemMem.ContainsKey(diKey))
// {
// if (vetoCheckStatus < adesso)
// {
// lgError($"Errore in getDataItemValue per {diKey} | dataItemMem non contiene la chiave richiesta ma altri {dataItemMem.Count} valori");
// // imposto veto per vetoSeconds...
// vetoCheckStatus = adesso.AddSeconds(vetoSeconds * 2);
// }
// numErroriCheck++;
// }
// else
// {
// try
// {
// var currDataItem = dataItemMem[diKey];
// answ = currDataItem.value;
// }
// catch (Exception exc)
// {
// lgError($"Errore in getDataItemValue per {diKey} | dataItemMem contiene {dataItemMem.Count} valori {Environment.NewLine}{exc}");
// if (dataItemMem != null)
// {
// lgError($"dataItemMem contiene {dataItemMem.Count} valori");
// int maxNum = 5;
// foreach (var item in dataItemMem)
// {
// maxNum--;
// if (maxNum < 0)
// {
// break;
// }
// lgInfo($"{item.Key} --> {item.Value.DisplayName} = {item.Value.value}");
// }
// }
// }
// }
// }
// // se supero soglia errori lettura --> disconnetto e resetto
// if (numErroriCheck > maxErroriCheck)
// {
// lgInfo($"numErroriCheck: {numErroriCheck} --> richiesta disconnessione adapter con tryDisconnect");
// numErroriCheck = 0;
// tryDisconnect();
// }
// }
// return answ;
//}
///// <summary>
///// Recupero dati dinamici...
///// </summary>
//public override Dictionary<string, string> getDynData()
//{
// Dictionary<string, string> outVal = new Dictionary<string, string>();
// return outVal;
//}
///// <summary>
///// Effettua vero processing contapezzi
///// </summary>
//public override void processContapezzi()
//{
// if (utils.CRB("enableContapezzi"))
// {
// // da ridefinire la gestione base del contapezzi OPC-UA...
// }
//}
///// <summary>
///// Effettua lettura semafori principale
///// <paramref name="currDispData">Parametri da aggiornare x display in form</paramref>
///// </summary>
//public override void readSemafori(ref newDisplayData currDispData)
//{
// base.readSemafori(ref currDispData);
// try
// {
// if (verboseLog)
// {
// lgInfo("inizio read semafori");
// }
// currDispData.semIn = Semaforo.SV;
// // verifico SE sia necessario forzare la lettura RAW
// if (doByteRead)
// {
// if (DateTime.Now.Subtract(lastCurrent).TotalSeconds > lastCurrentMaxElapsed)
// {
// // FIXME TODO !!!
// foreach (var item in dataItemMem)
// {
// // restituisce i 115 byte da deserializzare... qui HACK!
// var rawVal = UA_ref.ReadNodeRaw(item.Value.StartNodeId);
// if (rawVal != null)
// {
// byteRawData = getByteRaw((DataValue)rawVal);
// lastCurrent = DateTime.Now;
// currReadErrors = 0;
// }
// else
// {
// currReadErrors++;
// }
// }
// }
// }
// // decodifica e gestione
// decodeToBaseBitmap();
// reportRawInput(ref currDispData);
// }
// catch (Exception exc)
// {
// currDispData.semIn = Semaforo.SR;
// lgError($"Eccezione in readSemafori:{Environment.NewLine}{exc}");
// }
// // se > max errori --> disconnetto
// if (currReadErrors > maxReadErrors)
// {
// lgError($"Superato limite errori Read ({currReadErrors}) --> tryDisconnect");
// currReadErrors = 0;
// tryDisconnect();
// }
// else
// {
// // altrimenti pausa forzata
// Thread.Sleep(300);
// }
//}
///// <summary>
///// Effettua reset del contapezzi, NON POSSIBILE in questa versione
///// </summary>
///// <returns></returns>
//public override bool resetcontapezziPLC()
//{
// bool answ = false;
// return answ;
//}
///// <summary>
///// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE in questa versione
///// </summary>
///// <returns></returns>
//public override bool setcontapezziPLC(int newPzCount)
//{
// bool answ = false;
// return answ;
//}
/// <summary>
/// Verifica SE si debba fare log periodico (ogni "verboseLogTOut" sec...)
/// </summary>
public bool periodicLog
{
get
{
bool answ = false;
answ = (DateTime.Now.Subtract(lastPeriodicLog).TotalSeconds > confMan.GetValue<int>("verboseLogTOut"));
if (answ)
{
lastPeriodicLog = DateTime.Now;
}
return answ;
}
}
/// <summary>
/// Override connessione
/// </summary>
public override void tryConnect()
{
if (!connectionOk)
{
// controllo che il ping sia stato tentato almeno pingTestSec fa...
if (DateTime.Now.Subtract(lastPING).TotalSeconds > confMan.GetValue<int>("pingTestSec"))
{
if (verboseLog || periodicLog)
{
lgInfo("OpcUa: ConnKO - tryConnect");
}
// in primis salvo data ping...
lastPING = DateTime.Now;
// se passa il ping faccio il resto...
// completare fixme todo !!!
#if false
if (testPingMachine == IPStatus.Success)
{
string szStatusConnection = "";
try
{
// ora provo connessione...
parentForm.commPlcActive = true;
var task = Task.Run(async () =>
{
return await doConnect().ConfigureAwait(false);
});
short esitoLink = task.Result; // use returned result from async method here
lgInfo($"szStatusConnection OpcUa, esitoLink: {esitoLink}");
parentForm.commPlcActive = false;
connectionOk = true;
// refresh stato allarmi!!!
if (connectionOk)
{
if (adpRunning)
{
lgInfo("Connessione OK");
}
}
else
{
lgError("Impossibile procedere, connessione mancante...");
}
}
catch (Exception exc)
{
lgFatal($"Errore nella connessione all'adapter OpcUa: {szStatusConnection}{Environment.NewLine}{exc}");
connectionOk = false;
lgInfo($"Eccezione in TryConnect, Adapter OpcUa NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
}
}
else
{
// loggo no risposta ping ...
connectionOk = false;
if (verboseLog || periodicLog)
{
lgInfo($"Attenzione: OpcUa controllo PING fallito per IP {cIobConf.cncIpAddr}");
}
}
#endif
}
}
else
{
// completare fixme todo !!!
#if false
needRefresh = true;
#endif
}
// se non è ancora connesso faccio procesisng memoria caso disconnesso...
if (!connectionOk)
{
// completare fixme todo !!!
#if false
// processo semafori ed invio...
processMemoryDiscon();
#endif
}
}
///// <summary>
///// Override disconnessione
///// </summary>
//public override void tryDisconnect()
//{
// if (connectionOk)
// {
// if (UA_ref != null)
// {
// string szStatusConnection = "";
// try
// {
// UA_ref.Disconnect();
// connectionOk = false;
// lgInfo(szStatusConnection);
// lgInfo("Effettuata disconnessione adapter OpcUa!");
// }
// catch (Exception exc)
// {
// lgFatal(exc, "Errore nella disconnessione dall'adapter OpcUa");
// }
// }
// else
// {
// lgDebug("IMPOSSIBILE effettuare disconnessione OpcUa: UA_ref non disponibile...");
// }
// }
// else
// {
// lgError("IMPOSSIBILE effettuare disconnessione OpcUa: Connessione non disponibile...");
// }
//}
//#endregion Public Methods
//#region Internal Methods
///// <summary>
///// Verifica ed invia variazioni
///// </summary>
///// <param name="MonIt"></param>
///// <param name="NotifyValue"></param>
///// <param name="forceSend"></param>
//internal bool checkAndSend(Opc.Ua.Client.MonitoredItem MonIt, string NotifyValue, bool forceSend)
//{
// bool changed = false;
// if (MonIt != null)
// {
// if (!string.IsNullOrEmpty(NotifyValue))
// {
// string sVal = "";
// string descr = "";
// DateTime locTStamp = DateTime.Now;
// descr = itemTranslation("OPC", MonIt.DisplayName);
// sVal = $"Change: {locTStamp.ToString()} | descr: {descr} | Id: {MonIt.StartNodeId} | Val: {NotifyValue}";
// lgInfo(sVal);
// // verifico se salvare
// changed = checkSaveValue(MonIt, NotifyValue, true);
// // 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");
// }
// return changed;
//}
///// <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 bool checkAndSendRaw(Opc.Ua.Client.MonitoredItem MonIt, byte[] NotifyValue, bool forceSend)
//{
// bool changed = false;
// 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
// changed = checkSaveValue(MonIt, currVal, true) || forceSend;
// // 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");
// }
// return changed;
//}
//internal void sendDataItemListToServer(NodeId StartNodeId)
//{
// // converto gli attuali nell'elenco dataitem...
// List<machDataItem> elencoDataItems = dataItemMem.Select(d => new machDataItem()
// {
// uuid = d.Key,
// Category = DataItemCategory.EVENT,
// Name = d.Value.DisplayName,
// Type = $"{d.Value.NodeClass}",
// SubType = $"{StartNodeId}"
// }
// ).ToList();
// lgInfo($"Richiesta sendDataItemListToServer per {elencoDataItems.Count} dataItems");
// // aspetta un tempo random da 10-100 ms...
// Random rnd = new Random();
// Task.Delay(rnd.Next(10, 100));
// // invio il dataItem serializzato...
// sendDataItemsList(elencoDataItems);
//}
///// <summary>
///// Evento rilevazione modifica valori --&gt; chiamo checkSend
///// </summary>
///// <param name="sender"></param>
///// <param name="e"></param>
//internal virtual void UA_ref_eh_MonItChange(object sender, opcUaMonitItemChange e)
//{
// string currVal = "";
// // da verificare decodifica valore byte...
// if (doByteRead)
// {
// var currNot = e.CurrNotify;
// if (currNot != null)
// {
// byteRawData = getByteRaw((DataValue)currNot.Value);
// checkAndSendRaw(e.CurrMonitoredItem, byteRawData, false);
// }
// }
// else
// {
// currVal = $"{e.CurrNotify.Value}";
// checkAndSend(e.CurrMonitoredItem, currVal, false);
// }
// // aggiorno ultima lettura
// lastCurrent = DateTime.Now;
//}
//#endregion Internal Methods
//#region Protected Fields
///// <summary>
///// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing
///// </summary>
//protected Dictionary<string, OpcUaDataItemExt> dataItemMem = new Dictionary<string, OpcUaDataItemExt>();
/// <summary>
/// Abilitazione restart (da opt par...)
/// </summary>
protected bool enableCliRestart = false;
/// <summary>
/// Gestione filtraggio dati
/// </summary>
protected bool enableDataFilter = false;
/// <summary>
/// Determina se ha effettuata lettura items in memoria x confronto...
/// </summary>
protected bool hasReadItems = false;
/// <summary>
/// Ultimo current received x gestione update periodico...
/// </summary>
protected DateTime lastCurrent = DateTime.Now;
///// <summary>
///// Oggetto MAIN x connessione MTC
///// </summary>
//protected UAClient UA_ref;
///// <summary>
///// Veto controllo status x log...
///// </summary>
//protected DateTime vetoCheckStatus = DateTime.Now;
//protected int WatchDog = 0;
//#endregion Protected Fields
//#region Protected Properties
///// <summary>
///// Area dati raw per lettura encoded (SE presente)
///// </summary>
//protected byte[] byteRawData { get; set; } = new byte[1];
///// <summary>
///// Indica se si debba leggere un area di tipo "encoded" (byte raw --&gt; obj)
///// </summary>
//protected bool doByteRead { get; set; } = false;
///// <summary>
///// Verifico se abbia ALMENO un errore...
///// </summary>
//protected bool hasError
//{
// get
// {
// return checkMultiCondition(opcUaParams.condError);
// }
//}
///// <summary>
///// Indica se abbia emergenza ARMATA (cond normale)
///// </summary>
//protected bool hasEStopArmed
//{
// get
// {
// return checkMultiCondition(opcUaParams.condEStop);
// }
//}
///// <summary>
///// Indica se abbia stato POWER ON (multicondizione)
///// </summary>
//protected virtual bool hasPowerOn
//{
// get
// {
// return checkMultiCondition(opcUaParams.condPowerOn);
// }
//}
///// <summary>
///// Indica se abbia stato MANUAL (condizioni varie, es stopped)
///// </summary>
//protected virtual bool isManual
//{
// get
// {
// return checkMultiCondition(opcUaParams.condManual);
// }
//}
///// <summary>
///// Indica se abbia stato READY (condizioni varie, es ausiliari OK)
///// </summary>
//protected virtual bool isReady
//{
// get
// {
// return checkMultiCondition(opcUaParams.condReady);
// }
//}
///// <summary>
///// Indica se sia in stato Ssetup
///// </summary>
//protected bool isSetup
//{
// get
// {
// return checkMultiCondition(opcUaParams.condSetup);
// }
//}
///// <summary>
///// Indica se sia in stato WarmUp / CoolDown (riscaldamento/raffreddamento)
///// </summary>
//protected bool isWarmUpCoolDown
//{
// get
// {
// return checkMultiCondition(opcUaParams.condWarmUpCoolDown);
// }
//}
///// <summary>
///// Indica se sia in stato Warning
///// </summary>
//protected bool isWarning
//{
// get
// {
// return checkMultiCondition(opcUaParams.condWarning);
// }
//}
///// <summary>
///// Indica se abbia stato READY (condizioni varie, es ausiliari OK)
///// </summary>
//protected bool isWorking
//{
// get
// {
// // cerco SE HO cond OPC Ua o classica... nel caso creo e salvo
// if (opcUaParams.condWorkOpc.checkList == null || opcUaParams.condWorkOpc.checkList.Count == 0)
// {
// opcUaParams.condWorkOpc = new diCheckCondSetup()
// {
// checkList = opcUaParams.condWork,
// checkMode = boolCheckMode.AND,
// negateValue = false
// };
// }
// return checkMultiCondition(opcUaParams.condWorkOpc);
// }
//}
///// <summary>
///// Periodo massimo (in sec) per letture dati RAW in mancanza di eventi
///// </summary>
//protected int lastCurrentMaxElapsed { get; set; } = 120;
/// <summary>
/// Parametri specifici MTC
/// </summary>
protected OpcUaParamConf opcUaParams { get; set; }
///// <summary>
///// URL x salvataggio elenco dataItems OpcUa
///// </summary>
//protected string urlSaveDataItems
//{
// get
// {
// string answ = "";
// try
// {
// string machineName = Environment.MachineName;
// answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/saveDataItems/{cIobConf.codIOB}";
// }
// catch (Exception exc)
// {
// lgError(exc, "Errore in composizione urlSaveDataItems");
// }
// return answ;
// }
//}
//#endregion Protected Properties
//#region Protected Methods
///// <summary>
///// Verifica un DataItem e se il valore corrisponde a quello indicato come "true value"
///// restituisce true
///// </summary>
///// <param name="itemName"></param>
///// <param name="trueVal"></param>
///// <returns></returns>
//protected bool checkDataItem(string itemName, string trueVal)
//{
// bool answ = false;
// OpcUaDataItemExt currValue = null;
// try
// {
// currValue = dataItemMem[itemName];
// answ = (currValue.value.Equals(trueVal));
// }
// catch
// {
// lgError($"Errore in decodifica valore per {itemName} rispetto a {trueVal} | recuperato {currValue} / {currValue.value}");
// }
// return answ;
//}
///// <summary>
///// Verifica condizione "multipla" secondo setup json
///// </summary>
///// <param name="reqCondition">Set condizioni da validare</param>
///// <returns></returns>
//protected bool checkMultiCondition(diCheckCondSetup reqCondition)
//{
// bool answ = false;
// int numCondOk = 0;
// int numCond = 0;
// if (reqCondition.checkList != null && reqCondition.checkList.Count > 0)
// {
// numCond = reqCondition.checkList.Count;
// // cerco nell'elenco delle condizioni che indicano lavora se sono ok faccio +1 conteggio......
// foreach (var item in reqCondition.checkList)
// {
// if (string.IsNullOrEmpty(item.keyName))
// {
// lgError($"Attenzione: item vuoto in checkMultiCondition{Environment.NewLine}StackTrace: {Environment.StackTrace}");
// }
// else
// {
// if (getDataItemValue(item.keyName) == item.targetValue)
// {
// numCondOk++;
// }
// }
// }
// if (reqCondition.checkMode == boolCheckMode.AND)
// {
// answ = (numCond == numCondOk);
// }
// else if (reqCondition.checkMode == boolCheckMode.OR)
// {
// answ = numCondOk > 0;
// }
// }
// else
// {
// answ = true;
// }
// // verifico se devo negare il valore...
// answ = reqCondition.negateValue ? !answ : answ;
// // restituisco
// return answ;
//}
///// <summary>
///// Verifica / Salva valore e restitusice SE sia variato (e quindi da inviare...)
///// </summary>
///// <param name="dataItem"></param>
///// <param name="NotifyValue"></param>
///// <param name="sendItemList"></param>
///// <returns></returns>
//protected bool checkSaveValue(Opc.Ua.Client.MonitoredItem dataItem, string NotifyValue, bool sendItemList)
//{
// bool answ = !enableDataFilter;
// double oldVal = 0;
// double newVal = 0;
// if (dataItem != null)
// {
// if (!string.IsNullOrEmpty(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;
// if (dataItemMem.ContainsKey(uuid))
// {
// OpcUaDataItemExt currDataItemMem = dataItemMem[uuid];
// // controllo SE SIA scaduto il tempo massimo...
// if (Math.Abs(dataItemMem[uuid].valueTimestamp.Subtract(adesso).TotalSeconds) > currDataItemMem.samplePeriod)
// {
// answ = true;
// }
// else
// {
// // ALTRIMENTI controllo SE diverso
// if (dataItemMem[uuid].value != $"{NotifyValue}")
// {
// lgInfo($"Val uuid: {dataItemMem[uuid].value} | NotifyValue: {NotifyValue}");
// // controllo SE ho DeadBand...
// if (dataItemMem[uuid].thresholdDeadBand > 0)
// {
// // recupero i valori e testo DeadBand...
// bool isNum01 = double.TryParse(dataItemMem[uuid].value.Replace(".", ","), out oldVal);
// bool isNum02 = double.TryParse($"{NotifyValue}".Replace(".", ","), out newVal);
// // test deadband!
// if (!(isNum01 && isNum02))
// {
// answ = true;
// }
// else
// {
// if (Math.Abs(newVal - oldVal) > dataItemMem[uuid].thresholdDeadBand)
// {
// // indico da salvare..
// answ = true;
// }
// }
// lgInfo($"Test deadband: oldVal: {oldVal} | newVal: {newVal}");
// }
// }
// }
// if (answ)
// {
// // salvo!
// dataItemMem[uuid].value = $"{NotifyValue}";
// dataItemMem[uuid].valueTimestamp = adesso;
// }
// }
// else
// {
// // registro non trovato da aggiungere...
// lgInfo($"DataItem non trovato in checkSaveValue: {dataItem.DisplayName}");
// // provo a creare oggetto in memoria...
// try
// {
// int dSamplePeriod = 0;
// int threshDBand = 0;
// uuid = "";
// var currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, dataItem);
// // sistemo valore/periodo
// currDataItem.value = $"{NotifyValue}";
// currDataItem.valueTimestamp = adesso;
// // aggiungo
// dataItemMem.Add(uuid, currDataItem);
// if (sendItemList)
// {
// sendDataItemListToServer(dataItem.StartNodeId);
// }
// }
// catch (Exception exc)
// {
// lgError($"Eccezione in checkSaveSample{Environment.NewLine}{exc}");
// }
// }
// }
// else
// {
// lgError("Attenzione: checkSaveItem con Notify null!");
// }
// }
// else
// {
// lgError("Attenzione: checkSaveItem con MonIt null!");
// }
// return answ;
//}
///// <summary>
///// Effettua decodifica aree memoria alla bitmap usata x MAPO
///// </summary>
//protected virtual void decodeToBaseBitmap()
//{
// DateTime adesso = DateTime.Now;
// // init a zero...
// B_input = 0;
// /* -----------------------------------------------------
// * STATE MACHINE 60 STD / SIMULA
// *------------------------------------------------------
// * bitmap MAPO
// * B0: POWER_ON
// * B1: RUN
// * B2: pzCount
// * B3: allarme
// * B4: manuale
// * B5: SlowTC (NON gestito qui)
// * B6: warm-up / cool-down
// * B7: emergenza
// ---------------------------------------------------- */
// // se valido il check ping lo eseguo... altrimenti lo do x buono
// bool checkPing = !opcUaParams.pingAsPowerOn;
// string currRun = "";
// if (!checkPing)
// {
// checkPing = (testPingMachine == IPStatus.Success);
// }
// // 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 > lastCurrentMaxElapsed --> disconnetto
// if (!powerOnOk && adesso.Subtract(lastCurrent).TotalSeconds > lastCurrentMaxElapsed)
// {
// tryDisconnect();
// }
// // solo se non ho veto check
// int vFactor = 2;
// if (vetoCheckStatus < adesso)
// {
// lgTrace($"Stato variabili checkPing: {testPingMachine}");
// // imposto veto per vetoSeconds...
// vetoCheckStatus = adesso.AddSeconds(vetoSeconds * vFactor);
// }
// // se abilitato watchdog...
// if (opcUaParams.WatchDog.IsEnabled)
// {
// lgTrace("WatchDog 01");
// if (adesso.Subtract(lastWatchDogPLC).TotalSeconds > 2)
// {
// lastWatchDogPLC = adesso;
// WatchDog++;
// WatchDog = WatchDog > opcUaParams.WatchDog.MaxVal ? 0 : WatchDog;
// lgTrace($"WatchDog val: {WatchDog}");
// try
// {
// WriteValue commWriteVal = new WriteValue();
// commWriteVal.NodeId = new NodeId(opcUaParams.WatchDog.MemConfWrite);
// commWriteVal.AttributeId = Attributes.Value;
// commWriteVal.Value = new DataValue();
// commWriteVal.Value.Value = WatchDog;
// List<WriteValue> nodes2Write = new List<WriteValue>();
// nodes2Write.Add(commWriteVal);
// UA_ref.WriteNodes(nodes2Write);
// lgTrace("Effettuata scrittura WatchDog");
// }
// catch (Exception exc)
// {
// lgError($"Eccezione in gestione WatchDog, valore attuale {WatchDog}{Environment.NewLine}{exc}");
// }
// }
// }
// else
// {
// lgTrace("WatchDog disabilitato");
// }
// // log opzionale!
// if (verboseLog)
// {
// lgDebug($"Trasformazione checkPing: {checkPing} | hasPowerOn: {hasPowerOn} | B_input: {B_input} | currRun = {currRun}");
// }
//}
//protected byte[] getByteRaw(DataValue obj)
//{
// if (obj == null)
// return null;
// byte[] rawByte = new byte[1];
// if (obj != null)
// {
// try
// {
// var wrapVal = ((DataValue)obj).WrappedValue;
// //rawByte = ObjectToByteArray(rawVal);
// var bodyVal = ((Opc.Ua.ExtensionObject)wrapVal.Value).Body;
// rawByte = (byte[])bodyVal;
// }
// catch
// { }
// }
// return rawByte;
//}
///// <summary>
///// Effettua traduzione ITEM da LUT parametrica (key: tipo+id) del file di conf, se non
///// trovo uso key
///// </summary>
///// <param name="tipo"></param>
///// <param name="id"></param>
///// <returns></returns>
//protected string itemTranslation(string tipo, string id)
//{
// string answ = "";
// string lemma = id;
// if (!string.IsNullOrEmpty(tipo))
// {
// lemma = $"{tipo}_{id}";
// }
// // cerco nel dizionario delle traduzioni SE esiste un valore e prendo quello, altrimenti
// // uso il lemma...
// if (opcUaParams.itemTranslation.ContainsKey(lemma))
// {
// answ = opcUaParams.itemTranslation[lemma];
// }
// else
// {
// answ = lemma;
// }
// return answ;
//}
/// <summary>
/// Effettua lettura file di conf specifico OPC-UA da oggetto serializzato json <paramref
/// name="fileName">Nome file da cui leggere i parametri json</paramref>
/// </summary>
protected void loadOpcUaConf(string fileName)
{
string jsonFullPath = Path.Combine(configPath, fileName);
lgInfo($"Apertura file {jsonFullPath}");
using (StreamReader reader = new StreamReader(jsonFullPath))
{
string jsonData = reader.ReadToEnd().Replace("\n", "").Replace("\r", "");
if (!string.IsNullOrEmpty(jsonData))
{
lgDebug($"File json composto da {jsonData.Length} caratteri");
try
{
opcUaParams = JsonConvert.DeserializeObject<OpcUaParamConf>(jsonData);
lgDebug($"Decodifica aree OpcUaParamConf: trovati {opcUaParams.paramsEndThresh.Count} valori paramsEndThresh");
// sistemo se ci sono dati memMap...
memMap = new plcMemMap();
if (opcUaParams.mMapWrite != null)
{
memMap.mMapWrite = opcUaParams.mMapWrite;
}
if (opcUaParams.mMapRead != null)
{
memMap.mMapRead = opcUaParams.mMapRead;
}
setupMemMap();
}
catch (Exception exc)
{
lgError($"Eccezione in decodifica conf json OPC-UA:{Environment.NewLine}{exc}");
}
}
else
{
lgError("Errore in loadOpcUaConf: file json vuoto!");
}
}
}
//#endregion Protected Methods
//#region Private Fields
///// <summary>
///// Elenco degli items da monitorare come risultato del browse iniziale
///// </summary>
//private Dictionary<string, string> selectedItemList = new Dictionary<string, string>();
//#endregion Private Fields
//#region Private Methods
///// <summary>
///// Vera connessione ad OpcUa
///// </summary>
///// <returns></returns>
//private async Task<short> doConnect()
//{
// short esitoLink = 0;
// // reset memoria dataItem..
// dataItemMem = new Dictionary<string, OpcUaDataItemExt>();
// // predisposizione conf oggetto di comunicazione MTC
// int port = 4840;
// int.TryParse(cIobConf.cncPort, out port);
// // ora avvio
// try
// {
// lgInfo("Start init OpcUa Client");
// // Define the UA Client application
// ApplicationInstance application = new ApplicationInstance();
// application.ApplicationName = "Steamware IOB-WIN Client";
// application.ApplicationType = ApplicationType.Client;
// // load the application configuration.
// string confPath = $"{Application.StartupPath}\\DATA\\CONF\\IobOpcUaClient.Config.xml";
// await application.LoadApplicationConfiguration(confPath, silent: false).ConfigureAwait(false);
// // check the application certificate.
// await application.CheckApplicationInstanceCertificate(silent: false, minimumKeySize: 0).ConfigureAwait(false);
// lgInfo($"Chiamata UAClient con configurazione standard: {application.ApplicationConfiguration.ApplicationName}");
// UA_ref = new UAClient(application.ApplicationConfiguration, cIobConf.codIOB, opcUaParams.Identity.UserName, opcUaParams.Identity.Passwd, isVerboseLog, ClientBase.ValidateResponse);
// lgInfo($"Chiamata apertura OpcUa Client: {cIobConf.cncIpAddr}:{port}");
// UA_ref.ServerUrl = $"opc.tcp://{cIobConf.cncIpAddr}:{port}";
// var task = Task.Run(async () =>
// {
// return await UA_ref.ConnectAsync().ConfigureAwait(false);
// });
// bool connected = task.Result;
// if (connected)
// {
// // faccio un primo browse dei dati...
// Dictionary<string, string> nodeIdNameList = new Dictionary<string, string>();
// if (!string.IsNullOrEmpty(opcUaParams.BrowseFullVal))
// {
// try
// {
// UA_ref.Browse(opcUaParams.BrowseFullVal, opcUaParams.filterItemsNodeId, ref nodeIdNameList);
// }
// catch
// { }
// }
// else
// {
// UA_ref.Browse(opcUaParams.BrowseNSIndex, opcUaParams.BrowseValue, opcUaParams.filterItemsNodeId, ref nodeIdNameList);
// }
// // loggo elenco degli item sottocrivibili...
// lgDebug("---------- AVAILABLE FOR SUBSCRIBE ----------");
// foreach (var item in nodeIdNameList)
// {
// lgDebug(item.Key);
// }
// lgDebug("---------- END LIST ----------");
// // se ho un insieme non vuoto degli item sottoscritti carico solo quelli
// if (opcUaParams.subscribedItems != null && opcUaParams.subscribedItems.Count > 0)
// {
// // cerco e aggiungo SOLO quelle indicati
// foreach (var currItem in opcUaParams.subscribedItems)
// {
// var foundItems = nodeIdNameList.Where(x => x.Key.Contains(currItem)).ToList();
// if (foundItems != null && foundItems.Count > 0)
// {
// foreach (var fItem in foundItems)
// {
// // verifico di NON duplicare...
// if (!selectedItemList.ContainsKey(fItem.Key))
// {
// selectedItemList.Add(fItem.Key, fItem.Value);
// }
// }
// }
// else
// {
// lgDebug($"subscribedItems non trovato: {currItem}");
// }
// }
// lgDebug($"Aggiunti {selectedItemList.Count} items!");
// }
// // altrimenti tutti!
// else
// {
// selectedItemList = nodeIdNameList;
// }
// // loggo elenco degli item sottocrivibili...
// lgInfo("---------- SUBSCRIBED NODES ----------");
// foreach (var item in selectedItemList)
// {
// lgInfo(item.Key);
// }
// lgInfo("---------- END LIST ----------");
// // sottoscrivo a rilevazione cambio dati solo l'incrocio degli insiemi
// List<Opc.Ua.Client.MonitoredItem> subscribedItems = UA_ref.SubscribeToDataChanges(selectedItemList);
// // aggiungo come DataItems
// int dSamplePeriod = 0;
// int threshDBand = 0;
// string uuid = "";
// foreach (var item in subscribedItems)
// {
// bool changed = false;
// OpcUaDataItemExt newItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, item);
// // controllo non sia già stato aggiunto
// if (dataItemMem.ContainsKey(uuid))
// {
// lgDebug($"Item ALREADY subscribed: {uuid} | NOT re-adding");
// }
// else
// {
// dataItemMem.Add(uuid, newItem);
// lgDebug($"Item subscribed: {uuid}");
// // verifico se ho i dati complessi by design
// string currVal = "";
// if (doByteRead)
// {
// // restituisce i 115 byte da deserializzare... qui HACK!
// var rawVal = UA_ref.ReadNodeRaw(item.StartNodeId);
// if (rawVal != null)
// {
// byteRawData = getByteRaw((DataValue)rawVal);
// changed = checkAndSendRaw(item, byteRawData, true);
// }
// }
// else
// {
// currVal = UA_ref.ReadNode(item.StartNodeId);
// changed = checkAndSend(item, currVal, true);
// }
// }
// }
// // gestione eventi change
// UA_ref.eh_MonItChange += UA_ref_eh_MonItChange;
// lgInfo("eh_MonItChange event registered");
// }
// esitoLink = 1;
// // fix tempi!
// DateTime adesso = DateTime.Now;
// lastPzCountSend = adesso;
// lastWarnODL = adesso;
// lastCurrent = adesso;
// }
// catch (Exception exc)
// {
// lgError($"Eccezione in doConnect{Environment.NewLine}{exc}");
// }
// return esitoLink;
//}
///// <summary>
///// Formatta un dataitem x salvataggio in memoria locale
///// </summary>
///// <param name="dSamplePeriod"></param>
///// <param name="threshDBand"></param>
///// <param name="uuid"></param>
///// <param name="dataItem"></param>
///// <returns></returns>
//private OpcUaDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, Opc.Ua.Client.MonitoredItem dataItem)
//{
// OpcUaDataItemExt currDataItem;
// // calcolo parametri
// uuid = $"{dataItem.DisplayName}";
// // SOLO SE è abilitato il datafiltering...
// if (enableDataFilter)
// {
// threshDBand = 1;
// // controllo SE ho conf x deadband...
// if (opcUaParams.paramsEndThresh.Count > 0)
// {
// // ciclo su tutti i parametri indicati...
// foreach (var item in opcUaParams.paramsEndThresh)
// {
// if (uuid.EndsWith(item.Key))
// {
// threshDBand = item.Value;
// }
// }
// }
// }
// else
// {
// threshDBand = 0;
// }
// dSamplePeriod = 60;
// // salvo oggetto x "uso interno"
// currDataItem = new OpcUaDataItemExt(dataItem)
// {
// uid = uuid,
// thresholdDeadBand = threshDBand,
// samplePeriod = dSamplePeriod
// };
// return currDataItem;
//}
///// <summary>
///// Effettua invio a MP/IO dell'elenco serializzato dei dataItems
///// </summary>
///// <param name="dataItems"></param>
//private void sendDataItemsList(List<machDataItem> dataItems)
//{
// string rawData = JsonConvert.SerializeObject(dataItems);
// try
// {
// utils.callUrlNow($"{urlSaveDataItems}", rawData);
// lgInfo($"Effettuata chiamata sendDataItemsList all'url {urlSaveDataItems}");
// }
// catch (Exception exc)
// {
// lgError($"Eccezione in sendDataItemsList{Environment.NewLine} - url: {urlSaveDataItems}{Environment.NewLine}- payload:{rawData}{Environment.NewLine}Eccezione:{Environment.NewLine}{exc}");
// }
//}
//#endregion Private Methods
}
}