From a623b4f2db6a7477514da65bd27fdbd6fff23c9d Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Tue, 14 Jun 2022 10:51:02 +0200 Subject: [PATCH] Spostamento adapter in ADAPTER.OLD --- MP.MONO.ADAPTER.OLD/IobGeneric.cs | 631 ++++++++ MP.MONO.ADAPTER.OLD/IobOpcUa.cs | 1342 +++++++++++++++++ .../MP.MONO.ADAPTER.OLD.csproj | 59 + MP.MONO.ADAPTER.OLD/Program.cs | 291 ++++ .../Resources/ChangeLog-original.html | 26 + MP.MONO.ADAPTER.OLD/Resources/ChangeLog.html | 26 + MP.MONO.ADAPTER.OLD/Resources/VersNum.txt | 1 + .../Resources/logoSteamware.png | Bin 0 -> 3402 bytes .../Resources/manifest-original.xml | 7 + MP.MONO.ADAPTER.OLD/Resources/manifest.xml | 7 + MP.MONO.ADAPTER.OLD/UAClient.cs | 1005 ++++++++++++ MP.MONO.ADAPTER.OLD/appsettings.json | 47 + MP.MONO.ADAPTER.OLD/conf/AlarmList.json | 52 + MP.MONO.ADAPTER.OLD/conf/MULTIAX.json | 129 ++ MP.MONO.ADAPTER.OLD/conf/ModeList.json | 58 + MP.MONO.ADAPTER.OLD/conf/ParamList.json | 125 ++ MP.MONO.ADAPTER.OLD/conf/StatusList.json | 58 + MP.MONO.ADAPTER.OLD/post-build.ps1 | 32 + 18 files changed, 3896 insertions(+) create mode 100644 MP.MONO.ADAPTER.OLD/IobGeneric.cs create mode 100644 MP.MONO.ADAPTER.OLD/IobOpcUa.cs create mode 100644 MP.MONO.ADAPTER.OLD/MP.MONO.ADAPTER.OLD.csproj create mode 100644 MP.MONO.ADAPTER.OLD/Program.cs create mode 100644 MP.MONO.ADAPTER.OLD/Resources/ChangeLog-original.html create mode 100644 MP.MONO.ADAPTER.OLD/Resources/ChangeLog.html create mode 100644 MP.MONO.ADAPTER.OLD/Resources/VersNum.txt create mode 100644 MP.MONO.ADAPTER.OLD/Resources/logoSteamware.png create mode 100644 MP.MONO.ADAPTER.OLD/Resources/manifest-original.xml create mode 100644 MP.MONO.ADAPTER.OLD/Resources/manifest.xml create mode 100644 MP.MONO.ADAPTER.OLD/UAClient.cs create mode 100644 MP.MONO.ADAPTER.OLD/appsettings.json create mode 100644 MP.MONO.ADAPTER.OLD/conf/AlarmList.json create mode 100644 MP.MONO.ADAPTER.OLD/conf/MULTIAX.json create mode 100644 MP.MONO.ADAPTER.OLD/conf/ModeList.json create mode 100644 MP.MONO.ADAPTER.OLD/conf/ParamList.json create mode 100644 MP.MONO.ADAPTER.OLD/conf/StatusList.json create mode 100644 MP.MONO.ADAPTER.OLD/post-build.ps1 diff --git a/MP.MONO.ADAPTER.OLD/IobGeneric.cs b/MP.MONO.ADAPTER.OLD/IobGeneric.cs new file mode 100644 index 0000000..b661ac2 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/IobGeneric.cs @@ -0,0 +1,631 @@ +using Microsoft.Extensions.Configuration; +using MP.MONO.Core; +using MP.MONO.Core.CONF; +using Newtonsoft.Json; +using NLog; +using System.Net; +using System.Net.NetworkInformation; +using static MP.MONO.Core.CONF.OpcUaParamConf; +using static MP.MONO.Core.Enums; + +namespace MP.MONO.ADAPTER +{ + public class IobGeneric + { + #region Public Fields + + /// + /// Data/ora ultimo avvio adapter + /// + public DateTime dtAvvioAdp = DateTime.Now; + + /// + /// Data/ora ultimo spegnimento adapter + /// + public DateTime dtStopAdp = DateTime.Now; + + /// + /// dataOra ultimo log periodico... + /// + public DateTime lastPeriodicLog; + + /// + /// dataOra ultimo PING inviato verso il PLC... + /// + public DateTime lastPING = DateTime.Now.AddHours(-1); + + /// + /// Struttura memoria PLC x lettura/scrittura da JSON file + /// + public plcMemMap memMap; + + #endregion Public Fields + + #region Public Constructors + + /// + /// Avvia generico IOB + /// + /// + /// + public IobGeneric(string confPath, IConfigurationRoot? config) + { + lg = LogManager.GetCurrentClassLogger(); + connectionOk = false; + configPath = confPath; + confMan = config; + if (confMan != null) + { + var selection = confMan.GetSection("Endpoint"); + if (selection.Exists()) + { + // recupero dati endpoint + cIobConf = selection.Get(); + } + } + } + + #endregion Public Constructors + + #region Public Properties + + /// + /// Salva verifica stato connessione OK + /// + /// + public virtual bool connectionOk + { + get + { + return _connOk; + } + set + { + _connOk = value; + } + } + + /// + /// Verifica SE si debba fare log verboso (verboso + ogni tot letture IN) + /// + public bool verboseLog + { + get + { + bool answ = false; + int logEvery = confMan.GetValue("logEvery"); + if (logEvery < 1) + { + logEvery = 10; + } + + answ = confMan.GetValue("verbose") && (nReadIN % logEvery == 0); + return answ; + } + } + + #endregion Public Properties + + #region Public Methods + + /// + /// Esecuzione dei task richiesti e pulizia coda richieste eseguite + /// + /// + public virtual Dictionary executeTasks(Dictionary task2exe) + { + // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + if (task2exe != null) + { + // controllo se memMap != null... + if (memMap != null) + { + bool taskOk = false; + string taskVal = ""; + // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY... + switch (tName) + { + case taskType.setArt: + case taskType.setComm: + case taskType.setProg: + case taskType.setPzComm: + // recupero dati da memMap... + if (memMap != null && memMap.mMapWrite != null) + { + if (memMap.mMapWrite.ContainsKey(item.Key)) + { + dataConf currMem = memMap.mMapWrite[item.Key]; + string addr = currMem.memAddr; + taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte"; + // salvo il nuovo valore nella memoria... così prox invio lo trasmetterà + memMap.mMapWrite[item.Key].value = item.Value; + } + else + { + taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}"; + } + } + else + { + taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}"; + } + // salvo in currProd.. + saveProdData(new KeyValuePair(item.Key, item.Value)); + + break; + + case taskType.forceResetPzCount: + // reset contapezzi inizio setup + taskOk = resetcontapezziPLC(); + taskVal = taskOk ? "RESET PZ COUNT OK" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata forceResetPzCount: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + + case taskType.startSetup: + // reset contapezzi inizio setup + taskOk = resetcontapezziPLC(); + taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + + case taskType.stopSetup: + // reset contapezzi fine setup SE ESPLICITAMENTE IMPOSTATO + if (confMan.GetValue("ENABLE_PZ_RESET_stopSetup")) + { + taskOk = resetcontapezziPLC(); + } + taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + + case taskType.setParameter: + // richiedo da URL i parametri WRITE da popolare + lgInfo("Chiamata setParameter --> processMemWriteRequests"); + taskVal = processMemWriteRequests(); + // se restituiscce "" faccio altra prova... + if (string.IsNullOrEmpty(taskVal)) + { + // i parametri me li aspetto come stringa composta paramName|paramvalue + if (item.Value.Contains("|")) + { + string[] paramsJob = item.Value.Split('|'); + taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; + } + else + { + taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; + } + } + break; + + default: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + } + // aggiungo task! + taskDone.Add(item.Key, taskVal); + } + } + else + { + lgError($"Attenzione! memMap è nullo, non posso eseguire task2exe!"); + } + } + + return taskDone; + } + + /// + /// Metodo generico di reset contapezzi... + /// + /// + public virtual bool resetcontapezziPLC() + { + return false; + } + + /// + /// Salva valori indicati in prod data + /// + /// Item KVP di cui salvare i dati in currProdData come chiave/valore + /// + public void saveProdData(KeyValuePair item) + { + // imposto i valori... + if (currProdData.ContainsKey(item.Key)) + { + currProdData[item.Key] = item.Value; + } + else + { + currProdData.Add(item.Key, item.Value); + } + } + + /// + /// Metodo base connessione... + /// + public virtual void tryConnect() + { + dtAvvioAdp = DateTime.Now; + } + + #endregion Public Methods + + #region Protected Fields + + /// + /// wrapper di log + /// + protected static Logger lg; + + protected bool _connOk = false; + + /// + /// Dizionario valori impostati x produzione + /// + protected Dictionary currProdData = new Dictionary(); + + /// + /// Dizionario ultimi valori (double) delle TSVC + /// + protected Dictionary LastTSVC = new Dictionary(); + + /// + /// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...) + /// + protected Dictionary TSVC_Data = new Dictionary(); + + #endregion Protected Fields + + #region Protected Properties + + /// + /// Numero letture IN da avvio + /// + protected int nReadIN { get; set; } + + /// + /// COnfiguraizone Endpoint corrente + /// + private EndpointData cIobConf { get; set; } = new EndpointData(); + + /// + /// test ping all'indirizzo PLC/CNC impostato nei parametri + /// + /// + protected IPStatus testPingMachine + { + get + { + IPStatus answ = IPStatus.Unknown; + // se disabilitato salto... + if (pingDisabled) + { + answ = IPStatus.Success; + } + else + { + IPAddress address; + PingReply reply; + using (Ping pingSender = new Ping()) + { + address = IPAddress.Loopback; + int pingMsTimeout = cIobConf.PingMsTimeout; + IPAddress.TryParse(cIobConf.IpAddress, out address); + try + { + // se != null --> uso address... + if (address != null) + { + reply = pingSender.Send(address, pingMsTimeout); + } + else + { + reply = pingSender.Send(cIobConf.IpAddress, pingMsTimeout); + } + } + catch + { + reply = pingSender.Send(IPAddress.Loopback, pingMsTimeout); + } + answ = reply.Status; + } + } + return answ; + } + } + /// + /// indica se ping disabilitato da optPar + /// + public bool pingDisabled + { + get + { + bool answ = false; + bool.TryParse(confMan.GetValue("NO_PING"), out answ); + return answ; + } + } + + #endregion Protected Properties + + #region Protected Methods + + /// + /// Stringa raw dei parametri da scrivere... + /// + /// + protected string getParams2write() + { + string answ = ""; + // recuperare da una apposita area REDIS... +#if false + string url2call = $"{urlGetParams2Write}"; + if (verboseLog) + { + lgInfo("chiamata URL " + url2call); + } + answ = utils.callUrlNow(url2call); + // se vuoto faccio seconda prova... + if (string.IsNullOrEmpty(answ)) + { + answ = utils.callUrlNow(url2call); + } +#endif + return answ; + } + + /// + /// Effettua logging DEBUG corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgDebug(string message) + { + lg.Debug(message); + } + + /// + /// Effettua logging DEBUG corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + protected void lgDebug(string message, params object[] args) + { + lg.Debug(message, args); + } + + /// + /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgError(string message) + { + lg.Error(message); + } + + /// + /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + protected void lgError(string message, params object[] args) + { + lg.Error(message, args); + } + + /// + /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + /// + protected void lgError(Exception exception, string message, params object[] args) + { + lg.Error(exception, message, args); + } + + /// + /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgFatal(string message) + { + lg.Fatal(message); + } + + /// + /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + protected void lgFatal(string message, params object[] args) + { + lg.Fatal(message, args); + } + + /// + /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + /// + protected void lgFatal(Exception exception, string message, params object[] args) + { + lg.Fatal(exception, message, args); + } + + /// + /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgInfo(string message) + { + lg.Info(message); + } + + /// + /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + protected void lgInfo(string message, params object[] args) + { + lg.Info(message, args); + } + + /// + /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgTrace(string message) + { + lg.Trace(message); + } + + /// + /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + protected void lgTrace(string message, params object[] args) + { + lg.Trace(message, args); + } + + /// + /// Metodo da overridare x scrivere DAVVERO i parametri sul PLC + /// + /// + protected virtual void plcWriteParams(ref List updatedPar) + { + // non faccio nulla di base... + } + + /// + /// Processa le richieste di scrittura memoria + /// + /// + protected string processMemWriteRequests() + { + string answ = ""; + // li salvo nei parametri in memoria locale (ogni adapter DOVREBBE salvare POI sul VERO PLC) + List writeList = new List(); + List updatedPar = new List(); + // recupero elenco delle cose da fare + string resp = getParams2write(); + if (!string.IsNullOrEmpty(resp)) + { + try + { + writeList = JsonConvert.DeserializeObject>(resp); + // se ho da fare chiamo esecuzione.. + if (writeList.Count > 0) + { + foreach (var item in writeList) + { + // scrivo in memoria + if (memMap.mMapWrite.ContainsKey(item.uid)) + { + memMap.mMapWrite[item.uid].value = item.reqValue; + // accodo in stringa taskVal... + answ += $" | Parameter {item.uid} --> {item.reqValue}"; + // sistemo valori + item.value = item.reqValue; + lgInfo($"Richiesta update parametro {item.uid} | actVal = {item.value} | reqVal = {item.reqValue}"); + item.reqValue = ""; + // salvo in lista da ritrasmettere + updatedPar.Add(item); + } + else + { + answ += $" | Error: parameter {item.uid} not found"; + } + } + // richiamo scrittura parametri su PLC + plcWriteParams(ref updatedPar); + // invio su cloud parametri! + string rawData = JsonConvert.SerializeObject(updatedPar); + lgInfo("Notifica a server scrittura parametri"); +#if false + utils.callUrl($"{urlUpdateWriteParams}", rawData); +#endif + } + } + catch (Exception exc) + { + lgError($"Eccezione in processMemWriteRequests:{Environment.NewLine}{exc}"); + } + } + else + { + lgError("Non è stata ricevuta risposta x task da eseguire"); + } + return answ; + } + + /// + /// setup parametri da file di conf + /// + protected void setupMemMap() + { + lgInfo($"setupMemMap | trovati {memMap.mMapRead.Count} parametri Read (TSVC)"); + lgInfo($"setupMemMap | trovati {memMap.mMapWrite.Count} parametri Write"); + if (confMan.GetValue("verbose")) + { + string rawMemConf = JsonConvert.SerializeObject(memMap, Formatting.Indented); + lgDebug($"setupMemMap | configurazione memoria R/W:{Environment.NewLine}{rawMemConf}"); + } + // se ho variabili read --> genero dati TSVC... + if (memMap.mMapRead.Count > 0) + { + TSVC_Data.Clear(); + LastTSVC.Clear(); + VCData currConf; + int periodo = 0; + VC_func funz = VC_func.POINT; + // accodo nella conf... + foreach (var item in memMap.mMapRead) + { + funz = item.Value.func; + periodo = item.Value.period; + currConf = new VCData() + { + Funzione = funz, + Period = periodo, + DTStart = DateTime.Now.AddHours(-1), + dataArray = new List() + }; + TSVC_Data.Add(item.Key, currConf); + } + // documento... + foreach (var item in TSVC_Data) + { + lgTrace($"TSVC: {item.Key} | periodo: {item.Value.Period} | funz: {item.Value.Funzione}"); + // salvo i valori PREC... + LastTSVC.Add(item.Key, 0); + } + } + } + + #endregion Protected Methods + + #region Private Properties + + internal string configPath { get; set; } = ""; + + internal IConfigurationRoot? confMan { get; set; } = null!; + + #endregion Private Properties + } +} \ No newline at end of file diff --git a/MP.MONO.ADAPTER.OLD/IobOpcUa.cs b/MP.MONO.ADAPTER.OLD/IobOpcUa.cs new file mode 100644 index 0000000..6a0c2a9 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/IobOpcUa.cs @@ -0,0 +1,1342 @@ +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 +{ + /// + /// Classe di comunicazione OPC-UA + /// + public class IobOpcUa : IobGeneric + { + private Logger Log = LogManager.GetCurrentClassLogger(); + + /// + /// 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 + /// + /// + public IobOpcUa(string confPath, IConfigurationRoot? config) : base(confPath , config) + { + + // gestione data filtering... + if (!string.IsNullOrEmpty(config.GetValue("ENABLE_DATA_FILTER"))) + { + bool.TryParse(config.GetValue("ENABLE_DATA_FILTER"), out enableDataFilter); + } + // gestione restart OpcUa client... + if (!string.IsNullOrEmpty(config.GetValue("ENABLE_CLI_RESTART"))) + { + bool.TryParse(config.GetValue("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("OPC_PARAM_CONF"); + if (!string.IsNullOrEmpty(jsonFileName)) + { + // leggo il file... + loadOpcUaConf(jsonFileName); + } + } + + + //#region Public Methods + + /// + /// Processo i task richiesti e li elimino dalla coda 1:1 + /// + /// + public override Dictionary executeTasks(Dictionary task2exe) + { + // uso metodo base x ora + return base.executeTasks(task2exe); + } + + ///// + ///// Recupera uno specifico dataItem + ///// + ///// + ///// + //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; + //} + + ///// + ///// Recupero dati dinamici... + ///// + //public override Dictionary getDynData() + //{ + // Dictionary outVal = new Dictionary(); + // return outVal; + //} + + ///// + ///// Effettua vero processing contapezzi + ///// + //public override void processContapezzi() + //{ + // if (utils.CRB("enableContapezzi")) + // { + // // da ridefinire la gestione base del contapezzi OPC-UA... + // } + //} + + ///// + ///// Effettua lettura semafori principale + ///// Parametri da aggiornare x display in form + ///// + //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); + // } + //} + + ///// + ///// Effettua reset del contapezzi, NON POSSIBILE in questa versione + ///// + ///// + //public override bool resetcontapezziPLC() + //{ + // bool answ = false; + // return answ; + //} + + ///// + ///// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE in questa versione + ///// + ///// + //public override bool setcontapezziPLC(int newPzCount) + //{ + // bool answ = false; + // return answ; + //} + + + /// + /// Verifica SE si debba fare log periodico (ogni "verboseLogTOut" sec...) + /// + public bool periodicLog + { + get + { + bool answ = false; + answ = (DateTime.Now.Subtract(lastPeriodicLog).TotalSeconds > confMan.GetValue("verboseLogTOut")); + if (answ) + { + lastPeriodicLog = DateTime.Now; + } + + return answ; + } + } + + /// + /// Override connessione + /// + public override void tryConnect() + { + if (!connectionOk) + { + // controllo che il ping sia stato tentato almeno pingTestSec fa... + if (DateTime.Now.Subtract(lastPING).TotalSeconds > confMan.GetValue("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 + } + } + + ///// + ///// Override disconnessione + ///// + //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 + + ///// + ///// Verifica ed invia variazioni + ///// + ///// + ///// + ///// + //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; + //} + + ///// + ///// Verifica ed invia variazioni DAL FORMATO RAW data (byte[]) + ///// + ///// + ///// + ///// + //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 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); + //} + + ///// + ///// Evento rilevazione modifica valori --> chiamo checkSend + ///// + ///// + ///// + //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 + + ///// + ///// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing + ///// + //protected Dictionary dataItemMem = new Dictionary(); + + /// + /// Abilitazione restart (da opt par...) + /// + protected bool enableCliRestart = false; + + /// + /// Gestione filtraggio dati + /// + protected bool enableDataFilter = false; + + /// + /// Determina se ha effettuata lettura items in memoria x confronto... + /// + protected bool hasReadItems = false; + + /// + /// Ultimo current received x gestione update periodico... + /// + protected DateTime lastCurrent = DateTime.Now; + + ///// + ///// Oggetto MAIN x connessione MTC + ///// + //protected UAClient UA_ref; + + ///// + ///// Veto controllo status x log... + ///// + //protected DateTime vetoCheckStatus = DateTime.Now; + + //protected int WatchDog = 0; + + //#endregion Protected Fields + + //#region Protected Properties + + ///// + ///// Area dati raw per lettura encoded (SE presente) + ///// + //protected byte[] byteRawData { get; set; } = new byte[1]; + + ///// + ///// Indica se si debba leggere un area di tipo "encoded" (byte raw --> obj) + ///// + //protected bool doByteRead { get; set; } = false; + + ///// + ///// Verifico se abbia ALMENO un errore... + ///// + //protected bool hasError + //{ + // get + // { + // return checkMultiCondition(opcUaParams.condError); + // } + //} + + ///// + ///// Indica se abbia emergenza ARMATA (cond normale) + ///// + //protected bool hasEStopArmed + //{ + // get + // { + // return checkMultiCondition(opcUaParams.condEStop); + // } + //} + + ///// + ///// Indica se abbia stato POWER ON (multicondizione) + ///// + //protected virtual bool hasPowerOn + //{ + // get + // { + // return checkMultiCondition(opcUaParams.condPowerOn); + // } + //} + + ///// + ///// Indica se abbia stato MANUAL (condizioni varie, es stopped) + ///// + //protected virtual bool isManual + //{ + // get + // { + // return checkMultiCondition(opcUaParams.condManual); + // } + //} + + ///// + ///// Indica se abbia stato READY (condizioni varie, es ausiliari OK) + ///// + //protected virtual bool isReady + //{ + // get + // { + // return checkMultiCondition(opcUaParams.condReady); + // } + //} + + ///// + ///// Indica se sia in stato Ssetup + ///// + //protected bool isSetup + //{ + // get + // { + // return checkMultiCondition(opcUaParams.condSetup); + // } + //} + + ///// + ///// Indica se sia in stato WarmUp / CoolDown (riscaldamento/raffreddamento) + ///// + //protected bool isWarmUpCoolDown + //{ + // get + // { + // return checkMultiCondition(opcUaParams.condWarmUpCoolDown); + // } + //} + + ///// + ///// Indica se sia in stato Warning + ///// + //protected bool isWarning + //{ + // get + // { + // return checkMultiCondition(opcUaParams.condWarning); + // } + //} + + ///// + ///// Indica se abbia stato READY (condizioni varie, es ausiliari OK) + ///// + //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); + // } + //} + + ///// + ///// Periodo massimo (in sec) per letture dati RAW in mancanza di eventi + ///// + //protected int lastCurrentMaxElapsed { get; set; } = 120; + + /// + /// Parametri specifici MTC + /// + protected OpcUaParamConf opcUaParams { get; set; } + + ///// + ///// URL x salvataggio elenco dataItems OpcUa + ///// + //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 + + ///// + ///// Verifica un DataItem e se il valore corrisponde a quello indicato come "true value" + ///// restituisce true + ///// + ///// + ///// + ///// + //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; + //} + + ///// + ///// Verifica condizione "multipla" secondo setup json + ///// + ///// Set condizioni da validare + ///// + //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; + //} + + ///// + ///// Verifica / Salva valore e restitusice SE sia variato (e quindi da inviare...) + ///// + ///// + ///// + ///// + ///// + //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; + //} + + ///// + ///// Effettua decodifica aree memoria alla bitmap usata x MAPO + ///// + //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 nodes2Write = new List(); + // 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; + //} + + ///// + ///// Effettua traduzione ITEM da LUT parametrica (key: tipo+id) del file di conf, se non + ///// trovo uso key + ///// + ///// + ///// + ///// + //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; + //} + + /// + /// Effettua lettura file di conf specifico OPC-UA da oggetto serializzato json Nome file da cui leggere i parametri json + /// + 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(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 + + ///// + ///// Elenco degli items da monitorare come risultato del browse iniziale + ///// + //private Dictionary selectedItemList = new Dictionary(); + + //#endregion Private Fields + + //#region Private Methods + + ///// + ///// Vera connessione ad OpcUa + ///// + ///// + //private async Task doConnect() + //{ + // short esitoLink = 0; + // // reset memoria dataItem.. + // dataItemMem = new Dictionary(); + // // 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 nodeIdNameList = new Dictionary(); + // 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 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; + //} + + ///// + ///// Formatta un dataitem x salvataggio in memoria locale + ///// + ///// + ///// + ///// + ///// + ///// + //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; + //} + + ///// + ///// Effettua invio a MP/IO dell'elenco serializzato dei dataItems + ///// + ///// + //private void sendDataItemsList(List 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 + + } +} diff --git a/MP.MONO.ADAPTER.OLD/MP.MONO.ADAPTER.OLD.csproj b/MP.MONO.ADAPTER.OLD/MP.MONO.ADAPTER.OLD.csproj new file mode 100644 index 0000000..3531e0d --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/MP.MONO.ADAPTER.OLD.csproj @@ -0,0 +1,59 @@ + + + + Exe + net6.0 + enable + enable + 1.12206.1410 + + + + + + + + + PreserveNewest + true + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + + + + diff --git a/MP.MONO.ADAPTER.OLD/Program.cs b/MP.MONO.ADAPTER.OLD/Program.cs new file mode 100644 index 0000000..5795497 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/Program.cs @@ -0,0 +1,291 @@ +using Microsoft.Extensions.Configuration; +using MP.MONO.ADAPTER; +using MP.MONO.Core; +using MP.MONO.Core.CONF; +using MP.MONO.Core.DTO; +using Newtonsoft.Json; +using NLog; +using StackExchange.Redis; + +// init parte config, vedere https://blog.hildenco.com/2020/05/configuration-in-net-core-console.html +var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); +var builder = new ConfigurationBuilder() + .AddJsonFile($"appsettings.json", true, true) + .AddJsonFile($"appsettings.{env}.json", true, true) + .AddEnvironmentVariables(); +var config = builder.Build(); + +// imposto variabili di base +string lineSep = "---------------------------------------------"; +string redisConf = config.GetConnectionString("Redis"); +string confPath = Path.Combine(Directory.GetCurrentDirectory(), "conf"); +#if false +string alarmSimMode = config.GetValue("AlarmSimMode"); +#endif +Logger Log = LogManager.GetCurrentClassLogger(); +Random rand = new Random(); +List? statusList = new List(); +List? modeList = new List(); + +// fix numero minimo dei thread pool x evitare collasso chiamate redis +ThreadPool.SetMinThreads(10, 10); + +Dictionary LogSimulator = new Dictionary(); +Dictionary LastSend = new Dictionary(); +DateTime lastLog = DateTime.Now.AddMinutes(-1); +bool verboseLog = false; +bool logWriting = false; + +logInfo(lineSep, true, true); +logInfo($"Starting Machine ADAPTER", true, true); +logInfo($"Redis server param: {redisConf.Substring(0, 20)}...", false, true); +logInfo(lineSep, true, true); +logInfo("", true, true); +logInfo("Running - press CTRL-C to stop SIM", false, true); +logInfo("", false, true); + +// Setup REDIS +ConnectionMultiplexer.SetFeatureFlag("preventthreadtheft", true); +ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(redisConf); +ISubscriber sub = redis.GetSubscriber(); +IDatabase? redisDb = redis.GetDatabase(); + +// salvo configurazioni in redis +setupConf(); + +// avvio il vero e proprio programma di comunicaizone OPC-UA +var currIob = new IobOpcUa(confPath, config); + +#if false +var currSimGen = new Simulator(confPath, modeList.Count, statusList.Count); + +// preparo la lista dei contatori invio... +LogSimulator.Add(Constants.ACT_LOG_M_QUEUE, 0); +LogSimulator.Add(Constants.ALARM_M_QUEUE, 0); +LogSimulator.Add(Constants.EVENT_LOG_M_QUEUE, 0); +LogSimulator.Add(Constants.PARAMS_M_QUEUE, 0); +LogSimulator.Add(Constants.PROD_M_QUEUE, 0); +LogSimulator.Add(Constants.MACH_STATS_M_QUEUE, 0); +LogSimulator.Add(Constants.MAINT_STATS_M_QUEUE, 0); +LogSimulator.Add(Constants.TOOLS_M_QUEUE, 0); + +// avvio tutti i thread... +Thread threadStatus = new Thread(simStatus); +Thread threadAlarms = new Thread(simAlarms); +Thread threadParams = new Thread(simParameters); +Thread threadProd = new Thread(simProd); +Thread threadMachStat = new Thread(simMachStat); +Thread threadMaint = new Thread(simMaint); +Thread threadTools = new Thread(simTools); +Thread threadEvHistory = new Thread(simEvents); +Thread threadActLog = new Thread(simActivityLog); + +threadStatus.Start(); +threadAlarms.Start(); +threadParams.Start(); +threadProd.Start(); +threadMachStat.Start(); +threadMaint.Start(); +threadTools.Start(); +threadEvHistory.Start(); +threadActLog.Start(); +#endif + +// Ciclo infinito x attesa chiusura con CTRL-C +do +{ + // se non fosse connesso... riprovo la connessione... + if (!currIob.connectionOk) + { + currIob.tryConnect(); + } + // attesa... + Thread.Sleep(100); +} while (true); + + +/// +/// verifica esistenza file oppure lo crea... +/// +void checkFilePresent(string filePath) +{ + // verific presenza file log... + if (!File.Exists(filePath)) + { + File.WriteAllText(filePath, $"{filePath} created!"); + } +} + +/// +/// Setup e salvataggio redis delle conf (es modi/stati) +/// +void setupConf() +{ +#if false + // leggo e salvo conf stati + string fullPath = Path.Combine(confPath, "StatusList.json"); + if (File.Exists(fullPath)) + { + var rawData = File.ReadAllText(fullPath); + if (!string.IsNullOrEmpty(rawData)) + { + List? statusList = JsonConvert.DeserializeObject>(rawData); + // salvo in redis! + redisDb.StringSetAsync(Constants.STATUS_CONF_KEY, JsonConvert.SerializeObject(statusList)); + } + } + + // leggo e salvo conf modi + fullPath = Path.Combine(confPath, "ModeList.json"); + if (File.Exists(fullPath)) + { + var rawData = File.ReadAllText(fullPath); + if (!string.IsNullOrEmpty(rawData)) + { + var localObj = JsonConvert.DeserializeObject>(rawData); + // salvo in redis! + redisDb.StringSetAsync(Constants.MODE_CONF_KEY, JsonConvert.SerializeObject(localObj)); + } + } + + // leggo e salvo conf allarmi + fullPath = Path.Combine(confPath, "AlarmList.json"); + if (File.Exists(fullPath)) + { + var rawData = File.ReadAllText(fullPath); + if (!string.IsNullOrEmpty(rawData)) + { + var localObj = JsonConvert.DeserializeObject>(rawData); + if (localObj != null) + { + // sistemo allarmi + foreach (var item in localObj) + { + item.setupData(); + // loggo + logInfo($"Decodifica aree alarmMap: {item.description} | {item.memAddr} x {item.size} byte | {item.messages.Count} messaggi allarme", true, true); + } + } + // salvo in redis! + redisDb.StringSetAsync(Constants.ALARMS_CONF_KEY, JsonConvert.SerializeObject(localObj)); + } + } + + // leggo e salvo conf parametri + fullPath = Path.Combine(confPath, "ParamList.json"); + if (File.Exists(fullPath)) + { + var rawData = File.ReadAllText(fullPath); + if (!string.IsNullOrEmpty(rawData)) + { + var localObj = JsonConvert.DeserializeObject>(rawData); + // salvo in redis! + redisDb.StringSetAsync(Constants.PARAMS_CONF_KEY, JsonConvert.SerializeObject(localObj)); + } + } +#endif + + ConfigManager configManager = new ConfigManager(redisConf, confPath); + _ = configManager.getAlarmsConf(); + _ = configManager.getMachineModeConf(); + _ = configManager.getMachineStatusConf(); + _ = configManager.getParamsConf(); +} + +/// +/// Effettua log INFO su file e se richiesto su console +/// +void logInfo(string msg, bool log2file = true, bool log2console = false) +{ + if (log2console) + { + Console.WriteLine(msg); + } + if (log2file) + { + Log.Info(msg); + } +} +/// +/// Effettua log ERROR su file e se richiesto su console +/// +void logError(string msg, bool log2file = true, bool log2console = false) +{ + if (log2console) + { + Console.WriteLine(msg); + } + if (log2file) + { + Log.Error(msg); + } +} + +void saveAndSendMessage(string memKey, string value, string notifyChannel, string message) +{ + // effettuo la scrittura nell'area di memoria indicata SE passato intervallo minimo + bool doSend = true; + if (LastSend.ContainsKey(memKey)) + { + if (DateTime.Now.Subtract(LastSend[memKey]).TotalSeconds < 60) + { + doSend = false; + } + } + else + { + LastSend.Add(memKey, DateTime.Now); + } + if (doSend) + { + redisDb.StringSetAsync(memKey, value); + LastSend[memKey] = DateTime.Now; + logInfo($"Redis Cache Key: {memKey}"); + } + //redisDb.SetAdd(memKey, value); + + // invio notifica tramite il canale richiesto + sub.Publish(notifyChannel, message); + if (verboseLog) + { + logInfo($"[{notifyChannel}] key: {memKey} | val: {value} | message: {message}"); + } + else + { + try + { + if (!logWriting) + { + if (LogSimulator.ContainsKey(notifyChannel)) + { + LogSimulator[notifyChannel]++; + } + else + { + LogSimulator.Add(notifyChannel, 1); + } + logWriting = true; + // vedo se loggare... + DateTime adesso = DateTime.Now; + if (adesso.Subtract(lastLog).TotalSeconds > 15) + { + lastLog = adesso; + logInfo(lineSep); + + // lavoro su copia... + var LogSimulatorCopy = new Dictionary(LogSimulator); + foreach (var item in LogSimulatorCopy) + { + logInfo($"Redis mQueue {item.Key,-20}{item.Value,12}"); + } + logInfo(lineSep); + } + logWriting = false; + } + } + catch (Exception ex) + { + logError($"ERROR{Environment.NewLine}{ex}"); + } + } +} \ No newline at end of file diff --git a/MP.MONO.ADAPTER.OLD/Resources/ChangeLog-original.html b/MP.MONO.ADAPTER.OLD/Resources/ChangeLog-original.html new file mode 100644 index 0000000..3cf89dd --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/Resources/ChangeLog-original.html @@ -0,0 +1,26 @@ + + MAPO-MONO +

Version: {{CURRENT-REL}}

+
Release Note: +
    +
  • + Last changes: +
      {{LAST-CHANGES}}
    +
  • +
  • + v.1.0.* → +
      +
    • Current CORE version
    • +
    • Release dotnet6
    • +
    +
  • +
+
+
+ +
+ +
+ \ No newline at end of file diff --git a/MP.MONO.ADAPTER.OLD/Resources/ChangeLog.html b/MP.MONO.ADAPTER.OLD/Resources/ChangeLog.html new file mode 100644 index 0000000..ecdcea3 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/Resources/ChangeLog.html @@ -0,0 +1,26 @@ + + MAPO-MONO +

Version: 1.12206.1410

+
Release Note: +
    +
  • + Last changes: +
      {{LAST-CHANGES}}
    +
  • +
  • + v.1.0.* → +
      +
    • Current CORE version
    • +
    • Release dotnet6
    • +
    +
  • +
+
+
+ +
+ +
+ diff --git a/MP.MONO.ADAPTER.OLD/Resources/VersNum.txt b/MP.MONO.ADAPTER.OLD/Resources/VersNum.txt new file mode 100644 index 0000000..3720595 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/Resources/VersNum.txt @@ -0,0 +1 @@ +1.12206.1410 diff --git a/MP.MONO.ADAPTER.OLD/Resources/logoSteamware.png b/MP.MONO.ADAPTER.OLD/Resources/logoSteamware.png new file mode 100644 index 0000000000000000000000000000000000000000..0958b50a1ee7f6a934e26cf55e2335d4cea6aa82 GIT binary patch literal 3402 zcmV-Q4Yl%#P)Kpl00004XF*Lt006O% z3;baP00009a7bBm000ia000ia0czHX2><{98FWQhbW?9;ba!ELWdKlNX>N2bPDNB8 zb~7$DE;85dX+r=2497`CK~#8N?VEXYRMi>4lgUh$nd~9N?8#&%lgvKZ7a%JLgb=8< zJ+;y z?+!1~Kq%Ee{3ChaIrqG~eD}UL@B6*)`|g{Wuy0Bd19D`vPgk>EW=B z{upI=m_+%c`RJTNcSmx!oT+rHqRMcI3&>_bIUd#}ol(j`U6)j)3=b3Z<}?0@#w%?H z#_YW32Q(?Y!Ej|*6;;kkq)##e$!CL50nS0aZ)B+OVzHEO83M9f=aaHy{L*~p*BJb= z3YIEgNJ6(98R3HyIED%LNjMf>C*1JAO!fMiKO#~X!rN)hNTWX{LH_1E-X zIXbg97@xsWQBh^AOV-+8RFqe;>b(6{z|ad11Te>h=K`|cc)ygasGgOM{&1aFY5~S= zK)yfDTZW1Jo%2 z6=gF<&*Yd!aZn6GFSSS3qL-2okYmC+B@YnpB7t8GSZM%S8snD}Lks>7AulTh+BaD9 zDD(S)^XmL{vQ`;ZWi$yPuarFNC5+uinH%GiV*%!m)b|3|yd=LIF^;ea6ger~a#Td8 z6iFU7MempFF>sk?yS5Rm+gP-v$9GGl8Zy;3$FXBH&{ z&Y+OHrA7JVP7ziKn{VOeTrocB2G%?|2o?Q-#DJ8fOi^Vt%lIBygSToVq}_}+DgY1z z06YQ+$AId7U@`&AE5Owe>zBqU(}oH9<>^^)K|`P$how5o<%?;;mO_vDm@|3810uX!=sgjb@rQ6#lTPR?EzbO2Q=Ugslnp{IfBf?iASlW##s>=HMm z_nx08jT5gU0+LQ?sxlS@FZCD+_J5MPJl)`hgMRZ-;&(feibi-X1FLr(LCV8}Bi1mtf6&8A47ya>P|MPG8aY{omi9v_fra?E19 zf;sA2a#e;)YL6T@zE>`f^_|_l4GJEr1MhVPkFs~z0VPJVk=?)3GRU>`R0oUC0UU}%9ldiM>yf1^xJ*AP3Vq3Y*Qq*4Ra<42h z7cO+!9Ud_@p{hnx;&i7L8ViR12vC*LDZrF~Hwxubz_m{44oT7aV0cfBRJSE3bY<-UYc_C$0M!9rK;UwO9hJZYm9BJ70 zpB>?J%0^%lzw|6ty3dmp_udy#Y_>daDKH%>GMV#=&4p1Ohcl(r?J*P|lL+nY$!yQtiZu>Wa!lK(^u~Z8eouaYDCcT8qB9p)tFuz9FZv zu0E9e(M}cZDNW63*Up`%nK5m8?4V9lUA^Jb<|(?$vhpk*1iLxk=qPo0jHT|9p=+z3 zRA=BCj24sGQIMPG;B$mLFxMOHb~sI9PGxCX&dk=C7yO!QOv=O;2gIv`%_66woC2)7 zVlMF8^55LIA`+N3b2Iniu@W)((92E?pNrS}Gh-((!27_prOZ>Rt)Dn4#%*^jX6#kQ zb^ymK=*|H|9YBTy<^z@j^ESq|7aC1Ftc8|GSa-ZwlfG*xn<#Gr-9K34MXRM~Dc8_T z-%k48Wd7rByE6}fE2wW|?C(yi?I%;3Cr5D&t3;bMpQx>>NpsrlSD^D6eShPcCUYHk zvZgrqZmxL`^*7MHt*X2tp7Xf5)(+9fdG;{g2Y^jHEUCc!2oK0EF^BeR=-%vcx<>qO z<(QNSFC7to(|TEf>LgGt{qp;&bH!e4UBu1&n42Bo32rGaw1hkhPrspV!o)e;V2QrR zn(7*+;R&=D_&QU*aUb*MRhL&5VW>MW(qRldQOx71p8;U?lWJ~EE}xE?Fe-NpI#(%wROhqX>qj?mwhmzCXyZcx!birzuImX+hvO5cY9Ec8!M zP6Fdq&5h0KHwuHoPOp)j-x`fqS`izN%}V!(!p%$J#{QHWxsUPzPwHcUQzXU+FD{IA z(3F?ANVEwN3Fxi^hSeo*Pa5qc#%t-@NBC-QZJ7}ch+2S10s=Fj%wRo{tF?>y0xHU< zqAmnjS{Oe#p{hCr-Nf37(HQtWpz}_su8C&+Nnvo--_DwCtRtZKoa1p|zmo9{Vw^R4 zN?h(Ft|uS3r&7MhoE7LDQS@*8GE`jKN_0x?Mb>&?;`8Mn1L)iMEOpfTgbtt4Us+b6 zdMhEGjX_PkPfkzoku&TYga21BgCPO(1ozl-i^ z=A2~Rw`dFRCgzGcTPUIYZcK~#u8+`n8#}|@c&R?>*F|+nQOfW|g&f0xVV>b;?kB{h zoeLE={St2aRt&J2oZ~9OTLoUtgi$j%>aB%ERm?jKY)hOrTP`{d#zg+|wV)!5S~0l9 zIgg^ZhvNX(^AN{RX}?Vop=tmRRS#qp)Pt0hoWGOy?bHu*jtfFXJ~oT>LlE)VKHzh0 zq;D0UnmAVth`T7al2WV5Y;mw8qPK@|APxkMD<|&M@ z8LwrnsjSY&Q}qGLRzhhzV=Jf&PqSE@@2f&pT~VQB?Yq%CB@E9wH~&j|;>9CSBvE}{Dwz^d_n(7;c zr?rXe;u^djhg0Nr&vNd?^jWggGpwxLF6LF0S2l$fN6?8vrp9kk&HU@PK gb@ksMRAFKN1+dqwbM3SFTL1t607*qoM6N<$g3&)|djJ3c literal 0 HcmV?d00001 diff --git a/MP.MONO.ADAPTER.OLD/Resources/manifest-original.xml b/MP.MONO.ADAPTER.OLD/Resources/manifest-original.xml new file mode 100644 index 0000000..a9269ca --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/Resources/manifest-original.xml @@ -0,0 +1,7 @@ + + + 1.0.0.0 + http://nexus.steamware.net/repository/SWS/{{DIRNAME}}/{{BRANCHNAME}}/{{PACKNAME}}.zip + http://nexus.steamware.net/repository/SWS/{{DIRNAME}}/{{BRANCHNAME}}/ChangeLog.html + false + diff --git a/MP.MONO.ADAPTER.OLD/Resources/manifest.xml b/MP.MONO.ADAPTER.OLD/Resources/manifest.xml new file mode 100644 index 0000000..23bb8cd --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/Resources/manifest.xml @@ -0,0 +1,7 @@ + + + 1.12206.1410 + http://nexus.steamware.net/repository/SWS/MP.MONO.ADAPTER/stable/LAST/MP.Mon.zip + http://nexus.steamware.net/repository/SWS/MP.MONO.ADAPTER/stable/LAST/ChangeLog.html + false + diff --git a/MP.MONO.ADAPTER.OLD/UAClient.cs b/MP.MONO.ADAPTER.OLD/UAClient.cs new file mode 100644 index 0000000..cd8fb8e --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/UAClient.cs @@ -0,0 +1,1005 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Collections; +using Opc.Ua; +using Opc.Ua.Client; +using NLog; + +namespace MP.MONO.ADAPTER +{ + /// + /// Evento per incapsulare dati x refresh pagina + /// + public class opcUaMonitItemChange : EventArgs + { + #region Private Fields + + /// + /// Monitored Item da notificare + /// + private readonly MonitoredItem _monitoredItem; + + /// + /// Valore notifica + /// + private readonly MonitoredItemNotification _notification; + + #endregion Private Fields + + #region Public Constructors + + /// + /// salvataggio obj + /// + /// + public opcUaMonitItemChange(MonitoredItem monitoredItem, MonitoredItemNotification notification) + { + _monitoredItem = monitoredItem; + _notification = notification; + } + + #endregion Public Constructors + + #region Public Properties + + /// + /// Proprietà lettura del MonitoredItem + /// + public MonitoredItem CurrMonitoredItem + { + get { return _monitoredItem; } + } + + /// + /// Proprietà lettura della notifica + /// + public MonitoredItemNotification CurrNotify + { + get { return _notification; } + } + + #endregion Public Properties + } + /// + /// OPC UA Client with examples of basic functionality. + /// + public class UAClient + { + #region Private Fields + + private readonly string currIob; + private readonly Action m_validateResponse; + private ApplicationConfiguration m_configuration; + private Session m_session; + + #endregion Private Fields + + #region Protected Fields + + protected static Logger lg; + protected static bool isLogVerbose = false; + + + /// + /// The user identity to use when creating the session. + /// + public IUserIdentity CurrUserIdentity { get; set; } = new UserIdentity(); + + #endregion Protected Fields + + #region Public Constructors + + /// + /// Initializes a new instance of the UAClient class. + /// + public UAClient(ApplicationConfiguration configuration, string codIOB, string user, string pwd, bool verboseLog, Action validateResponse) + { + m_validateResponse = validateResponse; + currIob = codIOB; + lg = LogManager.GetCurrentClassLogger(); + if (!string.IsNullOrEmpty(user) && !string.IsNullOrEmpty(pwd)) + { + CurrUserIdentity = new UserIdentity(user, pwd); + } + else + { + CurrUserIdentity = new UserIdentity(); + } + isLogVerbose = verboseLog; + m_configuration = configuration; + m_configuration.CertificateValidator.CertificateValidation += CertificateValidation; + } + + #endregion Public Constructors + + #region Public Events + + /// + /// Evento notifica variazione MonitoredItem + /// + public event EventHandler eh_MonItChange; + + #endregion Public Events + + #region Public Properties + + /// + /// Gets or sets the server URL. + /// + public string ServerUrl { get; set; } = "opc.tcp://localhost:4840"; + + /// + /// Gets the client session. + /// + public Session Session => m_session; + + #endregion Public Properties + + #region Private Methods + + /// + /// Handles the certificate validation event. + /// This event is triggered every time an untrusted certificate is received from the server. + /// + private void CertificateValidation(CertificateValidator sender, CertificateValidationEventArgs e) + { + bool certificateAccepted = true; + + // **** + // Implement a custom logic to decide if the certificate should be + // accepted or not and set certificateAccepted flag accordingly. + // The certificate can be retrieved from the e.Certificate field + // *** + + ServiceResult error = e.Error; + while (error != null) + { + lgError($"{error.StatusCode} | {error.Code} | {error.LocalizedText}"); + error = error.InnerResult; + } + + if (certificateAccepted) + { + lgInfo($"Untrusted Certificate accepted. SubjectName = {e.Certificate.SubjectName}"); + } + + e.AcceptAll = certificateAccepted; + } + + /// + /// Handle DataChange notifications from Server + /// + private void OnMonitoredItemNotification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e) + { + try + { + // Log MonitoredItem Notification event + MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification; + + // 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}"); + } + catch (Exception ex) + { + lgError($"OnMonitoredItemNotification error: {ex.Message}"); + } + } + + #endregion Private Methods + + #region Protected Methods + + /// + /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgError(string message) + { + lg.Factory.Configuration.Variables["codIOB"] = currIob; + lg.Error(message); + } + + /// + /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgInfo(string message) + { + lg.Factory.Configuration.Variables["codIOB"] = currIob; + lg.Info(message); + } + + /// + /// Effettua logging DEBUG corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgDebug(string message) + { + lg.Factory.Configuration.Variables["codIOB"] = currIob; + lg.Info(message); + } + /// + /// Effettua logging TRACE corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgTrace(string message) + { + lg.Factory.Configuration.Variables["codIOB"] = currIob; + lg.Trace(message); + } + + #endregion Protected Methods + + #region Public Methods + + /// + /// Browse Server nodes + /// + public bool Browse(ushort startNodeNS, uint startNodeVal, List vetoBrowse, ref Dictionary nodeIdNameList) + { + bool fatto = false; + if (m_session == null || m_session.Connected == false) + { + lgError("Session not connected!"); + return false; + } + + try + { + // Create a Browser object + Browser browser = new Browser(m_session); + + // Set browse parameters + browser.BrowseDirection = BrowseDirection.Forward; + browser.NodeClassMask = (int)NodeClass.Object | (int)NodeClass.Variable; + browser.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences; + + //NodeId nodeToBrowse = ObjectIds.Server; + //NodeId nodeToBrowse = new NodeId("ns=4,i=5001"); + NodeId nodeToBrowse = new NodeId(startNodeVal, startNodeNS); + + // Call Browse service + lgTrace($"Browsing {nodeToBrowse} node..."); + ReferenceDescriptionCollection browseResults = browser.Browse(nodeToBrowse); + + // Display the results + lgTrace($"Browse returned {browseResults.Count} results:"); + + foreach (ReferenceDescription result in browseResults) + { + lgTrace($" NodeId = {result.NodeId}, TypeId = {result.TypeId}, DisplayName = {result.DisplayName.Text}, NodeClass = {result.NodeClass}, Others: {result.BinaryEncodingId} | {result.BrowseName}"); + // se NON fa parte dell'elenco dei VETO di filterItems... + if (!vetoBrowse.Contains($"{result.NodeId}")) + { + // se mancasse aggiungo... + if (!nodeIdNameList.ContainsKey($"{result.NodeId}")) + { + nodeIdNameList.Add(result.NodeId.ToString(), result.DisplayName.Text); + } + } + } + fatto = true; + } + catch (Exception ex) + { + // Log Error + lgError($"Browse Error : {ex.Message}"); + } + + return fatto; + } + + /// + /// Browse Server nodes + /// + public bool Browse(string browsePath, List vetoBrowse, ref Dictionary nodeIdNameList) + { + bool fatto = false; + if (m_session == null || m_session.Connected == false) + { + lgError("Session not connected!"); + return false; + } + + try + { + // Create a Browser object + Browser browser = new Browser(m_session); + + // Set browse parameters + browser.BrowseDirection = BrowseDirection.Forward; + browser.NodeClassMask = (int)NodeClass.Object | (int)NodeClass.Variable; + browser.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences; + + //NodeId nodeToBrowse = ObjectIds.Server; + //NodeId nodeToBrowse = new NodeId("ns=4;i=5001"); + NodeId nodeToBrowse = new NodeId(browsePath); + //nodeToBrowse = ObjectIds.Server; + //nodeToBrowse = new NodeId("Calibratrice_L1", 4); + //nodeToBrowse = new NodeId("Dati_Mes", 4); + //nodeToBrowse = new NodeId(5001, 2); + //nodeToBrowse = new NodeId("ns=4;s=NxController"); + //nodeToBrowse = new NodeId("ns=4;s=Dati_Mes"); + //nodeToBrowse = new NodeId("NxController.GlobalVars", 4); + //nodeToBrowse = new NodeId("Dati_Mes", 4); + + // Call Browse service + lgTrace($"Browsing {nodeToBrowse} node..."); + ReferenceDescriptionCollection browseResults = browser.Browse(nodeToBrowse); + + // Display the results + lgTrace($"Browse returned {browseResults.Count} results:"); + + foreach (ReferenceDescription result in browseResults) + { + // se veto --> loggo veto + if (vetoBrowse.Contains($"{result.NodeId}")) + { + lgTrace($"| FILTERED --> NodeId = {result.NodeId}, DisplayName = {result.DisplayName.Text}, NodeClass = {result.NodeClass}, Others: {result.BinaryEncodingId} | {result.BrowseName}"); + } + // se NON fa parte dell'elenco dei VETO di filterItems... + else + { + lgTrace($" NodeId = {result.NodeId}, DisplayName = {result.DisplayName.Text}, NodeClass = {result.NodeClass}, Others: {result.BinaryEncodingId} | {result.BrowseName}"); + // se mancasse aggiungo... + if (!nodeIdNameList.ContainsKey($"{result.NodeId}")) + { + nodeIdNameList.Add($"{result.NodeId}", result.DisplayName.Text); + // se è un nodo object --> faccio sub browse! + if (result.NodeClass != NodeClass.Variable) + { + this.Browse($"{result.NodeId}", vetoBrowse, ref nodeIdNameList); + } + } + } + } + fatto = true; + } + catch (Exception ex) + { + // Log Error + lgError($"Browse Error : {ex.Message}"); + } + + return fatto; + } + + /// + /// Call UA method + /// + public void CallMethod() + { + if (m_session == null || m_session.Connected == false) + { + lgError("Session not connected!"); + return; + } + + try + { + // Define the UA Method to call + // Parent node - Objects\CTT\Methods + // Method node - Objects\CTT\Methods\Add + NodeId objectId = new NodeId("ns=2;s=Methods"); + NodeId methodId = new NodeId("ns=2;s=Methods_Add"); + + // Define the method parameters + // Input argument requires a Float and an UInt32 value + object[] inputArguments = new object[] { (float)10.5, (uint)10 }; + IList outputArguments = null; + + // Invoke Call service + lgDebug($"Calling UAMethod for node {methodId} ..."); + outputArguments = m_session.Call(objectId, methodId, inputArguments); + + // Display results + lgDebug($"Method call returned {outputArguments.Count} output argument(s):"); + + foreach (var outputArgument in outputArguments) + { + lgDebug($" OutputValue = {outputArgument}"); + } + } + catch (Exception ex) + { + lgError($"Method call error: {ex.Message}"); + } + } + + /// + /// Creates a session with the UA server + /// + public async Task ConnectAsync() + { + try + { + if (m_session != null && m_session.Connected == true) + { + lgInfo("Session already connected!"); + } + else + { + lgInfo("Connecting..."); + + // Get the endpoint by connecting to server's discovery endpoint. + // Try to find the first endopint without security. + EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(ServerUrl, false); + + EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration); + ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration); + + // Create the session + Session session = await Session.Create( + m_configuration, + endpoint, + false, + false, + m_configuration.ApplicationName, + 30 * 60 * 1000, + CurrUserIdentity, + null + ); + + // Assign the created session + if (session != null && session.Connected) + { + m_session = session; + } + + // Session created successfully. + lgInfo($"New Session Created with SessionName = {m_session.SessionName}"); + } + + return true; + } + catch (Exception ex) + { + // Log Error + lgError($"Create Session Error : {ex.Message}"); + return false; + } + } + + /// + /// Disconnects the session. + /// + public void Disconnect() + { + try + { + if (m_session != null) + { + lgInfo("Disconnecting..."); + + m_session.Close(); + m_session.Dispose(); + m_session = null; + + // Log Session Disconnected event + lgInfo("Session Disconnected."); + } + else + { + lgError("Session not created!"); + } + } + catch (Exception ex) + { + // Log Error + lgError($"Disconnect Error : {ex.Message}"); + } + } + + /// + /// Read a SINGLE of nodes value from Server + /// + /// + /// + public string ReadNode(NodeId reqNodeId) + { + string answ = ""; + if (m_session == null || m_session.Connected == false) + { + lgError("Session not connected!"); + return answ; + } + + try + { + //#region Read a node by calling the Read Service + + //// build a list of nodes to be read + //ReadValueIdCollection nodesToRead = new ReadValueIdCollection() + //{ + // // Value of ServerStatus + // new ReadValueId() { NodeId = Variables.Server_ServerStatus, AttributeId = Attributes.Value }, + // // BrowseName of ServerStatus_StartTime + // new ReadValueId() { NodeId = Variables.Server_ServerStatus_StartTime, AttributeId = Attributes.BrowseName }, + // // Value of ServerStatus_StartTime + // new ReadValueId() { NodeId = Variables.Server_ServerStatus_StartTime, AttributeId = Attributes.Value } + //}; + + //// Read the node attributes + //lgInfo("Reading nodes..."); + + //// Call Read Service + //m_session.Read( + // null, + // 0, + // TimestampsToReturn.Both, + // nodesToRead, + // out DataValueCollection resultsValues, + // out DiagnosticInfoCollection diagnosticInfos); + + //// Validate the results + //m_validateResponse(resultsValues, nodesToRead); + + //// Display the results. + //foreach (DataValue result in resultsValues) + //{ + // 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); + answ = $"{resp.Value}"; + } + catch (Exception exc) + { + // Log Error + lgError($"ReadValue Error : {Environment.NewLine}{exc}"); + } + + #endregion Read the Value attribute of a node by calling the Session.ReadValue method + } + catch (Exception ex) + { + // Log Error + lgError($"Read Nodes Error : {ex.Message}."); + } + return answ; + } + + + /// + /// Read a SINGLE of nodes value (RAW) from Server + /// + /// + /// + public object ReadNodeRaw(NodeId reqNodeId) + { + object answ = null; + if (m_session == null || m_session.Connected == false) + { + lgError("Session not connected!"); + return answ; + } + + try + { + + #region Read the Value attribute of a node by calling the Session.ReadValue method + + try + { + DataValue resp = m_session.ReadValue(reqNodeId); + answ = resp; + } + catch (Exception exc) + { + // Log Error + lgError($"ReadNodeRaw Error 01: {Environment.NewLine}{exc}"); + } + + #endregion Read the Value attribute of a node by calling the Session.ReadValue method + } + catch (Exception ex) + { + // Log Error + lgError($"ReadNodeRaw Error 02: {ex.Message}."); + } + return answ; + } + + + + /// + /// Read a list of nodes from Server + /// + public void ReadNodes() + { + if (m_session == null || m_session.Connected == false) + { + lgError("Session not connected!"); + return; + } + + try + { + #region Read a node by calling the Read Service + + // build a list of nodes to be read + ReadValueIdCollection nodesToRead = new ReadValueIdCollection() + { + // Value of ServerStatus + new ReadValueId() { NodeId = Variables.Server_ServerStatus, AttributeId = Attributes.Value }, + // BrowseName of ServerStatus_StartTime + new ReadValueId() { NodeId = Variables.Server_ServerStatus_StartTime, AttributeId = Attributes.BrowseName }, + // Value of ServerStatus_StartTime + new ReadValueId() { NodeId = Variables.Server_ServerStatus_StartTime, AttributeId = Attributes.Value } + }; + + // Read the node attributes + lgInfo("Reading nodes..."); + + // Call Read Service + m_session.Read( + null, + 0, + TimestampsToReturn.Both, + nodesToRead, + out DataValueCollection resultsValues, + out DiagnosticInfoCollection diagnosticInfos); + + // Validate the results + m_validateResponse(resultsValues, nodesToRead); + + // Display the results. + foreach (DataValue result in resultsValues) + { + lgTrace($"Read Value = {result.Value} , StatusCode = {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 + + // Read Server NamespaceArray + lgTrace("Reading Value of NamespaceArray node..."); + DataValue namespaceArray = m_session.ReadValue(Variables.Server_NamespaceArray); + // Display the result + lgTrace($"NamespaceArray Value = {namespaceArray}"); + + #endregion Read the Value attribute of a node by calling the Session.ReadValue method + } + catch (Exception ex) + { + // Log Error + lgError($"Read Nodes Error : {ex.Message}."); + } + } + + /// + /// Create Subscription and MonitoredItems for DataChanges + /// + public List SubscribeToDataChanges(Dictionary DataList) + { + List monItList = new List(); + if (m_session == null || m_session.Connected == false) + { + lgError("Session not connected!"); + return monItList; + } + + try + { + // Create a subscription for receiving data change notifications + + // Define Subscription parameters + Subscription subscription = new Subscription(m_session.DefaultSubscription); + + subscription.DisplayName = "Steamware IOB-WIN Subscription"; + subscription.PublishingEnabled = true; + subscription.PublishingInterval = 1000; + + m_session.AddSubscription(subscription); + + // Create the subscription on Server side + subscription.Create(); + lgInfo($"New Subscription created with SubscriptionId = {subscription.Id}"); + + // Create MonitoredItems for data changes + foreach (var item in DataList) + { + MonitoredItem currMonIt = new MonitoredItem(subscription.DefaultItem); + // Int32 Node - Objects\CTT\Scalar\Simulation\Int32 + currMonIt.StartNodeId = new NodeId(item.Key); + currMonIt.AttributeId = Attributes.Value; + currMonIt.DisplayName = item.Value; + currMonIt.SamplingInterval = 1000; + currMonIt.Notification += OnMonitoredItemNotification; + subscription.AddItem(currMonIt); + 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}"); + } + catch (Exception ex) + { + lgError($"Subscribe error: {ex.Message}"); + } + return monItList; + } + + /// Write a list of nodes to the Server + /// + public void WriteNodes(List node2Write) + { + if (m_session == null || m_session.Connected == false) + { + lgError("Session not connected!"); + return; + } + + try + { + // Write the configured nodes + WriteValueCollection nodesToWrite = new WriteValueCollection(); + nodesToWrite.AddRange(node2Write); + + // Write the node attributes + StatusCodeCollection results = null; + DiagnosticInfoCollection diagnosticInfos; + lgDebug("Writing nodes..."); + + // Call Write Service + m_session.Write(null, + nodesToWrite, + out results, + out diagnosticInfos); + + // Validate the response + m_validateResponse(results, nodesToWrite); + + // Display the results. + lgDebug("Write Results :"); + + foreach (StatusCode writeResult in results) + { + lgDebug($" {writeResult}"); + } + } + catch (Exception ex) + { + // Log Error + lgError($"Write Nodes Error : {ex.Message}"); + } + } + + /// + /// Write a list of nodes to the Server + /// + public void WriteSingleNode(WriteValue node2Write) + { + if (m_session == null || m_session.Connected == false) + { + lgError("Session not connected!"); + return; + } + + try + { + // Write the configured nodes + WriteValueCollection nodesToWrite = new WriteValueCollection(); + + nodesToWrite.Add(node2Write); + + // Write the node attributes + StatusCodeCollection results = null; + DiagnosticInfoCollection diagnosticInfos; + lgDebug("Writing nodes..."); + + // Call Write Service + m_session.Write(null, + nodesToWrite, + out results, + out diagnosticInfos); + + // Validate the response + m_validateResponse(results, nodesToWrite); + + // Display the results. + lgDebug("Write Results :"); + + foreach (StatusCode writeResult in results) + { + lgDebug(" {writeResult}"); + } + } + catch (Exception ex) + { + // Log Error + lgError($"Write Nodes Error : {ex.Message}"); + } + } + + /// + /// Write a list of nodes to the Server + /// + public void WriteTestNodes() + { + if (m_session == null || m_session.Connected == false) + { + lgError("Session not connected!"); + return; + } + + try + { + // scrivo vaslori a caso.. hhmm odierni + int hhmm = 9876; + int.TryParse(DateTime.Now.ToString("HHmm"), out hhmm); + // Write the configured nodes + WriteValueCollection nodesToWrite = new WriteValueCollection(); + + // Int32 Node - Objects\CTT\Scalar\Scalar_Static\Int32 + WriteValue commWriteVal = new WriteValue(); + commWriteVal.NodeId = new NodeId("ns=4;s=IO_151"); + commWriteVal.AttributeId = Attributes.Value; + commWriteVal.Value = new DataValue(); + commWriteVal.Value.Value = (int)hhmm - 10; + nodesToWrite.Add(commWriteVal); + + WriteValue artWriteVal = new WriteValue(); + artWriteVal.NodeId = new NodeId("ns=4;s=IO_151"); + artWriteVal.AttributeId = Attributes.Value; + artWriteVal.Value = new DataValue(); + artWriteVal.Value.Value = (int)hhmm; + nodesToWrite.Add(artWriteVal); + + WriteValue qtyWriteVal = new WriteValue(); + qtyWriteVal.NodeId = new NodeId("ns=4;s=IO_153"); + qtyWriteVal.AttributeId = Attributes.Value; + qtyWriteVal.Value = new DataValue(); + 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; + lgDebug("Writing nodes..."); + + // Call Write Service + m_session.Write(null, + nodesToWrite, + out results, + out diagnosticInfos); + + // Validate the response + m_validateResponse(results, nodesToWrite); + + // Display the results. + lgDebug("Write Results :"); + + foreach (StatusCode writeResult in results) + { + lgDebug($" {writeResult}"); + } + } + catch (Exception ex) + { + // Log Error + lgError($"Write Nodes Error : {ex.Message}."); + } + } + + #endregion Public Methods + } +} diff --git a/MP.MONO.ADAPTER.OLD/appsettings.json b/MP.MONO.ADAPTER.OLD/appsettings.json new file mode 100644 index 0000000..8958138 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/appsettings.json @@ -0,0 +1,47 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "Redis": "nkcredis.steamware.net:6379,DefaultDatabase=7,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false,password=nkc.password", + "AuthConnection": "Server=localhost;port=3306;database=GWMS;user=GWMS;pwd=GWMS_secret_pwd;sslmode=None;", + "DefaultConnection": "Server=localhost;port=3306;database=MAPO.MONO;user=GWMS;pwd=GWMS_secret_pwd;sslmode=None;", + "AdminConnection": "Server=localhost;port=3306;database=MAPO.MONO;user=root;pwd=Egalware_24068!;sslmode=None;", + "MP.MONO.Data": "Server=localhost;port=3306;database=MAPO.MONO;user=GWMS;pwd=GWMS_secret_pwd;sslmode=None;" + }, + "DbConfig": { + "Server": "10.74.82.230", + "nKey": "MONO", + "sKey": "Calcium0xide-CaO" + }, + "MachineId": 1, + "maxRecord": 15, + "ExternalProviders": { + "MailKit": { + "SMTP": { + "Address": "smtp.gmail.com", + "Port": "465", + "Account": "steamwarebot@gmail.com", + "Password": "drmfsls16", + "SenderEmail": "steamwarebot@gmail.com", + "SenderName": "Steamware Email BOT" + } + } + }, + "Endpoint": { + "IpAddress": "192.168.0.2", + "Port": "4840", + "PingMsTimeout": 1500 + }, + "ENABLE_DATA_FILTER": true, + "ENABLE_CLI_RESTART": true, + "logEvery": 10, + "OPC_PARAM_CONF": "MULTIAX.json", + "pingTestSec": 5, + "verbose": false, + "verboseLogTOut": 60 +} diff --git a/MP.MONO.ADAPTER.OLD/conf/AlarmList.json b/MP.MONO.ADAPTER.OLD/conf/AlarmList.json new file mode 100644 index 0000000..47037b0 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/conf/AlarmList.json @@ -0,0 +1,52 @@ +[ + { + "description": "General Alarm", + "tipoMem": "DInt", + "memAddr": "40901", + "index": 901, + "size": 2, + "messages": [ + "Alarm 001", + "Alarm 002", + "Alarm 003", + "Alarm 004", + "Alarm 005", + "Alarm 006", + "Alarm 007", + "Alarm 008", + "Alarm 009", + "Alarm 010", + "Alarm 011", + "Alarm 012", + "##Alarm 013", + "##Alarm 014", + "##Alarm 015", + "##Alarm 016" + ] + }, + { + "description": "Secondary Alarm", + "tipoMem": "DInt", + "memAddr": "40907", + "index": 907, + "size": 2, + "messages": [ + "Warning 001", + "Warning 002", + "Warning 003", + "Warning 004", + "Warning 005", + "Warning 006", + "Warning 007", + "Warning 008", + "##Warning 009", + "##Warning 010", + "##Warning 011", + "##Warning 012", + "Warning 013", + "Warning 014", + "Warning 015", + "Warning 016" + ] + } +] \ No newline at end of file diff --git a/MP.MONO.ADAPTER.OLD/conf/MULTIAX.json b/MP.MONO.ADAPTER.OLD/conf/MULTIAX.json new file mode 100644 index 0000000..3c73c68 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/conf/MULTIAX.json @@ -0,0 +1,129 @@ +{ + "BrowseFullVal": "ns=1;s=OSAI-PLC", + "BrowseNSIndex": 4, + "BrowseValue": 5001, + "keyPartCount": "50_2_COUNTER CYCLE", + "keyPartReq": "", + "keyPartId": "", + "keyProgName": "", + "keyRunMode": "51_1_MODE", + "pingAsPowerOn": true, + "condWork": [ + { + "keyName": "1_1_MACHINE STATUS", + "targetValue": "ON" + } + ], + "condPowerOn": { + "checkMode": "AND", + "checkList": [ + { + "keyName": "1_1_MACHINE STATUS", + "targetValue": "ON" + }, + { + "keyName": "51_1_MODE", + "targetValue": "AUTO" + }, + { + "keyName": "50_1_STATUS", + "targetValue": "RUN" + } + ] + }, + "condReady": { + "checkMode": "AND", + "checkList": [ + { + "keyName": "51_1_MODE", + "targetValue": "AUTO" + } + ] + }, + "condManual": { + "checkMode": "AND", + "checkList": [ + { + "keyName": "51_1_MODE", + "targetValue": "HOLD" + } + ] + }, + "condEStop": { + "checkMode": "AND", + "checkList": [ + { + "keyName": "IO_121.02", + "targetValue": "True" + } + ] + }, + "condError": { + "checkMode": "AND", + "checkList": [ + { + "keyName": "IO_120.08", + "targetValue": "True" + } + ] + }, + "condCountEnabled": { + "checkMode": "AND", + "checkList": [] + }, + "condWarmUpCoolDown": { + "checkMode": "OR", + "checkList": [ + { + "keyName": "IO_120.04", + "targetValue": "True" + }, + { + "keyName": "IO_120.05", + "targetValue": "True" + } + ] + }, + "fluxLogVeto": [ + "L2p1CommonVariable" + ], + "itemTranslation": { + "avail": "Machine Available", + "rstat": "Execution Mode", + "mode": "Controller Mode", + "ncprog": "Program Name", + "IO_150": "Qta Prodotta (metri)", + "lpremain": "Qta Richiesta", + "fdovrd": "PATH FEED OVERRIDE", + "rovrd": "PATH RAPID OVERRIDE" + }, + "paramsEndThresh": { + "InvDDone": 50 + }, + "mMapWrite": { + "setPzComm": { + "name": "setPzComm", + "description": "Qty", + "tipoMem": "Int", + "memAddr": "ns=4;s=IO_153", + "index": 0, + "size": -1 + }, + "setComm": { + "name": "setComm", + "description": "Commessa", + "tipoMem": "String", + "memAddr": "ns=4;s=ST80", + "index": 0, + "size": 20 + }, + "setArt": { + "name": "setArt", + "description": "Articolo", + "tipoMem": "String", + "memAddr": "ns=4;s=ST80", + "index": 20, + "size": 20 + } + } +} \ No newline at end of file diff --git a/MP.MONO.ADAPTER.OLD/conf/ModeList.json b/MP.MONO.ADAPTER.OLD/conf/ModeList.json new file mode 100644 index 0000000..c71df53 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/conf/ModeList.json @@ -0,0 +1,58 @@ +[ + { + "MModeID": 0, + "Description": "UNDEFINED", + "Css": "bg-dark text-light", + "Priority": 1, + "Group": "POWEROFF" + }, + { + "MModeID": 1, + "Description": "EXE", + "Css": "bg-success text-light", + "Priority": 2, + "Group": "RUN" + }, + { + "MModeID": 2, + "Description": "READY", + "Css": "bg-primary text-light", + "Priority": 3, + "Group": "MANUAL" + }, + { + "MModeID": 3, + "Description": "HOLD", + "Css": "bg-warning text-light", + "Priority": 3, + "Group": "MANUAL" + }, + { + "MModeID": 4, + "Description": "FEED_HOLD", + "Css": "bg-warning text-light", + "Priority": 3, + "Group": "MANUAL" + }, + { + "MModeID": 5, + "Description": "OPTIONAL_STOP", + "Css": "bg-danger text-warning", + "Priority": 3, + "Group": "ERROR" + }, + { + "MModeID": 6, + "Description": "PROGRAM_STOPPED", + "Css": "bg-warning text-light", + "Priority": 3, + "Group": "MANUAL" + }, + { + "MModeID": 7, + "Description": "DONE", + "Css": "bg-primary text-light", + "Priority": 3, + "Group": "MANUAL" + } +] \ No newline at end of file diff --git a/MP.MONO.ADAPTER.OLD/conf/ParamList.json b/MP.MONO.ADAPTER.OLD/conf/ParamList.json new file mode 100644 index 0000000..a5fa40e --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/conf/ParamList.json @@ -0,0 +1,125 @@ +[ + { + "Order": 3, + "Type": "SPEED-5000-10000", + "Title": "SPEED", + "Value": "4000", + "ValueNum": 4000, + "MinVal": 1000, + "MaxVal": 10000, + "DisplFormat": "N0", + "IsNumeric": true, + "EnablePlot": true, + "ShowBar": true, + "CssIcon": "fa-solid fa-gauge-high", + "SamplePeriod": 180, + "VcFunc": "MEDIAN" + }, + { + "Order": 2, + "Type": "FEED-3000-5000", + "Title": "FEED", + "Value": "2500", + "ValueNum": 2500, + "MinVal": 1000, + "MaxVal": 5000, + "DisplFormat": "N0", + "IsNumeric": true, + "EnablePlot": true, + "ShowBar": true, + "CssIcon": "fa-solid fa-gauge-high", + "SamplePeriod": 180, + "VcFunc": "MEDIAN" + }, + { + "Order": 1, + "Type": "LOAD", + "Title": "SPINDLE LOAD", + "Value": "30", + "ValueNum": 30, + "MinVal": 0, + "MaxVal": 100, + "DisplFormat": "N1", + "IsNumeric": true, + "EnablePlot": true, + "ShowBar": true, + "CssIcon": "fa-solid fa-bolt", + "SamplePeriod": 180, + "VcFunc": "MEDIAN" + }, + { + "Order": 4, + "Type": "POS", + "Title": "X POS", + "Value": "1500", + "ValueNum": 1500, + "MinVal": 0, + "MaxVal": 5000, + "DisplFormat": "N2", + "IsNumeric": true, + "EnablePlot": true, + "CssIcon": "fa-solid fa-ruler-horizontal", + "SamplePeriod": 180, + "VcFunc": "MEDIAN" + }, + { + "Order": 5, + "Type": "POS", + "Title": "Y POS", + "Value": "5000", + "ValueNum": 5000, + "MinVal": 0, + "MaxVal": 10000, + "DisplFormat": "N2", + "IsNumeric": true, + "EnablePlot": true, + "CssIcon": "fa-solid fa-ruler-horizontal", + "SamplePeriod": 180, + "VcFunc": "MEDIAN" + }, + { + "Order": 6, + "Type": "POS", + "Title": "Z POS", + "Value": "-1500", + "ValueNum": -1500, + "MinVal": -3000, + "MaxVal": 0, + "DisplFormat": "N2", + "IsNumeric": true, + "EnablePlot": true, + "CssIcon": "fa-solid fa-ruler-horizontal", + "SamplePeriod": 180, + "VcFunc": "MEDIAN" + }, + { + "Order": 7, + "Type": "POS", + "Title": "A POS", + "Value": "150", + "ValueNum": 150, + "MinVal": 0, + "MaxVal": 360, + "DisplFormat": "N3", + "IsNumeric": true, + "EnablePlot": true, + "CssIcon": "fa-solid fa-rotate-right", + "SamplePeriod": 180, + "VcFunc": "MEDIAN" + }, + { + "Order": 8, + "Type": "POS", + "Title": "B POS", + "Value": "150", + "ValueNum": 150, + "MinVal": 0, + "MaxVal": 360, + "DisplFormat": "N3", + "IsNumeric": true, + "EnablePlot": true, + "CssIcon": "fa-solid fa-rotate-right", + "SamplePeriod": 180, + "VcFunc": "MEDIAN" + } +] \ No newline at end of file diff --git a/MP.MONO.ADAPTER.OLD/conf/StatusList.json b/MP.MONO.ADAPTER.OLD/conf/StatusList.json new file mode 100644 index 0000000..e374c71 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/conf/StatusList.json @@ -0,0 +1,58 @@ +[ + { + "MStatusID": 0, + "Description": "UNDEFINED", + "Css": "bg-dark text-light", + "Priority": 1, + "Group": "POWEROFF" + }, + { + "MStatusID": 1, + "Description": "POWEROFF", + "Css": "bg-secondary text-light", + "Priority": 1, + "Group": "POWEROFF" + }, + { + "MStatusID": 2, + "Description": "AUTOMATIC", + "Css": "bg-success text-light", + "Priority": 2, + "Group": "RUN" + }, + { + "MStatusID": 3, + "Description": "EDIT", + "Css": "bg-warning text-light", + "Priority": 3, + "Group": "MANUAL" + }, + { + "MStatusID": 4, + "Description": "SEMIAUTOMATIC", + "Css": "bg-warning text-light", + "Priority": 3, + "Group": "MANUAL" + }, + { + "MStatusID": 5, + "Description": "MANUAL_JOG", + "Css": "bg-warning text-light", + "Priority": 3, + "Group": "MANUAL" + }, + { + "MStatusID": 6, + "Description": "ALARM", + "Css": "bg-danger text-warning", + "Priority": 3, + "Group": "ERROR" + }, + { + "MStatusID": 7, + "Description": "ESTOP", + "Css": "bg-danger text-light", + "Priority": 3, + "Group": "ERROR" + } +] \ No newline at end of file diff --git a/MP.MONO.ADAPTER.OLD/post-build.ps1 b/MP.MONO.ADAPTER.OLD/post-build.ps1 new file mode 100644 index 0000000..d89d097 --- /dev/null +++ b/MP.MONO.ADAPTER.OLD/post-build.ps1 @@ -0,0 +1,32 @@ +param([string]$ProjectDir, [string]$ProjectPath); + +$FileMajMin = "..\MajMin.vers" +$FileVers = "Resources\VersNum.txt" +$FileManIn = "Resources\manifest-original.xml" +$FileManOut = "Resources\manifest.xml" +$FileCLogIn = "Resources\ChangeLog-original.html" +$FileCLogOut = "Resources\ChangeLog.html" +$MajMin = Get-Content $FileMajMin +$currentDate = get-date -format yyMM; +$currentTime = get-date -format dHH; +$find = "(.|\n)*?"; +$currRelNum = $MajMin + $currentDate +"." + $currentTime +$replace = "" + $MajMin + $currentDate +"." + $currentTime + ""; +$csproj = Get-Content $ProjectPath +$csprojUpdated = $csproj -replace $find, $replace + +Set-Content -Path $ProjectPath -Value $csprojUpdated +Set-Content -Path $FileVers -Value $currRelNum + +# replace x manifest +$manData = Get-Content $FileManIn +$manData = $manData -replace "1.0.0.0", $currRelNum +$manData = $manData -replace "{{DIRNAME}}", "MP.MONO.ADAPTER" +$manData = $manData -replace "{{BRANCHNAME}}", "stable/LAST" +$manData = $manData -replace "{{PACKNAME}}", "MP.Mon" +Set-Content -Path $FileManOut -Value $manData + +# replace x ChangeLog +$clogData = Get-Content $FileCLogIn +$clogData = $clogData -replace "{{CURRENT-REL}}", $currRelNum +Set-Content -Path $FileCLogOut -Value $clogData