diff --git a/IOB-UT/ToMapo.cs b/IOB-UT/ToMapo.cs index 7711303a..79c7f49c 100644 --- a/IOB-UT/ToMapo.cs +++ b/IOB-UT/ToMapo.cs @@ -7,65 +7,93 @@ using System.Text; namespace IOB_UT { - /// - /// Classe gestione configurazione paraemtri MTC - /// - public class MtcParamConf - { /// - /// Nome variabile x pezzi FATTI + /// Classe per rappresentare oggetti chaive/valore target x controlo condizioni multiple /// - public string keyPartCount { get; set; } = ""; - /// - /// Nome variabile x pezzi RICHIESTI - /// - public string keyPartReq { get; set; } = ""; - /// - /// Nome variabile x Codice Articolo - /// - public string keyPartId { get; set; } = ""; - /// - /// Nome variabile x NOME PROGRAMMA - /// - public string keyProgName { get; set; } = ""; - /// - /// Nome variabile x RunMode - /// - public string keyRunMode { get; set; } = ""; - /// - /// Indica se il ping sia un criterio valido x determinare powerON impianto - /// - public bool pingAsPowerOn { get; set; } = true; - /// - /// Struttura dati x check condizione PowerOn - /// - public diCheckCondition condPowerOn { get; set; } = new diCheckCondition(); - /// - /// Struttura dati x check condizione LAVORA / Green - /// - public List condWork { get; set; } = new List(); + public class diCheckCondition + { + #region Public Properties + + /// + /// nome variabile + /// + public string keyName { get; set; } = ""; + + /// + /// valore target per esito richeisto + /// + public string targetValue { get; set; } = ""; + + #endregion Public Properties + } /// - /// Dictionary dei nomi da cercare come "endsWith" a cui applicare la soglia indicata + /// Classe gestione configurazione paraemtri MTC /// - public Dictionary paramsEndThresh { get; set; } = new Dictionary(); - /// - /// Array degli elementi di traduzione item - /// - public Dictionary itemTranslation { get; set; } = new Dictionary(); - } - /// - /// Classe per rappresentare oggetti chaive/valore target x controlo condizioni multiple - /// - public class diCheckCondition - { - /// - /// nome variabile - /// - public string keyName { get; set; } = ""; - /// - /// valore target per esito richeisto - /// - public string targetValue { get; set; } = ""; - } -} + public class MtcParamConf + { + #region Public Properties + + /// + /// Struttura dati x check condizione PowerOn + /// + public diCheckCondition condPowerOn { get; set; } = new diCheckCondition(); + + /// + /// Struttura dati x check condizione LAVORA / Green + /// + public List condWork { get; set; } = new List(); + + /// + /// Elenco items sottoposti a campionamento periodico e inviati come dynData + /// + public List dynDataItems { get; set; } = new List(); + + /// + /// Array degli elementi di traduzione item + /// + public Dictionary itemTranslation { get; set; } = new Dictionary(); + + /// + /// Nome variabile x EmergencyStop + /// + public string keyEStop { get; set; } = ""; + + /// + /// Nome variabile x pezzi FATTI + /// + public string keyPartCount { get; set; } = ""; + + /// + /// Nome variabile x Codice Articolo + /// + public string keyPartId { get; set; } = ""; + + /// + /// Nome variabile x pezzi RICHIESTI + /// + public string keyPartReq { get; set; } = ""; + + /// + /// Nome variabile x NOME PROGRAMMA + /// + public string keyProgName { get; set; } = ""; + + /// + /// Nome variabile x RunMode + /// + public string keyRunMode { get; set; } = ""; + + /// + /// Dictionary dei nomi da cercare come "endsWith" a cui applicare la soglia indicata + /// + public Dictionary paramsEndThresh { get; set; } = new Dictionary(); + + /// + /// Indica se il ping sia un criterio valido x determinare powerON impianto + /// + public bool pingAsPowerOn { get; set; } = true; + + #endregion Public Properties + } +} \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/GT576.ini b/IOB-WIN/DATA/CONF/GT576.ini new file mode 100644 index 00000000..6d91369a --- /dev/null +++ b/IOB-WIN/DATA/CONF/GT576.ini @@ -0,0 +1,67 @@ +;Configurazione IOB-WIN +[IOB] +;Centro di lavoro Okuma MTConnect +CNCTYPE=MTConnect +PING_MS_TIMEOUT=500 + +[MACHINE] +VENDOR=Okuma +MODEL=Lathe 2SP-35HG + +[CNC] +IP=192.168.2.82 +PORT=5000 +GETPRGNAME=true + +[SERVER] +MPIP=http://192.168.1.64 +MPURL=/MP/IO +CMDBASE=/IOB/input/ +CMDFLOG=/IOB/flog/ +CMDALIVE=/IOB +CMDENABLED=/IOB/enabled/ +CMDADV1=?valore= +CMDREBO=/sendReboot.aspx?idxMacchina= + +[MEMORY] +ADDR_READ=DB9999.DBB0 +ADDR_WRITE=DB9999.DBB0 +SIZE_READ=0 +SIZE_WRITE=0 +;BIT0=CONN +;BIT1=DB60.DBB1 +;BIT2=PZCOUNT.STD.DB700.DBW22 +;BIT3=DB60.DBB3 +;BIT4=DB60.DBB4 + + +[BLINK] +;MAX_COUNTER_BLINK = 30 +MAX_COUNTER_BLINK = 15 +;bit0 = 0 +;bit1 = 0 +;bit2 = 1 +;bit3 = 1 +;bit4 = 1 +;bit5 = 0 +;bit6 = 0 +;bit7 = 0 +BLINK_FILT=0 +;BLINK_FILT=28 + +[OPTPAR] +PZCOUNT_MODE=MTC +DISABLE_PZCOUNT=FALSE +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 +ENABLE_DYN_DATA=FALSE +FORCE_DYN_DATA=TRUE +ENABLE_DATA_FILTER=TRUE +ENABLE_MTC_RESTART=TRUE + +; conf parametri memoria READ/WRITE +MTC_PARAM_CONF=GT576.json + +[BRANCH] +NAME=master \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/GT576.json b/IOB-WIN/DATA/CONF/GT576.json new file mode 100644 index 00000000..0c5f2717 --- /dev/null +++ b/IOB-WIN/DATA/CONF/GT576.json @@ -0,0 +1,52 @@ +{ + "keyEStop": "L2estop", + "keyPartCount": "L2p2partcount", + "keyPartReq": "", + "keyPartId": "", + "keyProgName": "L2p2program", + "keyRunMode": "L2p2mode", + "pingAsPowerOn": true, + "condPowerOn": { + "keyName": "L2avail", + "targetValue": "AVAILABLE" + }, + "condWork": [ + { + "keyName": "L2p2execution", + "targetValue": "ACTIVE" + } + ], + "dynDataItems": [ + "L2S1speed", + "L2S1load", + "L2S1ovr", + "L2S2speed", + "L2S2load", + "L2S2ovr", + "L2p1OperatingTime", + "L2p1RunningTime" + ], + "itemTranslation": { + "L2avail": "Machine Available", + "L2p2execution": "Execution Mode", + "L2p2mode": "Controller Mode", + "L2p2program": "Program Name", + "L2p2partcount": "Contapezzi", + "L2estop": "Emergenza", + "p2Fovr": "PATH FEED OVERRIDE", + "rovrd": "PATH RAPID OVERRIDE", + "L2S1speed": "Spindle C1 Actual SPEED", + "L2S1load": "Spindle C1 LOAD", + "L2S1ovr": "Spindle C1 OVERRIDE", + "L2S2speed": "Spindle C2 Actual SPEED", + "L2S2load": "Spindle C2 LOAD", + "L2S2ovr": "Spindle C2 OVERRIDE", + "L2p1OperatingTime": "OPERATING TIME", + "L2p1RunningTime": "RUNNING TIME" + }, + "paramsEndThresh": { + "PosAct": 50, + "PosTgt": 50, + "InvDDone": 50 + } +} \ No newline at end of file diff --git a/IOB-WIN/IOB-WIN.csproj b/IOB-WIN/IOB-WIN.csproj index 68531793..963e457d 100644 --- a/IOB-WIN/IOB-WIN.csproj +++ b/IOB-WIN/IOB-WIN.csproj @@ -256,6 +256,12 @@ Always + + Always + + + Always + Always diff --git a/IOB-WIN/IobMTC.cs b/IOB-WIN/IobMTC.cs index caea7fdc..8968a757 100644 --- a/IOB-WIN/IobMTC.cs +++ b/IOB-WIN/IobMTC.cs @@ -15,7 +15,21 @@ namespace IOB_WIN { public class IobMTC : IobGeneric { - #region area comune (non modificare) + #region Private Fields + + /// + /// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing + /// + private Dictionary dataItemMem = new Dictionary(); + + /// + /// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO + /// + private Dictionary signLUT = new Dictionary(); + + #endregion Private Fields + + #region Protected Fields /// /// Gestione filtraggio dati @@ -37,6 +51,11 @@ namespace IOB_WIN /// protected DateTime lastCurrent = DateTime.Now; + /// + /// ultimo set valori dynData acquisiti + /// + protected Dictionary lastDynData = new Dictionary(); + /// /// Oggetto MAIN x connessione MTC /// @@ -47,15 +66,9 @@ namespace IOB_WIN /// protected DateTime vetoCheckStatus = DateTime.Now; - /// - /// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing - /// - private Dictionary dataItemMem = new Dictionary(); + #endregion Protected Fields - /// - /// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO - /// - private Dictionary signLUT = new Dictionary(); + #region Public Constructors /// /// Estende l'init della classe base, impiegando il pacchetto Nuget TrackHound @@ -91,6 +104,61 @@ namespace IOB_WIN } } + #endregion Public Constructors + + #region Protected Properties + + /// + /// Verifico se abbia ALMENO un errore... + /// + protected bool hasError + { + get + { + bool answ = false; + // controllo TUTTE le conditions... + foreach (var item in dataItemMem) + { + // se NON HO GIA' allarmi attivi... + if (!answ) + { + // se è una condition... + if (item.Value.Category == MTConnect.DataItemCategory.CONDITION) + { + // se ha valore !="" --> allarmi attivi + if (!string.IsNullOrEmpty(item.Value.value)) + { + answ = true; + } + } + } + } + return answ; + } + } + + /// + /// Indica se abbia emergenza premuta + /// + protected bool hasEStopTriggered + { + get + { + bool answ = false; + try + { + if (!string.IsNullOrEmpty(mtcParams.keyEStop)) + { + string currEStop = getDataItemValue(mtcParams.keyEStop); + answ = (currEStop == "TRIGGERED"); + } + } + catch + { } + return answ; + } + } + /// /// Parametri specifici MTC /// @@ -117,151 +185,487 @@ namespace IOB_WIN } } - /// - /// 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); - } + #endregion Protected Properties + + #region Private Methods /// - /// Recupera uno specifico dataItem + /// Verifica ed invia variazioni /// - /// - /// - public string getDataItemValue(string diKey) + /// + /// + private void checkAndSend(MTConnectStreams.Document document, bool forceSend) { - string answ = ""; - try + if (document != null) { - var currDataItem = dataItemMem[diKey]; - answ = currDataItem.value; - } - catch (Exception exc) - { - Logging.Instance.Error($"Errore in getDataItemValue per {diKey}{Environment.NewLine}{exc}"); - } - return answ; - } - - /// - /// Effettua reset del contapezzi, NON POSSIBILE per MTC (read only) - /// - /// - public override bool resetcontapezziPLC() - { - bool answ = false; - return answ; - } - - /// - /// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE per MTC (read only) - /// - /// - public override bool setcontapezziPLC(int newPzCount) - { - bool answ = false; - 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 > utils.CRI("pingTestSec")) + foreach (var deviceStream in document.DeviceStreams) { - if (verboseLog || periodicLog) + string sVal = ""; + string descr = ""; + DateTime locTStamp = DateTime.Now; + // check su Conditions + try { - lgInfo("MTC: ConnKO - tryConnect"); - } - // in primis salvo data ping... - lastPING = DateTime.Now; - // se passa il ping faccio il resto... - if (testPingMachine == IPStatus.Success) - { - string szStatusConnection = ""; - try + // check su dataItems (conditions + events + samples) + foreach (var dataItem in deviceStream.Conditions) { - // ora provo connessione... - parentForm.commPlcActive = true; - short esitoLink = doConnect(); - lgInfo($"szStatusConnection MTC, esitoLink: {esitoLink}"); - parentForm.commPlcActive = false; - connectionOk = true; - // refresh stato allarmi!!! - if (connectionOk) + descr = itemTranslation("C", dataItem.DataItemId); + locTStamp = dataItem.Timestamp.ToLocalTime(); + sVal = $"CONDITION: {locTStamp.ToString()} | Id: {dataItem.DataItemId} | | Name: {dataItem.Name} | descr: {descr} | Val: {dataItem.CDATA}"; + // condizion verboso SEMPRE! + lgInfo(sVal); + DateTime tStamp = dataItem.Timestamp; + var time2 = tStamp.ToLocalTime(); + // verifico se salvare + bool changed = checkSaveItem(dataItem); + if (changed || forceSend) { - if (adpRunning) - { - lgInfo("Connessione OK"); - } + // accodare ed invia nella coda ALARMS (che POI salva in document MongoDB anche ultimi x minuti di FluxLog...) + accodaAlarmLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); + } + } + } + catch (Exception exc) + { + lgError($"Eccezione in decodifica Conditions x StreamSuccesfull{Environment.NewLine}{exc}", false); + } + // check su events + try + { + // check su dataItems (conditions + events + samples) + foreach (var dataItem in deviceStream.Events) + { + descr = itemTranslation("E", dataItem.DataItemId); + locTStamp = dataItem.Timestamp.ToLocalTime(); + sVal = $"EVENT: {locTStamp.ToString()} | descr: {descr} | Id: {dataItem.DataItemId} | Name: {dataItem.Name} | Val: {dataItem.CDATA}"; + if (isVerboseLog) + { + lgInfo(sVal); + } + DateTime tStamp = dataItem.Timestamp; + var time2 = tStamp.ToLocalTime(); + // verifico se salvare + bool changed = checkSaveItem(dataItem); + if (changed || forceSend) + { + accodaFLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); + } + } + } + catch (Exception exc) + { + lgError($"Eccezione in decodifica Events x StreamSuccesfull{Environment.NewLine}{exc}", false); + } + + // check su samples + try + { + // check su dataItems (conditions + events + samples) + foreach (var dataItem in deviceStream.Samples) + { + descr = itemTranslation("S", dataItem.DataItemId); + locTStamp = dataItem.Timestamp.ToLocalTime(); + sVal = $"SAMPLE: {locTStamp.ToString()} | descr: {descr} | Id: {dataItem.DataItemId} | | Name: {dataItem.Name} | Val: {dataItem.CDATA}"; + if (isVerboseLog) + { + lgInfo(sVal); + } + DateTime tStamp = dataItem.Timestamp; + var time2 = tStamp.ToLocalTime(); + // verifico se salvare + bool changed = checkSaveSample(dataItem); + if (changed || forceSend) + { + accodaFLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); } else { - lgError("Impossibile procedere, connessione mancante..."); + if (isVerboseLog) + { + lgInfo($"NON ACCODATO sample poiché verifica variazione SAMPLE ha dato esito negativo", false); + } } } - catch (Exception exc) + } + catch (Exception exc) + { + lgError($"Eccezione in decodifica Samples x StreamSuccesfull{Environment.NewLine}{exc}"); + } + } + } + else + { + lgError("StreamsSuccessful ERROR: document è null"); + } + } + + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// + private void decodeToBaseBitmap() + { + // init a zero... + B_input = 0; + + /* ----------------------------------------------------- + * bitmap MAPO + * B0: POWER_ON + * B1: RUN + * B2: pzCount + * B3: allarme + * B4: manuale + * B5: emergenza + ----------------------------------------------------- */ + + // Controllo booleano PING e POWERON... + string currPowerOn = getDataItemValue(mtcParams.condPowerOn.keyName); + // se valido il check ping lo eseguo... altrimenti lo do x buono + bool checkPing = !mtcParams.pingAsPowerOn; + if (!checkPing) + { + checkPing = (testPingMachine == IPStatus.Success); + } + // verifico da target value richiesto... + bool checkPowerOn = (currPowerOn == mtcParams.condPowerOn.targetValue); + + // bit 0 (poweron) imposto a 1 SE pingo o PowerOn=="ON"... + B_input = (checkPing || checkPowerOn) ? 1 : 0; + + // variabili RUN... + string currRun = getDataItemValue(mtcParams.keyRunMode); + + // controllo RUN MODE preliminare... CABLATO poiché è GENERALE x MTC + if (currRun == "AUTOMATIC" || currRun == "SEMI_AUTO" || currRun == "SEMI_AUTOMATIC") + { + int numCond = mtcParams.condWork.Count; + int numCondOk = 0; + // cerco nell'elenco delle condizioni che indicano lavora se sono ok faccio +1 conteggio...... + foreach (var item in mtcParams.condWork) + { + if (getDataItemValue(item.keyName) == item.targetValue) + { + numCondOk++; + } + } + // se tutte condizioni rispettate --> lavora! + if (numCond == numCondOk) + { + // RUN = LAVORA! + B_input += (1 << 1); + } + } + // se ho emergenza premuta --> emergenza! + else if (hasEStopTriggered) + { + B_input += (1 << 5); + } + // se ho almeno 1 allarme E NON SONO IN AUTO --> ALARM! + else if (hasError) + { + B_input += (1 << 3); + } + else + { + // se ho run mode != auto --> manual + B_input += (1 << 4); + } + + DateTime adesso = DateTime.Now; + int vFactor = 1; + // controllo SE HO dati per fare verifiche... + if (string.IsNullOrEmpty(currRun)) + { + // se ho parametro x gestione reset... + if (enableMtcRestart) + { + // controllo se ho ricevuto il current da OLTRE 1 minuto... + if (lastCurrent.AddMinutes(3) < adesso) + { + lastCurrent = adesso; + // stop... + lgInfo("Fermato MTC_ref per mancanza dati current"); + MTC_ref.Stop(); + Thread.Sleep(1000); + // restart + lgInfo("Riavviato MTC_ref per mancanza dati current"); + MTC_ref.Start(); + } + } + } + else + { + vFactor = 6; + } + + // solo se non ho veto check + if (vetoCheckStatus < adesso) + { + lgInfo($"Stato variabili: currRun: {currRun}"); + // imposto veto per vetoSeconds... + vetoCheckStatus = adesso.AddSeconds(vetoSeconds * vFactor); + } + // log opzionale! + if (verboseLog) + { + lgInfo($"Trasformazione B_input: {B_input} | currRun = {currRun}"); + } + } + + /// + /// Vera connessione ad MTC + /// + /// + private short doConnect() + { + short esitoLink = 0; + // reset memoria dataItem.. + dataItemMem = new Dictionary(); + // predisposizione conf oggetto di comunicazione MTC + short port = 5000; + short.TryParse(cIobConf.cncPort, out port); + // test probe! + try + { + var probe = new Probe($"http://{cIobConf.cncIpAddr}:{port}").Execute(); + // se valido loggo! + if (probe != null) + { + lgInfo($"Effettuata correttamente PROBE per device MTC all'URL {probe.Url} | vers: {probe.Version} | send: {probe.Header.Sender}"); + lgInfo($"---------------- Elenco Devices ----------------"); + // loggo devices principali... + logDevicesList(probe.Devices); + } + } + catch (Exception exc) + { + lgError($"Eccezione durante test probe:{Environment.NewLine}{exc}"); + } + // attendo 1 sec... + Thread.Sleep(1000); + // ora avvio + try + { + lgInfo($"Chiamata apertura MTC Client: {cIobConf.cncIpAddr}:{port}"); + MTC_ref = new MTConnectClient($"http://{cIobConf.cncIpAddr}:{port}"); + // Subscribe to the Event handlers to receive the MTConnect documents + MTC_ref.ProbeReceived += DevicesSuccessful; + MTC_ref.CurrentReceived += CurrentSuccessful; + MTC_ref.SampleReceived += StreamsSuccessful; + + // attendo 1 sec... + Thread.Sleep(1000); + MTC_ref.Start(); + esitoLink = 1; + + // fix tempi! + DateTime adesso = DateTime.Now; + lastPzCountSend = adesso; + lastWarnODL = adesso; + lastCurrent = adesso; + } + catch + { } + return esitoLink; + } + + /// + /// Formatta un dataitem da uno stream SAMPLE + /// + /// + /// + /// + /// + /// + private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectStreams.Sample DISample) + { + // creo il nuovo dataitem da sample... + MTConnectDevices.DataItem newDataItem = new MTConnectDevices.DataItem() + { + Category = DISample.Category, + Id = DISample.DataItemId, + Name = DISample.Name, + SampleRate = DISample.SampleRate, + Statistic = DISample.Statistic, + SubType = DISample.SubType, + Type = DISample.Type + }; + return formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newDataItem); + } + + /// + /// Formatta un dataitem da uno stream GENERICO + /// + /// + /// + /// + /// + /// + private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectStreams.DataItem DIGen) + { + // creo il nuovo dataitem da sample... + MTConnectDevices.DataItem newDataItem = new MTConnectDevices.DataItem() + { + Category = DIGen.Category, + Id = DIGen.DataItemId, + Name = DIGen.Name, + SubType = DIGen.SubType, + Type = DIGen.Type + }; + return formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newDataItem); + } + + /// + /// Formatta un dataitem x salvataggio in memoria locale + /// + /// + /// + /// + /// + /// + private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectDevices.DataItem dataItem) + { + MtcDataItemExt currDataItem; + // uuid e parametri secondo categoria... + switch (dataItem.Category) + { + case MTConnect.DataItemCategory.CONDITION: + uuid = $"C_{dataItem.Id}"; + threshDBand = 0; + dSamplePeriod = 0; + break; + + case MTConnect.DataItemCategory.EVENT: + uuid = $"E_{dataItem.Id}"; + threshDBand = 0; + dSamplePeriod = 0; + break; + + case MTConnect.DataItemCategory.SAMPLE: + uuid = $"S_{dataItem.Id}"; + // SOLO SE è abilitato il datafiltering... + if (enableDataFilter) + { + threshDBand = 1; + // controllo SE ho conf x deadband... + if (mtcParams.paramsEndThresh.Count > 0) { - lgFatal($"Errore nella connessione all'adapter MTC: {szStatusConnection}{Environment.NewLine}{exc}"); - connectionOk = false; - lgInfo($"Eccezione in TryConnect, Adapter MTC NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione"); + // ciclo su tutti i parametri indicati... + foreach (var item in mtcParams.paramsEndThresh) + { + if (dataItem.Id.EndsWith(item.Key)) + { + threshDBand = item.Value; + } + } } } else { - // loggo no risposta ping ... - connectionOk = false; - if (verboseLog || periodicLog) - { - lgInfo($"Attenzione: MTC controllo PING fallito per IP {cIobConf.cncIpAddr}"); - } + threshDBand = 0; } - } + dSamplePeriod = 60; + break; + + default: + break; } - else + // salvo oggetto x "uso interno" + currDataItem = new MtcDataItemExt() { - needRefresh = true; - } - // se non è ancora connesso faccio procesisng memoria caso disconnesso... - if (!connectionOk) + Id = dataItem.Id, + Category = dataItem.Category, + Constraints = dataItem.Constraints, + CoordinateSystem = dataItem.CoordinateSystem, + Name = dataItem.Name, + NativeScale = dataItem.NativeScale, + NativeUnits = dataItem.NativeUnits, + SampleRate = dataItem.SampleRate, + Representation = dataItem.Representation, + SignificantDigits = dataItem.SignificantDigits, + Source = dataItem.Source, + Statistic = dataItem.Statistic, + SubType = dataItem.SubType, + Type = dataItem.Type, + TypePath = dataItem.TypePath, + Units = dataItem.Units, + XPath = dataItem.XPath, + uid = uuid, + thresholdDeadBand = threshDBand, + samplePeriod = dSamplePeriod + }; + // log x capire COME ho chiamato alcune cosette... + if (dataItem.Id.Contains("EXE_MODE") || dataItem.Id.Contains("RUN_MODE") || dataItem.Id.Contains("POWER") || dataItem.Id.EndsWith("_Status")) { - // processo semafori ed invio... - processMemoryDiscon(); + lgInfo($"DEBUG DATA | dataItem.Id : {dataItem.Id}"); } + + return currDataItem; } /// - /// Override disconnessione + /// Effettua lettura file di conf specifico MTC da oggetto serializzato json + /// Nome file da cui leggere i parametri json /// - public override void tryDisconnect() + private void loadMtcConf(string fileName) { - if (connectionOk) + string jsonFullPath = $"{Application.StartupPath}/DATA/CONF/{fileName}"; + lgInfo($"Apertura file {jsonFullPath}"); + StreamReader reader = new StreamReader(jsonFullPath); + string jsonData = reader.ReadToEnd().Replace("\n", "").Replace("\r", ""); + if (!string.IsNullOrEmpty(jsonData)) { - string szStatusConnection = ""; + lgInfo($"File json composto da {jsonData.Length} caratteri"); try { - MTC_ref.Stop(); - connectionOk = false; - lgInfo(szStatusConnection); - lgInfo("Effettuata disconnessione adapter MTC!"); + mtcParams = JsonConvert.DeserializeObject(jsonData); + lgInfo($"Decodifica aree MtcParamConf: trovati {mtcParams.paramsEndThresh.Count} valori paramsEndThresh"); } catch (Exception exc) { - lgFatal(exc, "Errore nella disconnessione dall'adapter MTC"); + lgError($"Eccezione in decodifica conf json MTC:{Environment.NewLine}{exc}"); } } else { - lgError("IMPOSSIBILE effettuare disconnessione MTC: Connessione non disponibile..."); + lgError("Errore in loadMtcConf: file json vuoto!"); } + reader.Dispose(); + } + + /// + /// Effettua invio a MP/IO dell'elenco serializzato dei dataItems + /// + /// + private void sendDataItemsList(List dataItems) + { + string rawData = JsonConvert.SerializeObject(dataItems); + utils.callUrlNow($"{urlSaveDataItems}", rawData); + } + + #endregion Private Methods + + #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; + MtcDataItemExt 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; } /// @@ -614,378 +1018,38 @@ namespace IOB_WIN checkAndSend(document, false); } - /// - /// Verifica ed invia variazioni - /// - /// - /// - private void checkAndSend(MTConnectStreams.Document document, bool forceSend) - { - if (document != null) - { - foreach (var deviceStream in document.DeviceStreams) - { - string sVal = ""; - string descr = ""; - DateTime locTStamp = DateTime.Now; - // check su Conditions - try - { - // check su dataItems (conditions + events + samples) - foreach (var dataItem in deviceStream.Conditions) - { - descr = itemTranslation("C", dataItem.DataItemId); - locTStamp = dataItem.Timestamp.ToLocalTime(); - sVal = $"CONDITION: {locTStamp.ToString()} | Id: {dataItem.DataItemId} | | Name: {dataItem.Name} | descr: {descr} | Val: {dataItem.CDATA}"; - // condizion verboso SEMPRE! - lgInfo(sVal); - DateTime tStamp = dataItem.Timestamp; - var time2 = tStamp.ToLocalTime(); - // verifico se salvare - bool changed = checkSaveItem(dataItem); - if (changed || forceSend) - { - // accodare ed invia nella coda ALARMS (che POI salva in document MongoDB anche ultimi x minuti di FluxLog...) - accodaAlarmLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); - } - } - } - catch (Exception exc) - { - lgError($"Eccezione in decodifica Conditions x StreamSuccesfull{Environment.NewLine}{exc}", false); - } - // check su events - try - { - // check su dataItems (conditions + events + samples) - foreach (var dataItem in deviceStream.Events) - { - descr = itemTranslation("E", dataItem.DataItemId); - locTStamp = dataItem.Timestamp.ToLocalTime(); - sVal = $"EVENT: {locTStamp.ToString()} | descr: {descr} | Id: {dataItem.DataItemId} | Name: {dataItem.Name} | Val: {dataItem.CDATA}"; - if (isVerboseLog) - { - lgInfo(sVal); - } - DateTime tStamp = dataItem.Timestamp; - var time2 = tStamp.ToLocalTime(); - // verifico se salvare - bool changed = checkSaveItem(dataItem); - if (changed || forceSend) - { - accodaFLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); - } - } - } - catch (Exception exc) - { - lgError($"Eccezione in decodifica Events x StreamSuccesfull{Environment.NewLine}{exc}", false); - } + #endregion Protected Methods - // check su samples - try - { - // check su dataItems (conditions + events + samples) - foreach (var dataItem in deviceStream.Samples) - { - descr = itemTranslation("S", dataItem.DataItemId); - locTStamp = dataItem.Timestamp.ToLocalTime(); - sVal = $"SAMPLE: {locTStamp.ToString()} | descr: {descr} | Id: {dataItem.DataItemId} | | Name: {dataItem.Name} | Val: {dataItem.CDATA}"; - if (isVerboseLog) - { - lgInfo(sVal); - } - DateTime tStamp = dataItem.Timestamp; - var time2 = tStamp.ToLocalTime(); - // verifico se salvare - bool changed = checkSaveSample(dataItem); - if (changed || forceSend) - { - accodaFLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA)); - } - else - { - if (isVerboseLog) - { - lgInfo($"NON ACCODATO sample poiché verifica variazione SAMPLE ha dato esito negativo", false); - } - } - } - } - catch (Exception exc) - { - lgError($"Eccezione in decodifica Samples x StreamSuccesfull{Environment.NewLine}{exc}"); - } - } - } - else - { - lgError("StreamsSuccessful ERROR: document è null"); - } + #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); } /// - /// Vera connessione ad MTC + /// Recupera uno specifico dataItem /// + /// /// - private short doConnect() + public string getDataItemValue(string diKey) { - short esitoLink = 0; - // reset memoria dataItem.. - dataItemMem = new Dictionary(); - // predisposizione conf oggetto di comunicazione MTC - short port = 5000; - short.TryParse(cIobConf.cncPort, out port); - // test probe! + string answ = ""; try { - var probe = new Probe($"http://{cIobConf.cncIpAddr}:{port}").Execute(); - // se valido loggo! - if (probe != null) - { - lgInfo($"Effettuata correttamente PROBE per device MTC all'URL {probe.Url} | vers: {probe.Version} | send: {probe.Header.Sender}"); - lgInfo($"---------------- Elenco Devices ----------------"); - // loggo devices principali... - logDevicesList(probe.Devices); - } + var currDataItem = dataItemMem[diKey]; + answ = currDataItem.value; } catch (Exception exc) { - lgError($"Eccezione durante test probe:{Environment.NewLine}{exc}"); - } - // attendo 1 sec... - Thread.Sleep(1000); - // ora avvio - try - { - lgInfo($"Chiamata apertura MTC Client: {cIobConf.cncIpAddr}:{port}"); - MTC_ref = new MTConnectClient($"http://{cIobConf.cncIpAddr}:{port}"); - // Subscribe to the Event handlers to receive the MTConnect documents - MTC_ref.ProbeReceived += DevicesSuccessful; - MTC_ref.CurrentReceived += CurrentSuccessful; - MTC_ref.SampleReceived += StreamsSuccessful; - - // attendo 1 sec... - Thread.Sleep(1000); - MTC_ref.Start(); - esitoLink = 1; - - // fix tempi! - DateTime adesso = DateTime.Now; - lastPzCountSend = adesso; - lastWarnODL = adesso; - lastCurrent = adesso; - } - catch - { } - return esitoLink; - } - - /// - /// Formatta un dataitem da uno stream SAMPLE - /// - /// - /// - /// - /// - /// - private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectStreams.Sample DISample) - { - // creo il nuovo dataitem da sample... - MTConnectDevices.DataItem newDataItem = new MTConnectDevices.DataItem() - { - Category = DISample.Category, - Id = DISample.DataItemId, - Name = DISample.Name, - SampleRate = DISample.SampleRate, - Statistic = DISample.Statistic, - SubType = DISample.SubType, - Type = DISample.Type - }; - return formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newDataItem); - } - - /// - /// Formatta un dataitem da uno stream GENERICO - /// - /// - /// - /// - /// - /// - private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectStreams.DataItem DIGen) - { - // creo il nuovo dataitem da sample... - MTConnectDevices.DataItem newDataItem = new MTConnectDevices.DataItem() - { - Category = DIGen.Category, - Id = DIGen.DataItemId, - Name = DIGen.Name, - SubType = DIGen.SubType, - Type = DIGen.Type - }; - return formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newDataItem); - } - - /// - /// Formatta un dataitem x salvataggio in memoria locale - /// - /// - /// - /// - /// - /// - private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectDevices.DataItem dataItem) - { - MtcDataItemExt currDataItem; - // uuid e parametri secondo categoria... - switch (dataItem.Category) - { - case MTConnect.DataItemCategory.CONDITION: - uuid = $"C_{dataItem.Id}"; - threshDBand = 0; - dSamplePeriod = 0; - break; - - case MTConnect.DataItemCategory.EVENT: - uuid = $"E_{dataItem.Id}"; - threshDBand = 0; - dSamplePeriod = 0; - break; - - case MTConnect.DataItemCategory.SAMPLE: - uuid = $"S_{dataItem.Id}"; - // SOLO SE è abilitato il datafiltering... - if (enableDataFilter) - { - threshDBand = 1; - // controllo SE ho conf x deadband... - if (mtcParams.paramsEndThresh.Count > 0) - { - // ciclo su tutti i parametri indicati... - foreach (var item in mtcParams.paramsEndThresh) - { - if (dataItem.Id.EndsWith(item.Key)) - { - threshDBand = item.Value; - } - } - } - } - else - { - threshDBand = 0; - } - dSamplePeriod = 60; - break; - - default: - break; - } - // salvo oggetto x "uso interno" - currDataItem = new MtcDataItemExt() - { - Id = dataItem.Id, - Category = dataItem.Category, - Constraints = dataItem.Constraints, - CoordinateSystem = dataItem.CoordinateSystem, - Name = dataItem.Name, - NativeScale = dataItem.NativeScale, - NativeUnits = dataItem.NativeUnits, - SampleRate = dataItem.SampleRate, - Representation = dataItem.Representation, - SignificantDigits = dataItem.SignificantDigits, - Source = dataItem.Source, - Statistic = dataItem.Statistic, - SubType = dataItem.SubType, - Type = dataItem.Type, - TypePath = dataItem.TypePath, - Units = dataItem.Units, - XPath = dataItem.XPath, - uid = uuid, - thresholdDeadBand = threshDBand, - samplePeriod = dSamplePeriod - }; - // log x capire COME ho chiamato alcune cosette... - if (dataItem.Id.Contains("EXE_MODE") || dataItem.Id.Contains("RUN_MODE") || dataItem.Id.Contains("POWER") || dataItem.Id.EndsWith("_Status")) - { - lgInfo($"DEBUG DATA | dataItem.Id : {dataItem.Id}"); - } - - return currDataItem; - } - - /// - /// Effettua lettura file di conf specifico MTC da oggetto serializzato json - /// Nome file da cui leggere i parametri json - /// - private void loadMtcConf(string fileName) - { - string jsonFullPath = $"{Application.StartupPath}/DATA/CONF/{fileName}"; - lgInfo($"Apertura file {jsonFullPath}"); - StreamReader reader = new StreamReader(jsonFullPath); - string jsonData = reader.ReadToEnd().Replace("\n", "").Replace("\r", ""); - if (!string.IsNullOrEmpty(jsonData)) - { - lgInfo($"File json composto da {jsonData.Length} caratteri"); - try - { - mtcParams = JsonConvert.DeserializeObject(jsonData); - lgInfo($"Decodifica aree MtcParamConf: trovati {mtcParams.paramsEndThresh.Count} valori paramsEndThresh"); - } - catch (Exception exc) - { - lgError($"Eccezione in decodifica conf json MTC:{Environment.NewLine}{exc}"); - } - } - else - { - lgError("Errore in loadMtcConf: file json vuoto!"); - } - reader.Dispose(); - } - - /// - /// Effettua invio a MP/IO dell'elenco serializzato dei dataItems - /// - /// - private void sendDataItemsList(List dataItems) - { - string rawData = JsonConvert.SerializeObject(dataItems); - utils.callUrlNow($"{urlSaveDataItems}", rawData); - } - - #endregion area comune (non modificare) - - #region Metodi specifici (da verificare/completare in implementazione) - - /// - /// Verifico se abbia ALMENO un errore... - /// - protected bool hasError - { - get - { - bool answ = false; - // controllo TUTTE le conditions... - foreach (var item in dataItemMem) - { - // se NON HO GIA' allarmi attivi... - if (!answ) - { - // se è una condition... - if (item.Value.Category == MTConnect.DataItemCategory.CONDITION) - { - // se ha valore !="" --> allarmi attivi - if (!string.IsNullOrEmpty(item.Value.value)) - { - answ = true; - } - } - } - } - return answ; + Logging.Instance.Error($"Errore in getDataItemValue per {diKey}{Environment.NewLine}{exc}"); } + return answ; } /// @@ -993,8 +1057,34 @@ namespace IOB_WIN /// public override Dictionary getDynData() { - // valore non presente in vers default... se gestito fare override Dictionary outVal = new Dictionary(); + // verifico x ogni valore indicato SE sia disponibile da MTC ed invio (SE variato) + if (mtcParams.dynDataItems.Count > 0) + { + string currVal = ""; + foreach (var item in mtcParams.dynDataItems) + { + // cerco SE SIA tra i valori acquisiti da MTC + currVal = getDataItemValue(item); + if (!string.IsNullOrEmpty(currVal)) + { + // controlo 1:1 i parametri SE fossero variati/aggiunti + if (lastDynData.ContainsKey(item)) + { + if (lastDynData[item] != currVal) + { + lastDynData[item] = currVal; + outVal.Add(item, currVal); + } + } + else + { + lastDynData.Add(item, currVal); + outVal.Add(item, currVal); + } + } + } + } return outVal; } @@ -1046,133 +1136,122 @@ namespace IOB_WIN } /// - /// Verifica un DataItem e se il valore corrisponde a quello indicato come "true value" restituisce true + /// Effettua reset del contapezzi, NON POSSIBILE per MTC (read only) /// - /// - /// /// - protected bool checkDataItem(string itemName, string trueVal) + public override bool resetcontapezziPLC() { bool answ = false; - MtcDataItemExt 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; } /// - /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE per MTC (read only) /// - private void decodeToBaseBitmap() + /// + public override bool setcontapezziPLC(int newPzCount) { - // init a zero... - B_input = 0; + bool answ = false; + return answ; + } - /* ----------------------------------------------------- - * bitmap MAPO - * B0: POWER_ON - * B1: RUN - * B2: pzCount - * B3: allarme - * B4: manuale - ----------------------------------------------------- */ - - // Controllo booleano PING e POWERON... - string currPowerOn = getDataItemValue(mtcParams.condPowerOn.keyName); - // se valido il check ping lo eseguo... altrimenti lo do x buono - bool checkPing = !mtcParams.pingAsPowerOn; - if (!checkPing) + /// + /// Override connessione + /// + public override void tryConnect() + { + if (!connectionOk) { - checkPing = (testPingMachine == IPStatus.Success); - } - // verifico da target value richiesto... - bool checkPowerOn = (currPowerOn == mtcParams.condPowerOn.targetValue); - - // bit 0 (poweron) imposto a 1 SE pingo o PowerOn=="ON"... - B_input = (checkPing || checkPowerOn) ? 1 : 0; - - // variabili RUN... - string currRun = getDataItemValue(mtcParams.keyRunMode); - - // controllo RUN MODE preliminare... CABLATO poiché è GENERALE x MTC - if (currRun == "AUTOMATIC" || currRun == "SEMI_AUTO" || currRun == "SEMI_AUTOMATIC") - { - int numCond = mtcParams.condWork.Count; - int numCondOk = 0; - // cerco nell'elenco delle condizioni che indicano lavora se sono ok faccio +1 conteggio...... - foreach (var item in mtcParams.condWork) + // controllo che il ping sia stato tentato almeno pingTestSec fa... + if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec")) { - if (getDataItemValue(item.keyName) == item.targetValue) + if (verboseLog || periodicLog) { - numCondOk++; + lgInfo("MTC: ConnKO - tryConnect"); } - } - // se tutte condizioni rispettate --> lavora! - if (numCond == numCondOk) - { - // RUN = LAVORA! - B_input += (1 << 1); - } - } - // se ho almeno 1 allarme E NON SONO IN AUTO --> ALARM! - else if (hasError) - { - B_input += (1 << 3); - } - else - { - // se ho run mode != auto --> manual - B_input += (1 << 4); - } - - DateTime adesso = DateTime.Now; - int vFactor = 1; - // controllo SE HO dati per fare verifiche... - if (string.IsNullOrEmpty(currRun)) - { - // se ho parametro x gestione reset... - if (enableMtcRestart) - { - // controllo se ho ricevuto il current da OLTRE 1 minuto... - if (lastCurrent.AddMinutes(3) < adesso) + // in primis salvo data ping... + lastPING = DateTime.Now; + // se passa il ping faccio il resto... + if (testPingMachine == IPStatus.Success) { - lastCurrent = adesso; - // stop... - lgInfo("Fermato MTC_ref per mancanza dati current"); - MTC_ref.Stop(); - Thread.Sleep(1000); - // restart - lgInfo("Riavviato MTC_ref per mancanza dati current"); - MTC_ref.Start(); + string szStatusConnection = ""; + try + { + // ora provo connessione... + parentForm.commPlcActive = true; + short esitoLink = doConnect(); + lgInfo($"szStatusConnection MTC, 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 MTC: {szStatusConnection}{Environment.NewLine}{exc}"); + connectionOk = false; + lgInfo($"Eccezione in TryConnect, Adapter MTC 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: MTC controllo PING fallito per IP {cIobConf.cncIpAddr}"); + } } } } else { - vFactor = 6; + needRefresh = true; } - - // solo se non ho veto check - if (vetoCheckStatus < adesso) + // se non è ancora connesso faccio procesisng memoria caso disconnesso... + if (!connectionOk) { - lgInfo($"Stato variabili: currRun: {currRun}"); - // imposto veto per vetoSeconds... - vetoCheckStatus = adesso.AddSeconds(vetoSeconds * vFactor); - } - // log opzionale! - if (verboseLog) - { - lgInfo($"Trasformazione B_input: {B_input} | currRun = {currRun}"); + // processo semafori ed invio... + processMemoryDiscon(); } } - #endregion Metodi specifici (da verificare/completare in implementazione) + /// + /// Override disconnessione + /// + public override void tryDisconnect() + { + if (connectionOk) + { + string szStatusConnection = ""; + try + { + MTC_ref.Stop(); + connectionOk = false; + lgInfo(szStatusConnection); + lgInfo("Effettuata disconnessione adapter MTC!"); + } + catch (Exception exc) + { + lgFatal(exc, "Errore nella disconnessione dall'adapter MTC"); + } + } + else + { + lgError("IMPOSSIBILE effettuare disconnessione MTC: Connessione non disponibile..."); + } + } + + #endregion Public Methods } } \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 7ac8e6ad..b3a7fbfe 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,9 +9,9 @@ pipeline { steps { /* calcolo numero versione... diverso x branch MASTER/DEVELOP */ script { - withEnv(['NEXT_BUILD_NUMBER=747']) { - // env.versionNumber = VersionNumber(versionNumberString : '3.3.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true) - env.versionNumber = VersionNumber(versionNumberString : '3.3.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true, overrideBuildsAllTime: '${NEXT_BUILD_NUMBER}') + withEnv(['NEXT_BUILD_NUMBER=748']) { + // env.versionNumber = VersionNumber(versionNumberString : '3.4.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true) + env.versionNumber = VersionNumber(versionNumberString : '3.4.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true, overrideBuildsAllTime: '${NEXT_BUILD_NUMBER}') env.APP_NAME = 'MAPO-IOB-WIN' } }