From 57faa3704b0df416cbafe3153680a5fff23470ef Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Sat, 9 Nov 2024 11:31:48 +0100 Subject: [PATCH 1/3] REST Basse/Citizen: - continuo implementazione variabili - imposto check connessione --- IOB-UT-NEXT/Enums.cs | 10 + IOB-UT-NEXT/IOB-UT-NEXT.csproj | 16 +- IOB-UT-NEXT/ToMapo.cs | 72 +++ IOB-UT-NEXT/app.config | 6 +- IOB-UT-NEXT/packages.config | 6 +- IOB-WIN-NEXT/AdapterForm.cs | 11 + IOB-WIN-NEXT/App.config | 6 +- IOB-WIN-NEXT/DATA/CONF/L019.ini | 77 +++ IOB-WIN-NEXT/DATA/CONF/L020.ini | 75 +++ IOB-WIN-NEXT/DATA/CONF/L020_Rest.json | 141 +++++ IOB-WIN-NEXT/DATA/CONF/VL27.json | 44 +- IOB-WIN-NEXT/IOB-WIN-NEXT.csproj | 22 +- IOB-WIN-NEXT/Iob/Generic.cs | 6 + IOB-WIN-NEXT/IobOpc/OpcUa.cs | 2 +- IOB-WIN-NEXT/IobRest/Base.cs | 778 ++++++++++++++++++++++++++ IOB-WIN-NEXT/IobRest/Citizen.cs | 231 ++++++++ IOB-WIN-NEXT/packages.config | 6 +- 17 files changed, 1484 insertions(+), 25 deletions(-) create mode 100644 IOB-WIN-NEXT/DATA/CONF/L019.ini create mode 100644 IOB-WIN-NEXT/DATA/CONF/L020.ini create mode 100644 IOB-WIN-NEXT/DATA/CONF/L020_Rest.json create mode 100644 IOB-WIN-NEXT/IobRest/Base.cs create mode 100644 IOB-WIN-NEXT/IobRest/Citizen.cs diff --git a/IOB-UT-NEXT/Enums.cs b/IOB-UT-NEXT/Enums.cs index 4f96e586..ee9c46b9 100644 --- a/IOB-UT-NEXT/Enums.cs +++ b/IOB-UT-NEXT/Enums.cs @@ -532,6 +532,16 @@ namespace IOB_UT_NEXT /// PingWatchdog, + /// + /// Adapter REST (base) + /// + REST, + + /// + /// Adapter REST Citizen + /// + REST_CITIZEN, + /// /// Adapter SIEMENS /// diff --git a/IOB-UT-NEXT/IOB-UT-NEXT.csproj b/IOB-UT-NEXT/IOB-UT-NEXT.csproj index d03ea652..271c0d28 100644 --- a/IOB-UT-NEXT/IOB-UT-NEXT.csproj +++ b/IOB-UT-NEXT/IOB-UT-NEXT.csproj @@ -84,8 +84,8 @@ ..\packages\MapoSDK.6.14.2309.1908\lib\MapoSDK.dll - - ..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll + + ..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll @@ -96,6 +96,9 @@ ..\packages\Pipelines.Sockets.Unofficial.2.2.8\lib\net461\Pipelines.Sockets.Unofficial.dll + + ..\packages\RestSharp.112.1.0\lib\netstandard2.0\RestSharp.dll + ..\packages\StackExchange.Redis.2.6.122\lib\net461\StackExchange.Redis.dll @@ -130,6 +133,12 @@ + + ..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll + + + ..\packages\System.Text.Json.8.0.4\lib\net462\System.Text.Json.dll + ..\packages\System.Threading.Channels.6.0.0\lib\net461\System.Threading.Channels.dll @@ -137,6 +146,9 @@ ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + diff --git a/IOB-UT-NEXT/ToMapo.cs b/IOB-UT-NEXT/ToMapo.cs index f67d2cbf..a3909105 100644 --- a/IOB-UT-NEXT/ToMapo.cs +++ b/IOB-UT-NEXT/ToMapo.cs @@ -723,6 +723,78 @@ namespace IOB_UT_NEXT #endregion Public Properties } + + /// + /// Classe gestione configurazione parametri specifici Rest Client da BaseParamConf + /// + public class RestParamConf : BaseParamConf + { + /// + /// Timeout chiamate REST + /// + public int timeOutSec { get; set; } = 60; + + /// + /// API di base x chiamate REST, eventuali variabili van indicate come [[nomevar]] + /// + public string apiUrl { get; set; } = ""; + + /// + /// Elenco delle chiamate x ID / struttura + /// + public Dictionary CallList { get; set; } = new Dictionary(); + +#if false + /// + /// Dizionario "tampone" di variabili da poter reimpiegare in chiamate successive (es token) + /// + public Dictionary TempVars { get; set; } = new Dictionary(); + + /// + /// Elenco delle chiamate VIETATE (con nota opzionale sul motivo) + /// + public Dictionary CallVeto { get; set; } = new Dictionary(); +#endif + + public class CallStruc + { + /// + /// ID univoco chiamata per poterla recuperare + /// + public int Idx { get; set; } = 0; + + /// + /// Metodo chaimata + /// + public RestSharp.Method Method { get; set; } = RestSharp.Method.Get; + + /// + /// Url chiamata + /// + public string Url { get; set; } = ""; + + /// + /// Nome x invio a MES + /// + public string Name { get; set; } = ""; + + /// + /// Nome x salvataggio valore output in ProdData da poter richiamare + /// + public string OutVarName { get; set; } = ""; + + /// + /// Intervallo di campionamento (minimo) da rispettare x evitare flood chiamate + /// + public int SamplePeriod { get; set; } = 5000; + + /// + /// Elenco chiamate richieste se non fosse trovata/valida una variabile + /// + public List ListPrevCall { get; set; } = new List(); + } + } + public class UserIdent { #region Public Properties diff --git a/IOB-UT-NEXT/app.config b/IOB-UT-NEXT/app.config index 15273954..6878afb3 100644 --- a/IOB-UT-NEXT/app.config +++ b/IOB-UT-NEXT/app.config @@ -20,7 +20,7 @@ - + @@ -38,6 +38,10 @@ + + + + diff --git a/IOB-UT-NEXT/packages.config b/IOB-UT-NEXT/packages.config index 5c2a3f51..3a637b5d 100644 --- a/IOB-UT-NEXT/packages.config +++ b/IOB-UT-NEXT/packages.config @@ -1,10 +1,11 @@  - + + @@ -15,6 +16,9 @@ + + + \ No newline at end of file diff --git a/IOB-WIN-NEXT/AdapterForm.cs b/IOB-WIN-NEXT/AdapterForm.cs index b1b94347..6e148ac8 100644 --- a/IOB-WIN-NEXT/AdapterForm.cs +++ b/IOB-WIN-NEXT/AdapterForm.cs @@ -1,4 +1,5 @@ using IOB_UT_NEXT; +using IOB_WIN_NEXT.IobSoap; using MapoSDK; using Newtonsoft.Json; using NLog; @@ -1848,6 +1849,16 @@ namespace IOB_WIN_NEXT start.Enabled = true; break; + case tipoAdapter.REST: + iobObj = new IobRest.Base(this, IOBConf); + start.Enabled = true; + break; + + case tipoAdapter.REST_CITIZEN: + iobObj = new IobRest.Citizen(this, IOBConf); + start.Enabled = true; + break; + case tipoAdapter.SIEMENS: iobObj = new IobSiemens.Siemens(this, IOBConf); start.Enabled = true; diff --git a/IOB-WIN-NEXT/App.config b/IOB-WIN-NEXT/App.config index d477e977..f83fb883 100644 --- a/IOB-WIN-NEXT/App.config +++ b/IOB-WIN-NEXT/App.config @@ -133,7 +133,7 @@ - + @@ -179,6 +179,10 @@ + + + + diff --git a/IOB-WIN-NEXT/DATA/CONF/L019.ini b/IOB-WIN-NEXT/DATA/CONF/L019.ini new file mode 100644 index 00000000..14502e3a --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/L019.ini @@ -0,0 +1,77 @@ +;Configurazione IOB-WIN +[IOB] +CNCTYPE=FANUC + +[MACHINE] +VENDOR=COLCOM +MODEL=DMG-MORI-02 + +[CNC] +; TEST FANUC! +;IP=192.168.100.81 +;Nuovo ip in sottorete .80. +IP=192.168.80.34 +PORT=8193 +GETPRGNAME=true + +[SERVER] +MPIP=192.168.111.104 +MPURL=/MP/IO +CMDBASE=/IOB/input/ +CMDFLOG=/IOB/flog/ +CMDALIVE=/IOB +CMDENABLED=/IOB/enabled/ +CMDADV1=?valore= +CMDREBO=/sendReboot.aspx?idxMacchina= + +[MEMORY] +; Red: Y12.4 | Yellow: Y51.1 (porta chiusa, da NEGARE) | Green Y12.6 | Alarm Y 51.4 | Blu Y12.7 +;BIT0=CONN +BIT1=Y12.6 +;BIT2=PZCOUNT.PAR.6711 +BIT3=Y12.4 +BIT4=Y12.7 +;BIT5=Y11.2 +BIT5=X18.3 +BIT6=X11.3 +AREAD_START=0 +AREAD_SIZE=9999 +AREAG_SIZE=48 +AREAR_START=0 +AREAR_SIZE=64 +AREAX_START=0 +AREAX_SIZE=64 +AREAY_START=0 +AREAY_SIZE=64 +PAR_START=6711 +PAR_SIZE=3 + +[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=STD|BIT +;PZCOUNT_MODE=STD.PAR.6711 +;PZGTOT_MODE=STD.PAR.6712 +;PZREQ_MODE=STD.PAR.6713 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE +;gestione invio pezzi in blocco +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=10 +MAX_SEND_PZC_BLOCK=100 +DISABLE_SEND_WDST=TRUE + +[BRANCH] +NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/L020.ini b/IOB-WIN-NEXT/DATA/CONF/L020.ini new file mode 100644 index 00000000..01c502f2 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/L020.ini @@ -0,0 +1,75 @@ +;Configurazione IOB-WIN +[IOB] +CNCTYPE=REST_CITIZEN + +[MACHINE] +VENDOR=Citizen_Mecmatica +MODEL=Citizen + +[CNC] +IP=192.168.80.61 +PORT=8733 +GETPRGNAME=true + +[SERVER] +MPIP=192.168.111.104 +MPURL=/MP/IO +CMDBASE=/IOB/input/ +CMDFLOG=/IOB/flog/ +CMDALIVE=/IOB +CMDENABLED=/IOB/enabled/ +CMDADV1=?valore= +CMDREBO=/sendReboot.aspx?idxMacchina= + +[MEMORY] +; Red: Y12.4 | Yellow: Y51.1 (porta chiusa, da NEGARE) | Green Y12.6 | Alarm Y 51.4 | Blu Y12.7 +;BIT0=CONN +BIT1=Y12.6 +;BIT2=PZCOUNT.PAR.6711 +BIT3=Y12.4 +BIT4=Y12.7 +;BIT5=Y11.2 +BIT5=X18.3 +BIT6=X11.3 +AREAD_START=0 +AREAD_SIZE=9999 +AREAG_SIZE=48 +AREAR_START=0 +AREAR_SIZE=64 +AREAX_START=0 +AREAX_SIZE=64 +AREAY_START=0 +AREAY_SIZE=64 +PAR_START=6711 +PAR_SIZE=3 + +[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=STD|BIT +;PZCOUNT_MODE=STD.PAR.6711 +;PZGTOT_MODE=STD.PAR.6712 +;PZREQ_MODE=STD.PAR.6713 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE +;gestione invio pezzi in blocco +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=10 +MAX_SEND_PZC_BLOCK=100 +DISABLE_SEND_WDST=TRUE +REST_CONF=L020_Rest.conf + +[BRANCH] +NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/L020_Rest.json b/IOB-WIN-NEXT/DATA/CONF/L020_Rest.json new file mode 100644 index 00000000..286fe115 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/L020_Rest.json @@ -0,0 +1,141 @@ +{ + "timeOutSec": 60, + "apiUrl": "http://192.168.80.61:8733/DRIVER_MES/rest/", + "mMapRead": { + //"GetQtyTot": { + // "name": "GetQtyTot", + // "description": "Contatore GTot", + // //"memAddr": "", + // "tipoMem": "Int", + // //"index": 0, + // //"size": 4, + // "func": "LAST", + // //"period": 60, + // "factor": 1, + // "displOrdinal": 1 + //} + }, + "mMapWrite": { + }, + "CallList": { + "GetConnection": { + "Method": "Get", + "Url": "checkconnection", + "Name": "Connection", + "OutVarName": "Connected" + }, + "GetToken": { + "Method": "Get", + "Url": "gettoken/mecmaticames/mecmatica@mes", + "OutVarName": "token", + "SamplePeriod": 1000 + }, + "GetLampGreen": { + "Method": "Get", + "Url": "getsingleladderio/[[token]]/Y/8E", + "Name": "Lampada Verde", + "OutVarName": "LampGreen", + "ListPrevCall": [ "GetToken" ], + "SamplePeriod": 1000 + }, + "GetLampYellow": { + "Method": "Get", + "Url": "getsingleladderio/[[token]]/Y/21", + "Name": "Lampada Gialla", + "OutVarName": "LampYellow", + "ListPrevCall": [ "GetToken" ], + "SamplePeriod": 1000 + }, + "GetLampRed": { + "Method": "Get", + "Url": "getsingleladderio/[[token]]/Y/22", + "Name": "Lampada Rossa", + "OutVarName": "LampRed", + "ListPrevCall": [ "GetToken" ], + "SamplePeriod": 1000 + }, + //"GetStateAlarm": { + // "Method": "Get", + // "Url": "getsingleladderio/[[token]]/Y/200", + // "Name": "Macchina in Allarme", + // "OutVarName": "AlarmState", + // "ListPrevCall": [ "GetToken" ], + // "SamplePeriod": 2000 + //}, + //"GetStateCaution": { + // "Method": "Get", + // "Url": "getsingleladderio/[[token]]/Y/201", + // "Name": "Macchina in Caution", + // "OutVarName": "CautionState", + // "ListPrevCall": [ "GetToken" ], + // "SamplePeriod": 2000 + //}, + //"GetStateStart": { + // "Method": "Get", + // "Url": "getsingleladderio/[[token]]/Y/222", + // "Name": "Macchina in Start", + // "OutVarName": "StartState", + // "ListPrevCall": [ "GetToken" ], + // "SamplePeriod": 2000 + //}, + //"GetStateStop": { + // "Method": "Get", + // "Url": "getsingleladderio/[[token]]/Y/223", + // "Name": "Macchina in Stop", + // "OutVarName": "StopState", + // "ListPrevCall": [ "GetToken" ], + // "SamplePeriod": 2000 + //}, + "GetQtyTot": { + "Method": "Get", + "Url": "gettotalquantity/[[token]]", + "Name": "Contapezzi Assoluto", + "OutVarName": "ContapezziAssoluto", + "ListPrevCall": [ "GetToken" ] + }, + "GetQtyReq": { + "Method": "Get", + "Url": "getneededquantity/[[token]]", + "Name": "Qta Richiesta", + "OutVarName": "setPzComm", + "ListPrevCall": [ "GetToken" ] + }, + "GetQtyProd": { + "Method": "Get", + "Url": "getworkedquantity/[[token]]", + "Name": "Contapezzi Parziale", + "OutVarName": "ContapezziParziale", + "ListPrevCall": [ "GetToken" ] + }, + "GetCycleTime": { + "Method": "Get", + "Url": "getcycletime/[[token]]", + "Name": "tempoCiclo (sec)", + "OutVarName": "LastTC", + "ListPrevCall": [ "GetToken" ] + }, + "GetProgName": { + "Method": "Get", + "Url": "getmainprogram/[[token]]", + "Name": "Programma MAIN", + "OutVarName": "PROG", + "ListPrevCall": [ "GetToken" ] + }, + "GetCurrAlarm": { + "Method": "Get", + "Url": "getalarm/[[token]]", + "Name": "Allarme attivo", + "OutVarName": "AlarmActive", + "ListPrevCall": [ "GetToken" ], + "SamplePeriod": 2000 + }, + "GetAllAlarmLog": { + "Method": "Get", + "Url": "getallalarmlog/[[token]]", + "Name": "Log Allarmi (last)", + "OutVarName": "", + "ListPrevCall": [ "GetToken" ], + "SamplePeriod": 20000 + } + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/VL27.json b/IOB-WIN-NEXT/DATA/CONF/VL27.json index 8db03ba7..3975a6ff 100644 --- a/IOB-WIN-NEXT/DATA/CONF/VL27.json +++ b/IOB-WIN-NEXT/DATA/CONF/VL27.json @@ -3,7 +3,7 @@ "setArt": { "name": "setArt", "description": "Articolo", - "memAddr": "", + "memAddr": "NONE.01", "tipoMem": "String", "index": 0, "size": 20, @@ -21,7 +21,7 @@ "setComm": { "name": "setComm", "description": "Commessa", - "memAddr": "", + "memAddr": "NONE.02", "tipoMem": "String", "index": 0, "size": 20, @@ -47,27 +47,41 @@ } }, "mMapRead": { - "ContatoreAssoluto": { - "name": "ContatoreAssoluto", - "description": "Contapezzi ASSOLUTO", - "memAddr": "MACRO.929", + "PZ_GTOT": { + "name": "PZ_GTOT", + "description": "Contatore GTot", + "memAddr": "", "tipoMem": "Int", - "index": 929, + "index": 0, "size": 4, "func": "MAX", "period": 60, - "factor": 1 + "factor": 1, + "displOrdinal": 7 }, - "ContatoreParziale": { - "name": "ContatoreParziale", - "description": "Contapezzi Parziale", - "memAddr": "MACRO.930", - "tipoMem": "DInt", - "index": 930, + "PZ_COUNT": { + "name": "PZ_COUNT", + "description": "Contatore", + "memAddr": "", + "tipoMem": "Int", + "index": 0, "size": 4, "func": "MAX", "period": 60, - "factor": 1 + "factor": 1, + "displOrdinal": 8 + }, + "PROG": { + "name": "PROG", + "description": "Programma", + "memAddr": "", + "tipoMem": "Int", + "index": 0, + "size": 4, + "func": "MAX", + "period": 60, + "factor": 1, + "displOrdinal": 9 } }, "mMapWriteLink": { diff --git a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj index 296c4125..9890afbb 100644 --- a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj +++ b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj @@ -153,6 +153,9 @@ ..\packages\MathNet.Numerics.4.15.0\lib\net461\MathNet.Numerics.dll + + ..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + ..\packages\Microsoft.Extensions.Logging.Abstractions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll @@ -204,9 +207,8 @@ ..\packages\OPCFoundation.NetStandard.Opc.Ua.Security.Certificates.1.4.367.75\lib\net462\Opc.Ua.Security.Certificates.dll - - ..\packages\RestSharp.105.2.3\lib\net46\RestSharp.dll - True + + ..\packages\RestSharp.112.1.0\lib\netstandard2.0\RestSharp.dll ..\packages\S7netplus.0.1.9\lib\net45\S7.Net.dll @@ -366,6 +368,15 @@ ..\packages\System.ServiceModel.Security.4.6.0\lib\net461\System.ServiceModel.Security.dll + + ..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll + + + ..\packages\System.Text.Json.8.0.4\lib\net462\System.Text.Json.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll @@ -403,6 +414,8 @@ + + @@ -514,6 +527,9 @@ + + + diff --git a/IOB-WIN-NEXT/Iob/Generic.cs b/IOB-WIN-NEXT/Iob/Generic.cs index 07cfcaba..cd55776b 100644 --- a/IOB-WIN-NEXT/Iob/Generic.cs +++ b/IOB-WIN-NEXT/Iob/Generic.cs @@ -7337,6 +7337,12 @@ namespace IOB_WIN_NEXT.Iob return fatto; } + /// + /// Aggiornamento virtuale della LUT da usare x decodifica stato macchina + /// + protected virtual void updateStateLUT() + { } + #endregion Protected Methods #region Private Fields diff --git a/IOB-WIN-NEXT/IobOpc/OpcUa.cs b/IOB-WIN-NEXT/IobOpc/OpcUa.cs index 58d82578..85a71de0 100644 --- a/IOB-WIN-NEXT/IobOpc/OpcUa.cs +++ b/IOB-WIN-NEXT/IobOpc/OpcUa.cs @@ -866,7 +866,7 @@ namespace IOB_WIN_NEXT.IobOpc } /// - /// Parametri specifici MTC + /// Parametri specifici OPC-UA /// protected OpcUaParamConf opcUaParams { get; set; } diff --git a/IOB-WIN-NEXT/IobRest/Base.cs b/IOB-WIN-NEXT/IobRest/Base.cs new file mode 100644 index 00000000..e4bdd989 --- /dev/null +++ b/IOB-WIN-NEXT/IobRest/Base.cs @@ -0,0 +1,778 @@ +using RestSharp; +using IOB_UT_NEXT; +using MapoSDK; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Net.NetworkInformation; +using System.IO; +using System.Windows.Forms; +using System.Threading; + +namespace IOB_WIN_NEXT.IobRest +{ + /// + /// Adapter base per sviluppo chiamate con servizi REST + /// + public class Base : Iob.Generic + { + #region Public Constructors + + /// + /// Costruttore dell'IOB Rest generico + /// + /// AdapterForm chiamante + /// Configurazione IOB per avvio + public Base(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + { + lgInfo($"Richiesto Adapter IobRest.Base con i parametri seguenti | ADDR: {IOBConf.cncIpAddr} | PORT: {IOBConf.cncPort}"); + lastPING = DateTime.Now.AddHours(-1); + // predispongo configurazione specifica Rest... + if (!string.IsNullOrEmpty(getOptJsonKVP("REST_CONF"))) + { + setupRestConf(getOptJsonKVP("REST_CONF")); + } + } + + protected void setupRestConf(string restConfFile) + { + + // se ho file specifico + if (!string.IsNullOrEmpty(getOptJsonKVP("REST_CONF"))) + { + string rawData = ""; + // leggo file e decodifico... + string confPath = $"{Application.StartupPath}/DATA/CONF/{restConfFile}"; + lgInfo($"Apertura file {confPath}"); + using (StreamReader sr = new StreamReader(confPath)) + { + rawData = sr.ReadToEnd().Replace("\n", "").Replace("\r", ""); + } + // continuo decodifica + if (!string.IsNullOrEmpty(rawData)) + { + restParams = JsonConvert.DeserializeObject(rawData); + if (restParams != null) + { + // inizializzo dal file di conf le variabili necessarie... + tOutSec = restParams.timeOutSec; + apiUrl = restParams.apiUrl ?? "http://localhost:8733"; + } + } + } + + // sistemo conf standard x call REST + restOptStd = new RestClientOptions + { + Timeout = TimeSpan.FromSeconds(tOutSec), + BaseUrl = new Uri(apiUrl) + }; + } + + #endregion Public Constructors + + #region Public Methods + + /// + /// Implementazione custom esecuzione task specifici + /// + /// + /// + public override Dictionary executeTasks(Dictionary task2exe) + { + /*--------------------------------------- + * gestione execute task SPECIFICI x pesa: + * - salva i parametri richiesta (RM, cod1..cod6) + * - esegue metodo richiesta (IN/OUT) + *---------------------------------------*/ + + // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); +#if false + if (task2exe != null) + { + lgTrace($"executeTasks: richiesta esecuzione {task2exe.Count} task"); + // controllo se memMap != null... + if (memMap != null) + { + bool taskOk = false; + string taskVal = ""; + // cerco task specifici: qui sono NON standard... + foreach (var item in task2exe) + { + lgInfo($"TASK | {item.Key} --> {item.Value}"); + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY... + switch (tName) + { + 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!"); + } + } +#endif + + return taskDone; + } + + /// + /// Recupero dati dinamici... + /// + public override Dictionary getDynData() + { + // valore non presente in vers default... se gestito fare override + Dictionary outVal = new Dictionary(); +#if false + // controllo se ho indicato ancora che ci siano pesate già lette da inviare... + if (num2send() > 0) + { + // preparo oggetti x confronto ... + List listaArch = listPesateArchivio; + + // se non ho nulla in archivio prendo ultima pesata (essendo DESC è la prima cronologicamente) + if (listaArch.Count == 0) + { + WeightRec lastRec = listPesateCurr.LastOrDefault(); + // aggiungo... + SavePesata(ref outVal, lastRec); + } + // ora il confronto è cronologico sulle pesate + recenti... + else + { + // prendo prima della lista pesate archiviate = più recente come dt da cui partire... + DateTime dtRif = listaArch.FirstOrDefault().DtEvent; + var firstRec = listPesateCurr + .Where(x => x.DtEvent > dtRif) + .OrderBy(x => x.DtEvent) + .FirstOrDefault(); + if (firstRec != null) + { + SavePesata(ref outVal, firstRec); + } + } + + // processo comunque le aree memoria READ... + if (memMap.mMapRead.Count > 0) + { + foreach (var item in memMap.mMapRead) + { + var currVal = getCurrProdData(item.Key, ""); + if (!outVal.ContainsKey(item.Key)) + { + outVal.Add(item.Key, $"{currVal}"); + } + // se fosse logReq --> resetto... + if (item.Key == "logReq" && !string.IsNullOrEmpty(currVal)) + { + upsertKey(item.Key, ""); + } + } + } + } + // altrimenti rileggo e cerco se ci siano + else + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + try + { + // test lettura elenco pesate... se NON nullo --> OK! + var weightArray = RestConn.reqWeightList("ALL", dataFrom, dataTo); + // riordino DESC + listPesateCurr = WeightRec.ConvertPesate(weightArray.OrderByDescending(x => x.dateIn).ToList()); + } + catch (Exception exc) + { + lgError($"Eccezione in RestConn.reqWeightList{Environment.NewLine}{exc}"); + } + sw.Stop(); + lgInfo($"getDynData | SOAP: effettuata chiamata reqWeightList in {sw.Elapsed.TotalMilliseconds}ms | {dataFrom} --> {dataTo} | {listPesateCurr.Count} rec"); + } +#endif + // indico esecuzione e proseguo + lastReadPLC = DateTime.Now; + return outVal; + } + + /// + /// Effettua lettura semafori principale + /// Parametri da aggiornare x display in form + /// + public override void readSemafori(ref newDisplayData currDispData) + { + DateTime adesso = DateTime.Now; + lastReadPLC = adesso; + // verifico non sia in veto invio iniziale... + if (queueInEnabCurr) + { + try + { + if (verboseLog) + { + lgInfo("inizio read semafori"); + } + + currDispData.semIn = Semaforo.SV; + // decodifica e gestione + decodeToBaseBitmap(); + // display + reportRawInput(ref currDispData); + } + catch (Exception exc) + { + currDispData.semIn = Semaforo.SR; + lgError($"Eccezione in readSemafori:{Environment.NewLine}{exc}"); + } + } + else + { + lgDebug($"[VETO readSemafori] | veto attivo alle {adesso:yyyy.MM.dd HH:mm:ss}"); + checkVetoQueueIn(); + } + + } + + + + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// + private void decodeToBaseBitmap() + { + // init a zero... + B_input = 0; + if (queueInEnabCurr) + { + /* ----------------------------------------------------- + * bitmap MAPO STD 60 + * B0: POWER_ON + * B1: RUN + * B2: pzCount + * B3: allarme + * B4: manuale + * B5: allarme TCiclo (SLOW) + * B6: WarmUp_CoolDown + * B7: EmergArmed (1 = NON emergenza, 0 = emergenza) + ----------------------------------------------------- */ + + // per prima cosa controllo ping e se sia connesso... + + + +#if false + if (connectionOk) + { + B_input = 1; + currDispData.semIn = Semaforo.SV; + + // se ho pesate in memoria nel periodo richiesto --> RUN + if (listPesateCurr != null && listPesateCurr.Count > 0) + { + B_input += (1 << 1); + } + // metto manuale + else + { + B_input += (1 << 4); + } + + // accodo NON emergenza + B_input += (1 << 7); + } + else + { + B_input = 0; + currDispData.semIn = Semaforo.SR; + } +#endif + +#if false + // Controllo booleano PING e POWERON... + string currPowerOn = getDataItemValue(mtcParams.condPowerOn.keyName); + // se valido il check ping lo eseguo... altrimenti lo do x buono + bool isPingOk = mtcParams.pingAsPowerOn && (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 = (isPingOk || checkPowerOn) ? 1 : 0; + + // variabili RUN... + string currRun = getDataItemValue(mtcParams.keyRunMode); + + // controllo RUN MODE preliminare... CABLATO - è 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 almeno 1 allarme E NON SONO IN AUTO --> ALARM! + else if (hasError) + { + B_input += (1 << 3); + } + // 2024.01.90: gestione dati UNAVAILABLE che indicano poweroff... + else if (hasUnavailableData && unavailPoweroff) + { + B_input = 0; + } + else + { + // se ho run mode != auto --> manual + B_input += (1 << 4); + } + + // emergenza armata da riportare con bit True/ 1 + if (mtcParams.emergencyArmedTrue) + { + //se NON premuta lazo il bit + if (!hasEStopTriggered) + { + B_input += (1 << 5); + } + } + // emergenza armata da riportare come False/0 (!mtcParams.emergencyArmedTrue) + else + { + // se premuta alzo il bit... + if (hasEStopTriggered) + { + B_input += (1 << 5); + } + } + + 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}"); + } +#endif + } + else + { + lgDebug($"[VETO getDataItemValue] | veto attivo alle {DateTime.Now:yyyy.MM.dd HH:mm:ss}"); + } + } + + protected string ExecuteCallGet(string resource) + { + string answ = ""; + // client chiamate rest + using (var client = new RestClient(restOptStd)) + { + var currReq = new RestRequest($"/api/attivazioni/verifica/?chiave={MKeyEnc}&codImpiego={CodImp}", Method.Get); + // effettuo vera chiamata + var currResp = await client.GetAsync(currReq); + if (currResp.StatusCode == System.Net.HttpStatusCode.OK && currResp.Content != null) + { + // salvo in redis contenuto serializzato + string rawData = $"{currResp.Content}"; + var currVal = JsonConvert.DeserializeObject(rawData); + if (currVal != null) + { + answ = currVal; + } + } + } + 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")) + { + if (verboseLog || periodicLog) + { + lgInfo("Rest: ConnKO - tryConnect"); + } + // in primis salvo data ping... + lastPING = DateTime.Now; + // se passa il ping faccio il resto... + if (testPingMachine == IPStatus.Success) + { + string szStatusConnection = ""; + try + { + // ora provo connessione... + parentForm.commPlcActive = true; + + // chiamo metodo connect + +#if false + // init del proxy!!! + string endpointAddr = $"https://{cIobConf.cncIpAddr}:{cIobConf.cncPort}/ws"; + lgInfo($"Tentativo avvio SOAP su endpoint {endpointAddr}"); + Stopwatch sw = new Stopwatch(); + sw.Start(); + + // salto verifica certificato + System.Net.ServicePointManager.ServerCertificateValidationCallback = (senderX, certificate, chain, sslPolicyErrors) => { return true; }; + + // riprovo connessione SE non fosse andata... + int maxTry = 5; + int nTry = 1; + // tento avvio WS SOAP! + RestConn = new EgwProxy.Rest.RestServ.lwpServiceClient("lwpServicePort", new System.ServiceModel.EndpointAddress(endpointAddr)); + while (RestConn == null || (nTry <= maxTry && !checkStateOk(RestConn.State))) + { + lgInfo($"Tentativo connessione Rest: | endpointAddr: {endpointAddr} | nTry: {nTry}"); + // tento avvio WS SOAP! + RestConn = new EgwProxy.Rest.RestServ.lwpServiceClient("lwpServicePort", new System.ServiceModel.EndpointAddress(endpointAddr)); + nTry++; + } + if (checkStateOk(RestConn.State)) + { + connectionOk = true; + List weightArray = new List(); + try + { + // test lettura elenco pesate... se NON nullo --> OK! + weightArray = RestConn.reqWeightList("ALL", dataFrom, dataTo).OrderByDescending(x => x.dateIn).ToList(); + // riordino DESC + listPesateCurr = WeightRec.ConvertPesate(weightArray); + } + catch (Exception exc) + { + lgError($"Eccezione in RestConn.reqWeightList{Environment.NewLine}{exc}"); + } + sw.Stop(); + lgInfo($"SOAP: effettuata chiamata connessione + reqWeightList in {sw.Elapsed.TotalMilliseconds}ms | {dataFrom} --> {dataTo}"); + if (listPesateCurr != null && listPesateCurr.Count >= 0) + { + lgInfo($"szStatusConnection Rest, recuperato elenco di {listPesateCurr.Count} pesate"); + parentForm.commPlcActive = false; + connectionOk = true; + // sistemo data da cui iniziare recuperi successivi se ho + di numLastWeight + if (weightArray.Count > numLastWeight) + { + var lastRec = weightArray + .OrderByDescending(x => x.dateIn) + .Skip(numLastWeight).FirstOrDefault(); + // metto giorno antecedente + dtStartLive = lastRec.dateIn.Date.AddDays(-1); + } + // processo pesate! + demFactDynData = 1; + processDynData(); + } + } + // refresh stato connessione!!! + if (connectionOk) + { + queueInEnabCurr = true; + if (adpRunning) + { + lgInfo("Connessione OK"); + } + } + else + { + lgError("Impossibile procedere, connessione mancante..."); + } +#endif + } + catch (Exception exc) + { + lgFatal($"Errore nella connessione all'Adapter IobRest.Base: {szStatusConnection}{Environment.NewLine}{exc}"); + connectionOk = false; + lgInfo($"Eccezione in TryConnect, Adapter IobRest.Base 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: Rest controllo PING fallito per IP {cIobConf.cncPingAddr}"); + } + } + } + } + else + { + needRefresh = true; + } + } + + public override void tryDisconnect() + { + // registro solo che è disconnesso + connectionOk = false; + queueInEnabCurr = false; + } + + #endregion Public Methods + + #region Protected Fields + + /// + /// Api Url di base x chiamate REST + /// + protected string apiUrl = "http://localhost:8733"; + + /// + /// Timeout chiamate REST + /// + protected int tOutSec = 60; + + #endregion Protected Fields + + #region Protected Methods + + /// + /// verifica stato ok ovvero connected oppure open + /// + /// + /// + protected bool checkStateOk(System.ServiceModel.CommunicationState currState) + { + bool answ = false; +#if false + answ == System.ServiceModel.CommunicationState.Opened || currState == System.ServiceModel.CommunicationState.Created; +#endif + return answ; + } + + /// + /// Metodo da overridare x scrivere DAVVERO i parametri sul PLC + /// + /// + protected override void plcWriteParams(ref List updatedPar) + { + lgTrace($"plcWriteParams: richiesta per {updatedPar.Count} params"); + foreach (var item in updatedPar) + { + lgInfo($"ITEM | {item.uid} | {item.value}"); + // salvo i valori di setup x prox pesata... + upsertKey(item.uid, item.value); +#if false + bool fatto = false; + bool isPesata = false; + bool isIN = false; + gestWeightOut answ = new gestWeightOut(); + // se è richiesta pesata IN/OUT --> mando chiamata + if (item.uid == "reqPesata") + { + isPesata = true; + isIN = item.reqValue.ToUpper() == "IN"; + //isIN = item.value.ToUpper() == "IN"; + try + { + answ = reqWeight(isIN); + } + catch (Exception exc) + { + lgError($"Eccezione in plcWriteParams.reqWeight | isIn: {isIN}{Environment.NewLine}{exc}"); + } + } + else if (item.uid == "RM" || item.uid.StartsWith("Cod")) + { + // comunque segno fatto x altri casi + fatto = true; + } + + // se è pesata... + if (isPesata) + { + // se è OK + if (answ.feedback == "C") + { + lgInfo($"reqWeight | Effettuato richiesta | {answ.feedback} | {answ.notes}"); + // resetto pesata + upsertKey(item.uid, ""); + } + else + { + lgError($"reqWeight | Errore in richiesta peso Rest | {answ.feedback} | {answ.notes}"); + } + item.value = ""; + item.reqValue = ""; + item.lastRead = DateTime.Now; + item.UM = ""; + // salvo esito richiesta comunque + upsertKey("logReq", $"{answ.feedback} | {answ.notes}"); + // faccio in modo di eseguire subito getDynData + demFactDynData = 1; + processDynData(); + } + else + { + // se fatto --> aggiorno! + if (fatto) + { + //item.value = item.reqValue; + item.reqValue = ""; + item.lastRead = DateTime.Now; + item.UM = ""; + } + } +#endif + } + } + + #endregion Protected Methods + + #region Private Fields + + /// + /// Conf client RestSharp standard: + /// - timeout 1 min + /// + private RestClientOptions restOptStd = new RestClientOptions { Timeout = TimeSpan.FromSeconds(60) }; + + #endregion Private Fields + +#if false + /// + /// Esegue richiesta PESO + /// + /// Tipo richiesta: IN (true) / OUT (false) + /// + protected gestWeightOut reqWeight(bool reqIN) + { + lgInfo($"reqWeight | IN: {reqIN}"); + gestWeightOut answ = null; + try + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + // preparo parametri + string tipoRic = reqIN ? "IN" : "OUT"; + string rm = getCurrProdData("RM", $"{DateTime.Now:yyyyMMdd-HHmmss}");// string.IsNullOrEmpty(currProdData["RM"]) ? $"{DateTime.Now:yyyyMMdd-HHmmss}" : currProdData["RM"]; + string Cod1 = getCurrProdData("Cod1", ""); //string.IsNullOrEmpty(currProdData["Cod1"]) ? "" : currProdData["Cod1"]; + string Cod2 = getCurrProdData("Cod2", ""); //string.IsNullOrEmpty(currProdData["Cod2"]) ? "" : currProdData["Cod2"]; + string Cod3 = getCurrProdData("Cod3", ""); //string.IsNullOrEmpty(currProdData["Cod3"]) ? "" : currProdData["Cod3"]; + string Cod4 = getCurrProdData("Cod4", ""); //string.IsNullOrEmpty(currProdData["Cod4"]) ? "" : currProdData["Cod4"]; + string Cod5 = getCurrProdData("Cod5", ""); //string.IsNullOrEmpty(currProdData["Cod5"]) ? "" : currProdData["Cod5"]; + string Cod6 = getCurrProdData("Cod6", ""); //string.IsNullOrEmpty(currProdData["Cod6"]) ? "" : currProdData["Cod6"]; + // faccio chiamata + answ = RestConn.memWeight(tipoRic, rm, Cod1, Cod2, Cod3, Cod4, Cod5, Cod6); + sw.Stop(); + lgInfo($"reqWeight: effettuata chiamata SOAP in {sw.Elapsed.TotalMilliseconds}ms | {dataFrom} --> {dataTo}"); + } + catch (Exception exc) + { + lgError($"reqWeight | errore richiesta pesatura{Environment.NewLine}{exc}"); + } + return answ; + } + + protected void SavePesata(ref Dictionary currDict, WeightRec newRec) + { + DictUpsert(ref currDict, "RM", newRec.RM ?? ""); + string tag = newRec.isIn ? "In" : "Out"; + DictUpsert(ref currDict, $"lastWeight{tag}", $"{newRec.weight:N2}"); + // registro record completo ultima pesata + DictUpsert(ref currDict, $"lastRec{tag}", formatPesata(newRec)); + // la aggiungo alle pesate archiviate... + AppendPesata(newRec); + } +#endif + + #region Private Properties + + + + + + /// + /// Parametri specifici Client Rest + /// + protected RestParamConf restParams { get; set; } = new RestParamConf(); + + #endregion Private Properties + + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobRest/Citizen.cs b/IOB-WIN-NEXT/IobRest/Citizen.cs new file mode 100644 index 00000000..8e102ffd --- /dev/null +++ b/IOB-WIN-NEXT/IobRest/Citizen.cs @@ -0,0 +1,231 @@ + +using IOB_UT_NEXT; +using MapoSDK; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Net.NetworkInformation; + +namespace IOB_WIN_NEXT.IobRest +{ + /// + /// Adapter specializzato per Citizen (Colcom, MT70) + /// + public class Citizen : Base + { + #region Public Constructors + + /// + /// Costruttore dell'IOB SOAP della bilancia RestCitizen + /// + /// AdapterForm chiamante + /// Configurazione IOB per avvio + public Citizen(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + { + lgInfo($"Richiesto Adapter IobRest.RestCitizen con i parametri seguenti | ADDR: {IOBConf.cncIpAddr} | PORT: {IOBConf.cncPort}"); + lastPING = DateTime.Now.AddHours(-1); + redKeyAlarm = redisMan.redHash($"IOB:Status:{cIobConf.codIOB}:Alarm:LastRead"); + lastPING = DateTime.Now.AddHours(-1); + // predispongo configurazione specifica Rest... + if (!string.IsNullOrEmpty(getOptJsonKVP("REST_CONF"))) + { + setupRestConf(getOptJsonKVP("REST_CONF")); + } + } + + + /// + /// CHiave redis di salvataggio ultimo set di allarmi scaricato + /// + private string redKeyAlarm { get; set; } = ""; + + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// + private void decodeToBaseBitmap() + { + // init a zero... + B_input = 0; + if (queueInEnabCurr) + { + /* ----------------------------------------------------- + * bitmap MAPO STD 60 + * B0: POWER_ON + * B1: RUN + * B2: pzCount + * B3: allarme + * B4: manuale + * B5: allarme TCiclo (SLOW) + * B6: WarmUp_CoolDown + * B7: EmergArmed (1 = NON emergenza, 0 = emergenza) + ----------------------------------------------------- */ + + // per prima cosa controllo ping e se sia connesso... + + + +#if false + if (connectionOk) + { + B_input = 1; + currDispData.semIn = Semaforo.SV; + + // se ho pesate in memoria nel periodo richiesto --> RUN + if (listPesateCurr != null && listPesateCurr.Count > 0) + { + B_input += (1 << 1); + } + // metto manuale + else + { + B_input += (1 << 4); + } + + // accodo NON emergenza + B_input += (1 << 7); + } + else + { + B_input = 0; + currDispData.semIn = Semaforo.SR; + } +#endif + +#if false + // Controllo booleano PING e POWERON... + string currPowerOn = getDataItemValue(mtcParams.condPowerOn.keyName); + // se valido il check ping lo eseguo... altrimenti lo do x buono + bool isPingOk = mtcParams.pingAsPowerOn && (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 = (isPingOk || checkPowerOn) ? 1 : 0; + + // variabili RUN... + string currRun = getDataItemValue(mtcParams.keyRunMode); + + // controllo RUN MODE preliminare... CABLATO - è 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 almeno 1 allarme E NON SONO IN AUTO --> ALARM! + else if (hasError) + { + B_input += (1 << 3); + } + // 2024.01.90: gestione dati UNAVAILABLE che indicano poweroff... + else if (hasUnavailableData && unavailPoweroff) + { + B_input = 0; + } + else + { + // se ho run mode != auto --> manual + B_input += (1 << 4); + } + + // emergenza armata da riportare con bit True/ 1 + if (mtcParams.emergencyArmedTrue) + { + //se NON premuta lazo il bit + if (!hasEStopTriggered) + { + B_input += (1 << 5); + } + } + // emergenza armata da riportare come False/0 (!mtcParams.emergencyArmedTrue) + else + { + // se premuta alzo il bit... + if (hasEStopTriggered) + { + B_input += (1 << 5); + } + } + + 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}"); + } +#endif + } + else + { + lgDebug($"[VETO getDataItemValue] | veto attivo alle {DateTime.Now:yyyy.MM.dd HH:mm:ss}"); + } + } + + #endregion Public Constructors + + + protected class AlarmRec + { + public int id { get; set; } = 0; + public DateTime date { get; set; } = DateTime.Now; + public string message { get; set; } = ""; + public string type { get; set; } = ""; + } + + /// + /// Elenco pesate attuali + /// + private List listAllarmiCurr { get; set; } = new List(); + + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/packages.config b/IOB-WIN-NEXT/packages.config index 9bfd01a6..c8d2b4a7 100644 --- a/IOB-WIN-NEXT/packages.config +++ b/IOB-WIN-NEXT/packages.config @@ -14,6 +14,7 @@ + @@ -33,7 +34,7 @@ - + @@ -88,9 +89,12 @@ + + + From 3cb7040609bcf2c58ed0a029404dd66055188a11 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Sat, 9 Nov 2024 11:33:15 +0100 Subject: [PATCH 2/3] typo --- IOB-WIN-NEXT/Iob/Generic.cs | 6 -- IOB-WIN-NEXT/IobRest/Base.cs | 132 +++++++++++++++++------------------ 2 files changed, 64 insertions(+), 74 deletions(-) diff --git a/IOB-WIN-NEXT/Iob/Generic.cs b/IOB-WIN-NEXT/Iob/Generic.cs index cd55776b..07cfcaba 100644 --- a/IOB-WIN-NEXT/Iob/Generic.cs +++ b/IOB-WIN-NEXT/Iob/Generic.cs @@ -7337,12 +7337,6 @@ namespace IOB_WIN_NEXT.Iob return fatto; } - /// - /// Aggiornamento virtuale della LUT da usare x decodifica stato macchina - /// - protected virtual void updateStateLUT() - { } - #endregion Protected Methods #region Private Fields diff --git a/IOB-WIN-NEXT/IobRest/Base.cs b/IOB-WIN-NEXT/IobRest/Base.cs index e4bdd989..a2db08b6 100644 --- a/IOB-WIN-NEXT/IobRest/Base.cs +++ b/IOB-WIN-NEXT/IobRest/Base.cs @@ -11,6 +11,8 @@ using System.Net.NetworkInformation; using System.IO; using System.Windows.Forms; using System.Threading; +using S7.Net.Types; +using System.Text.RegularExpressions; namespace IOB_WIN_NEXT.IobRest { @@ -439,23 +441,66 @@ namespace IOB_WIN_NEXT.IobRest } } + /// + /// Esecuzione chiamata Rest tipo GET + /// + /// + /// protected string ExecuteCallGet(string resource) { string answ = ""; - // client chiamate rest - using (var client = new RestClient(restOptStd)) + if (!string.IsNullOrEmpty(resource)) { - var currReq = new RestRequest($"/api/attivazioni/verifica/?chiave={MKeyEnc}&codImpiego={CodImp}", Method.Get); - // effettuo vera chiamata - var currResp = await client.GetAsync(currReq); - if (currResp.StatusCode == System.Net.HttpStatusCode.OK && currResp.Content != null) + // client chiamate rest + using (var client = new RestClient(restOptStd)) { - // salvo in redis contenuto serializzato - string rawData = $"{currResp.Content}"; - var currVal = JsonConvert.DeserializeObject(rawData); - if (currVal != null) + var currReq = new RestRequest(resource, Method.Get); + currReq.AddHeader("Content-type", "application/json"); + // effettuo vera chiamata + var currResp = client.Get(currReq); + if (currResp.StatusCode == System.Net.HttpStatusCode.OK && currResp.Content != null) { - answ = currVal; + answ = $"{currResp.Content}"; + } + } + } + return answ; + } + + /// + /// LookUpTable informazioni raccolte + /// + protected Dictionary dataLUT = new Dictionary(); + + /// + /// restituisce URL della risorsa eventualmente completato con token o altro + /// + /// + /// + protected string GetUrlResource(string resName) + { + string answ = ""; + if (restParams != null && restParams.CallList != null && restParams.CallList.Count > 0) + { + if (restParams.CallList.ContainsKey(resName)) + { + answ = restParams.CallList[resName].Url; + // eseguo eventuale sostituzione (se trovo "[[") + if (answ.Contains("[[")) + { + string pattern = @"\[\[.*\]\]"; + Regex regex = new Regex(pattern); + Match match = regex.Match(resName); + if (match.Success) + { + string key = match.Value.Replace("[[", "").Replace("]]", ""); + // cerco nella LUT... + if (dataLUT.ContainsKey(key)) + { + // sostituisco! + answ = answ.Replace($"[[{key}]]", dataLUT[key]); + } + } } } } @@ -488,64 +533,16 @@ namespace IOB_WIN_NEXT.IobRest parentForm.commPlcActive = true; // chiamo metodo connect - -#if false - // init del proxy!!! - string endpointAddr = $"https://{cIobConf.cncIpAddr}:{cIobConf.cncPort}/ws"; - lgInfo($"Tentativo avvio SOAP su endpoint {endpointAddr}"); - Stopwatch sw = new Stopwatch(); - sw.Start(); - - // salto verifica certificato - System.Net.ServicePointManager.ServerCertificateValidationCallback = (senderX, certificate, chain, sslPolicyErrors) => { return true; }; - - // riprovo connessione SE non fosse andata... - int maxTry = 5; - int nTry = 1; - // tento avvio WS SOAP! - RestConn = new EgwProxy.Rest.RestServ.lwpServiceClient("lwpServicePort", new System.ServiceModel.EndpointAddress(endpointAddr)); - while (RestConn == null || (nTry <= maxTry && !checkStateOk(RestConn.State))) - { - lgInfo($"Tentativo connessione Rest: | endpointAddr: {endpointAddr} | nTry: {nTry}"); - // tento avvio WS SOAP! - RestConn = new EgwProxy.Rest.RestServ.lwpServiceClient("lwpServicePort", new System.ServiceModel.EndpointAddress(endpointAddr)); - nTry++; - } - if (checkStateOk(RestConn.State)) + var checkResp = ExecuteCallGet(GetUrlResource("GetConnection")); + // forse va eliminato... + lgInfo($"GetConnection | {checkResp}"); + if (checkResp != null && checkResp.ToLower().Contains("true")) { connectionOk = true; - List weightArray = new List(); - try - { - // test lettura elenco pesate... se NON nullo --> OK! - weightArray = RestConn.reqWeightList("ALL", dataFrom, dataTo).OrderByDescending(x => x.dateIn).ToList(); - // riordino DESC - listPesateCurr = WeightRec.ConvertPesate(weightArray); - } - catch (Exception exc) - { - lgError($"Eccezione in RestConn.reqWeightList{Environment.NewLine}{exc}"); - } - sw.Stop(); - lgInfo($"SOAP: effettuata chiamata connessione + reqWeightList in {sw.Elapsed.TotalMilliseconds}ms | {dataFrom} --> {dataTo}"); - if (listPesateCurr != null && listPesateCurr.Count >= 0) - { - lgInfo($"szStatusConnection Rest, recuperato elenco di {listPesateCurr.Count} pesate"); - parentForm.commPlcActive = false; - connectionOk = true; - // sistemo data da cui iniziare recuperi successivi se ho + di numLastWeight - if (weightArray.Count > numLastWeight) - { - var lastRec = weightArray - .OrderByDescending(x => x.dateIn) - .Skip(numLastWeight).FirstOrDefault(); - // metto giorno antecedente - dtStartLive = lastRec.dateIn.Date.AddDays(-1); - } - // processo pesate! - demFactDynData = 1; - processDynData(); - } + } + else + { + lgError($"Errore check connessione | checkResp: {checkResp}"); } // refresh stato connessione!!! if (connectionOk) @@ -560,7 +557,6 @@ namespace IOB_WIN_NEXT.IobRest { lgError("Impossibile procedere, connessione mancante..."); } -#endif } catch (Exception exc) { From 6770ab73d04812fd531acdf49633fed76b3fa641 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Mon, 11 Nov 2024 19:57:49 +0100 Subject: [PATCH 3/3] Bozza adapter REST x Citizen --- IOB-WIN-NEXT/IobRest/Base.cs | 722 ++++++++++++++++---------------- IOB-WIN-NEXT/IobRest/Citizen.cs | 400 ++++++++++++++++-- 2 files changed, 715 insertions(+), 407 deletions(-) diff --git a/IOB-WIN-NEXT/IobRest/Base.cs b/IOB-WIN-NEXT/IobRest/Base.cs index a2db08b6..3ac2a2e6 100644 --- a/IOB-WIN-NEXT/IobRest/Base.cs +++ b/IOB-WIN-NEXT/IobRest/Base.cs @@ -39,41 +39,6 @@ namespace IOB_WIN_NEXT.IobRest } } - protected void setupRestConf(string restConfFile) - { - - // se ho file specifico - if (!string.IsNullOrEmpty(getOptJsonKVP("REST_CONF"))) - { - string rawData = ""; - // leggo file e decodifico... - string confPath = $"{Application.StartupPath}/DATA/CONF/{restConfFile}"; - lgInfo($"Apertura file {confPath}"); - using (StreamReader sr = new StreamReader(confPath)) - { - rawData = sr.ReadToEnd().Replace("\n", "").Replace("\r", ""); - } - // continuo decodifica - if (!string.IsNullOrEmpty(rawData)) - { - restParams = JsonConvert.DeserializeObject(rawData); - if (restParams != null) - { - // inizializzo dal file di conf le variabili necessarie... - tOutSec = restParams.timeOutSec; - apiUrl = restParams.apiUrl ?? "http://localhost:8733"; - } - } - } - - // sistemo conf standard x call REST - restOptStd = new RestClientOptions - { - Timeout = TimeSpan.FromSeconds(tOutSec), - BaseUrl = new Uri(apiUrl) - }; - } - #endregion Public Constructors #region Public Methods @@ -233,7 +198,7 @@ namespace IOB_WIN_NEXT.IobRest } /// - /// Effettua lettura semafori principale + /// Effettua lettura semafori principale /// Parametri da aggiornare x display in form /// public override void readSemafori(ref newDisplayData currDispData) @@ -251,8 +216,10 @@ namespace IOB_WIN_NEXT.IobRest } currDispData.semIn = Semaforo.SV; + // effettua refresh dati da leggere SPECIFICi x citizen... + refreshData(); // decodifica e gestione - decodeToBaseBitmap(); + decodeToBaseBitmap(ref currDispData); // display reportRawInput(ref currDispData); } @@ -267,22 +234,363 @@ namespace IOB_WIN_NEXT.IobRest lgDebug($"[VETO readSemafori] | veto attivo alle {adesso:yyyy.MM.dd HH:mm:ss}"); checkVetoQueueIn(); } - } + /// + /// 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")) + { + if (verboseLog || periodicLog) + { + lgInfo("Rest: ConnKO - tryConnect"); + } + // in primis salvo data ping... + lastPING = DateTime.Now; + // se passa il ping faccio il resto... + if (testPingMachine == IPStatus.Success) + { + string szStatusConnection = ""; + try + { + // ora provo connessione... + parentForm.commPlcActive = true; + // chiamo metodo connect + var checkResp = ExecuteCallGet(GetUrlResource("GetConnection")); + // forse va eliminato... + lgInfo($"GetConnection | {checkResp}"); + if (checkResp != null && checkResp.ToLower().Contains("true")) + { + connectionOk = true; + } + else + { + lgError($"Errore check connessione | checkResp: {checkResp}"); + } + // refresh stato connessione!!! + if (connectionOk) + { + queueInEnabCurr = true; + if (adpRunning) + { + lgInfo("Connessione OK"); + } + } + else + { + lgError("Impossibile procedere, connessione mancante..."); + } + } + catch (Exception exc) + { + lgFatal($"Errore nella connessione all'Adapter IobRest.Base: {szStatusConnection}{Environment.NewLine}{exc}"); + connectionOk = false; + lgInfo($"Eccezione in TryConnect, Adapter IobRest.Base 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: Rest controllo PING fallito per IP {cIobConf.cncPingAddr}"); + } + } + } + } + else + { + needRefresh = true; + } + } + + public override void tryDisconnect() + { + // registro solo che è disconnesso + connectionOk = false; + queueInEnabCurr = false; + } + + #endregion Public Methods + + #region Protected Fields + + /// + /// Api Url di base x chiamate REST + /// + protected string apiUrl = "http://localhost:8733"; + + /// + /// Timeout chiamate REST + /// + protected int tOutSec = 60; + + #endregion Protected Fields + + #region Protected Properties + + /// + /// Parametri specifici Client Rest + /// + protected RestParamConf restParams { get; set; } = new RestParamConf(); + + #endregion Protected Properties + + #region Protected Methods + + /// + /// verifica stato ok ovvero connected oppure open + /// + /// + /// + protected bool checkStateOk(System.ServiceModel.CommunicationState currState) + { + bool answ = false; +#if false + answ == System.ServiceModel.CommunicationState.Opened || currState == System.ServiceModel.CommunicationState.Created; +#endif + return answ; + } + + /// + /// Esecuzione chiamata Rest tipo GET + /// + /// + /// + protected string ExecuteCallGet(string resource) + { + string answ = ""; + if (!string.IsNullOrEmpty(resource)) + { + // client chiamate rest + using (var client = new RestClient(restOptStd)) + { + var currReq = new RestRequest(resource, Method.Get); + currReq.AddHeader("Content-type", "application/json"); + // effettuo vera chiamata + var currResp = client.Get(currReq); + if (currResp.StatusCode == System.Net.HttpStatusCode.OK && currResp.Content != null) + { + answ = currResp.Content ?? ""; + } + } + } + return answ; + } + + /// + /// restituisce URL della risorsa eventualmente completato con token o altro + /// + /// + /// + protected string GetUrlResource(string resName) + { + string answ = ""; + if (restParams != null && restParams.CallList != null && restParams.CallList.Count > 0) + { + if (restParams.CallList.ContainsKey(resName)) + { + answ = restParams.CallList[resName].Url; + // eseguo eventuale sostituzione (se trovo "[[") + if (answ.Contains("[[")) + { + string pattern = @"\[\[.*\]\]"; + Regex regex = new Regex(pattern); + Match match = regex.Match(resName); + if (match.Success) + { + string key = match.Value.Replace("[[", "").Replace("]]", ""); + // cerco nella LUT... + if (RestDataLUT.ContainsKey(key)) + { + // sostituisco! + answ = answ.Replace($"[[{key}]]", RestDataLUT[key]); + } + } + } + } + } + return answ; + } + /// + /// Upsert in cache LUT del parametro + /// + /// + /// + protected void RestLutUpsert(string key, string value) + { + if (RestDataLUT.ContainsKey(key)) + { + RestDataLUT[key] = value; + } + else + { + RestDataLUT.Add(key, value); + } + } + + /// + /// Recupero valore da cache LUT + /// + /// + /// + protected string RestLutGet(string key) + { + string value = ""; + if (RestDataLUT.ContainsKey(key)) + { + value = RestDataLUT[key]; + } + return value; + } + /// + /// Metodo da overridare x scrivere DAVVERO i parametri sul PLC + /// + /// + protected override void plcWriteParams(ref List updatedPar) + { + lgTrace($"plcWriteParams: richiesta per {updatedPar.Count} params"); + foreach (var item in updatedPar) + { + lgInfo($"ITEM | {item.uid} | {item.value}"); + // salvo i valori di setup x prox pesata... + upsertKey(item.uid, item.value); +#if false + bool fatto = false; + bool isPesata = false; + bool isIN = false; + gestWeightOut answ = new gestWeightOut(); + // se è richiesta pesata IN/OUT --> mando chiamata + if (item.uid == "reqPesata") + { + isPesata = true; + isIN = item.reqValue.ToUpper() == "IN"; + //isIN = item.value.ToUpper() == "IN"; + try + { + answ = reqWeight(isIN); + } + catch (Exception exc) + { + lgError($"Eccezione in plcWriteParams.reqWeight | isIn: {isIN}{Environment.NewLine}{exc}"); + } + } + else if (item.uid == "RM" || item.uid.StartsWith("Cod")) + { + // comunque segno fatto x altri casi + fatto = true; + } + + // se è pesata... + if (isPesata) + { + // se è OK + if (answ.feedback == "C") + { + lgInfo($"reqWeight | Effettuato richiesta | {answ.feedback} | {answ.notes}"); + // resetto pesata + upsertKey(item.uid, ""); + } + else + { + lgError($"reqWeight | Errore in richiesta peso Rest | {answ.feedback} | {answ.notes}"); + } + item.value = ""; + item.reqValue = ""; + item.lastRead = DateTime.Now; + item.UM = ""; + // salvo esito richiesta comunque + upsertKey("logReq", $"{answ.feedback} | {answ.notes}"); + // faccio in modo di eseguire subito getDynData + demFactDynData = 1; + processDynData(); + } + else + { + // se fatto --> aggiorno! + if (fatto) + { + //item.value = item.reqValue; + item.reqValue = ""; + item.lastRead = DateTime.Now; + item.UM = ""; + } + } +#endif + } + } + + protected void setupRestConf(string restConfFile) + { + // se ho file specifico + if (!string.IsNullOrEmpty(getOptJsonKVP("REST_CONF"))) + { + string rawData = ""; + // leggo file e decodifico... + string confPath = $"{Application.StartupPath}/DATA/CONF/{restConfFile}"; + lgInfo($"Apertura file {confPath}"); + using (StreamReader sr = new StreamReader(confPath)) + { + rawData = sr.ReadToEnd().Replace("\n", "").Replace("\r", ""); + } + // continuo decodifica + if (!string.IsNullOrEmpty(rawData)) + { + restParams = JsonConvert.DeserializeObject(rawData); + if (restParams != null) + { + // inizializzo dal file di conf le variabili necessarie... + tOutSec = restParams.timeOutSec; + apiUrl = restParams.apiUrl ?? "http://localhost:8733"; + } + } + } + + // sistemo conf standard x call REST + restOptStd = new RestClientOptions + { + Timeout = TimeSpan.FromSeconds(tOutSec), + BaseUrl = new Uri(apiUrl) + }; + } + + #endregion Protected Methods + + #region Private Fields + + /// + /// LookUpTable informazioni raccolte + /// + protected Dictionary RestDataLUT = new Dictionary(); + + /// + /// Conf client RestSharp standard: + /// - timeout 1 min + /// + private RestClientOptions restOptStd = new RestClientOptions { Timeout = TimeSpan.FromSeconds(60) }; + + #endregion Private Fields + + #region Private Methods /// /// Effettua decodifica aree memoria alla bitmap usata x MAPO /// - private void decodeToBaseBitmap() + protected virtual void decodeToBaseBitmap(ref newDisplayData currDispData) { // init a zero... B_input = 0; if (queueInEnabCurr) { /* ----------------------------------------------------- - * bitmap MAPO STD 60 + * bitmap MAPO STD 60 * B0: POWER_ON * B1: RUN * B2: pzCount @@ -295,8 +603,6 @@ namespace IOB_WIN_NEXT.IobRest // per prima cosa controllo ping e se sia connesso... - - #if false if (connectionOk) { @@ -432,7 +738,7 @@ namespace IOB_WIN_NEXT.IobRest if (verboseLog) { lgInfo($"Trasformazione B_input: {B_input} | currRun = {currRun}"); - } + } #endif } else @@ -442,333 +748,11 @@ namespace IOB_WIN_NEXT.IobRest } /// - /// Esecuzione chiamata Rest tipo GET + /// Esegue lettura dati + salvataggio in LUT /// - /// - /// - protected string ExecuteCallGet(string resource) - { - string answ = ""; - if (!string.IsNullOrEmpty(resource)) - { - // client chiamate rest - using (var client = new RestClient(restOptStd)) - { - var currReq = new RestRequest(resource, Method.Get); - currReq.AddHeader("Content-type", "application/json"); - // effettuo vera chiamata - var currResp = client.Get(currReq); - if (currResp.StatusCode == System.Net.HttpStatusCode.OK && currResp.Content != null) - { - answ = $"{currResp.Content}"; - } - } - } - return answ; - } - - /// - /// LookUpTable informazioni raccolte - /// - protected Dictionary dataLUT = new Dictionary(); - - /// - /// restituisce URL della risorsa eventualmente completato con token o altro - /// - /// - /// - protected string GetUrlResource(string resName) - { - string answ = ""; - if (restParams != null && restParams.CallList != null && restParams.CallList.Count > 0) - { - if (restParams.CallList.ContainsKey(resName)) - { - answ = restParams.CallList[resName].Url; - // eseguo eventuale sostituzione (se trovo "[[") - if (answ.Contains("[[")) - { - string pattern = @"\[\[.*\]\]"; - Regex regex = new Regex(pattern); - Match match = regex.Match(resName); - if (match.Success) - { - string key = match.Value.Replace("[[", "").Replace("]]", ""); - // cerco nella LUT... - if (dataLUT.ContainsKey(key)) - { - // sostituisco! - answ = answ.Replace($"[[{key}]]", dataLUT[key]); - } - } - } - } - } - 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")) - { - if (verboseLog || periodicLog) - { - lgInfo("Rest: ConnKO - tryConnect"); - } - // in primis salvo data ping... - lastPING = DateTime.Now; - // se passa il ping faccio il resto... - if (testPingMachine == IPStatus.Success) - { - string szStatusConnection = ""; - try - { - // ora provo connessione... - parentForm.commPlcActive = true; - - // chiamo metodo connect - var checkResp = ExecuteCallGet(GetUrlResource("GetConnection")); - // forse va eliminato... - lgInfo($"GetConnection | {checkResp}"); - if (checkResp != null && checkResp.ToLower().Contains("true")) - { - connectionOk = true; - } - else - { - lgError($"Errore check connessione | checkResp: {checkResp}"); - } - // refresh stato connessione!!! - if (connectionOk) - { - queueInEnabCurr = true; - if (adpRunning) - { - lgInfo("Connessione OK"); - } - } - else - { - lgError("Impossibile procedere, connessione mancante..."); - } - } - catch (Exception exc) - { - lgFatal($"Errore nella connessione all'Adapter IobRest.Base: {szStatusConnection}{Environment.NewLine}{exc}"); - connectionOk = false; - lgInfo($"Eccezione in TryConnect, Adapter IobRest.Base 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: Rest controllo PING fallito per IP {cIobConf.cncPingAddr}"); - } - } - } - } - else - { - needRefresh = true; - } - } - - public override void tryDisconnect() - { - // registro solo che è disconnesso - connectionOk = false; - queueInEnabCurr = false; - } - - #endregion Public Methods - - #region Protected Fields - - /// - /// Api Url di base x chiamate REST - /// - protected string apiUrl = "http://localhost:8733"; - - /// - /// Timeout chiamate REST - /// - protected int tOutSec = 60; - - #endregion Protected Fields - - #region Protected Methods - - /// - /// verifica stato ok ovvero connected oppure open - /// - /// - /// - protected bool checkStateOk(System.ServiceModel.CommunicationState currState) - { - bool answ = false; -#if false - answ == System.ServiceModel.CommunicationState.Opened || currState == System.ServiceModel.CommunicationState.Created; -#endif - return answ; - } - - /// - /// Metodo da overridare x scrivere DAVVERO i parametri sul PLC - /// - /// - protected override void plcWriteParams(ref List updatedPar) - { - lgTrace($"plcWriteParams: richiesta per {updatedPar.Count} params"); - foreach (var item in updatedPar) - { - lgInfo($"ITEM | {item.uid} | {item.value}"); - // salvo i valori di setup x prox pesata... - upsertKey(item.uid, item.value); -#if false - bool fatto = false; - bool isPesata = false; - bool isIN = false; - gestWeightOut answ = new gestWeightOut(); - // se è richiesta pesata IN/OUT --> mando chiamata - if (item.uid == "reqPesata") - { - isPesata = true; - isIN = item.reqValue.ToUpper() == "IN"; - //isIN = item.value.ToUpper() == "IN"; - try - { - answ = reqWeight(isIN); - } - catch (Exception exc) - { - lgError($"Eccezione in plcWriteParams.reqWeight | isIn: {isIN}{Environment.NewLine}{exc}"); - } - } - else if (item.uid == "RM" || item.uid.StartsWith("Cod")) - { - // comunque segno fatto x altri casi - fatto = true; - } - - // se è pesata... - if (isPesata) - { - // se è OK - if (answ.feedback == "C") - { - lgInfo($"reqWeight | Effettuato richiesta | {answ.feedback} | {answ.notes}"); - // resetto pesata - upsertKey(item.uid, ""); - } - else - { - lgError($"reqWeight | Errore in richiesta peso Rest | {answ.feedback} | {answ.notes}"); - } - item.value = ""; - item.reqValue = ""; - item.lastRead = DateTime.Now; - item.UM = ""; - // salvo esito richiesta comunque - upsertKey("logReq", $"{answ.feedback} | {answ.notes}"); - // faccio in modo di eseguire subito getDynData - demFactDynData = 1; - processDynData(); - } - else - { - // se fatto --> aggiorno! - if (fatto) - { - //item.value = item.reqValue; - item.reqValue = ""; - item.lastRead = DateTime.Now; - item.UM = ""; - } - } -#endif - } - } - - #endregion Protected Methods - - #region Private Fields - - /// - /// Conf client RestSharp standard: - /// - timeout 1 min - /// - private RestClientOptions restOptStd = new RestClientOptions { Timeout = TimeSpan.FromSeconds(60) }; - - #endregion Private Fields - -#if false - /// - /// Esegue richiesta PESO - /// - /// Tipo richiesta: IN (true) / OUT (false) - /// - protected gestWeightOut reqWeight(bool reqIN) - { - lgInfo($"reqWeight | IN: {reqIN}"); - gestWeightOut answ = null; - try - { - Stopwatch sw = new Stopwatch(); - sw.Start(); - // preparo parametri - string tipoRic = reqIN ? "IN" : "OUT"; - string rm = getCurrProdData("RM", $"{DateTime.Now:yyyyMMdd-HHmmss}");// string.IsNullOrEmpty(currProdData["RM"]) ? $"{DateTime.Now:yyyyMMdd-HHmmss}" : currProdData["RM"]; - string Cod1 = getCurrProdData("Cod1", ""); //string.IsNullOrEmpty(currProdData["Cod1"]) ? "" : currProdData["Cod1"]; - string Cod2 = getCurrProdData("Cod2", ""); //string.IsNullOrEmpty(currProdData["Cod2"]) ? "" : currProdData["Cod2"]; - string Cod3 = getCurrProdData("Cod3", ""); //string.IsNullOrEmpty(currProdData["Cod3"]) ? "" : currProdData["Cod3"]; - string Cod4 = getCurrProdData("Cod4", ""); //string.IsNullOrEmpty(currProdData["Cod4"]) ? "" : currProdData["Cod4"]; - string Cod5 = getCurrProdData("Cod5", ""); //string.IsNullOrEmpty(currProdData["Cod5"]) ? "" : currProdData["Cod5"]; - string Cod6 = getCurrProdData("Cod6", ""); //string.IsNullOrEmpty(currProdData["Cod6"]) ? "" : currProdData["Cod6"]; - // faccio chiamata - answ = RestConn.memWeight(tipoRic, rm, Cod1, Cod2, Cod3, Cod4, Cod5, Cod6); - sw.Stop(); - lgInfo($"reqWeight: effettuata chiamata SOAP in {sw.Elapsed.TotalMilliseconds}ms | {dataFrom} --> {dataTo}"); - } - catch (Exception exc) - { - lgError($"reqWeight | errore richiesta pesatura{Environment.NewLine}{exc}"); - } - return answ; - } - - protected void SavePesata(ref Dictionary currDict, WeightRec newRec) - { - DictUpsert(ref currDict, "RM", newRec.RM ?? ""); - string tag = newRec.isIn ? "In" : "Out"; - DictUpsert(ref currDict, $"lastWeight{tag}", $"{newRec.weight:N2}"); - // registro record completo ultima pesata - DictUpsert(ref currDict, $"lastRec{tag}", formatPesata(newRec)); - // la aggiungo alle pesate archiviate... - AppendPesata(newRec); - } -#endif - - #region Private Properties - - - - - - /// - /// Parametri specifici Client Rest - /// - protected RestParamConf restParams { get; set; } = new RestParamConf(); - - #endregion Private Properties + protected virtual void refreshData() + { } + #endregion Private Methods } } \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobRest/Citizen.cs b/IOB-WIN-NEXT/IobRest/Citizen.cs index 8e102ffd..4d0aa2de 100644 --- a/IOB-WIN-NEXT/IobRest/Citizen.cs +++ b/IOB-WIN-NEXT/IobRest/Citizen.cs @@ -1,13 +1,15 @@ - -using IOB_UT_NEXT; +using IOB_UT_NEXT; using MapoSDK; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.IO; using System.Linq; using System.Net.NetworkInformation; +using static IOB_WIN_NEXT.IobRest.Citizen.Responses; namespace IOB_WIN_NEXT.IobRest { @@ -34,25 +36,225 @@ namespace IOB_WIN_NEXT.IobRest { setupRestConf(getOptJsonKVP("REST_CONF")); } + // fixme todo levare forzatura test iniziale... + if (EnableTest || true) + { + // test folder salvataggio log + var appPath = System.Reflection.Assembly.GetExecutingAssembly().Location; + var fPath = Directory.GetParent(appPath).FullName; + basePath = Path.Combine(fPath, "Test"); + if (!Directory.Exists(basePath)) + { + Directory.CreateDirectory(basePath); + } + + string token = TestCitizenCall("gettoken/mecmaticames/mecmatica@mes"); + string gLamp = TestCitizenCall($"getsingleladderio/{token}/Y/8E"); + string yLamp = TestCitizenCall($"getsingleladderio/{token}/Y/21"); + string rLamp = TestCitizenCall($"getsingleladderio/{token}/Y/22"); + string qtyTot = TestCitizenCall($"gettotalquantity/{token}"); + string qtyReq = TestCitizenCall($"getneededquantity/{token}"); + string qtyWrk = TestCitizenCall($"getworkedquantity/{token}"); + string cTime = TestCitizenCall($"getcycletime/{token}"); + string pName = TestCitizenCall($"getmainprogram/{token}"); + + string cAlarm = ExecuteCallGet($"getalarm/{token}"); + var sAlarm = JsonConvert.DeserializeObject(cAlarm); + cAlarm = JsonConvert.SerializeObject(sAlarm, Formatting.Indented); + lgInfo($"Call: getalarm/{token} | resp: {cAlarm}"); + + string allAlarm = ExecuteCallGet($"getallalarmlog/{token}"); + var alarmList = JsonConvert.DeserializeObject>(allAlarm); + allAlarm = JsonConvert.SerializeObject(alarmList, Formatting.Indented); + lgInfo($"Call: getallalarmlog/{token} | resp: {allAlarm}"); + + string err = TestCitizenCall($"getsingleladderio/ABC/Y/22"); + + // salvo i valori + File.WriteAllText(Path.Combine(basePath, "token.txt"), token); + File.WriteAllText(Path.Combine(basePath, "gLamp.txt"), gLamp); + File.WriteAllText(Path.Combine(basePath, "yLamp.txt"), yLamp); + File.WriteAllText(Path.Combine(basePath, "rLamp.txt"), rLamp); + File.WriteAllText(Path.Combine(basePath, "qtyTot.txt"), qtyTot); + File.WriteAllText(Path.Combine(basePath, "qtyReq.txt"), qtyReq); + File.WriteAllText(Path.Combine(basePath, "qtyWrk.txt"), qtyWrk); + File.WriteAllText(Path.Combine(basePath, "cTime.txt"), cTime); + File.WriteAllText(Path.Combine(basePath, "pName.txt"), pName); + File.WriteAllText(Path.Combine(basePath, "cAlarm.txt"), cAlarm); + File.WriteAllText(Path.Combine(basePath, "allAlarm.txt"), allAlarm); + File.WriteAllText(Path.Combine(basePath, "err.txt"), err); + } } + #endregion Public Constructors + + #region Public Methods + + /// + /// 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")) + { + if (verboseLog || periodicLog) + { + lgInfo("Rest: ConnKO - tryConnect"); + } + // in primis salvo data ping... + lastPING = DateTime.Now; + bool checkMachine = false; + // se passa il ping faccio il resto... + if (testPingMachine == IPStatus.Success) + { + string szStatusConnection = ""; + try + { + // ora provo connessione... + parentForm.commPlcActive = true; + + // chiamo metodo connect + var checkResp = ExecuteCallGet(GetUrlResource("GetConnection")); + lgInfo($"GetConnection | {checkResp}"); + bool.TryParse(checkResp, out checkMachine); + // forse va eliminato... + if (checkMachine) + { + connectionOk = true; + queueInEnabCurr = true; + if (adpRunning) + { + lgInfo("Connessione OK"); + } + } + else + { + lgError($"Errore check connessione | checkResp: {checkResp}"); + } + } + catch (Exception exc) + { + lgFatal($"Errore nella connessione all'Adapter IobRest.Base: {szStatusConnection}{Environment.NewLine}{exc}"); + connectionOk = false; + lgInfo($"Eccezione in TryConnect, Adapter IobRest.Base 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: Rest controllo PING fallito per IP {cIobConf.cncPingAddr}"); + } + } + } + } + else + { + needRefresh = true; + } + } + + #endregion Public Methods + + #region Internal Classes + + /// + /// Struttura delle risposte alle chiamare REST specifiche + /// + internal class Responses + { + #region Internal Classes + + /// + /// Struttura info restituiti da AlarmList + /// + internal class AlarmInfo + { + #region Public Properties + + public DateTime date { get; set; } = DateTime.Today.AddYears(-10); + public string ErrorMessage { get; set; } = ""; + public int id { get; set; } = 0; + public string message { get; set; } = ""; + public string type { get; set; } = ""; + + #endregion Public Properties + } + + /// + /// Struttura info restituiti x lettura Ladder + /// + internal class LadderIO + { + #region Public Properties + + public string Address { get; set; } = ""; + public string Description { get; set; } = ""; + public string ErrorMessage { get; set; } = ""; + public string IOType { get; set; } = ""; + public string VarValue { get; set; } = ""; + + #endregion Public Properties + } + + /// + /// Struttura dato AlarmState (singolo, corrente) + /// + internal class WarnInfo + { + #region Public Properties + + public string ErrorMessage { get; set; } = ""; + public bool IsAlarm { get; set; } = false; + public bool IsCaution { get; set; } = false; + public string message { get; set; } = ""; + + #endregion Public Properties + } + + #endregion Internal Classes + } + + #endregion Internal Classes + + #region Private Fields + + private string basePath = ""; + + #endregion Private Fields + + #region Private Properties + + /// + /// Elenco pesate attuali + /// + private List listAllarmiCurr { get; set; } = new List(); /// /// CHiave redis di salvataggio ultimo set di allarmi scaricato /// private string redKeyAlarm { get; set; } = ""; + #endregion Private Properties + + #region Private Methods + /// /// Effettua decodifica aree memoria alla bitmap usata x MAPO /// - private void decodeToBaseBitmap() + protected override void decodeToBaseBitmap(ref newDisplayData currDispData) { // init a zero... B_input = 0; if (queueInEnabCurr) { /* ----------------------------------------------------- - * bitmap MAPO STD 60 + * bitmap MAPO STD 60 * B0: POWER_ON * B1: RUN * B2: pzCount @@ -65,34 +267,34 @@ namespace IOB_WIN_NEXT.IobRest // per prima cosa controllo ping e se sia connesso... - - -#if false - if (connectionOk) - { - B_input = 1; - currDispData.semIn = Semaforo.SV; - - // se ho pesate in memoria nel periodo richiesto --> RUN - if (listPesateCurr != null && listPesateCurr.Count > 0) + if (connectionOk) { - B_input += (1 << 1); + B_input = 1; + currDispData.semIn = Semaforo.SV; + + // controllo lampade... da rosso a verde... + if(RestLutGet("rLamp")=="1") + { + B_input += (1 << 3); + } + else if (RestLutGet("yLamp") == "1") + { + B_input += (1 << 4); + } + else if (RestLutGet("gLamp") == "1") + { + B_input += (1 << 1); + } + + // accodo NON emergenza ... poi da cercare meglio... + B_input += (1 << 7); } - // metto manuale else { - B_input += (1 << 4); + B_input = 0; + currDispData.semIn = Semaforo.SR; } - // accodo NON emergenza - B_input += (1 << 7); - } - else - { - B_input = 0; - currDispData.semIn = Semaforo.SR; - } -#endif #if false // Controllo booleano PING e POWERON... @@ -202,30 +404,152 @@ namespace IOB_WIN_NEXT.IobRest if (verboseLog) { lgInfo($"Trasformazione B_input: {B_input} | currRun = {currRun}"); - } + } #endif } else { - lgDebug($"[VETO getDataItemValue] | veto attivo alle {DateTime.Now:yyyy.MM.dd HH:mm:ss}"); + lgDebug($"[VETO queueInEnabCurr] | veto attivo alle {DateTime.Now:yyyy.MM.dd HH:mm:ss}"); } } - #endregion Public Constructors - - - protected class AlarmRec + /// + /// Esegue lettura dati + salvataggio in LUT + /// + protected override void refreshData() { - public int id { get; set; } = 0; - public DateTime date { get; set; } = DateTime.Now; - public string message { get; set; } = ""; - public string type { get; set; } = ""; + bool checkMachine = false; + LadderIO ladderResp = new LadderIO(); + // in primis testo che sia connessa... + var checkResp = ExecuteCallGet(GetUrlResource("GetConnection")); + lgInfo($"GetConnection | {checkResp}"); + bool.TryParse(checkResp, out checkMachine); + + // proseguo SOLO SE macchina OK, altrimenti disconnetto... + if (checkMachine) + { + // faccio refresh token comunque... + string token = ExecuteCallGet(GetUrlResource("GetToken")); + RestLutUpsert("token", token); + + // ora controllo valori lampada SE scaduti + // FixMe ToDo !!! gestione con scadenza info x evitare troppe letture... + if (true) + { + // resetto 3 valori lamp + RestLutUpsert("gLamp", "0"); + RestLutUpsert("yLamp", "0"); + RestLutUpsert("rLamp", "0"); + + int signVal = 0; + string gLamp = ExecuteCallGet(GetUrlResource("GetLampGreen")); + ladderResp = JsonConvert.DeserializeObject(gLamp); + if (string.IsNullOrEmpty(ladderResp.ErrorMessage)) + { + int.TryParse(gLamp, out signVal); + RestLutUpsert("gLamp", gLamp); + } + + // se il valore è zero --> proseguo con yellow! + if (signVal == 0) + { + string yLamp = ExecuteCallGet(GetUrlResource("GetLampYellow")); + ladderResp = JsonConvert.DeserializeObject(yLamp); + if (string.IsNullOrEmpty(ladderResp.ErrorMessage)) + { + int.TryParse(yLamp, out signVal); + RestLutUpsert("yLamp", yLamp); + } + } + + // se il valore è zero --> proseguo con red! + if (signVal == 0) + { + string rLamp = ExecuteCallGet(GetUrlResource("GetLampRed")); + ladderResp = JsonConvert.DeserializeObject(rLamp); + if (string.IsNullOrEmpty(ladderResp.ErrorMessage)) + { + int.TryParse(rLamp, out signVal); + RestLutUpsert("rLamp", rLamp); + } + } + } + } + else + { + tryDisconnect(); + } } /// - /// Elenco pesate attuali + /// Esegue gestioen contapezzi... /// - private List listAllarmiCurr { get; set; } = new List(); + public override void processContapezzi() + { + bool checkMachine = false; + LadderIO ladderResp = new LadderIO(); + // in primis testo che sia connessa... + var checkResp = ExecuteCallGet(GetUrlResource("GetConnection")); + lgInfo($"GetConnection | {checkResp}"); + bool.TryParse(checkResp, out checkMachine); + // proseguo SOLO SE macchina OK, altrimenti disconnetto... + if (checkMachine) + { + // faccio refresh token comunque... + string token = ExecuteCallGet(GetUrlResource("GetToken")); + RestLutUpsert("token", token); + + // contapezzi corrente + int intVal = 0; + string qtyWrk = ExecuteCallGet(GetUrlResource("GetQtyProd")); + int.TryParse(qtyWrk, out intVal); + contapezziPLC = intVal; + RestLutUpsert("qtyWrk", qtyWrk); + + // gestione altri contapezzi x + string qtyTot = ExecuteCallGet(GetUrlResource("GetQtyTot")); + string qtyReq = ExecuteCallGet(GetUrlResource("GetQtyReq")); + RestLutUpsert("qtyTot", qtyTot); + RestLutUpsert("qtyReq", qtyReq); + // gestione tempociclo e nome programma... + string cTime = ExecuteCallGet(GetUrlResource("GetCycleTime")); + string pName = ExecuteCallGet(GetUrlResource("GetProgName")); + RestLutUpsert("cTime", cTime); + RestLutUpsert("pName", pName); + } + } + + /// + /// Recupero dati DYN, impiegando i valori della LUT... + /// + /// + public override Dictionary getDynData() + { + return RestDataLUT; + } + + /// + /// Recupera il progName in modalità custom... + /// + /// + public override string getPrgName() + { + return RestLutGet("pName"); + } + + /// + /// Test Chiamata Citizen + /// + /// + /// + private string TestCitizenCall(string urlReq) + { + string answ = ExecuteCallGet(urlReq); + lgInfo($"Call: {urlReq} | resp: {answ}"); + return answ; + } + + #endregion Private Methods } } \ No newline at end of file