using MapoSDK; using Newtonsoft.Json; using NLog; using StackExchange.Redis; using SteamWare; using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Threading; namespace MapoDb { /// /// classe gestione operazioni su DB tramite MapoDb /// public class DataLayer { #region Public Fields /// /// Valori config da tabella corrente /// public DS_Utility.ConfigDataTable ListConfig = new DS_Utility.ConfigDataTable(); /// /// Oggetto MapoDb impiegato da DataLayer x i suoi accessi ai dati /// public MapoDb MapoDbObj = new MapoDb(); // Table adapter vari... public DS_applicazioneTableAdapters.AnagraficaGruppiTableAdapter taAG; public DS_applicazioneTableAdapters.AlarmLogTableAdapter taAlarmLog; public DS_ProdTempiTableAdapters.AnagArticoliTableAdapter taAnagArt; public DS_applicazioneTableAdapters.AnagraficaEventiTableAdapter taAnagEventi; public DS_applicazioneTableAdapters.AnagraficaStatiTableAdapter taAnagStati; public DS_applicazioneTableAdapters.AnagTagsTableAdapter taAnagTags; public DS_ArcaTableAdapters.GiacenzeTableAdapter taArcaGiac; public DS_IntServTableAdapters.ProduzioneAs400TableAdapter taAs400; public DS_ProdTempiTableAdapters.CalendFesteFerieTableAdapter taCalFF; public DS_UtilityTableAdapters.CommentiTableAdapter taComm; public DS_DossParTableAdapters.ConfFluxTableAdapter taConfFlux; public DS_UtilityTableAdapters.ConfigTableAdapter taConfig; public DS_ProdTempiTableAdapters.DatiConfermatiTableAdapter taDatiConf; public DS_ProdTempiTableAdapters.DatiMacchineTableAdapter taDatiMacchine; public DS_ProdTempiTableAdapters.DatiProduzioneTableAdapter taDatiProd; public DS_ProdTempiTableAdapters.stp_repDonati_getDatiProdMacchinaTableAdapter taDatiProdMacch; public DS_ProdTempiTableAdapters.stp_repDonati_getDatiProdMacchinaPeriodoTableAdapter taDatiProdMacchPer; public DS_ProdTempiTableAdapters.stp_repDonati_getLastStatoDurataMacchinaTableAdapter taDatiStatoMacch; public DS_applicazioneTableAdapters.DecNumArticoliTableAdapter taDecNA; public DS_applicazioneTableAdapters.DiarioDichiarazioniTableAdapter taDiarioDich; public DS_DossParTableAdapters.DossiersTableAdapter taDOSS; public DS_applicazioneTableAdapters.EventListTableAdapter taEventi; public DS_applicazioneTableAdapters.FluxLogTableAdapter taFL; public DS_IntServTableAdapters.TransitoDatiTableAdapter taIS_TrDati; public DS_IntServTableAdapters.IstanzeKITTableAdapter taIstK; public DS_applicazioneTableAdapters.KeepAliveTableAdapter taKeepAlive; public DS_UtilityTableAdapters.v_selListValTableAdapter taListVal; public DS_ProdTempiTableAdapters.Macchine2SlaveTableAdapter taM2S; public DS_applicazioneTableAdapters.MacchineTableAdapter taMacchine; public DS_PlanTableAdapters.MachineParamsTableAdapter taMacParams; public DS_MAGTableAdapters.ElencoLottiTableAdapter taMagELotti; public DS_ProdTempiTableAdapters.MappaStatoExplTableAdapter taMSE; public DS_ProdTempiTableAdapters.ODLTableAdapter taODL; public DS_applicazioneTableAdapters.AnagraficaOperatoriTableAdapter taOp; public DS_applicazioneTableAdapters.AnagraficaOperatori2insTableAdapter taOp2ins; public DS_PlanTableAdapters.CalDispTableAdapter taPlanCalDisp; public DS_PlanTableAdapters.CalStopTableAdapter taPlanCalStop; public DS_PlanTableAdapters.RichiesteTableAdapter taPlanRichieste; public DS_ProdTempiTableAdapters.PromesseODLTableAdapter taPODL; public DS_ProdTempiTableAdapters.PostazioniMapoTableAdapter taPostazioni; public DS_PlanTableAdapters.PromesseINTableAdapter taPromIn; public DS_PlanTableAdapters.PromesseOUTTableAdapter taPromOut; public DS_ProdTempiTableAdapters.stp_PzProd_getByMacchinaTableAdapter taPzProd2conf; public DS_ProdTempiTableAdapters.RegistroControlliTableAdapter taRC; public DS_applicazioneTableAdapters.RemoteRebootLogTableAdapter taRemReb; public DS_ProdTempiTableAdapters.RegistroScartiTableAdapter taRS; public DS_UtilityTableAdapters.v_selArticoliTableAdapter taSelArt; public DS_UtilityTableAdapters.v_selMacchineTableAdapter taSelMacc; public DS_UtilityTableAdapters.v_selODLTableAdapter taSelOdlFree; public DS_applicazioneTableAdapters.SignalLogTableAdapter taSigLog; public DS_SheetTechTableAdapters.ST_ActualTableAdapter taSTA; public DS_SheetTechTableAdapters.ST_ActualRowTableAdapter taSTAR; public DS_applicazioneTableAdapters.DiarioDiBordoTableAdapter taStati; public DS_applicazioneTableAdapters.StatoMacchineTableAdapter taStatoMacchine; public DS_ProdTempiTableAdapters.StatoProdTableAdapter taStatoProd; public DS_SheetTechTableAdapters.ST_CheckTableAdapter taSTChk; public DS_ProdTempiTableAdapters.TempiCicloRilevatiTableAdapter taTempiCicloRilevati; public DS_ProdTempiTableAdapters.stp_TempoByIdxMaccPeriodClassTableAdapter taTempoByClass; public DS_IntServTableAdapters.TKS_SearchTableAdapter taTKS; public DS_applicazioneTableAdapters.TransizioneIngressiTableAdapter taTranIngr; public DS_ProdTempiTableAdapters.TurniMacchinaTableAdapter taTurniMacc; public DS_IntServTableAdapters.WipSetupKitTableAdapter taWKS; #endregion Public Fields #region Public Constructors /// /// Init classe /// public DataLayer() { initTA(); setupConnectionStringBase(); // aggiunta x gestione timeout esteso (ove necessario)! fixCommandTimeout(); // init oggetto MapoDb MapoDbObj = new MapoDb(); // init config.. ListConfig = taConfig.GetData(); // altri init setupConf(); } /// /// Init class /// /// Abilitazione ch messaggi broadcast redis public DataLayer(bool enableRedisMsg) { initTA(); setupConnectionStringBase(); // aggiunta x gestione timeout esteso (ove necessario)! fixCommandTimeout(); // init oggetto MapoDb MapoDbObj = new MapoDb(); if (enableRedisMsg) { // init message channel... BroadastMsgPipe = new MessagePipe(connRedis, Constants.BROADCAST_M_PIPE); } } #endregion Public Constructors #region Public Properties /// /// Hash dati MSE /// /// public static string hMSE { get => mHash("hMSE_DATA"); } public static string redKeyArtUsed { get => mHash($"CACHE:CheckArtUsed"); } public static string redKeyRawTransfData { get => mHash($"RAW:TRANSFER"); } public static string redKeyTabCheckArt { get => mHash($"CACHE:TabCheckArt"); } public MessagePipe BroadastMsgPipe { get; set; } = null; /// /// Cognome Nome da MatrOpr in sessione /// public string CognomeNomeOpr { get { // cerco operatore... string answ = ""; try { DS_applicazione.AnagraficaOperatoriRow oper = taOp.getByMatrOpr(MatrOpr)[0]; answ = string.Format("{0} {1}", oper.Cognome, oper.Nome); } catch { } return answ; } } /// /// Oggetto statico connessione redis /// public ConnectionMultiplexer connRedis { get { return lazyConnection.Value; } } /// /// Dati MSE serializzati in REDIS (get/set) /// public string currMSE { get { string answ = ""; Log.Info("Richiesta MSE da REDIS"); answ = cMemLayer.getRSV(hMSE); return answ; } set { int MSE_cacheDuration = cMemLayer.CRI("MSE_cacheDuration"); cMemLayer.setRSV(hMSE, value, MSE_cacheDuration); } } /// /// Dati RawTransfer serializzati in REDIS (get/set) /// public string lastRawTrasfData { get { string answ = ""; Log.Info("Richiesta rawTransfData da REDIS"); answ = cMemLayer.getRSV(redKeyRawTransfData); return answ; } set { cMemLayer.setRSV(redKeyRawTransfData, value); } } /// /// MatrOpr in sessione /// public int MatrOpr { get { int idx = 0; try { idx = cMemLayer.IntSessionObj("MatrOpr"); } catch { } return idx; } set { cMemLayer.setSessionVal("MatrOpr", value); } } #endregion Public Properties #region Public Methods /// /// Hash dati ConfFlux x la macchina specificata /// /// /// public static string confFluxMaccHash(string idxMacchina) { return mHash($"MachineConfFlux:{idxMacchina}"); } /// /// Hash dati di configurazione IOB in formato YAML x la macchina specificata /// /// /// public static string ConfYamlHash(string idxMacchina) { return mHash($"IOB:{idxMacchina}:ConfYaml"); } /// /// Hash dati tabella AnagStati macchina /// /// public static string currAnagStatiMacc() { return mHash(string.Format("Anag:StatiMacc")); } /// /// Hash dati Current ODL x la macchina specificata /// /// /// public static string currODLHash(string idxMacchina) { return mHash(string.Format("CurrODL:{0}", idxMacchina)); } /// /// Hash dati Current ODL ROW x la macchina specificata /// /// /// public static string currOdlRowHash(string idxMacchina) { return mHash($"CurrOdlRow:{idxMacchina}"); } /// /// Hash dati CurrentParameters x la macchina specificata /// /// /// public static string currParametersHash(string idxMacchina) { return mHash(string.Format("CurrentParameters:{0}", idxMacchina)); } /// /// Hash dati Current StatoMacchina x la macchina specificata /// /// /// public static string currStatoMaccHash(string idxMacchina) { return mHash($"CurrStatoMacc:{idxMacchina}"); } public static List DataTableToList(DataTable dt) where T : class, new() { List lstItems = new List(); if (dt != null && dt.Rows.Count > 0) foreach (DataRow row in dt.Rows) lstItems.Add(ConvertDataRowToGenericType(row)); else lstItems = null; return lstItems; } /// /// Hash dati Dossier (last) x la macchina specificata /// /// /// public static string dossLastMaccHash(string idxMacchina) { return mHash($"MachineDossierLast:{idxMacchina}"); } /// /// Hash dati STATUS x la macchina specificata /// /// /// public static string dtMaccHash(string idxMacchina) { return mHash(string.Format("DtMac:{0}", idxMacchina)); } /// /// Hash dati EXE TASK x la macchina specificata /// /// /// public static string exeTaskHash(string idxMacchina) { return mHash(string.Format("ExeTask:{0}", idxMacchina)); } /// /// Hash dati FluxLog (iniziale) x la macchina specificata /// /// /// public static string fluxLogFirstMaccHash(string idxMacchina) { return mHash($"MachineFluxLogFirst:{idxMacchina}"); } /// /// Hash dati PODL ROW x la macchina specificata /// /// /// public static string getPOdlRowHash(int idxPODL) { return mHash($"PODLRow:{idxPODL}"); } /// Hash dati relativi all'associazione macchina <--> IOB Macchina public static string hIobDict(string IdxMacchina) { return mHash($"IOB:{IdxMacchina}:CurrInfo"); } /// Hash dati relativi all'associazione macchina <--> IOB Macchina PRINCIPALE public static string hM2IOB(string IdxMacchina) { return mHash(string.Format("hM2IOB:{0}", IdxMacchina)); } /// /// Hash dati relativi a macchina + IOB + conf speciali /// /// Macchina /// public static string hMachineIobConf(string IdxMacchina) { return mHash($"IOB:{IdxMacchina}:MachIobConf"); } /// /// Hash dati Macchine Multi SM Ingressi /// /// Macchina PRINCIPALE /// public static string hMSMI(string IdxMacchina) { return mHash(string.Format("hMSMI:{0}", IdxMacchina)); } /// /// Hash dati STATE MACHINE INGRESSI x la FAMIGLIA INGRESSI specificata (per completare poi /// manca singolo micro stato corrente + valore letto x definire chiave) /// /// /// public static string hSMI(int idxFamIn) { return mHash(string.Format("hSMI:{0}", idxFamIn)); } /// /// Hash dati BUFFER x la macchina specificata /// /// /// /// public static string LiveBufferHash(string idxMacchina, string bufferName) { return mHash($"LIVE:{idxMacchina}:{bufferName}"); } /// /// Hash dati LIVE x la macchina specificata /// /// /// public static string LiveCurrValHash(string idxMacchina) { return mHash($"LIVE:{idxMacchina}:CURR_VAL"); } /// /// KEY x i dati del FLog della machina specificata /// /// /// /// public static string LiveFLogKeyHash(string idxMacchina, string flog) { return mHash($"FLOG:{idxMacchina}:{flog}"); } /// /// Hash dati MemoryMap x la macchina specificata /// /// /// public static string memMapHash(string idxMacchina) { return mHash($"MemMap:{idxMacchina}"); } /// /// Hash Redis contenente i dati MP di una specifico TYPE (es StatusMacchina, /// StateMachineIngressi, ...) /// /// /// public static string mHash(string dataType) { return cMemLayer.redHash(dataType); } /// /// Hash dati OPT PARAMETERS x la macchina specificata /// /// /// public static string optParHash(string idxMacchina) { return mHash(string.Format("OptPar:{0}", idxMacchina)); } /// /// Hash dati COUNTER x la macchina specificata /// /// /// public static string pzCountHash(string idxMacchina) { return mHash(string.Format("PzCount:{0}", idxMacchina)); } /// /// Hash dati SAVED (EXE) TASK x la macchina specificata x poter ripristinare in caso di /// perdita valore WRITE /// /// /// public static string savedTaskHash(string idxMacchina) { return mHash(string.Format("SavedTask:{0}", idxMacchina)); } /// /// Hash dati STATUS x la macchina specificata. /// - dati ODL /// - dati articolo /// - dati produzione corrente /// /// /// public static string stMaccHash(string idxMacchina) { return mHash(string.Format("StMac:{0}", idxMacchina)); } /// /// Hash x VETO force Start PODL la macchina specificata /// /// /// public static string vetoForceStartPOdlMaccHash(string idxMacchina) { return mHash($"VetoStartPOdlMacc:{idxMacchina}"); } /// /// Hash x VETO dello SPLIT ODL la macchina specificata /// /// /// public static string vetoSplitOdlMaccHash(string idxMacchina) { return mHash($"VetoOdlMacc:{idxMacchina}"); } /// /// Salva richiesta azione /// /// /// public bool ActionSetReq(DisplayAction act2save) { bool fatto = false; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); // cerco in redis... string rawData = JsonConvert.SerializeObject(act2save); // invio broadcast + salvo in redis BroadastMsgPipe.saveAndSendMessage(Constants.redisActionReq, rawData); fatto = true; //await redisDb.StringSetAsync(redisActionReq, rawData); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Info($"ActionSetReq REDIS send to broadcast + Write cache: {ts.TotalMilliseconds}ms"); return fatto; } /// /// verifica se sia da reinviare un task alla macchina dall'elenco di quelli salvati (in /// modalità upsert) se non scaduti /// /// /// /// /// public bool addCheckTask4Machine(string idxMacchina, taskType taskKey, string taskVal) { bool answ = false; string currHash = exeTaskHash(idxMacchina); Log.Info($"addCheckTask4Machine idxMacchina: {idxMacchina} | taskKey: {taskKey} | taskVal: {taskVal}"); try { Dictionary savedTask = mSavedTaskMacchina(idxMacchina); // cerco valore saved string savedVal = savedTask[taskKey.ToString()]; // se ho un valore != "" --> rimetto in coda di invio... if (!string.IsNullOrEmpty(savedVal) && (savedVal != taskVal)) { // leggo task attuali... Dictionary currTask = mTaskMacchina(idxMacchina); // rimetto in task da eseguire... currTask[taskKey.ToString()] = savedVal; answ = cMemLayer.redSaveHashDict(currHash, currTask); Log.Info($"re-issued task4machine: idxMacchina: {idxMacchina} | taskKey: {taskKey} | savedVal: {savedVal}"); } } catch { } return answ; } /// /// Aggiunge un PARAMETRO OPZIONALE all'elenco di quelli salvati (in modalità upsert) /// /// /// /// /// public bool addOptPar4Machine(string idxMacchina, string taskKey, string taskVal) { bool answ = false; string currHash = optParHash(idxMacchina); try { // leggo task attuali... var currVal = mOptParMacchina(idxMacchina); currVal[taskKey] = taskVal; answ = cMemLayer.redSaveHashDict(currHash, currVal); } catch { } return answ; } /// /// Aggiunge un task all'elenco di quelli salvati (in modalità upsert) /// /// /// /// /// public bool addTask4Machine(string idxMacchina, taskType taskKey, string taskVal) { bool answ = false; string currHash = exeTaskHash(idxMacchina); string currSavedParHash = savedTaskHash(idxMacchina); Dictionary currTask = new Dictionary(); Dictionary savedTask = new Dictionary(); try { //Log.Info($"Request: idxMacchina: {idxMacchina} | taskKey: {taskKey} | taskVal: {taskVal}"); // leggo task attuali... currTask = mTaskMacchina(idxMacchina); if (currTask.ContainsKey($"{taskKey}")) { currTask[$"{taskKey}"] = taskVal; } else { currTask.Add($"{taskKey}", taskVal); } answ = cMemLayer.redSaveHashDict(currHash, currTask); Log.Info($"Task ADD - idxMacchina: {idxMacchina} | taskKey: {taskKey} | taskVal: {taskVal}"); } catch { } // verifico in base al tipo di task se fare backup... switch (taskKey) { case taskType.setArt: case taskType.setComm: case taskType.setPzComm: case taskType.setProg: // leggo task SALVATI attuali... savedTask = mSavedTaskMacchina(idxMacchina); savedTask[taskKey.ToString()] = taskVal; answ = cMemLayer.redSaveHashDict(currSavedParHash, savedTask); break; case taskType.endProd: // salvo un DICT vuoto x resettare savedTask = new Dictionary(); answ = cMemLayer.redSaveHashDict(currSavedParHash, savedTask); break; default: break; } return answ; } /// /// Elenco stati macchina /// /// public DS_applicazione.AnagraficaStatiDataTable AnagraficaStati() { DS_applicazione.AnagraficaStatiDataTable answTab = null; // cerco in cache... string rCall = ""; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("hasAnagStati"); try { rCall = cMemLayer.getRSV(currAnagStatiMacc()); if (!string.IsNullOrEmpty(rCall)) { answTab = JsonConvert.DeserializeObject(rCall); } else { //2020.01.31 nuovo obj x evitare concorrenza MapoDb man = new MapoDb(); answTab = man.taAnagSt.GetData(); //resultList = MapoDbObj.taAnagSt.GetData(); // salvo in redis... rCall = JsonConvert.SerializeObject(answTab); int anagrCacheDur = cMemLayer.CRI("anagrCacheDur"); cMemLayer.setRSV(currAnagStatiMacc(), rCall, anagrCacheDur); } } catch (Exception exc) { Log.Info($"Eccezione in recupero currODLRow{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } else { answTab = MapoDbObj.taAnagSt.GetData(); } return answTab; } /// /// Effettua split ODL /// /// macchina /// effettuare conferma qty /// imposta la qty prox ODL da ODL che si chiude /// matricola operatore /// /// STEP x cui arrotondare la quantità prox ODL (corrente come riferimento) /// /// Cod ext da associare all'ODL /// public string AutoStartOdl(string idxMacchina, bool doConfirm, bool qtyFromLast, int matrOpr, int roundStep = 100, string keyRichiesta = "") { string answ = "KO"; DateTime adesso = DateTime.Now; // verifico NON CI SIA un veto a NUOVI split... 2 min di default... string redKey = vetoSplitOdlMaccHash(idxMacchina); string rawData = cMemLayer.getRSV(redKey); if (string.IsNullOrEmpty(rawData)) { // registro VETO x altri split... 5 minuti cMemLayer.setRSV(redKey, $"Inizio SPLIT-ODL {adesso}", 300); // calcolo la qta da gestire int qtyConf = 0; int qtyNew = 0; int qtyScarto = 0; if (doConfirm) { DS_ProdTempi.stp_PzProd_getByMacchinaRow rigaProd; DS_ProdTempi.StatoProdRow statoProd; try { rigaProd = taPzProd2conf.GetData(idxMacchina)[0]; statoProd = taStatoProd.GetData(idxMacchina, adesso)[0]; qtyConf = rigaProd.pezziNonConfermati; qtyScarto = statoProd.Pz2RecScarto; // calcolo nuovi pezzi da confermare if (qtyFromLast) { roundStep = roundStep == 0 ? 1 : roundStep; double ratio = (double)qtyConf / roundStep; qtyNew = (int)Math.Round(Math.Ceiling(ratio) * roundStep, 0); } } catch (Exception exc) { Log.Info(string.Format("Errore recupero pezzi da confermare per la macchina {0}{1}{2}", idxMacchina, Environment.NewLine, exc), tipoLog.ERROR); } } // proseguo DS_ProdTempi.ODLDataTable currData = null; // chiamo metodo redis/db... try { // recupero ODL corrente currData = currODLRowTab(idxMacchina); if (currData.Count > 0) { // preparo var x master/slave bool isMachMaster = this.isMaster(idxMacchina); DS_ProdTempi.Macchine2SlaveDataTable slaveList = isMachMaster ? taM2S.getByMaster(idxMacchina) : new DS_ProdTempi.Macchine2SlaveDataTable(); // registro un evento di inizio attrezzaggio (idxTipoEv = 2) int idxEvento = 2; Log.Info($"Invio evento ODL-SPLIT per macchina {idxMacchina} | ev: {idxEvento} | art: {currData[0].CodArticolo} | qty conf: {qtyConf} | sty sca: {qtyScarto} | new qty: {qtyNew}", tipoLog.INFO); inputComandoMapo resCmd = scriviRigaEventoBarcode(idxMacchina, idxEvento, currData[0].CodArticolo, "ODL-SPLIT", 0, "", adesso, adesso); if (doConfirm) { // attendo 100 msec Thread.Sleep(100); adesso = DateTime.Now; // chiamo conferma produzione... try { string chiamata = confRett ? "confermaProdMacchinaFull" : "confermaProdMacchina"; Log.Info($"Chiamata a {chiamata} con parametri {currData[0].IdxMacchina} |{MatrOpr} | {DateTime.Now.AddDays(-10)} | {DateTime.Now} | {qtyConf} | 0 | {qtyScarto} | {DateTime.Now} | false", tipoLog.INFO); string idxMacchinaSel = currData[0].IdxMacchina; bool fatto = false; if (confRett) { // confermo al netto dei pezzi lasciati... fatto = confermaProdMacchinaFull(idxMacchinaSel, cMemLayer.CRI("modoConfProd"), qtyConf, 0, qtyScarto, adesso, matrOpr); if (cMemLayer.CRB("SlaveConfirmPzProd")) { foreach (var machine in slaveList) { confermaProdMacchinaFull(machine.IdxMacchinaSlave, cMemLayer.CRI("modoConfProd"), qtyConf, 0, qtyScarto, adesso, matrOpr); } } } else { fatto = confermaProdMacchina(idxMacchinaSel, cMemLayer.CRI("modoConfProd"), qtyConf, qtyScarto, adesso, matrOpr); if (cMemLayer.CRB("SlaveConfirmPzProd")) { foreach (var machine in slaveList) { confermaProdMacchina(idxMacchinaSel, cMemLayer.CRI("modoConfProd"), qtyConf, qtyScarto, adesso, matrOpr); } } } if (!fatto) { Log.Info($"ERRORE in chiamata {chiamata}", tipoLog.ERROR); } } catch (Exception exc) { Log.Info($"Eccezione in ConfermaProduzione{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } // 2025.02.19 portato da 100 a 1000 ms attesa x evitare che ODL sia avviato PRIMA della conferma // attendo 1000 msec x chiudere ODL Thread.Sleep(1000); // chiamo splitOdl MapoDbObj.taODL.autoStart(currData[0].IdxODL, 0, idxMacchina, currData[0].TCRichAttr, currData[0].PzPallet, $"Nuovo ODL da forceSplitOdl.autoStart", true, qtyNew, keyRichiesta); // elimino eventuale ODL precedente... string rKey = cMemLayer.redHash($"ODL:{idxMacchina}"); cMemLayer.setRSV(rKey, ""); // ricalcola ODL macchina var newOdl = currODL(idxMacchina, true); // attendo 1000 msec Thread.Sleep(1000); adesso = DateTime.Now; // registro fine ODL (idxTipoEv = 1) idxEvento = 1; Log.Info($"Invio evento FINE ODL-SPLIT per macchina {idxMacchina}, evento {idxEvento}, articolo {currData[0].CodArticolo}", tipoLog.INFO); resCmd = scriviRigaEventoBarcode(idxMacchina, idxEvento, currData[0].CodArticolo, "ODL-START"); // invio eventi setup a macchina.... string setArtVal = $"{currData[0].CodArticolo}"; string setPzCommVal = $"{qtyNew}"; string setCommVal = $"ODL{newOdl}"; if (!string.IsNullOrEmpty(keyRichiesta)) { setCommVal = $"{keyRichiesta} ODL{newOdl}"; } try { // invio task caricamento dati ODL addTask4Machine(idxMacchina, taskType.setArt, setArtVal); addTask4Machine(idxMacchina, taskType.setComm, setCommVal); addTask4Machine(idxMacchina, taskType.setPzComm, setPzCommVal); updateMachineParameter(idxMacchina, "setArt", setArtVal); updateMachineParameter(idxMacchina, "setComm", setCommVal); updateMachineParameter(idxMacchina, "setPzComm", setPzCommVal); } catch { } // chiamo refresh MSE taMSE.forceRecalc(0, idxMacchina); // resetto stato macchina... cMemLayer.redDelKey(currStatoMaccHash(idxMacchina)); answ = "OK"; Log.Info($"Effettuato reset e ricalcoli x split ODL per macchina {idxMacchina}", tipoLog.INFO); // se è una master richiamo fix x child... if (isMachMaster) { string ts = ""; string outData = ""; taODL.fixMachineSlave(idxMacchina, 30, 1); foreach (var machine in slaveList) { // invio chiusura attrezzaggio ts = string.Format("{0:yyMMdd}T{0:HHmmss.fff}Z", DateTime.Now); outData = $"TS:{ts}|MATR:{MatrOpr}|ODL:{newOdl}"; addTask4Machine(machine.IdxMacchinaSlave, taskType.fixStopSetup, outData); addTask4Machine(machine.IdxMacchinaSlave, taskType.forceResetPzCount, outData); // invio task caricamento dati ODL addTask4Machine(machine.IdxMacchinaSlave, taskType.setArt, setArtVal); addTask4Machine(machine.IdxMacchinaSlave, taskType.setComm, setCommVal); addTask4Machine(machine.IdxMacchinaSlave, taskType.setPzComm, setPzCommVal); updateMachineParameter(machine.IdxMacchinaSlave, "setArt", setArtVal); updateMachineParameter(machine.IdxMacchinaSlave, "setComm", setCommVal); updateMachineParameter(machine.IdxMacchinaSlave, "setPzComm", setPzCommVal); } } } } catch (Exception exc) { Log.Info($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } else { Log.Info($"VETO ATTIVO | Richiesto forceSplitOdl per impianto {idxMacchina} | impossibile procedere"); } return answ; } /// /// controlla se da il segnale di "microstato" deriva un evento da generare - modalità OFFLINE /// /// idx macchina /// valore ingresso /// data-ora evento (server) /// sequenza dati inviati /// public inputComandoMapo checkMicroStato(string idxMacchina, string valore, DateTime dtEve, string contatore) { int _logLevel = cMemLayer.CRI("_logLevel"); // recupero SE IMPIEGATO REDIS i valori del Dictionary della macchina... Dictionary datiMacc = mDatiMacchine(idxMacchina); if (_logLevel > 6) { Log.Info(string.Format("[ChkMiSt]{2}---------------------------{2}Richiesta verifica INPUT per Macchina {0}, seriale {1}", idxMacchina, valore, Environment.NewLine), tipoLog.INFO); } // formatto output inputComandoMapo answ = new inputComandoMapo(); DS_applicazione.TransizioneIngressiDataTable TabTransIn; DS_applicazione.TransizioneIngressiRow rigaTransIn = null; // verifico se esista la macchina altrimenti la creo... REDIS compliant verificaIdxMacchina(idxMacchina); string CodArticolo = ""; if (cMemLayer.CRB("IOB_RedEnab")) { try { // esecuzione in REDIS CodArticolo = datiMacc["CodArticolo"]; } catch { } } // ...oppure dritto su DB else { // esecuzione in DB... recupero CodArticolo corretto try { // 2017.07.11 se richiesto di NON usare singleton... riporto FUORI la gestione // NUOVO oggetto if (cMemLayer.CRB("disable_singleton")) { // 2017.07.10 forzo init x errori "sovrapposizioni" taDatiMacchine = new DS_ProdTempiTableAdapters.DatiMacchineTableAdapter(); } CodArticolo = taDatiMacchine.getByIdx(idxMacchina)[0].CodArticolo_A; } catch (Exception exc) { Log.Info(string.Format("[ChkMiSt_4a] - Eccezione in recupero CodArticolo:{0}{1}", Environment.NewLine, exc), tipoLog.EXCEPTION); } } // recupero next microstato int? valINT = 0; try { valINT = int.Parse(valore, System.Globalization.NumberStyles.HexNumber); // esecuzione in REDIS... if (cMemLayer.CRB("IOB_RedEnab")) { try { int idxFamIn = Convert.ToInt32(datiMacc["IdxFamIn"]); int idxMicroStato = Convert.ToInt32(datiMacc["IdxMicroStato"]); int valIOB = Convert.ToInt32(valINT); int idxTipoEv = 0; int next_idxMS = idxMicroStato; // verifico esistenza tab SMI... string fiHASH = DataLayer.hSMI(idxFamIn); string todoSMI = ""; bool trovato = cMemLayer.redHashPresentSz(fiHASH); if (!trovato) { // ricarico tabella! KeyValuePair[] valori = mTabSMI(idxFamIn); } // recupero singolo valore (stringa) x chiave todoSMI = valoreSMI(idxFamIn, idxMicroStato, valIOB); // solo se ho trovato un risultato nella tab SMI della famiglia macchina... if (todoSMI != "") { // splitto e salvo valori OUT... string[] valori = todoSMI.Split('_'); idxTipoEv = Convert.ToInt32(valori[0]); next_idxMS = Convert.ToInt32(valori[1]); // creo la riga tipizzata dai dati di redis x procedere... DS_applicazione.TransizioneIngressiDataTable tab = new DS_applicazione.TransizioneIngressiDataTable(); rigaTransIn = tab.NewTransizioneIngressiRow(); rigaTransIn.IdxFamigliaIngresso = idxFamIn; rigaTransIn.IdxMicroStato = idxMicroStato; rigaTransIn.ValoreIngresso = valIOB; rigaTransIn.IdxTipoEvento = idxTipoEv; rigaTransIn.next_IdxMicroStato = next_idxMS; } } catch { } } // ...oppure dritto su DB else { // 2017.07.11 se richiesto di NON usare singleton... riporto FUORI la gestione // NUOVO oggetto if (cMemLayer.CRB("disable_singleton")) { // 2017.06.09 forzo init x errori "sovrapposizioni" MapoDbObj.taTransIngr = new DS_applicazioneTableAdapters.TransizioneIngressiTableAdapter(); } TabTransIn = MapoDbObj.taTransIngr.getByIdxMacchinaValore(idxMacchina, valINT); if (TabTransIn.Rows.Count > 0) { rigaTransIn = TabTransIn[0]; } } } catch (Exception exc) { Log.Info(string.Format("[ChkMiSt_5a] - - Eccezione in recupero riga Trans ingressi per idxMacchina {3} e valore {2}:{0}{1}", Environment.NewLine, exc, valINT, idxMacchina), tipoLog.EXCEPTION); } // effettuo update vari SU DB!!! if (rigaTransIn != null) { try { if (_logLevel > 5) { Log.Info(string.Format("[ChkMiSt_6a] - Salvo Update Microstato:{0}macchina: {1} | valore seriale: {2} | next micro stato: {3}", Environment.NewLine, idxMacchina, valINT, rigaTransIn.next_IdxMicroStato), tipoLog.INFO); } // 2017.07.11 se richiesto di NON usare singleton... riporto FUORI la gestione // NUOVO oggetto if (cMemLayer.CRB("disable_singleton")) { // 2017.06.09 forzo init x errori "sovrapposizioni" MapoDbObj.taMSM = new DS_applicazioneTableAdapters.MicroStatoMacchinaTableAdapter(); } // salvo nuovo microstato... MapoDbObj.taMSM.updateQuery(rigaTransIn.next_IdxMicroStato, dtEve, valore, idxMacchina); // controllo se c'è evento if (rigaTransIn.IdxTipoEvento > 0) { if (_logLevel > 5) { Log.Info(string.Format("[ChkMiSt_7a] - Salvo evento:{0}macchina: {1} | tipoEvento: {2} | CodArticolo: {3} | contatore: {4} | valore: {5}", Environment.NewLine, idxMacchina, rigaTransIn.IdxTipoEvento, CodArticolo, contatore, valore), tipoLog.INFO); } string valEsteso = string.Format("[{0}] {1}", contatore.PadLeft(3, '0'), valore); // aggiunto contatore! answ = scriviRigaEvento(idxMacchina, rigaTransIn.IdxTipoEvento, CodArticolo, valEsteso, 0, "-", dtEve, DateTime.Now); // 2017.09.12 SE era in modalità redis RICARICA dati macchina... if (cMemLayer.CRB("IOB_RedEnab")) { resetDatiMacchina(idxMacchina); } if (_logLevel > 5) { Log.Info(string.Format("[ChkMiSt_a] - Macchina {0} | seriale(INT) {1} | valEsteso {3} | answ {4}{2}---------------------------{2}", idxMacchina, valINT, Environment.NewLine, valEsteso, answ), tipoLog.INFO); } } } catch (Exception exc) { Log.Info(string.Format("[ChkMiSt_8a] - Eccezione:{0}{1}", Environment.NewLine, exc), tipoLog.EXCEPTION); } } return answ; } /// /// controlla se da il segnale di "microstato" deriva un evento da generare - modalità OFFLINE /// /// idx macchina /// valore ingresso /// data-ora evento (server) /// public inputComandoMapo checkMicroStato(string idxMacchina, string valore, DateTime dtEve) { if (cMemLayer.CRI("_logLevel") > 6) { Log.Info(string.Format("{2}---------------------------{2}Richiesta verifica INPUT per Macchina {0}, seriale {1}", idxMacchina, valore, Environment.NewLine), tipoLog.INFO); } // formatto output inputComandoMapo answ = new inputComandoMapo(); DS_applicazione.TransizioneIngressiDataTable TabTransIn; DS_applicazione.TransizioneIngressiRow rigaTransIn = null; // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(idxMacchina); string CodArticolo = ""; // recupero CodArticolo corretto try { // 2017.07.10 forzo init x errori "sovrapposizioni" taDatiMacchine = new DS_ProdTempiTableAdapters.DatiMacchineTableAdapter(); CodArticolo = taDatiMacchine.getByIdx(idxMacchina)[0].CodArticolo_A; } catch (Exception exc) { Log.Info(string.Format("[ChkMiSt_4b] - Eccezione in recupero CodArticolo:{0}{1}", Environment.NewLine, exc), tipoLog.EXCEPTION); } // recupero next microstato //int? valINT = Convert.ToInt32(valore); int? valINT = 0; try { // 2017.06.09 forzo init x errori "sovrapposizioni" MapoDbObj.taTransIngr = new DS_applicazioneTableAdapters.TransizioneIngressiTableAdapter(); valINT = int.Parse(valore, System.Globalization.NumberStyles.HexNumber); TabTransIn = MapoDbObj.taTransIngr.getByIdxMacchinaValore(idxMacchina, valINT); if (TabTransIn.Rows.Count > 0) { rigaTransIn = TabTransIn[0]; } } catch (Exception exc) { Log.Info(string.Format("[ChkMiSt_5b] - Eccezione in recupero riga Trans ingressi per idxMacchina {3} e valore {2}:{0}{1}", Environment.NewLine, exc, valINT, idxMacchina), tipoLog.EXCEPTION); } int _logLevel = cMemLayer.CRI("_logLevel"); // effettuo update vari if (rigaTransIn != null) { try { if (_logLevel > 5) { Log.Info(string.Format("[ChkMiSt_6b] - Salvo Update Microstato:{0}macchina: {1} | valore seriale: {2} | next micro stato: {3}", Environment.NewLine, idxMacchina, valINT, rigaTransIn.next_IdxMicroStato), tipoLog.INFO); } // salvo nuovo microstato... MapoDbObj.taMSM.updateQuery(rigaTransIn.next_IdxMicroStato, dtEve, valore, idxMacchina); // controllo se c'è evento if (rigaTransIn.IdxTipoEvento > 0) { if (_logLevel > 5) { Log.Info(string.Format("[ChkMiSt_7b] - Salvo evento:{0}macchina: {1} | tipoEvento: {2} | CodArticolo: {3}", Environment.NewLine, idxMacchina, rigaTransIn.IdxTipoEvento, CodArticolo), tipoLog.INFO); } answ = scriviRigaEvento(idxMacchina, rigaTransIn.IdxTipoEvento, CodArticolo, valore, 0, "-", dtEve, DateTime.Now); if (_logLevel > 5) { Log.Info(string.Format("[ChkMiSt_b] -Macchina {0}, seriale(INT) {1}{2}---------------------------{2}", idxMacchina, valINT, Environment.NewLine), tipoLog.INFO); } } } catch (Exception exc) { Log.Info(string.Format("[ChkMiSt_8b] - Eccezione:{0}{1}", Environment.NewLine, exc), tipoLog.EXCEPTION); } } return answ; } /// /// controlla se da il segnale di "microstato" deriva un evento da generare /// /// /// /// public inputComandoMapo checkMicroStato(string idxMacchina, string valore) { // wrapper ad ora corrente... return checkMicroStato(idxMacchina, valore, DateTime.Now); } /// /// Effettua conferma prod macchina dell'intero periodo da confermare (ultima conferma /// --> dtEvent) /// /// idx macchina da confermare /// 0=periodo, 1 = giorno, 2 = turno /// qta pezzi BUONI da confermare /// qta pezzi SCARTO da confermare /// DataOra in cui registrare approvazione /// public bool confermaProdMacchina(string idxMacchina, int modoConfProd, int numPzConfermati, int numPzScarto, DateTime DataOraApp, int matrOpr) { bool answ = false; try { DS_ProdTempi.stp_PzProd_getByMacchinaRow rigaProd = taPzProd2conf.GetData(idxMacchina.ToString())[0]; taPzProd2conf.stp_ConfermaProduzCompleta(idxMacchina, matrOpr, rigaProd.DataFrom, DataOraApp, numPzConfermati, numPzScarto, modoConfProd, DataOraApp, true); // indico eseguito! answ = true; } catch (Exception exc) { Log.Info($"Errore in conferma prod macchina:{Environment.NewLine}{exc}"); } return answ; } /// /// Effettua conferma prod macchina dell'intero periodo da confermare (ultima conferma /// --> dtEvent) /// /// idx macchina da confermare /// 0=periodo, 1 = giorno, 2 = turno /// qta pezzi BUONI da confermare /// /// qta pezzi LASCIATI alla macchina da confermare (2 eventi 121 rettifica neg/pos) /// /// qta pezzi SCARTO da confermare /// DataOra in cui registrare approvazione /// public bool confermaProdMacchinaFull(string idxMacchina, int modoConfProd, int numPzConfermati, int numPzLasciati, int numPzScarto, DateTime DataOraApp, int matrOpr) { bool answ = false; try { DS_ProdTempi.stp_PzProd_getByMacchinaRow rigaProd = taPzProd2conf.GetData(idxMacchina.ToString())[0]; taPzProd2conf.stp_ConfermaProduzCompletaFull(idxMacchina, matrOpr, rigaProd.DataFrom, DataOraApp, numPzConfermati, numPzLasciati, numPzScarto, modoConfProd, DataOraApp, true); // indico eseguito! answ = true; } catch (Exception exc) { Log.Info($"Errore in conferma prod macchina con rett ev121:{Environment.NewLine}{exc}"); } return answ; } /// /// Restituisce l'elenco codici flusso (da confFlux) x una macchina (se presenti) Impiegata /// anche cache redis /// /// /// public List confFluxMach(string idxMacchina) { List resultList = new List(); string rawData = ""; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("confFluxMach"); string redKey = confFluxMaccHash(idxMacchina); try { DataLayer man = new DataLayer(); rawData = cMemLayer.getRSV(redKey); if (!string.IsNullOrEmpty(rawData)) { var redisResult = JsonConvert.DeserializeObject>(rawData); resultList = redisResult != null ? redisResult : new List(); } else { resultList = man.taConfFlux .GetData() .Where(x => x.IdxMacchina == idxMacchina) .Select(x => x.CodFlux) .ToList(); // salvo in redis... rawData = JsonConvert.SerializeObject(resultList); int IO_CacheConfFluxMin = cMemLayer.CRI("IO_CacheConfFluxMin"); cMemLayer.setRSV(redKey, rawData, IO_CacheConfFluxMin * 60); } } catch (Exception exc) { Log.Info($"Eccezione in recupero confFluxMach{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } else { resultList = taConfFlux .GetData() .Where(x => x.IdxMacchina == idxMacchina) .Select(x => x.CodFlux) .ToList(); } if (resultList == null) { resultList = new List(); } return resultList; } /// /// Restituisce il valore dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza /// ODL NO invio/gestione ODL) /// /// /// public string currODL(string idxMacchina) { string answ = ""; string rCall = ""; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("hasODL"); try { rCall = cMemLayer.getRSV(currODLHash(idxMacchina)); if (!string.IsNullOrEmpty(rCall)) { answ = rCall; } else { answ = getCurrODL(idxMacchina); // salvo in redis... saveCurrODL(idxMacchina, answ); } } catch { } } return answ; } /// /// Restituisce il valore dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza /// ODL NO invio/gestione ODL) /// /// /// indica se forzare lettura da db (true) o meno /// public string currODL(string idxMacchina, bool forceDb) { string answ = ""; // faccio comunque verifica se sia stato letto da poco il valore... x cui anche a fronte // di richiesta lettura da DB per 3 sec tengo buono valore in cache redis... string rKey = cMemLayer.redHash($"ODL:{idxMacchina}"); string _idxOdl = cMemLayer.getRSV(rKey); if (forceDb) { if (!string.IsNullOrEmpty(_idxOdl)) { answ = _idxOdl; } else { answ = getCurrODL(idxMacchina); // salvo in redis... saveCurrODL(idxMacchina, answ); cMemLayer.setRSV(rKey, answ, 3); } } else { answ = currODL(idxMacchina); } return answ; } /// /// Restituisce il valore dell'intera RIGA ODL corrente (da redis o da DB se non trovata...) /// /// /// public DS_ProdTempi.ODLDataTable currODLRowTab(string idxMacchina) { DS_ProdTempi.ODLDataTable answTab = null; string rCall = ""; string rKey = currOdlRowHash(idxMacchina); if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("hasODL_row"); try { rCall = cMemLayer.getRSV(rKey); if (!string.IsNullOrEmpty(rCall)) { answTab = JsonConvert.DeserializeObject(rCall); } if (answTab == null || answTab.Count == 0) { // istanzio un NUOVO oggetto lettura MapoDb connDb = new MapoDb(); answTab = connDb.currODLTab(idxMacchina); // salvo in redis... rCall = JsonConvert.SerializeObject(answTab); int currOdlRowCacheDur = cMemLayer.CRI("currOdlRowCacheDur"); cMemLayer.setRSV(rKey, rCall, currOdlRowCacheDur); } } catch (Exception exc) { Log.Info($"Eccezione in recupero currODLRow{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } else { // istanzio un NUOVO oggetto lettura MapoDb connDb = new MapoDb(); answTab = connDb.currODLTab(idxMacchina); } return answTab; } /// /// Restituisce il valore dell'intera RIGA stato macchina corrente (da redis o da DB se non trovata...) /// /// /// public DS_applicazione.StatoMacchineDataTable currSMTab(string idxMacchina) { DS_applicazione.StatoMacchineDataTable answTab = null; string rCall = ""; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("hasStatoMacc"); try { rCall = cMemLayer.getRSV(currStatoMaccHash(idxMacchina)); if (!string.IsNullOrEmpty(rCall)) { answTab = JsonConvert.DeserializeObject(rCall); } else { // 2020.01.31 uso nuovo oggetto connessione MapoDb man = new MapoDb(); answTab = man.currStatoMaccTab(idxMacchina); //resultList = MapoDbObj.currStatoMaccTab(idxMacchina); // salvo in redis... rCall = JsonConvert.SerializeObject(answTab); int currStatoMaccCacheDur = cMemLayer.CRI("currStatoMaccCacheDur"); cMemLayer.setRSV(currStatoMaccHash(idxMacchina), rCall, currStatoMaccCacheDur); } } catch (Exception exc) { Log.Info($"Eccezione in recupero currODLRow{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } else { answTab = MapoDbObj.currStatoMaccTab(idxMacchina); } return answTab; } /// /// Restituisce l'elenco delle date dei dossier x una macchina (se presenti) Impiegata anche /// cache redis /// /// /// public List dossierLastByMach(string idxMacchina) { List resultList = new List(); string rawData = ""; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("dossierLastByMach"); string redKey = dossLastMaccHash(idxMacchina); try { DataLayer man = new DataLayer(); rawData = cMemLayer.getRSV(redKey); if (!string.IsNullOrEmpty(rawData) && rawData.Length > 2) { var redisResult = JsonConvert.DeserializeObject>(rawData); resultList = redisResult != null ? redisResult : new List(); } else { resultList = man.taDOSS .getLastByMacc(idxMacchina) .Select(x => x.DtRif) .ToList(); // salvo in redis... rawData = JsonConvert.SerializeObject(resultList); int IO_CacheDossLastMin = cMemLayer.CRI("IO_CacheDossLastMin"); cMemLayer.setRSV(redKey, rawData, IO_CacheDossLastMin * 60); } } catch (Exception exc) { Log.Info($"Eccezione in recupero dossierLastByMach{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } else { resultList = taDOSS .getLastByMacc(idxMacchina) .Select(x => x.DtRif) .ToList(); } if (resultList == null) { resultList = new List(); } return resultList; } /// /// Svuota la cache redis x l'elenco delle righe di confFlux x una macchina (se presenti) /// /// /// public bool dossierLastByMachReset(string idxMacchina) { bool answ = false; string rawData = ""; string redKey = dossLastMaccHash(idxMacchina); cMemLayer.setRSV(redKey, rawData, 1); return answ; } /// /// Rimuove Key dell'ODL corrente x una data macchina IOB /// /// /// public string emptyCurrODL(string idxMacchina) { string answ = ""; try { cMemLayer.redDelKey(currODLHash(idxMacchina)); cMemLayer.redDelKey(currOdlRowHash(idxMacchina)); answ = "OK"; } catch { answ = "KO"; } return answ; } /// /// effettua enroll del device /// /// /// /// /// /// /// public bool enrollDevice(string UserAuthKey, string IPv4, string DeviceName, string Description, int matricola) { bool fatto = false; // in primis testo se dipendente ed authKey sono validi.. if (taOp.getByMatrAuthKey(matricola, UserAuthKey).Rows.Count > 0) { // salvo matrOpr MatrOpr = matricola; /************************************************ * Gestione riconoscimento devices * * - cerco IP del device, testo se è rete interna (A) o extranet/internet (B) cercando substring "localNet" da web.config * (A): device interni: c'è un DHCP, e "dhcpLeaseTime" deve essere pari a lease time--- * - verifico se IP già in uso da un tempo < "dhcpLeaseTime" --> in questo caso segnalo errore e rimbalzo (NON permetto di registrare device a nuovo utente... sospetto uso "improprio" del device * - se tempo > dhcpLeaseTime allora può aver cambiato IP: aggiorno IP e descrizione del device e proseguo * (B): all'esterno vedo tutta una subnet NATtata con unico IP, non è + discriminante * - le timbrature "da esterno" devono essere confermate (instrodurre "tipo timbratura" x cui interne sono autoconfermate, esterne sono "grayed" (da confermare, da admin o ad esempio se si accende secondo device utente entro 5/10 min) * - le timbrature ext DOVREBBERO chiedere location (jScript?) e inviarla, visibile in conferma * * * **********************************************/ // calcolo il secret... DateTime adesso = DateTime.Now; string Dominio = cMemLayer.CRS("dominio"); string UsrName = cMemLayer.CRS("user"); // recupero dati da matricola... try { DataLayer_AnagGen.UTENTERow rigaUt = user_std.UtSn.rigaUtenteDaMatricola($"{matricola}"); if (rigaUt != null) { Dominio = rigaUt.DOMINIO; UsrName = rigaUt.USER_NAME; } else { Log.Info($"Non sono riuscito a recuperare RIGA utente per matricola {matricola}", tipoLog.ERROR); } } catch { Log.Info($"Eccezione! non sono riuscito a recuperare utente per matricola {matricola}", tipoLog.ERROR); Dominio = cMemLayer.CRS("dominio"); UsrName = cMemLayer.CRS("user"); } string cookieName = cMemLayer.CRS("cookieName"); //DateTime expDate = DateTime.Now.AddDays(cMemLayer.CRI("cookieDayExpire")); string cookieDayExpire = cMemLayer.CRS("cookieDayExpire").Replace(".", ","); double dayExp = 1; NumberStyles style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands; CultureInfo culture = CultureInfo.CreateSpecificCulture("it-IT"); double.TryParse(cookieDayExpire, style, culture, out dayExp); DateTime expDate = DateTime.Now.AddDays(dayExp); string Secret = authProxy.getSecret(Dominio, UsrName, matricola, DeviceName, adesso); string devSecret = SteamCrypto.EncryptString(Secret, cookieName); try { // creo device + cookie! fatto = authProxy.createNewCookie(Dominio, UsrName, matricola, DeviceName, Description, IPv4, cookieName, expDate); // loggo! Log.Info(string.Format("Effettuato enroll nuovo device: utente {0}\\{1} | matricola {2} | DeviceName {3} | Descrizione {4} | IP {5} | nome cookie {6} | valido sino a {7:yyyy/MM/dd HH:mm:ss}", Dominio, UsrName, matricola, DeviceName, Description, IPv4, cookieName, expDate)); } catch (Exception exc) { Log.Info($"Errore enroll nuovo device:{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } return fatto; } /// /// Restituisce l'elenco delle data-ora di confFlux x una macchina (se presenti) Impiegata /// anche cache redis /// /// /// num record da recuperare /// public List fluxLogFirstByMach(string idxMacchina, int numMax = 10) { List resultList = new List(); string rawData = ""; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("fluxLogFirstByMach"); string redKey = fluxLogFirstMaccHash(idxMacchina); try { DataLayer man = new DataLayer(); rawData = cMemLayer.getRSV(redKey); if (!string.IsNullOrEmpty(rawData)) { var redisResult = JsonConvert.DeserializeObject>(rawData); resultList = redisResult != null ? redisResult : new List(); } else { resultList = man.taFL .getFirstByMacc(idxMacchina, numMax) .Select(x => x.dtEvento) .ToList(); // salvo in redis... rawData = JsonConvert.SerializeObject(resultList); int IO_CacheFluxLogFirstMin = cMemLayer.CRI("IO_CacheFluxLogFirstMin"); cMemLayer.setRSV(redKey, rawData, IO_CacheFluxLogFirstMin * 60); } } catch (Exception exc) { Log.Info($"Eccezione in recupero fluxLogFirstByMach{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } else { resultList = taFL .getFirstByMacc(idxMacchina, numMax) .Select(x => x.dtEvento) .ToList(); } if (resultList == null) { resultList = new List(); } return resultList; } /// /// Effettua force Start PODL [CurrProdStatus = 1] se fosse già in essere ODL collegato /// --> lascia aperto [CurrProdStatus = 2] se esistesse un ODL da altro PODL x diverso /// articolo/fase --> chiude vecchio x poi far partire nuovo [CurrProdStatus = 3] se /// fosse chiuso ODL collegato --> duplica PODL e poi avvia nuovo ODL [CurrProdStatus = /// 4] se fosse già in essere ODL non collegato --> lascia aperto e collego /// /// macchina /// Codice articolo x PODL da creare /// Qty assegnata /// Codice Gruppo opzionale, default = ND-00 /// TCiclo assegnato opzionale, default = 1 /// public int ForceCreatePOdl(string idxMacchina, string CodArt, int NumPz, string CodGruppo = "ND-00", decimal TCiclo = 1) { int answ = 0; DateTime adesso = DateTime.Now; // sistemo codice e descrizione... string DescArt = CodArt; CodArt = CodArt.Replace(" ", "_"); // creazione record articolo SE non ci fosse... var listArt = taAnagArt.getByCod(CodArt); if (listArt == null || listArt.Count == 0) { // cerco x descrizione... listArt = taAnagArt.getByDescr(DescArt); // seleziono come codArt il primo trovato... if (listArt != null && listArt.Count > 0) { CodArt = listArt.FirstOrDefault().CodArticolo; } } // ricontrollo se devo creare articolo... if (listArt == null || listArt.Count == 0) { // recupero conf azienda... string CodAzienda = "*"; var listConf = taConfig.GetData(); var recAzienda = listConf.Where(x => x.chiave.Equals("AZIENDA", StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault(); if (recAzienda != null) { CodAzienda = recAzienda.valore != "*" ? recAzienda.valore : recAzienda.valoreStd; } taAnagArt.insert(CodArt, DescArt, "", CodArt, "ART", CodAzienda); } // creazione richiesta string keyRich = $"{idxMacchina}-{adesso:yyyyMMdd-HHmmss}"; taPODL.insertQuery(keyRich, keyRich, true, CodArt, CodGruppo, idxMacchina, NumPz, TCiclo, adesso, 1, 1, ""); // cerco PODL da chiave... var listPOdl = taPODL.getByCodArt(CodArt, true); var thisPodl = listPOdl.Where(x => x.KeyRichiesta == keyRich).FirstOrDefault(); if (thisPodl != null) { answ = thisPodl.idxPromessa; } return answ; } /// /// Effettua force Start PODL [CurrProdStatus = 1] se fosse già in essere ODL collegato /// --> lascia aperto [CurrProdStatus = 2] se esistesse un ODL da altro PODL x diverso /// articolo/fase --> chiude vecchio x poi far partire nuovo [CurrProdStatus = 3] se /// fosse chiuso ODL collegato --> duplica PODL e poi avvia nuovo ODL [CurrProdStatus = /// 4] se fosse già in essere ODL non collegato --> lascia aperto e collego /// /// macchina /// IDX PODL da processare /// effettuare conferma qty /// effettuare conferma qty /// data-ora di avvio (opzionale) /// data-ora attuale (opzionale) /// public string ForceStartPOdl(string idxMacchina, int idxPODL, bool doConfirm, int matrOpr = 0, string dtEve = "", string dtCurr = "") { string answ = "KO"; int CurrProdStatus = 0; string sIdxODL = ""; // Verifica se evento realtime oppure ho data specificata x processing @dtEve DateTime dtEvent = DateTime.Now; bool rtimeProc = string.IsNullOrEmpty(dtEve); if (!rtimeProc) { dtEvent = GetSrvDtEvent(dtEve, dtCurr); } // verifico NON CI SIA un veto altre chiamate (es split...) - 30 sec di default... string redKey = vetoForceStartPOdlMaccHash(idxMacchina); string rawData = cMemLayer.getRSV(redKey); if (!string.IsNullOrEmpty(rawData)) { Log.Info($"VETO ATTIVO | Richiesto ForceStartPOdl per impianto {idxMacchina} | impossibile procedere"); } else { // determino veto: se realtime 30sec, altrimenti 1 soltanto int vetoTtl = rtimeProc ? 30 : 1; // registro VETO x altre chiamate (es split...) 30sec cMemLayer.setRSV(redKey, $"Inizio FORCE START PODL: {idxPODL} | realtime: {rtimeProc} | dtEve: {dtEvent}", vetoTtl); // calcolo la qta da gestire int qtyConf = 0; if (doConfirm) { DS_ProdTempi.stp_PzProd_getByMacchinaRow rigaProd; try { rigaProd = taPzProd2conf.GetData(idxMacchina)[0]; qtyConf = rigaProd.pezziNonConfermati; } catch (Exception exc) { Log.Info($"Errore recupero pezzi da confermare per la macchina {idxMacchina}{Environment.NewLine}{exc}", tipoLog.ERROR); } } // proseguo DS_ProdTempi.ODLDataTable currODLData = null; DS_ProdTempi.PromesseODLDataTable reqPODLData = null; DS_ProdTempi.ODLRow OdlRow = null; DS_ProdTempi.PromesseODLRow POdlRow = null; // metodo principale... try { sIdxODL = getCurrODL(idxMacchina); // recupero dati da PODL reqPODLData = getPODLRowTab(idxPODL); // recupero ODL corrente... currODLData = currODLRowTab(idxMacchina); // procedo SOLO SE ho trovato un PODL if (reqPODLData != null && reqPODLData.Rows.Count > 0) { POdlRow = reqPODLData[0]; // prima cosa: verifico se sia un PODL libero (idxODL==0) if (reqPODLData[0].IdxODL == 0) { if (currODLData != null && currODLData.Count > 0) { OdlRow = currODLData[0]; // verifico ODL corrente, se compatibili... if (OdlRow.CodArticolo == POdlRow.CodArticolo && OdlRow.KeyRichiesta == POdlRow.KeyRichiesta && OdlRow.IdxMacchina == POdlRow.IdxMacchina) { // compatibili --> caso 4 CurrProdStatus = 4; } else { // anche qui chiusura ed avvio CurrProdStatus = 2; } } else { CurrProdStatus = 2; } } // altrimenti se PODL già associato else { // se trovo qualcosa come ODL if (currODLData != null && currODLData.Count > 0) { OdlRow = currODLData[0]; // se è quello già associato if ($"{reqPODLData[0].IdxODL}" == sIdxODL) { // non devo fare nulla CurrProdStatus = 1; } else { // altrimenti devo clonare CurrProdStatus = 3; } } else { // anche in questo caso devo clonare PODL CurrProdStatus = 3; } } } else { Log.Info($"Errore in ForceStartPOdl: non trovato PODL per idxPODL{idxPODL}", tipoLog.ERROR); } // OVVIAMENTE solo se ho POdlRow... if (POdlRow != null) { switch (CurrProdStatus) { case 1: // --> non tocco nulla PODL/ODL Log.Info($"Richiesto ForceStartPOdl, caso 1 | PODL {idxPODL} | ODL {sIdxODL} | nessun intervento", tipoLog.INFO); break; case 2: // eventuale chiusura vecchio ODL, 2 sec prima... if (currODLData.Count > 0) { doCloseCurrODL(idxMacchina, doConfirm, qtyConf, currODLData, dtEvent.AddSeconds(-2), matrOpr); } // avvio PODL: creo nuovo ODL da promessa ed associo taODL.inizioSetupPromessa(idxPODL, MatrOpr, POdlRow.IdxMacchina, POdlRow.TCAssegnato, POdlRow.PzPallet, POdlRow.Note, dtEvent); // resetto info PODL resetPODLData(idxPODL); // fix (invio ) dati ODL alla macchina tramite IOB Thread.Sleep(200); answ = saveOdlData(idxMacchina, currODLData, reqPODLData); break; case 3: // eventuale chiusura vecchio ODL if (currODLData.Count > 0) { doCloseCurrODL(idxMacchina, doConfirm, qtyConf, currODLData, dtEvent.AddSeconds(-2), matrOpr); } // duplico PODL... inserisco nuovo record... taPODL.insertQuery(POdlRow.KeyRichiesta, POdlRow.KeyBCode, true, POdlRow.CodArticolo, POdlRow.CodGruppo, POdlRow.IdxMacchina, POdlRow.NumPezzi, POdlRow.TCAssegnato, POdlRow.DueDate, POdlRow.Priorita, POdlRow.PzPallet, POdlRow.Note); // recupero PODL attivabili... var podlList = taPODL.getByCodArt(POdlRow.CodArticolo, true); // cerco quello che ha la stessa fase/macchina e + recente... var lastPodl = podlList.Where(x => x.KeyRichiesta == POdlRow.KeyRichiesta && x.IdxMacchina == POdlRow.IdxMacchina).OrderByDescending(x => x.idxPromessa).FirstOrDefault(); int newPODL = lastPodl != null ? lastPodl.idxPromessa : POdlRow.idxPromessa; // avvio (nuovo) PODL taODL.inizioSetupPromessa(idxPODL, MatrOpr, POdlRow.IdxMacchina, POdlRow.TCAssegnato, POdlRow.PzPallet, POdlRow.Note, dtEvent); // resetto info PODL resetPODLData(idxPODL); // fix (invio ) dati ODL alla macchina tramite IOB Thread.Sleep(200); answ = saveOdlData(idxMacchina, currODLData, reqPODLData); break; case 4: // eventuale chiusura vecchio ODL, 2 sec prima... if (currODLData.Count > 0) { doCloseCurrODL(idxMacchina, doConfirm, qtyConf, currODLData, dtEvent.AddSeconds(-2), matrOpr); } // avvio PODL: creo nuovo ODL da promessa ed associo taODL.inizioSetupPromessa(idxPODL, MatrOpr, POdlRow.IdxMacchina, POdlRow.TCAssegnato, POdlRow.PzPallet, POdlRow.Note, dtEvent); // reseetto info PODL resetPODLData(idxPODL); // fix (invio ) dati ODL alla macchina tramite IOB Thread.Sleep(200); answ = saveOdlData(idxMacchina, currODLData, reqPODLData); break; default: break; } } else { answ = "NF"; } } catch (Exception exc) { Log.Info($"Eccezione in ForceStartPOdl{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } return answ; } /// /// Recupera ArtNum dato CodArt (per impianti che accettano solo INT in scrittura) /// /// /// CodArt richiesto, se vuoto restituisce TUTTI i valori in tabella di decodifica /// /// Dizionario contenente le righe delle codifiche attive Articolo/Numero public Dictionary getArtNum(string codArt) { Dictionary answ = new Dictionary(); DS_applicazione.DecNumArticoliDataTable rawData; // se vuoto --> leggo tabella if (string.IsNullOrEmpty(codArt)) { rawData = taDecNA.GetData(); } // se non vuoto --> chiamo stored x recuperare info else { rawData = taDecNA.getByKey(codArt); } foreach (var item in rawData) { answ.Add(item.CodArticolo, item.NumART); } return answ; } /// /// GET elenco parametri correnti x IOB /// /// /// public List getCurrObjItems(string idxMacchina) { string serVal = cMemLayer.getRSV(currParametersHash(idxMacchina)); List actValues = new List(); if (serVal != null) { try { var rawVal = JsonConvert.DeserializeObject>(serVal); // ordino! actValues = rawVal .OrderBy(x => x.displOrdinal) .ThenBy(x => x.description) .ToList(); #if false actValues.Sort((a, b) => (a.name.CompareTo(b.name))); #endif } catch (Exception exc) { Log.Info($"Eccezione in deserializzazione getCurrObjItems{Environment.NewLine}{exc}"); } } return actValues; } /// /// GET elenco parametri che richiedono una WRITE x IOB /// /// /// public List getCurrObjItemsPendigWrite(string idxMacchina) { string serVal = cMemLayer.getRSV(currParametersHash(idxMacchina)); List actValues = new List(); List writeValues = new List(); if (serVal != null) { try { actValues = JsonConvert.DeserializeObject>(serVal); // cerco e rimuovo parametri sola lettura o SENZA richieste scrittura foreach (var item in actValues) { if (item.writable && !string.IsNullOrEmpty(item.reqValue)) { writeValues.Add(item); } } } catch (Exception exc) { Log.Info($"Eccezione in deserializzazione getCurrObjItemsPendigWrite{Environment.NewLine}{exc}"); } } return writeValues; } /// /// restituisce valore dell'ODL attivo (iniziato e NON concluso) /// /// /// public string getCurrODL(string idxMacchina) { string answ = ""; // recupero con stored NUOVA... DS_ProdTempi.ODLDataTable tabOdl = taODL.getByMacchina(idxMacchina); if (tabOdl.Rows.Count > 0) { // solo SE ho idxODL (altrimenti loggo errore) if (tabOdl[0].IdxODL > 0) { answ = tabOdl[0].IdxODL.ToString(); answ = answ == "" ? "0" : answ; } else { answ = "0"; Log.Info("[currODL] Errore in currODL x idxMacchina " + idxMacchina + ": IdxODL = 0"); } } else { // se è empty --> 0!!! answ = "0"; } // ultimo controllo su idxOdl... answ = answ == "" ? "0" : answ; // restituisco! return answ; } /// /// Dati deroga SchedaTecnica serializzati in REDIS (get/set) /// public StCheckOverride getDerogaSt(int idxST) { StCheckOverride answ = new StCheckOverride() { IdxST = idxST }; string keyDerogaST = cMemLayer.redHash($"DerogaSt:{user_std.UtSn.utente}:{idxST:000}"); string rawData = cMemLayer.getRSV(keyDerogaST); if (!string.IsNullOrEmpty(rawData)) { try { answ = JsonConvert.DeserializeObject(rawData); } catch { } } return answ; } /// /// restituisce una tabella con tutte le transizioni degli ingressi per una data macchina /// /// /// public DS_applicazione.TransizioneIngressiDataTable getMatriceIngressi(string idxMacchina) { DS_applicazione.TransizioneIngressiDataTable answ; try { answ = taTranIngr.getMatriceByIdxMacchina(idxMacchina); } catch { answ = null; } return answ; } /// /// Recupera (da DB) i dati della State Machine multi ingressi nel formato /// key: IdxMacchina /// value: IdxFamigliaIngresso /// /// /// public KeyValuePair[] getMSMI_DB(string idxMacchina) { DS_applicazione.MSFDDataTable tabMSMI = new DS_applicazione.MSFDDataTable(); // 2017.09.13: inserisco gestione singleton condizionale if (cMemLayer.CRB("disable_singleton")) { // instanzio un nuovo oggetto MapoDb MapoDb connDb = new MapoDb(); tabMSMI = connDb.taMSFD.getMulti(idxMacchina); } else { // leggo DB da singleton tabMSMI = MapoDbObj.taMSFD.getMulti(idxMacchina); } KeyValuePair[] answ = new KeyValuePair[tabMSMI.Count]; // salvo tutti i valori StateMachineIngressi... int i = 0; foreach (var item in tabMSMI) { answ[i] = new KeyValuePair(item.IdxMacchina, item.IdxFamigliaIngresso.ToString()); i++; } return answ; } /// /// Restituisce il valore dell'intera RIGA PODL data chiave (da redis o da DB se non trovata...) /// /// IDX della PODL /// public DS_ProdTempi.PromesseODLDataTable getPODLRowTab(int idxPODL) { DS_ProdTempi.PromesseODLDataTable answTab = null; string rCall = ""; string rKey = getPOdlRowHash(idxPODL); if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("hasPODL_row"); try { rCall = cMemLayer.getRSV(rKey); if (!string.IsNullOrEmpty(rCall)) { answTab = JsonConvert.DeserializeObject(rCall); } if (answTab == null || answTab.Count == 0) { answTab = taPODL.getByKey(idxPODL); // salvo in redis... rCall = JsonConvert.SerializeObject(answTab); int currOdlRowCacheDur = cMemLayer.CRI("currOdlRowCacheDur"); cMemLayer.setRSV(rKey, rCall, currOdlRowCacheDur); } } catch (Exception exc) { Log.Info($"Eccezione in recupero getPODLRowTab{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } else { answTab = taPODL.getByKey(idxPODL); } return answTab; } /// /// Effettua calcolo data-ora di riferimento per il server a poartire da /// /// /// /// public DateTime GetSrvDtEvent(string dtEve, string dtCurr) { DateTime dataOraEvento = DateTime.Now; // 2017.09.14 trimmo eventualmente lo zero finale dalle date SE supera i millisecondi... dtEve = dtEve.Length > 17 ? dtEve.Substring(0, 17) : dtEve; dtCurr = dtCurr.Length > 17 ? dtCurr.Substring(0, 17) : dtCurr; DateTime dtEvento, dtCorrente; // controllo: se ho valori dt x evento e orario DIVERSI per acquisitore IOB calcolo // dataOraEvento corretto if (dtEve != dtCurr) { Int64 delta = 0; try { // se ho meno decimali x evento rispetto dtCorrente... if (dtEve.Length < dtCurr.Length) { dtEve = dtEve.PadRight(dtCurr.Length, '0'); } delta = Convert.ToInt64(dtCurr) - Convert.ToInt64(dtEve); // se meno di 60'000 ms ... if (delta < 59999) { dataOraEvento = dataOraEvento.AddMilliseconds(-delta); } else { // in questo caso elimino i MS dalle stringhe e converto i datetime.... CultureInfo provider = CultureInfo.InvariantCulture; string format = "yyyyMMddHHmmssfff"; dtEvento = DateTime.ParseExact(dtEve, format, provider); dtCorrente = DateTime.ParseExact(dtCurr, format, provider); TimeSpan deltaTS = dtCorrente.Subtract(dtEvento); dataOraEvento = dataOraEvento.Add(-deltaTS); } } catch (Exception exc) { Log.Info($"getSrvDtEvent | Errore calcolo ms evento/ora corrente da device remoto:{Environment.NewLine}" + $"dtEve : {dtEve}{Environment.NewLine}" + $"dtCurr: {dtCurr}{Environment.NewLine}" + $"{exc}", tipoLog.EXCEPTION); } } return dataOraEvento; } /// /// restituisce il TempoCiclo effettivo (tecnico) della macchina /// /// /// public decimal getTcEffMacchina(string idxMacchina) { decimal tc = 0; try { DS_ProdTempi.stp_repDonati_getDatiProdMacchinaPeriodoRow riga = taDatiProdMacchPer.GetData(idxMacchina, DateTime.Now.AddMinutes(-30), DateTime.Now)[0]; if (riga.TCEffRT > 0) { tc = riga.TCEffRT; } else { tc = riga.TCAssegnato; } } catch { } // imposto a 99'TC if (tc == 0) { tc = 99.9M; // scrivo log per indicare mancato caricamento dati tc dichiarato e conseguente // errore sul timer - 2/11/2012 EN&CV Log.Info(string.Format("Impostato TC Tempo Ciclo a 99' (99.9M) causa mancato inserimento tempo ciclo dichiarato")); } return tc; } /// /// Restituisce il valore booleano se la macchina sia abilitata all'input /// /// /// public bool insEnab(string idxMacchina) { bool answ = false; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("insEnabled"); try { answ = Convert.ToBoolean(mDatiMacchinaVal(idxMacchina, "insEnabled")); } catch { } } // ...oppure dritto su DB else { if (cMemLayer.CRB("disable_singleton")) { // instanzio un nuovo oggetto MapoDb MapoDb connDb = new MapoDb(); answ = connDb.insEnabled(idxMacchina); } else { // leggo DB da singleton answ = MapoDbObj.insEnabled(idxMacchina); } } return answ; } /// /// Restituisce il valore booleano se la macchina sia di tipo MASTER (imposta ODL x gli slave) /// /// /// public bool isMaster(string idxMacchina) { bool answ = false; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("isMaster"); try { answ = Convert.ToBoolean(mDatiMacchinaVal(idxMacchina, "Master") == "1"); } catch { } } // ...oppure dritto su DB else { answ = MapoDbObj.isMaster(idxMacchina); } return answ; } /// /// Restituisce il valore booleano se la macchina sia di tipo MULTI (con più state machine x INGRESSI) /// /// /// public bool isMulti(string idxMacchina) { bool answ = false; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("isMulti"); try { answ = Convert.ToBoolean(mDatiMacchinaVal(idxMacchina, "Multi") == "1"); } catch { } } // ...oppure dritto su DB else { answ = MapoDbObj.isMulti(idxMacchina); } return answ; } /// /// Restituisce il valore booleano se la macchina sia di tipo SLAVE (ODL impostato da MASTER) /// /// /// public bool isSlave(string idxMacchina) { bool answ = false; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("isSlave"); try { answ = Convert.ToBoolean(mDatiMacchinaVal(idxMacchina, "Slave") == "1"); } catch { } } // ...oppure dritto su DB else { answ = MapoDbObj.isSlave(idxMacchina); } return answ; } /// /// Restituisce valore di una singola chiave del dizionario DatiMacchina /// /// /// /// public string mDatiMacchinaVal(string idxMacchina, string chiave) { string answ = ""; try { answ = mDatiMacchine(idxMacchina)[chiave]; } catch { } return answ; } /// /// Restitusice elenco KVP dei campi DatiMacchine + StatoMacchine per l'impianto indicato /// /// /// public Dictionary mDatiMacchine(string idxMacchina) { // hard coded dimensione vettore DatiMacchine Dictionary answ = new Dictionary(); // ORA recupero da memoria redis... try { string currHash = dtMaccHash(idxMacchina); answ = cMemLayer.redGetHashDict(currHash); // se è vuoto... leggo da DB e popolo! if (answ.Count == 0) { answ = resetDatiMacchina(idxMacchina); } } catch (Exception exc) { Log.Info(string.Format("Errore in compilazione dati Macchine x Redis - idxMacchina {2}:{0}{1}", Environment.NewLine, exc, idxMacchina)); } return answ; } /// /// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato /// /// /// public Dictionary mOptParMacchina(string idxMacchina) { // hard coded dimensione vettore DatiMacchine Dictionary answ = new Dictionary(); // ORA recupero da memoria redis... try { string currHash = optParHash(idxMacchina); answ = cMemLayer.redGetHashDict(currHash); } catch (Exception exc) { Log.Info(string.Format("Errore in compilazione dati OPT PARAM x Redis - idxMacchina {2}:{0}{1}", Environment.NewLine, exc, idxMacchina)); } return answ; } /// /// Restitusice elenco KVP dei TASK SALVATI (da passare a IOB-WIN) per l'impianto indicato /// /// /// public Dictionary mSavedTaskMacchina(string idxMacchina) { // hard coded dimensione vettore DatiMacchine Dictionary answ = new Dictionary(); // ORA recupero da memoria redis... try { string currHash = savedTaskHash(idxMacchina); answ = cMemLayer.redGetHashDict(currHash); } catch (Exception exc) { Log.Info($"Errore in recupero dati SAVED TASK x Redis mSavedTaskMacchina | idxMacchina {idxMacchina}{Environment.NewLine}{exc}"); } return answ; } /// /// Restitusice elenco KVP /// key: IdxMacchina /// value: IdxFamigliaIngresso /// /// /// public KeyValuePair[] mTabMSMI(string idxMacchina) { // hard coded dimensione vettore DatiMacchine KeyValuePair[] answ = new KeyValuePair[1]; // iniziualizzo con un valore... 0/0 answ[0] = new KeyValuePair("0", "0"); // ORA recupero da memoria redis... try { string currHash = hMSMI(idxMacchina); answ = cMemLayer.redGetHash(currHash); // se è vuoto... leggo da DB e popolo! if (answ.Length == 0) { answ = resetMSMI(idxMacchina); } } catch (Exception exc) { Log.Info(string.Format("Errore in compilazione Tabella Multi State Machine Ingressi x Redis:{0}{1}", Environment.NewLine, exc)); } return answ; } /// /// Restitusice elenco KVP dei campi della State Machine ingressi nel formato /// key: cState_nVal (current MICRO-STATE + "_" + new Value) /// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE /// /// /// public KeyValuePair[] mTabSMI(int idxFamIn) { // hard coded dimensione vettore DatiMacchine KeyValuePair[] answ = new KeyValuePair[1]; // iniziualizzo con un valore... 0/0 answ[0] = new KeyValuePair("0", "0"); // ORA recupero da memoria redis... try { string currHash = hSMI(idxFamIn); answ = cMemLayer.redGetHash(currHash); // se è vuoto... leggo da DB e popolo! if (answ.Length == 0) { answ = resetSMI(idxFamIn); } } catch (Exception exc) { Log.Info(string.Format("Errore in compilazione State Machine Ingressi x Redis:{0}{1}", Environment.NewLine, exc)); } return answ; } /// /// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato /// /// /// public Dictionary mTaskMacchina(string idxMacchina) { // hard coded dimensione vettore DatiMacchine Dictionary answ = new Dictionary(); // ORA recupero da memoria redis... try { string currHash = exeTaskHash(idxMacchina); answ = cMemLayer.redGetHashDict(currHash); } catch (Exception exc) { Log.Info(string.Format("Errore in recupero dati EXE TASK x Redis mTaskMacchina - idxMacchina {2}:{0}{1}", Environment.NewLine, exc, idxMacchina)); } return answ; } /// /// Processa registrazione FL da IOB /// /// /// /// /// /// /// /// /// public string processFluxLog(string idxMacchina, string flux, string valore, string dtEve, string dtCurr, int contatore, bool disabKA) { // instanzio un nuovo oggetto MapoDb MapoDb connDb = new MapoDb(); // se non vietato... if (!disabKA) { // scrivo keep alive!!! (se necessario, altrimenti è in cache...) connDb.scriviKeepAlive(idxMacchina, DateTime.Now); } // registro conteggio impiego chiamate REDIS if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("processFluxLog"); } string answ = ""; DateTime dataOraEvento = GetSrvDtEvent(dtEve, dtCurr); // inizio processing vero e proprio INPUT... if (idxMacchina != null && valore != null) { if (idxMacchina != "" && valore != "") { // 2020.01.31 nuovo OBJ DataLayer man = new DataLayer(); man.taFL.InsNew(idxMacchina, dataOraEvento, flux, valore, contatore); // 2022.06.06 salvo su redis il valore ULTIMO del flux x recupero rapido ultimo valore string key = DataLayer.LiveFLogKeyHash(idxMacchina, flux); // 10 min cache max... int ttlFlog = 60 * 10; cMemLayer.setRSV(key, valore, ttlFlog); // registro in risposta che è andato tutto bene... answ = "OK"; } else { string errore = "processFluxLog | Errore: parametri macchina/valore vuoti"; Log.Info(errore, tipoLog.INFO); answ = errore; } } else { string errore = "processFluxLog | Errore: mancano parametri macchina/valore"; Log.Info(errore, tipoLog.INFO); answ = errore; } return answ; } /// /// Processa input da IOB eventualmente registrando i segnali inviati /// /// /// /// /// /// /// public string processInput(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore) { string answ = ""; // 2018.10.26 controllo dtEve e dtCurr if (dtEve == null || dtCurr == null) { Log.Info(string.Format("procInput: valori nulli date: idxMacchina: {0} | valore: {1} | dtEve: {2} | dtCurr:{3}", idxMacchina, valore, dtEve, dtCurr)); } else if (dtEve.Length < 17 || dtCurr.Length < 17) { Log.Info(string.Format("procInput: valori data non corretti: idxMacchina: {0} | valore: {1} | dtEve: {2} | dtCurr:{3}", idxMacchina, valore, dtEve, dtCurr)); } else { // 2017.09.14 trimmo eventualmente lo zero finale dalle date SE supera i millisecondi... dtEve = dtEve.Length > 17 ? dtEve.Substring(0, 17) : dtEve; dtCurr = dtCurr.Length > 17 ? dtCurr.Substring(0, 17) : dtCurr; // registro conteggio impiego chiamate REDIS if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("processInput"); } DateTime dataOraEvento = DateTime.Now; DateTime dtEvento, dtCorrente; // controllo: se ho valori dt x evento e orario DIVERSI per acquisitore IOB calcolo // dataOraEvento corretto if (dtEve != dtCurr) { // delta è un calcolo MOLTO approssimativo della differenza temporale... Int64 delta = 0; try { // se ho meno decimali x evento rispetto dtCorrente... if (dtEve.Length < dtCurr.Length) { Log.Info(string.Format("processInput: fix valore dtEve: {0} vs dtCurr: {1}", dtEve, dtCurr), tipoLog.INFO); dtEve = dtEve.PadRight(dtCurr.Length, '0'); } delta = Convert.ToInt64(dtCurr) - Convert.ToInt64(dtEve); // log della classe del delta (1-10, 10-100, 100-1k, 1k-10k, > 10k ms) string deltaClass = ""; // faccio SEMPRE calcolo esatto sennò sbaglia... CultureInfo provider = CultureInfo.InvariantCulture; string format = "yyyyMMddHHmmssfff"; dtEvento = DateTime.ParseExact(dtEve, format, provider); dtCorrente = DateTime.ParseExact(dtCurr, format, provider); Int64 tiks = dtCorrente.Ticks - dtEvento.Ticks; TimeSpan ts = new TimeSpan(tiks); double ms = Math.Abs(ts.TotalMilliseconds); // calcolo ESATTO dataora evento dataOraEvento = dataOraEvento.AddTicks(-tiks); if (ms <= 10) { deltaClass = "delta 0-10 ms"; } else if (ms <= 100) { deltaClass = "delta 10-100 ms"; } else if (ms <= 1000) { deltaClass = "delta 100-1000 ms"; } else if (ms <= 10000) { deltaClass = "delta 1-10 sec"; } else { deltaClass = "delta > 10 sec"; } // se ho deltaClass loggo if (deltaClass != "") { Log.Info("Correzione " + deltaClass); } } catch (Exception exc) { Log.Info(string.Format("Errore calcolo ms evento/ora corrente da device remoto:{0}dtEve : {1}{0}dtCurr: {2}{0}{3}", Environment.NewLine, dtEve, dtCurr, exc), tipoLog.EXCEPTION); } } // inizio processing vero e proprio INPUT... if (idxMacchina != null && valore != null) { if (idxMacchina != "" && valore != "") { // 2017.07.11 se richiesto di NON usare singleton... riporto FUORI la // gestione NUOVO oggetto if (cMemLayer.CRB("disable_singleton")) { // instanzio un nuovo oggetto MapoDb MapoDb connDb = new MapoDb(); // se abilitato registro evento sul DB if (idxMacchina != "" && sLogEnab(idxMacchina)) { saveSigLog(idxMacchina, valore, dataOraEvento, contatore); } // continuo col resto try { // scrivo keep alive!!! (se necessario, altrimenti è in cache...) connDb.scriviKeepAlive(idxMacchina, DateTime.Now); // verifico se sia una macchina MULTI ed in tal caso calcolo i // SUB-systems e CHIAMERO' alla fine pure loro.... if (isMulti(idxMacchina)) { // inizio preprocessing string newVal = ""; // processo OGNI macchina a stati dell'impianto... (KEY: // IdxMacchina / IdxMacchina#qualcosa, Val = IdxFamIn) foreach (var item in mTabMSMI(idxMacchina)) { newVal = preProcInput(item.Key, valore); // ora processo e salvo il valore del microstato... // INTERNAMENTE gestisce i casi DB/REDIS secondo necessità checkMicroStato(item.Key, newVal, dataOraEvento, contatore); } } else { // ora processo e salvo il valore del microstato... INTERNAMENTE // gestisce i casi DB/REDIS secondo necessità checkMicroStato(idxMacchina, valore, dataOraEvento, contatore); } // registro in risposta che è andato tutto bene... answ = "OK"; } catch (Exception exc) { if (cMemLayer.CRI("_logLevel") > 5) { string errore = string.Format("Errore: {0}{1}", Environment.NewLine, exc); Log.Info(errore, tipoLog.EXCEPTION); answ = errore; } } } else { // se abilitato registro evento sul DB if (idxMacchina != "" && MapoDbObj.sLogEnabled(idxMacchina)) { saveSigLog(idxMacchina, valore, dataOraEvento, contatore); } // continuo col resto try { // scrivo keep alive!!! (se encessario, altrimenti è in cache...) MapoDbObj.scriviKeepAlive(idxMacchina, DateTime.Now); // verifico se sia una macchina MULTI ed in tal caso calcolo i // SUB-systems e CHIAMERO' alla fine pure loro.... if (MapoDbObj.isMulti(idxMacchina)) { // inizio preprocessing string newVal = ""; // processo OGNI macchina a stati dell'impianto... (KEY: // IdxMacchina / IdxMacchina#qualcosa, Val = IdxFamIn) foreach (var item in getMSMI_DB(idxMacchina)) { newVal = preProcInput(item.Key, valore); // ora processo e salvo il valore del microstato... checkMicroStato(item.Key, newVal, dataOraEvento, contatore); } } else { // ora processo e salvo il valore del microstato... checkMicroStato(idxMacchina, valore, dataOraEvento, contatore); } answ = "OK"; // registro in risposta che è andato tutto bene... } catch (Exception exc) { if (cMemLayer.CRI("_logLevel") > 5) { string errore = string.Format("Errore: {0}{1}", Environment.NewLine, exc); Log.Info(errore, tipoLog.EXCEPTION); answ = errore; } } } } else { string errore = "Errore: parametri macchina/valore vuoti"; Log.Info(errore, tipoLog.INFO); answ = errore; } } else { string errore = "Errore: mancano parametri macchina/valore"; Log.Info(errore, tipoLog.INFO); answ = errore; } } return answ; } /// /// Processa registrazione di uno stream di dati LIVE da IOB /// /// /// Dati live nel formato di lista di KVP chiave/valore1 /// public string processLiveJson(string idxMacchina, liveIOB liveData) { if (liveData == null) { throw new ArgumentNullException(nameof(liveData)); } // registro conteggio impiego chiamate REDIS if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("processLiveJson"); } string answ = ""; DateTime dataOraEvento = DateTime.Now; // inizio processing vero e proprio INPUT... if (!string.IsNullOrEmpty(idxMacchina) && liveData != null) { // SE ho dei segnali... if (liveData.dataList.Count > 0) { // salvo in Redis nell'area CURR_VAL TUTTI i valori live cMemLayer.redSaveHashList(LiveCurrValHash(idxMacchina), liveData.dataList); // accodo in buffer ULTIMI valori con dataora uno ad uno... KeyValuePair[] newData = new KeyValuePair[1]; foreach (var item in liveData.dataList) { // accodo update valori... newData[0] = new KeyValuePair(dataOraEvento.ToString(), item.Value); cMemLayer.redSaveHash(LiveBufferHash(idxMacchina, item.Key), newData); } } else { string errore = "Errore: formato liveData errato (split #)"; Log.Info(errore, tipoLog.ERROR); answ = errore; } // registro in risposta che è andato tutto bene... answ = "OK"; } else { string errore = "Errore: mancano parametri macchina/liveData come Json"; Log.Info(errore, tipoLog.ERROR); answ = errore; } return answ; } /// /// Processa registrazione di uno stream di dati LIVE da IOB /// /// /// Dati live nel formato chiave1|valore1#chiave2|valore2#chiave3|valore3 /// public string processLiveRec(string idxMacchina, string liveData) { if (liveData == null) { throw new ArgumentNullException(nameof(liveData)); } // registro conteggio impiego chiamate REDIS if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("processLiveRec"); } string answ = ""; DateTime dataOraEvento = DateTime.Now; // inizio processing vero e proprio INPUT... if (idxMacchina != null && liveData != null) { if (idxMacchina != "" && liveData != "") { // prendo il vettore LiveData e lo splitto per variabili inviate string[] liveSignals = liveData.Split('|'); // SE ho dei segnali... if (liveSignals.Length > 0) { KeyValuePair[] liveSet = new KeyValuePair[liveSignals.Length]; string[] kvp; int i = 0; foreach (string liveKVP in liveSignals) { // ogni variabile la splitto come chiave/valore kvp = liveKVP.Split(':'); liveSet[i] = new KeyValuePair(kvp[0], kvp[1]); i++; } // salvo in Redis nell'area CURR_VAL TUTTI i valori live cMemLayer.redSaveHash(LiveCurrValHash(idxMacchina), liveSet); // accodo in buffer ULTIMI valori con dataora uno ad uno... KeyValuePair[] newData = new KeyValuePair[1]; foreach (var item in liveSet) { // accodo update valori... newData[0] = new KeyValuePair(dataOraEvento.ToString(), item.Value); cMemLayer.redSaveHash(LiveBufferHash(idxMacchina, item.Key), newData); } } else { string errore = "Errore: formato liveData errato (split #)"; Log.Info(errore, tipoLog.ERROR); answ = errore; } // registro in risposta che è andato tutto bene... answ = "OK"; } else { string errore = "Errore: parametri macchina/liveData vuoti"; Log.Info(errore, tipoLog.ERROR); answ = errore; } } else { string errore = "Errore: mancano parametri macchina/liveData"; Log.Info(errore, tipoLog.ERROR); answ = errore; } return answ; } /// /// Processa registrazione UserLog da IOB /// /// Macchina /// Flusso: DI/RC/RC /// valore = note/valString /// data evento /// data corrente /// contatore invio /// Matricola Operatore /// label = causale scarto / tagCode /// valNum = esitoOk (0/1) / Quantità di scarto associata /// public string processUserLog(string idxMacchina, string flux, string valore, string dtEve, string dtCurr, int contatore, int matrOpr, string label, int valNum) { // instanzio un nuovo oggetto MapoDb MapoDb connDb = new MapoDb(); // scrivo keep alive!!! (se necessario, altrimenti è in cache...) connDb.scriviKeepAlive(idxMacchina, DateTime.Now); // 2017.09.14 trimmo eventualmente lo zero finale dalle date SE supera i millisecondi... dtEve = dtEve.Length > 17 ? dtEve.Substring(0, 17) : dtEve; dtCurr = dtCurr.Length > 17 ? dtCurr.Substring(0, 17) : dtCurr; // registro conteggio impiego chiamate REDIS if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("processUserLog"); } string answ = ""; DateTime dataOraEvento = DateTime.Now; DateTime dtEvento, dtCorrente; // controllo: se ho valori dt x evento e orario DIVERSI per acquisitore IOB calcolo // dataOraEvento corretto if (dtEve != dtCurr) { Int64 delta = 0; try { // se ho meno decimali x evento rispetto dtCorrente... if (dtEve.Length < dtCurr.Length) { dtEve = dtEve.PadRight(dtCurr.Length, '0'); } delta = Convert.ToInt64(dtCurr) - Convert.ToInt64(dtEve); // se meno di 60'000 ms ... if (delta < 59999) { dataOraEvento = dataOraEvento.AddMilliseconds(-delta); } else { // in questo caso elimino i MS dalle stringhe e converto i datetime.... CultureInfo provider = CultureInfo.InvariantCulture; string format = "yyyyMMddHHmmssfff"; dtEvento = DateTime.ParseExact(dtEve, format, provider); dtCorrente = DateTime.ParseExact(dtCurr, format, provider); Int64 tiks = dtCorrente.Ticks - dtEvento.Ticks; dataOraEvento = dataOraEvento.AddTicks(-tiks); } } catch (Exception exc) { Log.Info(string.Format("processUserLog | Errore calcolo ms evento/ora corrente da device remoto:{0}dtEve : {1}{0}dtCurr: {2}{0}{3}", Environment.NewLine, dtEve, dtCurr, exc), tipoLog.EXCEPTION); } } // inizio processing vero e proprio INPUT... if (string.IsNullOrEmpty(idxMacchina)) { string errore = "processUserLog | Errore: macchina mancante"; Log.Info(errore, tipoLog.INFO); answ = errore; } else { if (string.IsNullOrEmpty(flux)) { string errore = "processUserLog | Errore: parametro flux vuoto"; Log.Info(errore, tipoLog.INFO); answ = errore; } else { // 2020.01.31 nuovo OBJ DataLayer DLMan = new DataLayer(); // in base al flusso decido dove e cosa scrivere... switch (flux) { case "DI": DLMan.taDiarioDich.insertQuery(label, idxMacchina, dataOraEvento, matrOpr, valore); break; case "RC": bool esitoOk = valNum != 0; DLMan.taRC.insertQuery(idxMacchina, matrOpr, esitoOk, valore, dataOraEvento); break; case "RS": DLMan.taRS.insertQuery(idxMacchina, dataOraEvento, label, valNum, valore, matrOpr); break; default: break; } // registro in risposta che è andato tutto bene... answ = "OK"; } } return answ; } /// /// Restituisce il contapezzi salvato per la macchina /// /// /// public int pzCounter(string idxMacchina) { int answ = -1; string rCall = ""; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("getCounter"); try { rCall = cMemLayer.getRSV(pzCountHash(idxMacchina)); if (rCall != "" && rCall != null) { int.TryParse(rCall, out answ); } else { answ = pzCounterTC(idxMacchina); // salvo in redis... saveCounter(idxMacchina, answ.ToString()); } } catch { } } return answ; } /// /// Restituisce il contapezzi come CONTEGGIO da TCRilevati per la macchina /// /// /// public int pzCounterTC(string idxMacchina) { int answ = -1; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("getCounterTC"); } // variabile x controllo dati recuperati DS_ProdTempi.StatoProdDataTable datiProdAct = null; bool okDatiProd = false; int taSP_ms_ant = cMemLayer.cdvi("taStatoProd_ms_anticipo"); DateTime dataRif = DateTime.Now.AddMilliseconds(-taSP_ms_ant); okDatiProd = getStatoProd(idxMacchina, ref datiProdAct, dataRif); // se NON avesse recuperato --> aspetto taSP_ms_ant e poi RICHIAMO procedura... int maxTry = 3; while (!okDatiProd && maxTry > 0) { Log.Info(string.Format("[pzCounterTC] Impossibile recuperare dati ODL x idxMacchina {0}", idxMacchina), tipoLog.WARNING); // sleep... Thread.Sleep(taSP_ms_ant * 2); // riprovo lettura... okDatiProd = getStatoProd(idxMacchina, ref datiProdAct, dataRif); maxTry--; } // ora proseguo SE ho trovato i dati... if (okDatiProd) { if (datiProdAct != null) { if (datiProdAct.Count > 0) { if (!datiProdAct[0].IsPzTotODLNull()) { // ...a questo punto recupero DAVVERO i dati (o almeno ci provo...) try { // controllo answ = datiProdAct[0].PzTotODL; } catch (Exception exc) { Log.Info(string.Format("[pzCounterTC] Eccezione in recupero PzTotODL x idxMacchina {0}{1}{2}", idxMacchina, Environment.NewLine, exc), tipoLog.EXCEPTION); } } } } } else { Log.Info(string.Format("[pzCounterTC] Dati ODL x idxMacchina {0} non recuperati dopo tentativi reiterati...", idxMacchina), tipoLog.WARNING); } return answ; } /// /// RIMUOVE un PARAMETRO OPZIONALE dall'elenco di quelli salvati /// /// /// /// public bool remOptPar4Machine(string idxMacchina, string taskKey) { bool answ = false; string currHash = optParHash(idxMacchina); try { // leggo task attuali... var currVal = mOptParMacchina(idxMacchina); currVal.Remove(taskKey); cMemLayer.redDelKey(currHash); answ = cMemLayer.redSaveHashDict(currHash, currVal); } catch { } return answ; } /// /// RIMUOVE un task dall'elenco di quelli salvati /// /// /// /// public bool remTask4Machine(string idxMacchina, taskType taskKey) { bool answ = false; string currHash = exeTaskHash(idxMacchina); try { // leggo task attuali... var currTask = mTaskMacchina(idxMacchina); currTask.Remove(taskKey.ToString()); cMemLayer.redDelKey(currHash); answ = cMemLayer.redSaveHashDict(currHash, currTask); Log.Info($"Task REM - idxMacchina: {idxMacchina} | taskKey: {taskKey.ToString()}"); } catch { } return answ; } /// /// Resetta (rileggendo) i dati della macchina /// /// /// public Dictionary resetDatiMacchina(string idxMacchina) { string currHash = dtMaccHash(idxMacchina); // inizio con un bel reset... cMemLayer.redFlushKey(currHash); Dictionary answ = new Dictionary(); DS_applicazione.MSFDDataTable tabMSFD = new DS_applicazione.MSFDDataTable(); // 2018.01.08 SEMPRE senza singleton: instanzio un nuovo oggetto MapoDb MapoDb connDb = new MapoDb(); tabMSFD = connDb.taMSFD.getByIdxMacc(idxMacchina); bool trovato = false; // se ho righe... DS_applicazione.MSFDDataTable tab = new DS_applicazione.MSFDDataTable(); DS_applicazione.MSFDRow rigaMSFD; if (tabMSFD.Rows.Count > 0) { try { rigaMSFD = tabMSFD[0]; trovato = true; } catch { rigaMSFD = tab.NewMSFDRow(); } } else { rigaMSFD = tab.NewMSFDRow(); } if (trovato) { // ora provo a compilare... try { // salvo 1:1 i valori... STATO answ.Add("IdxMicroStato", rigaMSFD.IdxMicroStato.ToString()); answ.Add("IdxStato", rigaMSFD.IdxStato.ToString()); answ.Add("CodArticolo", rigaMSFD.CodArticolo); answ.Add("insEnabled", rigaMSFD.insEnabled.ToString()); answ.Add("sLogEnabled", rigaMSFD.sLogEnabled.ToString()); answ.Add("pallet", rigaMSFD.pallet); answ.Add("CodArticolo_A", rigaMSFD.CodArticolo_A); answ.Add("CodArticolo_B", rigaMSFD.CodArticolo_B); answ.Add("TempoCicloBase", rigaMSFD.TempoCicloBase.ToString()); answ.Add("PzPalletProd", rigaMSFD.PzPalletProd.ToString()); answ.Add("MatrOpr", rigaMSFD.MatrOpr.ToString()); answ.Add("lastVal", rigaMSFD.lastVal); answ.Add("TCBase", rigaMSFD.TempoCicloBase.ToString()); //...e SETUP answ.Add("CodMacc", rigaMSFD.codmacchina); answ.Add("IdxFamIn", rigaMSFD.IdxFamigliaIngresso.ToString()); answ.Add("Multi", rigaMSFD.Multi.ToString()); answ.Add("BitFilt", rigaMSFD.BitFilt.ToString()); answ.Add("MaxVal", rigaMSFD.MaxVal.ToString()); answ.Add("BSR", rigaMSFD.BSR.ToString()); answ.Add("ExplodeBit", rigaMSFD.ExplodeBit.ToString()); answ.Add("NumBit", rigaMSFD.NumBit.ToString()); answ.Add("IdxFamMacc", rigaMSFD.IdxFamiglia.ToString()); answ.Add("simplePallet", rigaMSFD.simplePallet.ToString()); answ.Add("palletChange", rigaMSFD.palletChange.ToString()); } catch (Exception exc) { Log.Info(string.Format("Errore in compilazione dati MSFD:{0}{1}", Environment.NewLine, exc), tipoLog.EXCEPTION); } // cerco dati master/slave... string isMaster = connDb.taM2S.getByMaster(idxMacchina).Count > 0 ? "1" : "0"; string isSlave = connDb.taM2S.getBySlave(idxMacchina).Count > 0 ? "1" : "0"; answ.Add("Master", isMaster); answ.Add("Slave", isSlave); // verifico il timeout che cambia a seconda che sia vero o falso insEnabled... int tOutShort = cMemLayer.cdvi("TmOut.MS.S"); int tOutLong = cMemLayer.cdvi("TmOut.MS.L"); int redDtMacTOut = tOutLong; try { redDtMacTOut = (answ["insEnabled"].ToLower() == "true") ? tOutShort : tOutLong; } catch (Exception exc) { Log.Info($"Eccezione in calcolo timeout dati macchina: idxMacchina{idxMacchina} | TShort: {tOutShort} | TLong {tOutLong}{Environment.NewLine}{exc}"); } // salvo in redis! cMemLayer.redSaveHashDict(currHash, answ, redDtMacTOut); } else { Log.Info("Errore in chiamata stp_MSFD_getMacc (connDb.taMSFD.getByIdxMacc(idxMacchina))"); } return answ; } /// /// Effettua reset microstato macchina /// /// public void resetMicrostatoMacchina(string idxMacchina) { // salvo microstato 0... DateTime dtEve = DateTime.Now; MapoDbObj.taMSM.updateQuery(0, dtEve, "FER", idxMacchina); // reset in redis resetDatiMacchina(idxMacchina); } /// /// Resetta (rileggendo) i dati della State Machine multi ingressi nel formato /// key: IdxMacchina /// value: IdxFamigliaIngresso /// /// /// public KeyValuePair[] resetMSMI(string idxMacchina) { string currHash = hMSMI(idxMacchina); DS_applicazione.MSFDDataTable tabMSMI = new DS_applicazione.MSFDDataTable(); // 2017.09.13: inserisco gestione singleton condizionale if (cMemLayer.CRB("disable_singleton")) { // instanzio un nuovo oggetto MapoDb MapoDb connDb = new MapoDb(); tabMSMI = connDb.taMSFD.getMulti(idxMacchina); } else { // leggo DB da singleton tabMSMI = MapoDbObj.taMSFD.getMulti(idxMacchina); } KeyValuePair[] answ = new KeyValuePair[tabMSMI.Count]; // salvo tutti i valori StateMachineIngressi... int i = 0; foreach (var item in tabMSMI) { answ[i] = new KeyValuePair(item.IdxMacchina, item.IdxFamigliaIngresso.ToString()); i++; } // verifico il timeout (default 60 sec...) int tOut = (cMemLayer.cdvi("TmOut.MSMI") <= 0) ? 60 : cMemLayer.cdvi("TmOut.MSMI"); // salvo in redis! cMemLayer.redSaveHash(currHash, answ, tOut); return answ; } /// /// Resetta (rileggendo) i dati della State Machine ingressi nel formato /// key: cState_nVal (current MICRO-STATE + "_" + new Value) /// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE) /// /// /// public KeyValuePair[] resetSMI(int idxFamIn) { string currHash = hSMI(idxFamIn); DS_applicazione.TransizioneIngressiDataTable tabSMI = new DS_applicazione.TransizioneIngressiDataTable(); // 2017.09.13: inserisco gestione singleton condizionale if (cMemLayer.CRB("disable_singleton")) { // instanzio un nuovo oggetto MapoDb MapoDb connDb = new MapoDb(); tabSMI = connDb.taTransIngr.getByIdxFamIng(idxFamIn); } else { // leggo DB da singleton tabSMI = MapoDbObj.taTransIngr.getByIdxFamIng(idxFamIn); } KeyValuePair[] answ = new KeyValuePair[tabSMI.Count]; // salvo tutti i valori StateMachineIngressi... int i = 0; string key = ""; string val = ""; foreach (var item in tabSMI) { key = string.Format("{0}_{1}", item.IdxMicroStato, item.ValoreIngresso); val = string.Format("{0}_{1}", item.IdxTipoEvento, item.next_IdxMicroStato); answ[i] = new KeyValuePair(key, val); i++; } // verifico il timeout (default 60 sec...) int tOut = (cMemLayer.cdvi("TmOut.SMI") <= 0) ? 60 : cMemLayer.cdvi("TmOut.SMI"); // salvo in redis! cMemLayer.redSaveHash(currHash, answ, tOut); return answ; } /// /// rigenera la tab diario di bordo x la macchian richiesta nell'intervallo definito /// /// /// /// public void rigeneraDiarioDiBordo(string IdxMacchina, DateTime dataInizio, DateTime dataFine) { // elimino da diario di bordo i valori nell'intervallo... MapoDbObj.taDiario.DeleteByMacchinaPeriodo(IdxMacchina, dataInizio, dataFine); // seleziono le righe eventi interessate e le processo 1 ad 1... DS_applicazione.EventListDataTable tabEventi = MapoDbObj.taEvList.GetByMacchinaPeriodo(IdxMacchina, dataInizio, dataFine); foreach (DS_applicazione.EventListRow rigaEv in tabEventi) { if (rigaEv.IdxTipo <= 12) // è barcode { checkCambiaStatoBatch(tipoInputEvento.barcode, IdxMacchina, rigaEv.InizioStato, rigaEv.IdxTipo, rigaEv.CodArticolo, rigaEv.Value, rigaEv.MatrOpr, rigaEv.pallet); } else // è hw { checkCambiaStatoBatch(tipoInputEvento.hw, IdxMacchina, rigaEv.InizioStato, rigaEv.IdxTipo, rigaEv.CodArticolo, rigaEv.Value, rigaEv.MatrOpr, rigaEv.pallet); } } } /// /// Processa registrazione EVENTO CONTEGGIO PEZZI x una data macchina IOB /// /// Macchina /// Pezzi da registrare /// public string saveCaricoPezzi(string idxMacchina, string qty) { // default: 0, non registrato come cautela... string answ = "0"; // controllo per proseguire if (!string.IsNullOrEmpty(idxMacchina) && !string.IsNullOrEmpty(qty)) { int numPzIncr = -1; int.TryParse(qty, out numPzIncr); // se il conteggio è >= 0 SALVO evento... if (numPzIncr >= 0) { // recupero ODL corrente var currData = currODLRowTab(idxMacchina); // registro evento 120 --> contapezzi in blocco !!!HARD CODED!!! !!!FIXME!!! int idxEvento = 120; // istanziato un NUOVO oggetto x scrivere... scriviRigaEventoBarcode(idxMacchina, idxEvento, currData[0].CodArticolo, qty); } // registro in risposta che è andato tutto bene... ovvero la qty richiesta... answ = qty; } else { string errore = $"Errore: mancano parametri macchina/incremento: idxMacchina {idxMacchina} | qty {qty}"; Log.Info(errore, tipoLog.ERROR); answ = errore; } return answ; } /// /// Processa registrazione EVENTO CONTEGGIO PEZZI x una data macchina IOB /// /// Macchina /// Pezzi da registrare /// public string saveCaricoPezzi(string idxMacchina, string qty, string dtEve = "", string dtCurr = "") { // default: 0, non registrato come cautela... string answ = "0"; // Verifica se evento realtime oppure ho data specificata x processing @dtEve DateTime adesso = DateTime.Now; DateTime dtEvent = adesso; bool rtimeProc = string.IsNullOrEmpty(dtEve); if (!rtimeProc) { dtEvent = GetSrvDtEvent(dtEve, dtCurr); } // controllo per proseguire if (!string.IsNullOrEmpty(idxMacchina) && !string.IsNullOrEmpty(qty)) { int numPzIncr = -1; int.TryParse(qty, out numPzIncr); // se il conteggio è >= 0 SALVO evento... if (numPzIncr >= 0) { string codArt = ""; // recupero ODL ALLA DATA.. da evento a 1 sec dopo DataLayer man = new DataLayer(); var listOdl = man.taODL.getByMacchinaPeriodo(idxMacchina, dtEvent, dtEvent.AddSeconds(1)); if (listOdl != null && listOdl.Count > 0) { codArt = listOdl.FirstOrDefault().CodArticolo; // registro evento 120 --> contapezzi in blocco !!!HARD CODED!!! !!!FIXME!!! int idxEvento = 120; // istanziato un NUOVO oggetto x scrivere... scriviRigaEventoBarcode(idxMacchina, idxEvento, codArt, qty, 0, "", dtEvent, adesso); // registro in risposta che è andato tutto bene... ovvero la qty richiesta... answ = qty; } } } else { string errore = $"Errore: mancano parametri macchina/incremento: idxMacchina {idxMacchina} | qty {qty}"; Log.Info(errore, tipoLog.ERROR); answ = errore; } return answ; } /// /// Processa registrazione di un counter x una data macchina IOB /// /// /// contapezzi /// public string saveCounter(string idxMacchina, string counter) { // registro conteggio impiego chiamate REDIS if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("saveCounter"); } string answ = "0"; // inizio processing vero e proprio INPUT... if (!string.IsNullOrEmpty(idxMacchina)) { if (!string.IsNullOrEmpty(counter)) { int newCounter = -1; int.TryParse(counter, out newCounter); // se il conteggio è >= 0 SALVO come nuovo conteggio... if (newCounter >= 0) { string redKey = pzCountHash(idxMacchina); // verifico SE ci sia chiave in redis (ALTRIMENTI rileggo da DB) string redVal = cMemLayer.getRSV(redKey); if (!string.IsNullOrEmpty(redVal)) { // salvo in Redis nell'area corretta il valore richiesto cMemLayer.setRSV(redKey, counter); // imposto risposta... answ = counter; } else { // rileggo da DB e salvo e poi restituisco questo... int currCount = pzCounterTC(idxMacchina); cMemLayer.setRSV(redKey, currCount.ToString()); // imposto risposta... answ = currCount.ToString(); } } } else { string errore = "Errore: parametro counter vuoto"; Log.Info(errore, tipoLog.ERROR); answ = errore; } } else { string errore = "Errore: parametro macchina vuoto"; Log.Info(errore, tipoLog.ERROR); answ = errore; } return answ; } /// /// Processa registrazione ODL corrente x macchina /// /// /// cod ODL in produzione, se "" --> non c'è... /// public string saveCurrODL(string idxMacchina, string currODL) { if (currODL == null) { throw new ArgumentNullException(nameof(currODL)); } // registro conteggio impiego chiamate REDIS if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("saveCurrODL"); } string answ = ""; // inizio processing vero e proprio INPUT... if (idxMacchina != null && currODL != null) { if (idxMacchina != "" && currODL != "") { int currOdlCacheDur = cMemLayer.CRI("currOdlCacheDur"); // se ODL fosse 0 USO DURATA CACHE 1/4... if (currODL == "0") { currOdlCacheDur = currOdlCacheDur / 4; } cMemLayer.setRSV(currODLHash(idxMacchina), currODL, currOdlCacheDur); // registro in risposta che è andato tutto bene... answ = "OK"; } else { string errore = string.Format("Errore: parametri macchina/currODL vuoti ({0}/{1})", idxMacchina, currODL); Log.Info(errore, tipoLog.ERROR); answ = errore; } } else { string errore = "Errore: mancano parametri macchina/currODL"; Log.Info(errore, tipoLog.ERROR); answ = errore; } return answ; } /// /// salva il segnale di "microstato" /// /// idx macchina /// valore ingresso /// data-ora evento (server) /// sequenza dati inviati /// public void saveSigLog(string idxMacchina, string valore, DateTime dtEve, string contatore) { int cont = 0; try { cont = Convert.ToInt32(contatore); } catch { } // 2017.07.11 se richiesto di NON usare singleton... riporto FUORI la gestione NUOVO oggetto if (cMemLayer.CRB("disable_singleton")) { // 2017.06.09 forzo init x errori "sovrapposizioni" taSigLog = new DS_applicazioneTableAdapters.SignalLogTableAdapter(); } taSigLog.Insert(DateTime.Now, idxMacchina, valore, dtEve, cont); } /// /// scrive una riga di evento nel db /// /// codice macchina /// idx evento /// Codice Articolo /// valore /// matricola operatore /// pallet (vuoto se nd) /// data-ora dell'evento /// data-ora corrente dell'invio /// public inputComandoMapo scriviRigaEvento(string IdxMacchina, int IdxTipo, string CodArticolo, string Value, int MatrOpr, string pallet, DateTime eventTime, DateTime currentTime) { int inserito = 0; // 2017.07.11 se richiesto di NON usare singleton... riporto FUORI la gestione NUOVO oggetto if (cMemLayer.CRB("disable_singleton")) { // 2017.06.09 forzo init x errori "sovrapposizioni" MapoDbObj.taEvList = new DS_applicazioneTableAdapters.EventListTableAdapter(); } try { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); // calcolo dataOra reale (evento + delta(ora server - ora remota) DateTime dataOra = eventTime.Add(DateTime.Now - currentTime); // inserisco evento inserito = MapoDbObj.taEvList.Insert(IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, MatrOpr, pallet); // faccio controllo per eventuale cambio stato da tab transizioni... checkCambiaStatoBatch(tipoInputEvento.hw, IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, MatrOpr, pallet); } catch (Exception exc) { Log.Info(string.Format("Errore in fase di scrittura evento con i seguenti dati:{0} macchina {1}{0} IdxTipo {2}{0} CodArticolo {3}{0} Value {4}{0} MatrOpr {5}{0} Pallet {6}{0} eventTime {7}{0} currentTime {8}{0} eccezione: {0}{9}", Environment.NewLine, IdxMacchina, IdxTipo, CodArticolo, Value, MatrOpr, pallet, eventTime, currentTime, exc), tipoLog.EXCEPTION); } // formatto output inputComandoMapo answ = new inputComandoMapo(); answ.outValue = inserito.ToString(); answ.needStatusRefresh = true; return answ; } /// /// scrive una riga di evento nel db /// /// codice macchina /// idx evento /// Codice Articolo /// valore /// matricola operatore /// pallet (vuoto se nd) /// public inputComandoMapo scriviRigaEvento(string IdxMacchina, int IdxTipo, string CodArticolo, string Value, int MatrOpr, string pallet) { int inserito = 0; // 2017.06.09 forzo init x errori "sovrapposizioni" MapoDbObj.taEvList = new DS_applicazioneTableAdapters.EventListTableAdapter(); try { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); DateTime dataOra = DateTime.Now; // inserisco evento inserito = MapoDbObj.taEvList.Insert(IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, MatrOpr, pallet); // faccio controllo per eventuale cambio stato da tab transizioni... checkCambiaStatoBatch(tipoInputEvento.hw, IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, MatrOpr, pallet); } catch (Exception exc) { Log.Info(string.Format("Errore in fase di scrittura evento con i seguenti dati:{0} macchina {1}{0} IdxTipo {2}{0} CodArticolo {3}{0} Value {4}{0} MatrOpr {5}{0} Pallet {6}{0} eccezione:{0}{7}", Environment.NewLine, IdxMacchina, IdxTipo, CodArticolo, Value, MatrOpr, pallet, exc), tipoLog.EXCEPTION); } // formatto output inputComandoMapo answ = new inputComandoMapo(); answ.outValue = inserito.ToString(); answ.needStatusRefresh = true; return answ; } /// /// scrive una riga di evento nel db SENZA passare operatore e pallet (mette a 0 e "-") /// /// codice macchina /// idx evento /// Codice Articolo /// valore /// public inputComandoMapo scriviRigaEvento(string IdxMacchina, int IdxTipo, string CodArticolo, string Value) { int inserito = 0; try { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); DateTime dataOra = DateTime.Now; // inserisco evento inserito = MapoDbObj.taEvList.Insert(IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, 0, "-"); // faccio controllo per eventuale cambio stato da tab transizioni... checkCambiaStatoBatch(tipoInputEvento.hw, IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, 0, "-"); } catch { Log.Info(string.Format("Errore in fase di scrittura evento con i seguenti dati:{0} macchina {1}{0} IdxTipo {2}{0} CodArticolo {3}{0} Value {4}{0} eccezione: {0}{5}", Environment.NewLine, IdxMacchina, IdxTipo, CodArticolo, Value), tipoLog.EXCEPTION); } // formatto output inputComandoMapo answ = new inputComandoMapo(); answ.outValue = inserito.ToString(); answ.needStatusRefresh = true; return answ; } /// /// scrive una riga di evento inviato da Barcode nel db /// /// codice macchina /// idx evento /// Codice Articolo /// valore /// matricola operatore /// pallet (vuoto se nd) /// data-ora dell'evento /// data-ora corrente dell'invio /// public inputComandoMapo scriviRigaEventoBarcode(string IdxMacchina, int IdxTipo, string CodArticolo, string Value, int MatrOpr, string pallet, DateTime eventTime, DateTime currentTime) { int inserito = 0; // calcolo dataOra reale (evento + delta(ora server - ora remota) DateTime dataOra = eventTime.Add(DateTime.Now - currentTime); try { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); // inserisco evento inserito = MapoDbObj.taEvList.Insert(IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, MatrOpr, pallet); } catch (Exception exc) { Log.Info(string.Format("Errore in fase di scrittura evento con i seguenti dati:{0} macchina {1}{0} IdxTipo {2}{0} CodArticolo {3}{0} Value {4}{0} MatrOpr {5}{0} Pallet {6}{0} eventTime {7}{0} currentTime {8}{0} eccezione: {0}{9}", Environment.NewLine, IdxMacchina, IdxTipo, CodArticolo, Value, MatrOpr, pallet, eventTime, currentTime, exc), tipoLog.EXCEPTION); } try { // faccio controllo per eventuale cambio stato da tab transizioni... checkCambiaStatoBatch(tipoInputEvento.barcode, IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, MatrOpr, pallet); } catch (Exception exc) { Log.Info($"Eccezione in checkCambiaStatoBatch(8) | tipoInputEvento: {tipoInputEvento.barcode} | IdxMacchina: {IdxMacchina} | dataOra: {dataOra} | IdxTipo: {IdxTipo} | CodArticolo: {CodArticolo} | Value: {Value} | MatrOpr: {MatrOpr} | pallet: {pallet}{Environment.NewLine}{exc}"); } // formatto output inputComandoMapo answ = new inputComandoMapo(); answ.outValue = inserito.ToString(); answ.needStatusRefresh = true; return answ; } /// /// scrive una riga di evento inviato da Barcode nel db /// /// codice macchina /// idx evento /// Codice Articolo /// valore /// matricola operatore /// pallet (vuoto se nd) /// public inputComandoMapo scriviRigaEventoBarcode(string IdxMacchina, int IdxTipo, string CodArticolo, string Value, int MatrOpr, string pallet) { int inserito = 0; DateTime dataOra = DateTime.Now; try { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); // inserisco evento inserito = MapoDbObj.taEvList.Insert(IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, MatrOpr, pallet); } catch (Exception exc) { Log.Info(string.Format("Errore in fase di scrittura evento con i seguenti dati:{0} macchina {1}{0} IdxTipo {2}{0} CodArticolo {3}{0} Value {4}{0} MatrOpr {5}{0} Pallet {6}{0} eccezione: {0}{7}", Environment.NewLine, IdxMacchina, IdxTipo, CodArticolo, Value, MatrOpr, pallet, exc), tipoLog.EXCEPTION); } try { // faccio controllo per eventuale cambio stato da tab transizioni... checkCambiaStatoBatch(tipoInputEvento.barcode, IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, MatrOpr, pallet); } catch (Exception exc) { Log.Info($"Eccezione in checkCambiaStatoBatch(6) | tipoInputEvento: {tipoInputEvento.barcode} | IdxMacchina: {IdxMacchina} | dataOra: {dataOra} | IdxTipo: {IdxTipo} | CodArticolo: {CodArticolo} | Value: {Value} | MatrOpr: {MatrOpr} | pallet: {pallet}{Environment.NewLine}{exc}"); } // formatto output inputComandoMapo answ = new inputComandoMapo(); answ.outValue = inserito.ToString(); answ.needStatusRefresh = true; return answ; } /// /// scrive una riga di evento inviato da Barcode nel db SENZA operatore e pallet (mette a 0 /// e "-") /// /// codice macchina /// idx evento /// Codice Articolo /// valore /// public inputComandoMapo scriviRigaEventoBarcode(string IdxMacchina, int IdxTipo, string CodArticolo, string Value) { int inserito = 0; DateTime dataOra = DateTime.Now; try { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); // inserisco evento inserito = MapoDbObj.taEvList.Insert(IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, 0, "-"); } catch { Log.Info(string.Format("Errore in fase di scrittura evento con i seguenti dati:{0} macchina {1}{0} IdxTipo {2}{0} CodArticolo {3}{0} Value {4}{0} eccezione: {0}{5}", Environment.NewLine, IdxMacchina, IdxTipo, CodArticolo, Value), tipoLog.EXCEPTION); } try { // faccio controllo per eventuale cambio stato da tab transizioni... checkCambiaStatoBatch(tipoInputEvento.barcode, IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, 0, "-"); } catch (Exception exc) { Log.Info($"Eccezione in checkCambiaStatoBatch(4) | tipoInputEvento: {tipoInputEvento.barcode} | IdxMacchina: {IdxMacchina} | dataOra: {dataOra} | IdxTipo: {IdxTipo} | CodArticolo: {CodArticolo} | Value: {Value} | MatrOpr: 0 | pallet: -{Environment.NewLine}{exc}"); } // formatto output inputComandoMapo answ = new inputComandoMapo(); answ.outValue = inserito.ToString(); answ.needStatusRefresh = true; return answ; } public int scriviRigaEventoSimulata(DateTime dataOra, string IdxMacchina, int IdxTipo, string CodArticolo, string Value, int MatrOpr, string pallet) { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); // inserisco evento int inserito = MapoDbObj.taEvList.Insert(IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, MatrOpr, pallet); return inserito; } public int scriviRigaEventoSimulata(DateTime dataOra, string IdxMacchina, int IdxTipo, string CodArticolo, string Value) { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); // inserisco evento int inserito = MapoDbObj.taEvList.Insert(IdxMacchina, dataOra, IdxTipo, CodArticolo, Value, 0, "-"); return inserito; } /// /// scrive una riga di stato nel diario di bordo /// /// codice macchina /// idx stato /// Codice Articolo /// valore /// matricola operatore /// pallet (vuoto se nd) /// data-ora dell'evento /// data-ora corrente dell'invio /// public inputComandoMapo scriviRigaStato(string IdxMacchina, int IdxStato, string CodArticolo, string Value, int MatrOpr, string pallet, DateTime eventTime, DateTime currentTime) { int inserito = 0; try { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); // calcolo dataOra reale (evento + delta(ora server - ora remota) DateTime dataOra = eventTime.Add(DateTime.Now - currentTime); // inserisco la nuova riga di stato mentre il trigger aggiorna le tab... inserito = MapoDbObj.taDiario.Insert(IdxMacchina, dataOra, null, IdxStato, null, Value, CodArticolo, null, null, MatrOpr, pallet); } catch { Log.Info(string.Format("Errore in fase di scrittura stato con i seguenti dati:{0} macchina {1}{0} IdxStato {2}{0} CodArticolo {3}{0} Value {4}{0} MatrOpr {5}{0} Pallet {6}{0} eventTime {7}{0} currentTime {8}{0} eccezione: {0}{9}", Environment.NewLine, IdxMacchina, IdxStato, CodArticolo, Value, MatrOpr, pallet, eventTime, currentTime), tipoLog.EXCEPTION); } // formatto output inputComandoMapo answ = new inputComandoMapo(); answ.outValue = inserito.ToString(); answ.needStatusRefresh = true; return answ; } public int scriviRigaStatoSimulata(DateTime dataOra, string IdxMacchina, int IdxStato, string CodArticolo, string Value, int MatrOpr, string pallet) { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); // inserisco la nuova riga di stato mentre il trigger aggiorna le tab... int inserito = MapoDbObj.taDiario.Insert(IdxMacchina, dataOra, null, IdxStato, null, Value, CodArticolo, null, null, MatrOpr, pallet); return inserito; } public int scriviRigaStatoSimulata(DateTime dataOra, string IdxMacchina, int IdxStato, string CodArticolo, string Value) { // verifico se esista la macchina altrimenti la creo... verificaIdxMacchina(IdxMacchina); // inserisco la nuova riga di stato mentre il trigger aggiorna le tab... int inserito = MapoDbObj.taDiario.Insert(IdxMacchina, dataOra, null, IdxStato, null, Value, CodArticolo, null, null, 0, "-"); return inserito; } /// /// Invia una mail al destinatario con oggetto e contenuto /// /// /// /// /// public bool sendEmail(string destinatario, string oggetto, string corpo) { bool fatto = false; try { // compongo la stringa string mittente = cMemLayer.CRS("_fromEmail"); gestEmail.geAuth.mandaEmail(mittente, destinatario, oggetto, corpo); fatto = true; } catch (Exception exc) { Log.Info($"Eccezione in sendEmail{Environment.NewLine}{exc}", tipoLog.ERROR); } return fatto; } /// /// invia una mail al destinatario x linkare nuovi devices tramite URL /// /// /// /// /// public bool sendUserAuthEmail(string destinatario, string UserAuthKey, int idxDipendente) { bool fatto = false; string smtpCli = ""; string mittente = ""; string oggetto = ""; string userUrl = ""; string baseUrl = ""; string userWebUrl = ""; string baseWebUrl = ""; string corpo = ""; try { // compongo la stringa smtpCli = cMemLayer.CRS("_smtpCli"); mittente = cMemLayer.CRS("_fromEmail"); oggetto = "Link autorizzazione device per GPW"; baseUrl = cMemLayer.CRS("baseUrl"); baseWebUrl = cMemLayer.CRS("baseWebUrl"); userUrl = string.Format("{2}jumper.aspx?UserAuthkey={0}&idxDipendente={1}", UserAuthKey, idxDipendente, baseUrl); userWebUrl = string.Format("{2}jumper.aspx?UserAuthkey={0}&idxDipendente={1}", UserAuthKey, idxDipendente, baseWebUrl); corpo = string.Format("Hai ricevuto questa email su richiesta tua o dell'Admin per poter procedere a registrare un (nuovo) devices con GPW:{0}
Per proseguire clicca sul link seguente(rete interna):
{0}{0}{1}{0}{0}

oppure sul link seguente (internet):
{0}{0}{2}{0}{0}

Team GPW Steamware", Environment.NewLine, userUrl, userWebUrl); gestEmail.geAuth.mandaEmail(mittente, destinatario, oggetto, corpo); fatto = true; } catch { } return fatto; } /// /// Invia email di avviso che ci sono dei TC da confermare /// /// /// public bool sendWarnTcChangeReq(string destinatario) { bool fatto = false; string mittente = ""; string oggetto = ""; string pageUrl = ""; string corpo = ""; try { // compongo la stringa mittente = cMemLayer.CRS("_fromEmail"); oggetto = cMemLayer.CRS("oggettoChgTc"); pageUrl = string.Format("{0}{1}", cMemLayer.CRS("baseUrlAdmin"), cMemLayer.CRS("pageUrlApprODL")); corpo = string.Format(cMemLayer.CRS("corpoChgTc"), Environment.NewLine, pageUrl); if (cMemLayer.CRB("_useAuthSmtp")) { gestEmail.geAuth.mandaEmail(mittente, destinatario, oggetto, corpo); } else { gestEmail.ge.mandaEmail(mittente, destinatario, oggetto, corpo); } fatto = true; } catch { } return fatto; } /// /// SET elenco parametri correnti x IOB /// /// /// /// public bool setCurrObjItems(string idxMacchina, List currValues) { bool answ = false; if (currValues != null) { string serVal = JsonConvert.SerializeObject(currValues); cMemLayer.setRSV(currParametersHash(idxMacchina), serVal); // controllo se ha valori write... foreach (var item in currValues) { // se fosse un valore WRITE e mi ha dato un valore vuoto --> mando un fix x riscrittura if (item.writable && (string.IsNullOrEmpty(item.value) || string.IsNullOrEmpty(item.reqValue))) { Log.Info($"setCurrObjItems | parametro empty | {item.uid} | Value: {item.value} | reqVal: {item.reqValue}"); // se è un parametro dei "task principali... try { taskType currTask = (taskType)Enum.Parse(typeof(taskType), item.uid); string newVal = !string.IsNullOrEmpty(item.reqValue) ? item.reqValue : $"{item.value}"; addCheckTask4Machine(idxMacchina, currTask, newVal); } catch (Exception exc) { Log.Info($"Eccezione in setCurrObjItems in fase di riaccodamento{Environment.NewLine}{exc}"); } } } answ = true; } return answ; } public bool setDerogaSt(StCheckOverride deroga) { bool fatto = false; try { string keyDerogaST = cMemLayer.redHash($"DerogaSt:{user_std.UtSn.utente}:{deroga.IdxST:000}"); string rawData = JsonConvert.SerializeObject(deroga); cMemLayer.setRSV(keyDerogaST, rawData, 60 * 2); fatto = true; } catch { } return fatto; } /// /// Salvataggio YAML completo di configurazione dell'IOB /// /// /// /// public bool setIobConfYaml(string idxMacchina, string iobConfFull) { bool answ = false; // se ho un area memoria valida... if (!string.IsNullOrEmpty(iobConfFull)) { // salvo! cMemLayer.setRSV(ConfYamlHash(idxMacchina), iobConfFull); } return answ; } /// /// Salvataggio della mappa di memoria dell'IOB x ulteriori impieghi /// /// /// /// public bool setIobMemMap(string idxMacchina, plcMemMap currMemMap) { bool answ = false; // se ho un area memoria valida... if (currMemMap != null) { // salvo! string serVal = JsonConvert.SerializeObject(currMemMap); cMemLayer.setRSV(memMapHash(idxMacchina), serVal); } return answ; } /// /// Restituisce il valore booleano se la macchina sia abilitata all'inserimento COMPLETO nel /// Signal Log /// /// /// public bool sLogEnab(string idxMacchina) { bool answ = false; if (cMemLayer.CRB("IOB_RedEnab")) { saveCallRec("sLogEnabled"); try { answ = Convert.ToBoolean(mDatiMacchinaVal(idxMacchina, "sLogEnabled")); } catch { } } // ...oppure dritto su DB else { answ = MapoDbObj.sLogEnabled(idxMacchina); } return answ; } /// /// Effettua chiamata DB x snapshot del FluxLog della macchina richiesta (insieme set ultimi dati) /// /// IdxMacchina /// /// Dimensione della finestra temporale da ultimo record indietro x salvare valori /// /// public string takeFlogSnapshot(string id, int windSize) { string answ = "ND"; // instanzio un nuovo oggetto MapoDb MapoDb connDb = new MapoDb(); // scrivo keep alive!!! (se necessario, altrimenti è in cache...) connDb.scriviKeepAlive(id, DateTime.Now); try { // ora chiamo la stored di duplicazione DataLayer DLMan = new DataLayer(); DLMan.taFL.takeSnapshot(id, windSize); answ = "OK"; } catch (Exception exc) { Log.Info($"takeFlogSnapshot:{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } return answ; } /// /// Effettua chiamata DB x snapshot del FluxLog della macchina richiesta (insieme set ultimi dati) /// /// IdxMacchina /// DT start x effettuare snapshot /// DT end x effettuare snapshot /// public string takeFlogSnapshotLast(string id, DateTime dtMin, DateTime dtMax) { string answ = "ND"; // instanzio un nuovo oggetto MapoDb MapoDb connDb = new MapoDb(); // scrivo keep alive!!! (se necessario, altrimenti è in cache...) connDb.scriviKeepAlive(id, DateTime.Now); try { // ora chiamo la stored di duplicazione DataLayer DLMan = new DataLayer(); DLMan.taFL.TakeSnapshotLast(id, dtMin, dtMax); answ = "OK"; } catch (Exception exc) { Log.Info($"TakeSnapshotLast:{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } return answ; } /// /// Aggiornamento parametro per macchina /// /// /// Parametro macchina come definito in file json /// /// public bool updateMachineParameter(string idxMacchina, string Original_uid, string reqValue) { bool answ = false; // recupero items... List dcList = getCurrObjItems(idxMacchina); List list2Update = new List(); // cerco quello da aggiornare objItem trovato = dcList.Find(obj => obj.uid == Original_uid); // se non trova --> crea ed aggiunge... if (trovato == null) { dcList.Add(new objItem() { uid = Original_uid }); trovato = dcList.Find(obj => obj.uid == Original_uid); } // se trovato procedo if (trovato != null) { // aggiorno valore richiesto + dt richiesta trovato.reqValue = reqValue; trovato.lastRequest = DateTime.Now; list2Update.Add(trovato); upsertCurrObjItems(idxMacchina, list2Update); // accodo in task 2 exe la richiesta di processing addTask4Machine(idxMacchina, taskType.setParameter, trovato.uid); // salvo ANCHE il valore di setup ASSOCIATO... taskType currTask = (taskType)Enum.Parse(typeof(taskType), trovato.uid); addTask4Machine(idxMacchina, currTask, reqValue); answ = true; } return answ; } /// /// Effettua UPSERT elenco parametri correnti x IOB (se c'è UPDATE, se manca ADD) /// /// /// /// public bool upsertCurrObjItems(string idxMacchina, List innovations) { bool answ = false; if (innovations != null) { Log.Info($"upsertCurrObjItems | idxMacchina: {idxMacchina} | {innovations.Count} innovations"); // leggo i valori attuali... List actValues = getCurrObjItems(idxMacchina); // per ogni valore passatomi faccio insert o update rispetto elenco valori correnti // in REDIS foreach (var item in actValues) { // cerco nelle innovazioni SE CI SIA il valore... objItem trovato = innovations.Find(obj => obj.uid == item.uid); // se non trovato nelle innovazioni... if (trovato == null) { // lo ri-aggiungo x non perderlo innovations.Add(item); Log.Trace($"innovations | add | item.uid: {item.uid} | item.value: {item.value}"); } else // altrimenti aggiorno campo (non trasmesso) name e tengo il resto... { trovato.name = item.name; Log.Info($"innovations | update | item.uid: {item.uid} | item.value: {item.value} --> {trovato.value} "); } } // serializzo e salvo string serVal = JsonConvert.SerializeObject(innovations); cMemLayer.setRSV(currParametersHash(idxMacchina), serVal); } return answ; } /// /// Restituisce il valore SPECIFICATO per la state machine ingressi /// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE) /// /// /// /// /// public string valoreSMI(int idxFamIn, int idxMicroStato, int valoreIn) { string currHash = hSMI(idxFamIn); string field = string.Format("{0}_{1}", idxMicroStato, valoreIn); return cMemLayer.redGetHashField(currHash, field); } #endregion Public Methods #region Protected Fields /// /// indica conferma con rettifica (evento 121) /// protected bool confRett = false; #endregion Protected Fields #region Protected Methods /// /// init dei table adapters /// protected void initTA() { // istanzio oggetto taAG = new DS_applicazioneTableAdapters.AnagraficaGruppiTableAdapter(); taAlarmLog = new DS_applicazioneTableAdapters.AlarmLogTableAdapter(); taAnagArt = new DS_ProdTempiTableAdapters.AnagArticoliTableAdapter(); taAnagEventi = new DS_applicazioneTableAdapters.AnagraficaEventiTableAdapter(); taAnagStati = new DS_applicazioneTableAdapters.AnagraficaStatiTableAdapter(); taAnagTags = new DS_applicazioneTableAdapters.AnagTagsTableAdapter(); taAs400 = new DS_IntServTableAdapters.ProduzioneAs400TableAdapter(); taArcaGiac = new DS_ArcaTableAdapters.GiacenzeTableAdapter(); taDecNA = new DS_applicazioneTableAdapters.DecNumArticoliTableAdapter(); taCalFF = new DS_ProdTempiTableAdapters.CalendFesteFerieTableAdapter(); taComm = new DS_UtilityTableAdapters.CommentiTableAdapter(); taConfFlux = new DS_DossParTableAdapters.ConfFluxTableAdapter(); taConfig = new DS_UtilityTableAdapters.ConfigTableAdapter(); taDatiConf = new DS_ProdTempiTableAdapters.DatiConfermatiTableAdapter(); taDatiMacchine = new DS_ProdTempiTableAdapters.DatiMacchineTableAdapter(); taDatiProd = new DS_ProdTempiTableAdapters.DatiProduzioneTableAdapter(); taDatiProdMacch = new DS_ProdTempiTableAdapters.stp_repDonati_getDatiProdMacchinaTableAdapter(); taDatiProdMacchPer = new DS_ProdTempiTableAdapters.stp_repDonati_getDatiProdMacchinaPeriodoTableAdapter(); taDatiStatoMacch = new DS_ProdTempiTableAdapters.stp_repDonati_getLastStatoDurataMacchinaTableAdapter(); taDiarioDich = new DS_applicazioneTableAdapters.DiarioDichiarazioniTableAdapter(); taDOSS = new DS_DossParTableAdapters.DossiersTableAdapter(); taEventi = new DS_applicazioneTableAdapters.EventListTableAdapter(); taFL = new DS_applicazioneTableAdapters.FluxLogTableAdapter(); taIS_TrDati = new DS_IntServTableAdapters.TransitoDatiTableAdapter(); taIstK = new DS_IntServTableAdapters.IstanzeKITTableAdapter(); taKeepAlive = new DS_applicazioneTableAdapters.KeepAliveTableAdapter(); taListVal = new DS_UtilityTableAdapters.v_selListValTableAdapter(); taM2S = new DS_ProdTempiTableAdapters.Macchine2SlaveTableAdapter(); taMacchine = new DS_applicazioneTableAdapters.MacchineTableAdapter(); taMacParams = new DS_PlanTableAdapters.MachineParamsTableAdapter(); taMagELotti = new DS_MAGTableAdapters.ElencoLottiTableAdapter(); taMSE = new DS_ProdTempiTableAdapters.MappaStatoExplTableAdapter(); taODL = new DS_ProdTempiTableAdapters.ODLTableAdapter(); taOp = new DS_applicazioneTableAdapters.AnagraficaOperatoriTableAdapter(); taOp2ins = new DS_applicazioneTableAdapters.AnagraficaOperatori2insTableAdapter(); taPlanCalDisp = new DS_PlanTableAdapters.CalDispTableAdapter(); taPlanCalStop = new DS_PlanTableAdapters.CalStopTableAdapter(); taPlanRichieste = new DS_PlanTableAdapters.RichiesteTableAdapter(); taPODL = new DS_ProdTempiTableAdapters.PromesseODLTableAdapter(); taPostazioni = new DS_ProdTempiTableAdapters.PostazioniMapoTableAdapter(); taPromIn = new DS_PlanTableAdapters.PromesseINTableAdapter(); taPromOut = new DS_PlanTableAdapters.PromesseOUTTableAdapter(); taPzProd2conf = new DS_ProdTempiTableAdapters.stp_PzProd_getByMacchinaTableAdapter(); taRC = new DS_ProdTempiTableAdapters.RegistroControlliTableAdapter(); taRemReb = new DS_applicazioneTableAdapters.RemoteRebootLogTableAdapter(); taRS = new DS_ProdTempiTableAdapters.RegistroScartiTableAdapter(); taSelArt = new DS_UtilityTableAdapters.v_selArticoliTableAdapter(); taSelMacc = new DS_UtilityTableAdapters.v_selMacchineTableAdapter(); taSelOdlFree = new DS_UtilityTableAdapters.v_selODLTableAdapter(); taSigLog = new DS_applicazioneTableAdapters.SignalLogTableAdapter(); taSTA = new DS_SheetTechTableAdapters.ST_ActualTableAdapter(); taSTAR = new DS_SheetTechTableAdapters.ST_ActualRowTableAdapter(); taStati = new DS_applicazioneTableAdapters.DiarioDiBordoTableAdapter(); taStatoMacchine = new DS_applicazioneTableAdapters.StatoMacchineTableAdapter(); taStatoProd = new DS_ProdTempiTableAdapters.StatoProdTableAdapter(); taSTChk = new DS_SheetTechTableAdapters.ST_CheckTableAdapter(); taTempiCicloRilevati = new DS_ProdTempiTableAdapters.TempiCicloRilevatiTableAdapter(); taTempoByClass = new DS_ProdTempiTableAdapters.stp_TempoByIdxMaccPeriodClassTableAdapter(); taTKS = new DS_IntServTableAdapters.TKS_SearchTableAdapter(); taTranIngr = new DS_applicazioneTableAdapters.TransizioneIngressiTableAdapter(); taTurniMacc = new DS_ProdTempiTableAdapters.TurniMacchinaTableAdapter(); taWKS = new DS_IntServTableAdapters.WipSetupKitTableAdapter(); } // cMemLayer.CRB("confRett"); /// /// effettua setup dei connection strings da web.config delal singola applicazione /// protected virtual void setupConnectionStringBase() { string connectionString = cMemLayer.confReadString("MoonProConnectionString"); string connectionStringIS = cMemLayer.confReadString("MoonProConnectionStringIS"); string connectionStringArca = cMemLayer.confReadString("MoonProConnectionStringArca"); string connectionStringES3 = cMemLayer.confReadString("MoonProConnectionStringES3"); string connectionStringFluxData = cMemLayer.confReadString("MoonProConnectionStringFluxData"); string connectionStringMAG = cMemLayer.confReadString("MoonProConnectionStringMAG"); // connections del db taAG.Connection.ConnectionString = connectionString; taAlarmLog.Connection.ConnectionString = connectionString; taAnagArt.Connection.ConnectionString = connectionString; taAnagEventi.Connection.ConnectionString = connectionString; taAnagStati.Connection.ConnectionString = connectionString; taAnagTags.Connection.ConnectionString = connectionString; taAs400.Connection.ConnectionString = connectionStringIS; taArcaGiac.Connection.ConnectionString = connectionStringArca; taDecNA.Connection.ConnectionString = connectionString; taCalFF.Connection.ConnectionString = connectionString; taConfig.Connection.ConnectionString = connectionString; taComm.Connection.ConnectionString = connectionString; taConfFlux.Connection.ConnectionString = connectionStringFluxData; taDatiConf.Connection.ConnectionString = connectionString; taDatiMacchine.Connection.ConnectionString = connectionString; taDatiProd.Connection.ConnectionString = connectionString; taDatiProdMacch.Connection.ConnectionString = connectionString; taDatiProdMacchPer.Connection.ConnectionString = connectionString; taDatiStatoMacch.Connection.ConnectionString = connectionString; taDiarioDich.Connection.ConnectionString = connectionString; taDOSS.Connection.ConnectionString = connectionStringFluxData; taEventi.Connection.ConnectionString = connectionString; taFL.Connection.ConnectionString = connectionStringFluxData; taIS_TrDati.Connection.ConnectionString = connectionStringIS; taIstK.Connection.ConnectionString = connectionStringIS; taKeepAlive.Connection.ConnectionString = connectionString; taListVal.Connection.ConnectionString = connectionString; taM2S.Connection.ConnectionString = connectionString; taMacchine.Connection.ConnectionString = connectionString; taMacParams.Connection.ConnectionString = connectionStringES3; taMagELotti.Connection.ConnectionString = connectionStringMAG; taMSE.Connection.ConnectionString = connectionString; taODL.Connection.ConnectionString = connectionString; taOp.Connection.ConnectionString = connectionString; taOp2ins.Connection.ConnectionString = connectionString; taPlanCalDisp.Connection.ConnectionString = connectionStringES3; taPlanCalStop.Connection.ConnectionString = connectionStringES3; taPlanRichieste.Connection.ConnectionString = connectionStringES3; taPODL.Connection.ConnectionString = connectionString; taPostazioni.Connection.ConnectionString = connectionString; taPromIn.Connection.ConnectionString = connectionStringES3; taPromOut.Connection.ConnectionString = connectionStringES3; taPzProd2conf.Connection.ConnectionString = connectionString; taRC.Connection.ConnectionString = connectionString; taRemReb.Connection.ConnectionString = connectionString; taRS.Connection.ConnectionString = connectionString; taSelArt.Connection.ConnectionString = connectionString; taSelMacc.Connection.ConnectionString = connectionString; taSelOdlFree.Connection.ConnectionString = connectionString; taSigLog.Connection.ConnectionString = connectionString; taSTA.Connection.ConnectionString = connectionString; taSTAR.Connection.ConnectionString = connectionString; taStati.Connection.ConnectionString = connectionString; taStatoMacchine.Connection.ConnectionString = connectionString; taStatoProd.Connection.ConnectionString = connectionString; taSTChk.Connection.ConnectionString = connectionString; taTempiCicloRilevati.Connection.ConnectionString = connectionString; taTempoByClass.Connection.ConnectionString = connectionString; taTKS.Connection.ConnectionString = connectionStringIS; taTranIngr.Connection.ConnectionString = connectionString; taTurniMacc.Connection.ConnectionString = connectionString; taWKS.Connection.ConnectionString = connectionStringIS; } #endregion Protected Methods #region Private Fields private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); /// /// Connessione lazy a redis... /// private Lazy lazyConnection = new Lazy(() => { string RedisConn = cMemLayer.confReadString("RedisConnSPEC"); if (string.IsNullOrEmpty(RedisConn)) { RedisConn = cMemLayer.confReadString("RedisConn"); } if (string.IsNullOrEmpty(RedisConn)) { RedisConn = "localhost,abortConnect=false,ssl=false"; } return ConnectionMultiplexer.Connect(RedisConn); }); /// /// Connessione lazy a redis... /// private Lazy lazyConnectionAdmin = new Lazy(() => { string RedisConnAdmin = cMemLayer.confReadString("RedisConnSPECAdmin"); if (string.IsNullOrEmpty(RedisConnAdmin)) { RedisConnAdmin = cMemLayer.confReadString("RedisConnAdmin"); } if (string.IsNullOrEmpty(RedisConnAdmin)) { RedisConnAdmin = "localhost,abortConnect=false,ssl=false,allowAdmin=true"; } return ConnectionMultiplexer.Connect(RedisConnAdmin); }); #endregion Private Fields #region Private Properties private static memLayer cMemLayer { get; set; } = new memLayer(); #endregion Private Properties #region Private Methods private static T ConvertDataRowToGenericType(DataRow row) where T : class, new() { Type entityType = typeof(T); T objEntity = new T(); foreach (DataColumn column in row.Table.Columns) { object value = row[column.ColumnName]; if (value == DBNull.Value) value = null; PropertyInfo property = entityType.GetProperty(column.ColumnName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public); try { if (property != null && property.CanWrite) property.SetValue(objEntity, value, null); } catch (Exception ex) { throw ex; } } return objEntity; } /// /// registra su REDIS eventuale superamento numero limite di call x il metodo in oggetto /// /// private static void saveCallRec(string callCountKey) { // conto la richiesta nel contatore REDIS long nCall = cMemLayer.setRCntI(mHash($"COUNT:pCall:{callCountKey}")); //... se == nCall2Log scrivo su log e resetto long nCall2Log = cMemLayer.cdvi("nCall2Log"); if (nCall >= nCall2Log) { // loggo Log.Info($"{callCountKey}: {nCall} call received", tipoLog.INFO); // resetto! cMemLayer.resetRCnt(mHash($"COUNT:pCall:{callCountKey}")); } } /// /// verifica se sia necessario inserire un cambio di stato impianto in modalità batch /// /// /// /// /// /// /// /// /// private void checkCambiaStatoBatch(tipoInputEvento tipoInput, string IdxMacchina, DateTime InizioStato, int IdxTipo, string CodArt, string Value, int MatrOpr, string pallet) { int _logLevel = cMemLayer.CRI("_logLevel"); DS_applicazione.TransizioneStatiDataTable tabTransStati; DS_applicazione.TransizioneStatiRow rigaTransStati; switch (tipoInput) { case tipoInputEvento.barcode: // effettuo cambio stato INDIPENDENTEMENTE da stato precedente try { tabTransStati = MapoDbObj.taTranSt.GetUserForcedTransitions(IdxMacchina, IdxTipo); if (tabTransStati != null) { if (tabTransStati.Count > 0) { rigaTransStati = tabTransStati[0]; // solo se cambia stato... if (rigaTransStati.IdxStato != rigaTransStati.next_IdxStato) { MapoDbObj.taDiario.InsStatoBatch(IdxMacchina, InizioStato, rigaTransStati.next_IdxStato, CodArt, Value, MatrOpr, pallet); // aggiorno MSE taMSE.forceRecalc(0, IdxMacchina); } } else { if (_logLevel > 6) { Log.Info($"Non trovata riga per: BARCODE | IdxMacchina: {IdxMacchina} | IdxTipo: {IdxTipo} | CodArt: {CodArt} | Value: {Value} | MatrOpr: {MatrOpr} | pallet: {pallet}", tipoLog.INFO); } } } } catch (Exception exc) { // non dovrebbe succedere... input utente da barcode dovrebbero TUTTI essere // inseriti in tab transizione con famiglia 1... Log.Info($"Errore controllo transizione stato x evento barcode: BARCODE | IdxMacchina: {IdxMacchina} | IdxTipo: {IdxTipo} | CodArt: {CodArt} | Value: {Value} | MatrOpr: {MatrOpr} | pallet: {pallet}{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } break; case tipoInputEvento.hw: // verifico se ci sia necessità di cambio stato try { tabTransStati = MapoDbObj.taTranSt.GetHwTransitions(IdxMacchina, IdxTipo); if (tabTransStati != null) { if (tabTransStati.Count > 0) { rigaTransStati = tabTransStati[0]; if (rigaTransStati != null) { // solo se cambia stato... if (rigaTransStati.IdxStato != rigaTransStati.next_IdxStato) { MapoDbObj.taDiario.InsStatoBatch(IdxMacchina, InizioStato, rigaTransStati.next_IdxStato, CodArt, Value, MatrOpr, pallet); } } } else { if (_logLevel > 6) { Log.Info($"Non trovata riga per: HW | IdxMacchina: {IdxMacchina} | IdxTipo: {IdxTipo} | CodArt: {CodArt} | Value: {Value} | MatrOpr: {MatrOpr} | pallet: {pallet}", tipoLog.INFO); } } } } catch (Exception exc) { // non trovo riga [0]... NON scrivo! Log.Info($"Errore controllo transizione stato x evento barcode: HW | IdxMacchina: {IdxMacchina} | IdxTipo: {IdxTipo} | CodArt: {CodArt} | Value: {Value} | MatrOpr: {MatrOpr} | pallet: {pallet}{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } break; } } private bool doCloseCurrODL(string idxMacchina, bool doConfirm, int qtyConf, DS_ProdTempi.ODLDataTable currODLData, DateTime dtEvento, int matrOpr) { DateTime adesso = DateTime.Now; bool fatto = false; // registro un evento di attrezzaggio (idxTipoEv = 2) PRIMA di chiudere ODL int idxEvento = 2; Log.Info($"Invio evento attrezzaggio x CHIUSURA ODL | idxMacc {idxMacchina} | idxEv {idxEvento} | CodArt {currODLData[0].CodArticolo} | qtyConf {qtyConf}", tipoLog.INFO); // invio un evento x messa in manuale macchina x attrezzaggio in chiusura inputComandoMapo resCmd = scriviRigaEventoBarcode(idxMacchina, idxEvento, currODLData[0].CodArticolo, "ODL-CLOSE-ATTR", 0, "", dtEvento, adesso); if (doConfirm) { // modifico la dataEvento dtEvento.AddMilliseconds(200); // chiamo conferma produzione... try { string chiamata = confRett ? "confermaProdMacchinaFull" : "confermaProdMacchina"; Log.Info($"Chiamata a {chiamata} con parametri | IdxMacchina: {currODLData[0].IdxMacchina} | MatrOpr: {MatrOpr} | dtEvent {dtEvento} | {qtyConf} | modoConf: {cMemLayer.CRI("modoConfProd")}", tipoLog.INFO); string idxMacchinaSel = currODLData[0].IdxMacchina; if (confRett) { // confermo al netto dei pezzi lasciati... fatto = confermaProdMacchinaFull(idxMacchinaSel, cMemLayer.CRI("modoConfProd"), qtyConf, 0, 0, dtEvento, matrOpr); } else { fatto = confermaProdMacchina(idxMacchinaSel, cMemLayer.CRI("modoConfProd"), qtyConf, 0, dtEvento, matrOpr); } if (!fatto) { Log.Info($"ERRORE in chiamata {chiamata}", tipoLog.ERROR); } } catch (Exception exc) { Log.Info($"Eccezione in doCloseCurrODL{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } } dtEvento.AddMilliseconds(200); // chiamo chiusura MapoDbObj.taODL.forceClose(currODLData[0].IdxODL, idxMacchina, dtEvento); // elimino eventuale ODL precedente... string rKey = cMemLayer.redHash($"ODL:{idxMacchina}"); cMemLayer.setRSV(rKey, ""); fatto = true; return fatto; } /// /// sistemazione timeout comandi nei tableadapter /// private void fixCommandTimeout() { int sqlLongCommandTimeout = cMemLayer.CRI("sqlLongCommandTimeout") > 1 ? cMemLayer.CRI("sqlLongCommandTimeout") : 300; SetAllCommandTimeouts(taComm, sqlLongCommandTimeout); } /// /// Recupero dati stato prod da macchina... /// /// /// /// /// private bool getStatoProd(string idxMacchina, ref DS_ProdTempi.StatoProdDataTable datiProdAct, DateTime dataRif) { bool answ = false; try { // recupero con stored NUOVA... //2020.01.31 NUOVO oggetto (NON singleton) DataLayer man = new DataLayer(); datiProdAct = man.taStatoProd.GetData(idxMacchina, dataRif); if (datiProdAct.Rows.Count > 0) { // solo SE ho idxODL (altrimenti loggo errore) if (datiProdAct[0].IdxOdl > 0) { answ = true; } else { // verifico se ho già questo errore attivo IN REDIS (altrimenti reinvio) Log.Info($"pzCounterTC: Non trovato currODL x idxMacchina {idxMacchina} ", $"idxMacchina {idxMacchina} | IdxOdl {datiProdAct[0].IdxOdl} | pzTot {datiProdAct[0].PzTotODL} | dataRif {dataRif}", tipoLog.WARNING); } } else { Log.Info($"pzCounterTC: Non trovate righe in currODL {idxMacchina}", $"Non trovate righe in currODL x idxMacchina {idxMacchina}: datiProdAct vuota", tipoLog.WARNING); } } catch (Exception exc) { Log.Info($"[pzCounterTC] Eccezione in pzCounterTC x idxMacchina {idxMacchina}", $"[pzCounterTC] Eccezione in pzCounterTC x idxMacchina {idxMacchina}{Environment.NewLine}{exc}", tipoLog.EXCEPTION); } return answ; } /// /// Calcola l'effettivo valore da passare alla macchina a stati INGRESSI data conf Macchine2FamigliaIngressi /// /// /// /// private string preProcInput(string idxMacchina, string valore) { string newVal = ""; try { // variabili int valINT = 0; int BitFilt = 0; int BSR = 0; bool ExplodeBit = false; int NumBit = 0; int newValInt = 0; // recupero parametri... int.TryParse(mDatiMacchinaVal(idxMacchina, "BitFilt"), out BitFilt); int.TryParse(mDatiMacchinaVal(idxMacchina, "BSR"), out BSR); Boolean.TryParse(mDatiMacchinaVal(idxMacchina, "ExplodeBit"), out ExplodeBit); int.TryParse(mDatiMacchinaVal(idxMacchina, "NumBit"), out NumBit); // non usato (x ora) // recupero valore valINT = int.Parse(valore, NumberStyles.HexNumber); // filtro newValInt = utility.bMaskInt(valINT, BitFilt); // effettuo eventuale BitShiftRight if (BSR > 0) { newValInt = newValInt >> BSR; } // effettuo eventuale esplosione in BIT esclusivi if (ExplodeBit) { newValInt = Convert.ToInt32(1 << newValInt); } // riconverto a STRING HEX!!! newVal = newValInt.ToString("X"); } catch { newVal = valore; } return newVal; } /// /// Reset cache REDIS dati PODL /// /// private void resetPODLData(int idxPODL) { string rKey = getPOdlRowHash(idxPODL); cMemLayer.setRSV(rKey, "", 1); } private string saveOdlData(string idxMacchina, DS_ProdTempi.ODLDataTable currODLData, DS_ProdTempi.PromesseODLDataTable reqPODLData) { string answ; // recupera ODL macchina var newOdl = currODL(idxMacchina, true); // attendo 1000 msec registro fine ODL (idxTipoEv = 1) int idxEvento = 1; Log.Info($"Invio evento ODL-forced start per macchina {idxMacchina}, evento {idxEvento}, articolo {currODLData[0].CodArticolo}", tipoLog.INFO); var resCmd = scriviRigaEventoBarcode(idxMacchina, idxEvento, currODLData[0].CodArticolo, "ODL-FORCE-START"); // invio eventi setup a macchina.... string setArtVal = $"{currODLData[0].CodArticolo}"; string setPzCommVal = $"{reqPODLData[0].NumPezzi}"; string setCommVal = $"ODL{newOdl}"; if (!string.IsNullOrEmpty(reqPODLData[0].KeyRichiesta)) { setCommVal = $"{reqPODLData[0].KeyRichiesta} ODL{newOdl}"; } try { // invio task caricamento dati ODL addTask4Machine(idxMacchina, taskType.setArt, setArtVal); addTask4Machine(idxMacchina, taskType.setComm, setCommVal); addTask4Machine(idxMacchina, taskType.setPzComm, setPzCommVal); updateMachineParameter(idxMacchina, "setArt", setArtVal); updateMachineParameter(idxMacchina, "setComm", setCommVal); updateMachineParameter(idxMacchina, "setPzComm", setPzCommVal); } catch { } // chiamo refresh MSE taMSE.forceRecalc(0, idxMacchina); // resetto stato macchina... cMemLayer.redDelKey(currStatoMaccHash(idxMacchina)); answ = "OK"; Log.Info($"Effettuato reset e ricalcoli x split ODL per macchina {idxMacchina}", tipoLog.INFO); // se è una master richiamo fix x child... if (isMaster(idxMacchina)) { string ts = ""; string outData = ""; taODL.fixMachineSlave(idxMacchina, 30, 1); // ciclo su ogni slave la gestione reinvio pezzi -->calcolo gli slave... var slaveList = taM2S.getByMaster(idxMacchina); foreach (var machine in slaveList) { // invio chiusura attrezzaggio ts = string.Format("{0:yyMMdd}T{0:HHmmss.fff}Z", DateTime.Now); outData = $"TS:{ts}|MATR:{MatrOpr}|ODL:{newOdl}"; addTask4Machine(machine.IdxMacchinaSlave, taskType.fixStopSetup, outData); // invio task caricamento dati ODL addTask4Machine(machine.IdxMacchinaSlave, taskType.setArt, setArtVal); addTask4Machine(machine.IdxMacchinaSlave, taskType.setComm, setCommVal); addTask4Machine(machine.IdxMacchinaSlave, taskType.setPzComm, setPzCommVal); updateMachineParameter(machine.IdxMacchinaSlave, "setArt", setArtVal); updateMachineParameter(machine.IdxMacchinaSlave, "setComm", setCommVal); updateMachineParameter(machine.IdxMacchinaSlave, "setPzComm", setPzCommVal); } } return answ; } private void SetAllCommandTimeouts(object adapter, int timeout) { var commands = adapter.GetType().InvokeMember( "CommandCollection", BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic, null, adapter, new object[0]); var sqlCommand = (SqlCommand[])commands; foreach (var cmd in sqlCommand) { cmd.CommandTimeout = timeout; } } private void setupConf() { confRett = cMemLayer.CRB("confRett"); } /// /// cerca codice in anagrafica macchine ed eventualmente inserisce nuova macchina /// /// private void verificaIdxMacchina(string IdxMacchina) { bool needDB = false; if (!cMemLayer.CRB("disable_verificaIdxMacchina")) { if (cMemLayer.CRB("IOB_RedEnab")) { try { // esecuzione in REDIS...cerco status macchina... if (mDatiMacchine(IdxMacchina).Count == 0) { needDB = true; } } catch { } } // ...oppure segno richiesta DB... else { needDB = true; } if (needDB) { // 2017.07.11 se richiesto di NON usare singleton... riporto FUORI la gestione // NUOVO oggetto if (cMemLayer.CRB("disable_singleton")) { taMacchine = new DS_applicazioneTableAdapters.MacchineTableAdapter(); MapoDbObj.taMSM = new DS_applicazioneTableAdapters.MicroStatoMacchinaTableAdapter(); } // verifico esistenza macchina if (taMacchine.GetByIdx(IdxMacchina).Rows.Count == 0) { // inserisco nuova macchina... taMacchine.Insert(IdxMacchina, "9999", IdxMacchina, "Macchina non codificata", "-", "http://", "nd", "col", 0, 0); } // verifico ci sia un microstato macchina... if (MapoDbObj.taMSM.getByIdxMacchina(IdxMacchina).Rows.Count == 0) { // inserisco nuovo stato... MapoDbObj.taMSM.Insert(IdxMacchina, 0, DateTime.Now, "00"); } } } } #endregion Private Methods } }