using Microsoft.AspNetCore.Mvc; using MP.Core.DTO; using MP.Core.Objects; using MP.Data.DbModels; using MP.Data.Services.IOC; using MP.IOC.Data; using Newtonsoft.Json; using NLog; using System.Diagnostics; using System.Reflection; using static MP.Core.Objects.Enums; namespace MP.IOC.Controllers { [Route("api/[controller]")] [ApiController] public class IOBController : ControllerBase { #region Public Constructors public IOBController(IConfiguration configuration, MpDataService DataService, IIocService IService) { _configuration = configuration; DService = DataService; IOCService = IService; } #endregion Public Constructors #region Public Methods /// /// SALVA x macchina KVP parametro/valore: /// GET: api/IOB/addOptPar/SIMUL_03?pName=PZREQ&pValue=1000 /// [HttpGet("addOptPar/{id}")] public async Task AddOptPar(string id, string pName, string pValue) { await DService.ScriviKeepAliveAsync(id, DateTime.Now); try { DService.AddOptPar4Machine(id, pName, pValue); return await GetOptPar(id); } catch { return StatusCode(StatusCodes.Status500InternalServerError, "Errore interno | AddOptPar"); } } [HttpGet("addTask2Exe/{id}")] public async Task AddTask2Exe(string id, string taskName, string taskVal) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { await DService.ScriviKeepAliveAsync(id, DateTime.Now); taskType tName = taskType.nihil; bool isOk = Enum.TryParse(taskName, out tName); if (isOk) { // elimino se trovato + rileggo da REDIS elenco task restanti x macchina... var newList = DService.AddTask4Machine(id, tName, taskVal); answ = JsonConvert.SerializeObject(newList); } } catch (Exception exc) { Log.Error($"Errore in AddTask2Exe{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// GET: IOB/ /// /// [HttpGet] public IActionResult Alive() { return Ok("OK"); // Restituisce Status 200 } /// /// GET: IOB/enabled/SIMUL_03 /// /// /// [HttpGet("enabled/{id}")] public async Task Enabled(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); try { // Il metodo ora restituisce direttamente il booleano logico bool isEnabled = await IOCService.IobInsEnabAsync(id); return isEnabled ? Ok("OK") : UnprocessableEntity("NO"); } catch (Exception ex) { Log.Error(ex, "Errore durante la verifica abilitazione per {Id}", id); return StatusCode(500, "Errore interno del server"); } } /// /// Processa una chiamata POST per l'invio di un array Json di oggetti input (EVENTI) /// POST: IOB/evListJson/SIMUL_03 /// /// ID dell'IOB /// [HttpPost("evListJson/{id}")] public async Task EvListJson(string id, [FromBody] string content = "") { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); string answ = "-"; try { // se ho dati... if (content != "") { answ = await processEvListJsonAsync(id, content); } else { Log.Error($"Errore in EvListJson - no content"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } catch (Exception exc) { Log.Error($"Errore in EvListJson{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Sistema Dossier/Snapshot giornalieri x impianto indicato, andando a generare 1 Dossier /// giornaliero x ogni giornata dall'ultimo registrato alla data corrente /// es: http://url_site/MP/IO/IOB/fixDailyDossier/SIMUL_03 /// /// /// [HttpGet("fixDailyDossier/{id}")] public async Task FixDailyDossier(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { answ = await DService.FixDailyDossierAsync(id); } catch (Exception exc) { Log.Error($"Errore in FixDailyDossier{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Sistema ODL giornalieri x impianto indicato, andando a generare 1 ODL giornaliero x ogni /// giornata dall'ultimo ODL aperto alla data corrente /// es: http://url_site/MP/IO/IOB/fixDailyOdl/SIMUL_03 /// /// /// [HttpGet("fixDailyOdl/{id}")] public async Task FixDailyOdl(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; // chiamo metodo redis/db... try { // recupero ultimo ODL macchina... var lastOdlStarted = await DService.GetLastOdlAsync(id); if (lastOdlStarted != null && lastOdlStarted.DataInizio.HasValue) { // calcolo data ultimo avviato e chiedo dal giorno dopo... DateTime dtFrom = lastOdlStarted.DataInizio.Value.AddDays(1); DateTime dtTo = DateTime.Today; if (dtTo >= dtFrom) { string codArt = lastOdlStarted.CodArticolo; // chiamo la stored x sistemare gli ODL bool fatto = await DService.OdlAutoDayGenAsync(id, dtFrom, dtTo, codArt); answ = fatto ? "OK" : "KO"; } } return Ok(answ); } catch (Exception exc) { Log.Error($"Errore in FixDailyOdl{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } /// /// Sistema ODL giornalieri x impianto indicato, andando a generare 1 ODL giornaliero x ogni /// giornata dall'ultimo ODL aperto alla data corrente + conferma pezzi (es TFT x ODL /// giornalieri energia) /// es: http://url_site/MP/IO/IOB/fixDailyOdlConfPzCount/SIMUL_03 /// /// /// [HttpGet("fixDailyOdlConfPzCount/{id}")] public async Task FixDailyOdlConfPzCount(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; // chiamo metodo redis/db... try { // recupero ultimo ODL macchina... var lastOdlStarted = await DService.GetLastOdlAsync(id); if (lastOdlStarted != null && lastOdlStarted.DataInizio.HasValue) { // calcolo data ultimo avviato e chiedo dal giorno dopo... DateTime dtFrom = lastOdlStarted.DataInizio.Value.AddDays(1); DateTime dtTo = DateTime.Today; if (dtTo >= dtFrom) { string codArt = lastOdlStarted.CodArticolo; // chiamo la stored x sistemare gli ODL bool fatto = await DService.OdlAutoDayGenFullAsync(id, dtFrom, dtTo, codArt, null, null, null, null, null, true, false); answ = fatto ? "OK" : "KO"; } } return Ok(answ); } catch (Exception exc) { Log.Error($"Errore in FixDailyOdlConfPzCount{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } /// /// Invio record flog direttamente via URL GET /// GET: IOB/flog/SIMUL_03?flux=PROG&valore=P0001&dtEve=20161223180600000&dtCurr=20161223180600000&cnt=999&disabKA=false /// /// IdxMacchina /// CodFlux /// Valore da registrare /// DataOra evento (IOB time) /// DataOra corrente (IOB time) /// Contatore eventi (IOB) /// Disabilitazione scrittura record KeepAlive /// [HttpGet("flog/{id}")] public async Task Flog(string id, string flux, string valore, string dtEve, string dtCurr, string cnt = "0", string disabKA = "false") { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; // formato yyyymmddHHMMSSnnn ovvero da anno a millisecondi DateTime dataOraEvento = DateTime.Now; Log.Trace($"Valori letti: id: {id} | flux: {flux} valore: {valore}"); try { int count = 0; Int32.TryParse(cnt, out count); bool disKa = false; bool.TryParse(disabKA, out disKa); answ = await DService.ProcessFluxLogAsync(id, flux, valore, dtEve, dtCurr, count, disKa); return Ok(answ); } catch (Exception exc) { Log.Error($"Errore in flog{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } /// /// Processa una chiamata POST per l'invio di un array Json di oggetti fluxLog /// PUT: IOB/flogJson/SIMUL_03 /// /// ID dell'IOB /// Disabilitazione della scrittura del record KeepAlive /// [HttpPost("flogJson/{id}")] public async Task FlogJson(string id, string disabKA = "false", [FromBody] string content = "") { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); bool disableKa = false; bool.TryParse(disabKA, out disableKa); string answ = "-"; // se ho dati... if (content != "") { answ = await processFLogJsonAsync(id, disableKa, content); return Ok(answ); } else { Log.Error($"Errore in FlogJson - no content"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } [HttpGet("forceSplitOdl/{id}")] public async Task ForceSplitOdl(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { answ = await DService.AutoStartOdlAsync(id, true, true, 100, 0, ""); } catch (Exception exc) { Log.Error($"Errore in ForceSplitOdl{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Chiude ODL precedente ed avvia uno nuovo (duplicandolo e sitemando quantità RIMANENTE), /// e CONFERMA produzione... /// /// GET: IOB/forceSplitOdl/SIMUL_03 /// /// /// Esito chiamata (OK/vuoto) /// /// Recupera ArtNum dato CodXdl (per impianti che accettano solo INT in scrittura): /// GET: IOB/getArtNum/SIMUL_03?CodXdl=ABC123 /// /// IdxMacchina (NON considerato) /// CodXdl richiesto, se vuoto restituisce TUTTI i valori in tabella di decodifica /// Json contenente le righe delle codifiche attive Articolo/Numero [HttpGet("getArtNum/{id}")] public async Task GetArtNum(string id, string CodArt = "") { // in realtà ID macchina non conterebbe... if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { await DService.ScriviKeepAliveAsync(id, DateTime.Now); // leggo da REDIS eventuale elenco task x macchina... Dictionary valori = await DService.GetArtNumAsync(CodArt); answ = JsonConvert.SerializeObject(valori); } catch (Exception exc) { Log.Error($"Errore in GetArtNum{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Recupera COUNTER x macchina: /// GET: IOB/getCounter/SIMUL_03 /// /// /// Il conteggio pezzi o un errore strutturato [HttpGet("getCounter/{id}")] public async Task GetCounter(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); try { var pzCount = await DService.pzCounter(id); return Ok(pzCount); } catch (Exception exc) { Log.Error(exc, "Errore durante il recupero del counter per la macchina {MachineId}", id); return StatusCode(StatusCodes.Status500InternalServerError, "Errore interno | GetCounter"); } } /// /// Recupera COUNTER x macchina dal CONTEGGIO dei TCRecorded: /// /// GET: IOB/getCounterTCRec/5 /// /// /// Il conteggio pezzi o un errore strutturato [HttpGet("getCounterTCRec/{id}")] public async Task GetCounterTCRec(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); try { var pzCount = await IOCService.PzCounterTcAsync(id); //var pzCount = await DService.PzCounterTcAsync(id); return Ok(pzCount); } catch (Exception exc) { Log.Error(exc, "Errore durante il recupero del counter TC per la macchina {MachineId}", id); //return StatusCode(StatusCodes.Status500InternalServerError, "NO"); return StatusCode(StatusCodes.Status500InternalServerError, "Errore interno | GetCounterTCRec"); } } /// /// GET elenco parametri correnti x IOB /// /// /// [HttpGet("getCurrObjItems/{id}")] public async Task GetCurrObjItems(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); var rawData = await DService.MachineParamListAsync(id); List actValues = new List(); // ordino! actValues = rawData .OrderBy(x => x.displOrdinal) .ThenBy(x => x.description) .ToList(); return Ok(actValues); } /// /// Recupera ODL corrente x macchina: /// GET: IOB/getCurrODL/SIMUL_03 /// /// /// [HttpGet("getCurrODL/{id}")] public async Task GetCurrODL(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); try { var odl = await IOCService.GetCurrOdlAsync(id); //var odl = await DService.GetCurrOdlAsync(id); return Ok($"{odl}"); } catch (Exception exc) { Log.Error(exc, "Errore GetCurrODL | macchina {MachineId}", id); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); //return StatusCode(StatusCodes.Status500InternalServerError, "Errore interno | GetCurrODL"); } } /// /// Restituisce la quantità pezzi dell'odl correntemente in lavorazione sulla macchina... /// GET: IOB/getCurrOdlQtaReq/SIMUL_01 /// /// /// [HttpGet("getCurrOdlQtaReq/{id}")] public async Task GetCurrOdlQtaReq(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); int answ = 0; // chiamo metodo redis/db... try { var odlData = await DService.OdlCurrByMaccAsync(id); if (odlData != null && odlData.DataInizio.HasValue) { answ = odlData.NumPezzi; } } catch (Exception exc) { Log.Error($"Eccezione in recupero GetCurrOdlQtaReq{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Restituisce data-ora inizio dell'odl correntemente in lavorazione sulla macchina... /// es: http://url_site/MP/IO/IOB/getCurrOdlStart/SIMUL_03 /// /// /// [HttpGet("getCurrOdlStart/{id}")] public async Task GetCurrOdlStart(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); DateTime answ = new DateTime(DateTime.Now.Year - 1, 12, 31); // chiamo metodo redis/db... try { var odlData = await DService.OdlCurrByMaccAsync(id); if (odlData != null && odlData.DataInizio.HasValue) { answ = odlData.DataInizio.Value; } } catch (Exception exc) { Log.Error($"Eccezione in recupero getCurrOdlStart{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ.ToString("yyyy-MM-dd HH:mm:ss")); } /// /// Restituisce il valore dello stato di IDLE della macchina, quindi SOLO SE NON é in lavoro /// e già convertito in minuti... /// GET: IOB/getIdlePeriod/SIMUL_01 /// /// /// [HttpGet("getIdlePeriod/{id}")] public async Task GetIdlePeriod(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); int answ = 0; // chiamo metodo x avere stato macchina... try { await DService.ScriviKeepAliveAsync(id, DateTime.Now); var mseData = await DService.MseGetAllAsync(); if (mseData.Count > 0) { var currRec = mseData.FirstOrDefault(x => x.IdxMacchina == id); if (currRec != null) { // recupero da redis elenco stati var anagStati = await DService.AnagStatiGetAllAsync(); var currStato = anagStati.FirstOrDefault(x => x.IdxStato == currRec.IdxStato); // calcolo SE sia idle... OVVERO SEMAFORO NON VERDE!!! if (currStato != null && currStato.Semaforo != "sVe") { // calcolo durata... answ = (int)(currRec.Durata ?? 0); } } } } catch (Exception exc) { Log.Error($"Errore in GetIdlePeriod{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Recupera elenco articoli USATI per ultimi: /// - quelli dei PODL correnti /// - quelli degli ultimi n (DOSS_LastArt in config) ODL lavorati /// /// GET: IOB/getArtByMacc /// /// Json contenente lista oggetti ARTICOLI serializzati [HttpGet("getLastArtByMacc/{id}")] public async Task GetLastArtByMacc(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { // recupero dati macchina... var elencoArt = await DService.ArticoliGetLastByMaccAsync(id); answ = JsonConvert.SerializeObject(elencoArt); } catch (Exception exc) { Log.Error($"Errore in GetLastArtByMacc{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Recupera DATI dell'ultimo dossier dato articolo: /// /// GET: IOB/getLastDossArt/cod_articolo /// /// codice articolo, se vuoto --> non fa nulla /// Json contenente lista oggetti DOSSIER serializzati [HttpGet("getLastDossByMacc/{id}")] public async Task GetLastDossByMacc(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { // recupero dati macchina... var elencoDoss = await DService.DossierLastByMachAsync(id); answ = JsonConvert.SerializeObject(elencoDoss); } catch (Exception exc) { Log.Error($"Errore in GetLastDossByMacc{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Recupera elenco ListValues data tabella: /// /// GET: IOB/getListValByTable /// /// nome tabella x cui filtrare risultati, se "" mostra tutto /// Json contenente lista oggetti ListValue serializzati [HttpGet("getListValByTable/{id}")] public async Task GetListValByTable(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { // recupero dati macchina... var elencoOdl = DService.ListValuesFilt(id, ""); answ = JsonConvert.SerializeObject(elencoOdl); } catch (Exception exc) { Log.Error($"Errore in GetListValByTable{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// restituisce elenco parametri correnti come una List Json di oggetti objItem /// GET: IOB/getObjItems/SIMUL_03 /// /// ID dell'IOB /// [HttpGet("getObjItems/{id}")] public async Task GetObjItems(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; // procedo a recuperare l'oggetto... List currParams = new List(); try { // deserializzo var rawData = await DService.MachineParamListAsync(id); currParams = rawData.OrderBy(x => x.displOrdinal) .ThenBy(x => x.description) .ToList(); // se != null --> salvo! if (currParams != null) { answ = JsonConvert.SerializeObject(currParams); } } catch (Exception exc) { Log.Error($"Errore in GetObjItems{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } [HttpGet("getObjItems2Write/{id}")] public async Task GetObjItems2Write(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; // procedo a recuperare l'oggetto... List currParams = new List(); try { // deserializzo currParams = await DService.MachineParamListPendingWriteAsync(id); // se != null --> salvo! if (currParams != null) { answ = JsonConvert.SerializeObject(currParams); } } catch (Exception exc) { Log.Error($"Errore in GetObjItems2Write{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Recupera TASK richiesto x macchina: /// GET: IOB/getOptPar/SIMUL_03 /// /// /// Json contenente 1..n task da eseguire [HttpGet("getOptPar/{id}")] public async Task GetOptPar(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; // scrivo keep alive!!! (se necessario, altrimenti è in cache...) await DService.ScriviKeepAliveAsync(id, DateTime.Now); try { // leggo da REDIS eventuale elenco task x macchina... Dictionary valori = DService.mOptParMacchina(id); answ = JsonConvert.SerializeObject(valori); } catch { } return Ok(answ); } [HttpGet("getPOdlNext/{id}")] public async Task GetPOdlNext(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { // recupero dati macchina... var elencoOdl = await DService.POdlGetByMaccArtAsync(id, "", "", true); answ = JsonConvert.SerializeObject(elencoOdl); } catch (Exception exc) { Log.Error($"Errore in GetPOdlNext{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Recupera i task richiesti per la macchina indicata: /// GET: IOB/getTask2Exe/SIMUL_03 /// /// ID della macchina /// Dictionary contenente i task da eseguire [HttpGet("getTask2Exe/{id}")] public async Task GetTask2Exe(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); id = id.Replace('|', '#'); try { await DService.ScriviKeepAliveAsync(id, DateTime.UtcNow); var valori = await IOCService.GetTask2ExeMacchinaAsync(id); //var valori = await DService.GetTask2ExeMacchinaAsync(id); if (valori == null || valori.Count == 0) return Ok(new Dictionary()); return Ok(valori); } catch (Exception exc) { Log.Error(exc, "Errore nel recupero dei task per la macchina {MachineId}", id); return StatusCode(StatusCodes.Status500InternalServerError, "Errore interno | GetTask2Exe"); } } /// /// Recupera codice numerico ODL/PODL dato CodXdl, in pratica la parte finale SENZA ODL/PODL /// Funzione per impianti che accettano solo INT in scrittura: /// GET: IOB/getXdlNum/SIMUL_03?CodXdl=ODL00000123 /// /// IdxMacchina (NON considerato) /// /// CodXdl richiesto, se vuoto restituisce TUTTI i valori in tabella di decodifica /// /// SINGOLO VALORE calcolato on the fly [HttpGet("getXdlNum/{id}")] public async Task GetXdlNum(string id, string CodXdl = "") { // in realtà ID macchina non conta e lo ignoriamo... string answ = ""; await DService.ScriviKeepAliveAsync(id, DateTime.Now); try { // sostituisco PODL/ODL con "" e lascio zero iniziali (conversione INT in IOB) answ = CodXdl.Replace("PODL", "").Replace("ODL", ""); } catch (Exception exc) { Log.Error($"Errore in GetXdlNum{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Metodo di dichiarazione "improprio" tramite get call totalmetne definita da URL /// GET: IOB/input/SIMUL_03?valore=3&dtEve=20181206180600000&dtCurr=20181206180600000&cnt=999 /// /// /// /// /// /// /// [HttpGet("input/{id}")] public async Task Input(string id, string valore, string dtEve, string dtCurr, string cnt) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); string answ = ""; cnt = string.IsNullOrEmpty(cnt) ? "0" : cnt; try { Stopwatch sw = new Stopwatch(); sw.Start(); answ = await IOCService.ProcessInputAsync(id, valore, dtEve, dtCurr, cnt); //answ = await DService.ProcessInputAsync(id, valore, dtEve, dtCurr, cnt); sw.Stop(); Log.Debug($"Input | elapsed: {sw.Elapsed.TotalMilliseconds:N1} | id: {id} | val: {valore} | cnt: {cnt}"); return Ok(answ); } catch (Exception exc) { Log.Error($"Errore in ProcessInputAsync{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } /// /// AGGIUNGE TASK richiesto x macchina: /// /// GET: IOB/addTask2Exe/3010?taskName=startSetup&taskVal=T190406101512 /// GET: IOB/addTask2Exe/3010?taskName=stopSetup&taskVal=T190406101512 /// GET: IOB/addTask2Exe/SIMUL_03?taskName=setProg&taskVal=P00000001 /// GET: IOB/addTask2Exe/SIMUL_03?taskName=setComm&taskVal=ODL_0000123 /// GET: IOB/addTask2Exe/SIMUL_03?taskName=setArt&taskVal=ART_0000321 /// /// /// /// /// /// ELIMINA TASK richiesto x macchina: /// /// GET: IOB/remTask2Exe/SIMUL_03?taskName=T180326160502 /// /// /// [HttpGet("remTask2Exe/{id}")] public async Task RemTask2Exe(string id, string taskName) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { await DService.ScriviKeepAliveAsync(id, DateTime.Now); taskType tName = taskType.nihil; bool isOk = Enum.TryParse(taskName, out tName); if (isOk) { // elimino se trovato + rileggo da REDIS elenco task restanti x macchina... var newList = await DService.RemTask2ExeMacchinaAsync(id, tName); answ = JsonConvert.SerializeObject(newList); } } catch (Exception exc) { Log.Error($"Errore in GetTask2Exe{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Processa una chiamata POST per l'invio di un array Json di oggetti plcMemConf /// PUT: IOB/saveConf/SIMUL_03 /// /// ID dell'IOB /// [HttpPost("saveConf/{id}")] public async Task SaveConf(string id, [FromBody] string content = "") { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; // procedo a deserializzare in blocco l'oggetto... PlcMemMapDto currMemMap = null; try { // deserializzo. currMemMap = JsonConvert.DeserializeObject(content) ?? new(); // se != null --> salvo! if (currMemMap != null) { bool done = await DService.SetIobMemMap(id, currMemMap); answ = done ? "OK" : "KO"; } } catch (Exception exc) { Log.Error($"Errore in SaveConf{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Processa una chiamata POST per l'invio di un oggetto YAML testuale corrispondente alla configurazione dell'IOB /// PUT: IOB/saveConfYaml/SIMUL_03 /// /// ID dell'IOB /// [HttpPost("saveConfYaml/{id}")] public async Task SaveConfYaml(string id, [FromBody] string content = "") { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { bool done = await DService.SetIobConfYamlAsync(id, content); answ = done ? "OK" : "KO"; } catch (Exception exc) { Log.Error($"Errore in SaveConfYaml{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Processa una chiamata POST per l'invio di un array Json di oggetti di conf DataItems (es /// per MTC) /// PUT: IOB/saveDataItems/SIMUL_03 /// /// ID dell'IOB /// [HttpPost("saveDataItems/{id}")] public async Task SaveDataItems(string id, [FromBody] List dataList) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { bool done = await DService.SaveDataItemsAsync(id, dataList); answ = done ? "OK" : "KO"; } catch (Exception exc) { Log.Error($"Errore in SaveDataItems{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Processa una chiamata POST per l'invio di una Dictionary HashList da salvare in redis /// POST: IOB/saveMachineIobConf/SIMUL_03 /// /// ID dell'IOB /// [HttpPost("saveMachineIobConf/{id}")] public async Task SaveMachineIobConf(string id, [FromBody] Dictionary currDict) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = "NA"; try { bool fatto = await DService.SaveMachineIobConf(id, currDict); answ = fatto ? "OK" : "KO"; } catch (Exception exc) { Log.Error($"Errore in saveMachineIobConf{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// SALVA in blocco un incremento pezzi x macchina restituendo il valore appena inviato o, /// se mancasse chaive redis, del valore da DB /// /// GET: IOB/savePzCountInc/5?qty=10 /// /// codice macchina /// num peziz da salvare in blocco /// [HttpGet("savePzCountInc/{id}")] public async Task SavePzCountInc(string id, string qty) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; DateTime dataOraEvento = DateTime.Now; // salvo SEMPRE log x questo tipo di dati! Log.Info($"Salvataggio incremento contapezzi | id: {id} | pezzi: {qty}"); try { answ = await DService.saveCaricoPezzi(id, qty); return Ok(answ); } catch (Exception exc) { Log.Error($"Errore in savePzCountInc{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } /// /// Registrazione variazione allarmi /// /// GET: IOB/sendAlarmBankUpdate/SIMUL_03?memAddr=SIM_BANK&index=0&currStatus=22 /// /// /// [HttpPost("sendAlarmBankUpdate/{id}")] public async Task SendAlarmBankUpdate(string id, string memAddr, int index, int currStatus, [FromBody] string content = "") { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); // esempio valido x MAPO string answ = ""; Log.Debug($"Richiesta sendAlarmBankUpdate per id {id}"); // procedo a deserializzare in blocco l'oggetto... List ActiveAlarms = new(); try { Log.Info($"Ricevuto payload di {content.Length} chars"); // deserializzo. ActiveAlarms = JsonConvert.DeserializeObject>(content) ?? new List(); // se != null --> salvo! if (ActiveAlarms != null) { string alarmDecoded = "-"; if (ActiveAlarms != null && ActiveAlarms.Count > 0) { alarmDecoded = String.Join(" | ", ActiveAlarms); } await DService.AlarmInsertAsync(DateTime.Now, id, memAddr, index, currStatus, alarmDecoded); answ = "OK"; } } catch (Exception exc) { Log.Error($"Errore in saveMachineIobConf{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Salva MAC adress + IP dopo il reboot /// GET: IOB/sendReboot/SIMUL_05?mac=18:C0:4D:37:3C:8C /// /// ID macchina /// MAC address macchina /// [HttpGet("sendReboot/{id}")] public async Task SendReboot(string id, string mac) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); id = id.Replace("|", "#"); string answ = "NO"; try { // recupero IP del client remoto, se vuoto IOC string agent = Request.Headers["User-Agent"].ToString() ?? "IOC"; agent = string.IsNullOrWhiteSpace(agent) ? "IOC" : agent; var ipv4 = HttpContext.Connection.RemoteIpAddress?.MapToIPv4().ToString(); // chiamo registrazione reboot RemoteRebootLogModel newRec = new() { Agent = agent, DataOraBoot = DateTime.Now, IdxMacchina = id, IPv4 = ipv4, MacAddr = mac }; var success = await DService.RemRebootLogAddAsync(newRec); answ = success ? "OK" : "KO"; if (success) { return Ok(answ); //return Ok(new { status = "ok", id = id }); } else { return BadRequest(new { status = "ko", message = "DB operation failed" }); } } catch (Exception exc) { Log.Error($"Errore in sendReboot{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } /// /// Salva IP del gateway dopo il reboot /// /// IP del Gateway /// [HttpGet("sendRebootGateway/{id}")] public async Task SendRebootGateway(string GWIP) { string answ = "OK"; // !!!FARE!!! deve salvare il riavvio dell'applicazione GATEWAY multiclient return Ok(answ); } /// /// SALVA Counter x macchina restituendo il valore appena inviato o, se mancasse chiave /// redis, valore da DB /// /// GET: IOB/setCounter/5?counter=10 /// /// cod macchina /// contapezzi da salvare /// [HttpGet("setCounter/{id}")] public async Task SetCounter(string id, string counter) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = "-1"; DateTime dataOraEvento = DateTime.Now; Log.Debug($"Salvataggio counter | id: {id} | pzCount: {counter}"); try { answ = await IOCService.SaveCounterAsync(id, counter); //answ = await DService.SaveCounterAsync(id, counter); } catch (Exception exc) { Log.Error($"Errore in SetCounter{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Salva associazione tra macchina, device IOB chiamante e sue info /// /// Id della macchina /// Nome dell'IOB di acquisizione della macchina /// [HttpGet("setM2IOB/{id}")] public async Task SetM2IOB(string id, string IOB_name) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); try { // recupero IP del client remoto var agent = Request.Headers["User-Agent"].ToString(); var IPv4 = HttpContext.Connection.RemoteIpAddress?.ToString(); // creo oggetto IOB_data... IOB_data m2IOB = new IOB_data { name = IOB_name, IP = IPv4, iType = IobType.ND, typeCss = "fa fa-question-circle-o", CNC_Counter = false }; // imposto tipo ed icona come windows/linux secondo UserAgent... if (agent.IndexOf("WIN") >= 0) { m2IOB.iType = IobType.WIN; m2IOB.typeCss = "fa fa-windows"; m2IOB.CNC_Counter = true; } else if (agent.IndexOf("Python") >= 0) { m2IOB.iType = IobType.rPi; m2IOB.typeCss = "fa fa-linux"; } // serializzo... string dataSer = JsonConvert.SerializeObject(m2IOB); // salvo... await DService.SaveMachine2Iob(id, dataSer); // salvo tutto OK return Ok("OK"); } catch (Exception exc) { Log.Error($"Errore in SetM2IOB{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } /// /// Processa una chiamata POST per l'invio di una List Json di oggetti objItem /// POST: IOB/setObjItems/SIMUL_03 /// /// ID dell'IOB /// [HttpPost("setObjItems/{id}")] public async Task SetObjItems(string id, [FromBody] List currParams) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; try { // se != null --> salvo! if (currParams != null) { bool fatto = await DService.MachineParamListSetAsync(id, currParams); answ = fatto ? "OK" : "KO"; } } catch (Exception exc) { Log.Error($"Errore in GetObjItems2Write{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Processa una chiamata GET x salvare UserLog /// GET: IOB/ulog/SIMUL_03?flux=PROG&valore=P0001&dtEve=20161223180600000&dtCurr=20161223180600000&cnt=999&matrOpr=0=0&label=&valNum /// /// /// /// /// /// /// /// /// /// /// [HttpGet("ulog/{id}")] public async Task ULog(string id, string flux, string valore, string dtEve, string dtCurr, string cnt, string matrOpr, string label, string valNum) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = ""; // formato yyyymmddHHMMSSnnn ovvero da anno a millisecondi if (string.IsNullOrEmpty(cnt)) { cnt = "0"; } DateTime dataOraEvento = DateTime.Now; try { int count = 0; int nMatrOpr = 0; int nValNum = 0; Int32.TryParse(cnt, out count); Int32.TryParse(matrOpr, out nMatrOpr); Int32.TryParse(valNum, out nValNum); answ = await DService.ProcessUserLogAsync(id, flux, valore, dtEve, dtCurr, count, nMatrOpr, label, nValNum); return Ok(answ); } catch (Exception exc) { Log.Error($"Errore in ulog{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } /// /// Processa una chiamata POST per l'invio di una List Json 1+ UserAction (contiene /// controlli, scarti, dichiarazioni) /// POST: IOB/ulogJson/SIMUL_03 /// /// ID dell'IOB /// [HttpPost("ulogJson/{id}")] public async Task ulogJson(string id, [FromBody] string content = "") { string answ = "-"; // se ho dati... if (content != "") { answ = await processULogJsonAsync(id, content); return Ok(answ); } else { Log.Error($"Errore in ULogJson - no content"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } /// /// Processa una chiamata POST per l'invio di una List Json di UNO O PIU' oggetti objItem /// POST: IOB/upsertObjItems/SIMUL_03 /// /// ID dell'IOB /// [HttpPost("upsertObjItems/{id}")] public async Task UpsertObjItems(string id, [FromBody] List innovazioni) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); string answ = "NA"; try { // se != null --> salvo! if (innovazioni != null) { // salvo bool fatto = await DService.MachineParamUpsertAsync(id, innovazioni); answ = "OK"; } } catch (Exception exc) { Log.Error($"Errore in upsertObjItems{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } return Ok(answ); } /// /// Verifica versione corrente REST API /// /// [HttpGet("version")] public IActionResult Version() { var version = Assembly .GetExecutingAssembly() .GetName() .Version? .ToString() ?? "unknown"; return Ok(version); } #endregion Public Methods #region Private Fields private static IConfiguration _configuration = null!; private static Logger Log = LogManager.GetCurrentClassLogger(); private IIocService IOCService; #endregion Private Fields #region Private Properties /// /// Dataservice x accesso DB /// private MpDataService DService { get; set; } #endregion Private Properties #region Private Methods /// /// Processing effettivo EvListJson /// /// /// /// private async Task processEvListJsonAsync(string idxMacc, string content) { string answ = ""; int insDone = 0; // procedo a deserializzare in blocco l'oggetto... EvJsonPayloadDto receivedData = JsonConvert.DeserializeObject(content) ?? new(); // se ho qualcosa da processare... if (receivedData != null) { // per ogni valore --> processo! try { foreach (var item in receivedData.eventList) { // formato datetime come yyyyMMddHHmmssfff -->es: 20181223180600000 answ = await DService.ProcessInputAsync(idxMacc, item.valore, item.dtEve.ToString("yyyyMMddHHmmssfff"), item.dtCurr.ToString("yyyyMMddHHmmssfff"), item.cnt.ToString()); insDone++; } // se vuoto --> OK! if (string.IsNullOrEmpty(answ)) { answ = $"OK {insDone} processed"; } } catch (Exception exc) { Log.Error($"Errore in fase invio valori inputJson{Environment.NewLine}{exc}"); answ = "NO"; } } return answ; } /// /// Effettivo processing FLogJson /// /// /// /// /// /// private async Task processFLogJsonAsync(string idxMacc, bool disabKA, string content) { string answ = ""; int insDone = 0; // procedo a deserializzare in blocco l'oggetto... FLogJsonPayloadDto receivedData = new FLogJsonPayloadDto(); try { // deserializzo. receivedData = JsonConvert.DeserializeObject(content) ?? new(); } catch (Exception exc) { Log.Error($"Errore in fase deserializzazione flogJson{Environment.NewLine}{exc}"); answ = "NO"; } // se ho qualcosa da processare... if (receivedData != null) { // per ogni valore --> salvo! try { foreach (var item in receivedData.fluxData) { // formato datetime come yyyyMMddHHmmssfff -->es: 20181223180600000 answ = await DService.ProcessFluxLogAsync(idxMacc, item.flux, item.valore, item.dtEve.ToString("yyyyMMddHHmmssfff"), item.dtCurr.ToString("yyyyMMddHHmmssfff"), item.cnt, disabKA); } // se vuoto --> OK! if (string.IsNullOrEmpty(answ)) { answ = $"OK {insDone} processed"; } } catch (Exception exc) { Log.Error($"Errore in fase invio valori flogJson{Environment.NewLine}{exc}"); answ = "NO"; } // leggo parametri correnti... DateTime adesso = DateTime.Now; try { List currParams = await DService.MachineParamListAsync(idxMacc); // ora per ogni valore RICEVUTO costruisco un oggetto in innovazioni da // inviare...x salvare in stato parametri... List innovazioni = new List(); foreach (var item in receivedData.fluxData) { // flux = uuid del parametro ObjItemDTO? trovato = currParams.Find(obj => obj.uid == item.flux); // se lo trovo aggiorno... if (trovato != null) { // aggiorno valore e data trovato.value = item.valore; trovato.lastRead = adesso; trovato.lastMessage = item.valore; // se fosse un valore WRITE if (trovato.writable) { // ...e mi ha dato un valore vuoto --> mando un fix x riscrittura if (string.IsNullOrEmpty(item.valore)) { Log.Debug($"flogJson | verifica parametri | {trovato.uid} | reqVal: {trovato.reqValue}"); taskType currTask = (taskType)Enum.Parse(typeof(taskType), trovato.uid); DService.AddCheckTask4Machine(idxMacc, currTask, item.valore); } } else { // richiesto 10 sec prima... trovato.lastRequest = adesso.AddSeconds(-10); } } // altrimenti AGGIUNGO (READ ONLY)... else { trovato = new ObjItemDTO { uid = item.flux, name = item.flux, value = item.valore, lastRead = adesso, lastRequest = adesso.AddSeconds(-10), writable = false }; } // lo carico in innovation innovazioni.Add(trovato); } // faccio upsert innovations! await DService.UpsertCurrObjItemsAsync(idxMacc, innovazioni); Log.Info($"processFLogJsonAsync | {idxMacc} | Updated {innovazioni.Count} par"); } catch (Exception exc) { Log.Error($"Errore in fase salvataggio innovazioni parametri correnti da flogJson{Environment.NewLine}{exc}"); answ = "NO"; } } return answ; } /// /// Effettua processing UserLog /// /// /// /// private async Task processULogJsonAsync(string id, string content) { string answ = ""; int insDone = 0; // procedo a deserializzare in blocco l'oggetto... ULogJsonPayloadDto receivedData = new ULogJsonPayloadDto(); try { // deserializzo. receivedData = JsonConvert.DeserializeObject(content) ?? new(); } catch (Exception exc) { Log.Error($"Errore in fase deserializzazione ulogJson{Environment.NewLine}{exc}"); answ = "NO"; } // se ho qualcosa da processare... if (receivedData != null) { // per ogni valore --> salvo! try { foreach (var item in receivedData.fluxData) { // formato datetime come yyyyMMddHHmmssfff -->es: 20181223180600000 answ = await DService.ProcessUserLogAsync(id, item.flux, item.valore, item.dtEve.ToString("yyyyMMddHHmmssfff"), item.dtCurr.ToString("yyyyMMddHHmmssfff"), item.cnt, item.matrOpr, item.label, item.valNum); } // se vuoto --> OK! if (string.IsNullOrEmpty(answ)) { answ = $"OK {insDone} processed"; } } catch (Exception exc) { Log.Error($"Errore in fase invio valori ulogJson{Environment.NewLine}{exc}"); answ = "NO"; } } return answ; } #endregion Private Methods } }