From cfaf57f34f5ad80d4b7292ce22d64521e397cb86 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Mon, 3 Oct 2022 15:55:14 +0200 Subject: [PATCH] UPdate gestione SIM x nuovo val --- MP.MONO.Core/Constants.cs | 3 +- MP.MONO.DECODER/ParamsManager.cs | 1 + MP.MONO.DECODER/Program.cs | 95 +++++++++++++ MP.MONO.DECODER/ToolsManager.cs | 155 +++++++++++++++++++++ MP.MONO.DECODER/lua/CountersDecoder.lua | 4 +- MP.MONO.DECODER/lua/ParamsDecoder.lua | 2 +- MP.MONO.DECODER/lua/ToolsDecoder.lua | 105 ++++++++++++++ MP.MONO.Data/Controllers/MpDbController.cs | 5 +- MP.MONO.SIM/Program.cs | 3 +- MP.MONO.UI/Data/CurrentDataService.cs | 17 ++- 10 files changed, 379 insertions(+), 11 deletions(-) create mode 100644 MP.MONO.DECODER/ToolsManager.cs create mode 100644 MP.MONO.DECODER/lua/ToolsDecoder.lua diff --git a/MP.MONO.Core/Constants.cs b/MP.MONO.Core/Constants.cs index 0941556..4c2e9c6 100644 --- a/MP.MONO.Core/Constants.cs +++ b/MP.MONO.Core/Constants.cs @@ -74,9 +74,10 @@ namespace MP.MONO.Core // REDIS Channels messaggi (verso DECODER) public static readonly string ALARM_RAW_QUEUE = $"AlarmsRawVal"; + public static readonly string COUNT_RAW_QUEUE = $"CountRawVal"; public static readonly string PARAMS_RAW_QUEUE = $"ParamsRawVal"; public static readonly string STATUS_RAW_QUEUE = $"StatusRawVal"; - public static readonly string COUNT_RAW_QUEUE = $"CountRawVal"; + public static readonly string TOOLS_RAW_QUEUE = $"ToolsRawVal"; #endregion Public Fields } diff --git a/MP.MONO.DECODER/ParamsManager.cs b/MP.MONO.DECODER/ParamsManager.cs index cf6b60b..e131fa7 100644 --- a/MP.MONO.DECODER/ParamsManager.cs +++ b/MP.MONO.DECODER/ParamsManager.cs @@ -133,6 +133,7 @@ namespace MP.MONO.DECODER DtRif = adesso, FluxType = item.Key, MachineId = 1, + DataType = Enums.DataLogType.Parameter, ValNum = calcVal, ValStr = $"{calcVal:N3}" diff --git a/MP.MONO.DECODER/Program.cs b/MP.MONO.DECODER/Program.cs index 75ad3aa..88e1832 100644 --- a/MP.MONO.DECODER/Program.cs +++ b/MP.MONO.DECODER/Program.cs @@ -100,6 +100,7 @@ setupConf(); DateTime lastExecParams = DateTime.Now.AddHours(-1); DateTime lastLogDetail = DateTime.Now.AddHours(-1); int numSendParam = 1; +int numSendTools = 1; int numSendMStatus = 1; /* -------------------------------- @@ -126,6 +127,19 @@ DateTime lastExecStatus = DateTime.Now.AddHours(-1); // registro gestione eventi mpStatusRecvPipe.EA_NewMessage += MpStatusRecvPipe_EA_NewMessage; + +/* -------------------------------- + * Setup Gestione Tools + * --------------------------------*/ +ToolsManager toolsMan = new ToolsManager(); +// inizializzo gestione messagePipe da Redis x allarmi +MessagePipe toolsSendPipe = new MessagePipe(redisConn, Constants.TOOLS_M_QUEUE); +MessagePipe toolsRecvPipe = new MessagePipe(redisConn, Constants.TOOLS_RAW_QUEUE); +// datetime dell'inizio esecuzione task... x usare un semaforo di veto doppia esecuzione entro 30 sec +DateTime lastExecTools = DateTime.Now.AddHours(-1); +// registro gestione eventi +toolsRecvPipe.EA_NewMessage += ToolsRecvPipe_EA_NewMessage; + /* -------------------------------- * Setup Gestione Parametri * --------------------------------*/ @@ -535,6 +549,87 @@ void AlarmsValPipe_EA_NewMessage(object? sender, EventArgs e) } } +/// +/// Gestione evento ricezione messaggi tools +/// +void ToolsRecvPipe_EA_NewMessage(object? sender, EventArgs e) +{ + PubSubEventArgs currArgs = (PubSubEventArgs)e; + // conversione on-the-fly Dictionary --> parametri valorizzati (tra quelli configurati) + if (!string.IsNullOrEmpty(currArgs.newMessage)) + { + DateTime adesso = DateTime.Now; + List? redisToolsConf = new List(); + try + { + // verifico codici ricevuti + var toolsList = JsonConvert.DeserializeObject>(currArgs.newMessage); + if (toolsList != null) + { + // recupero elenco parametri salvati in redis... + string rawData = redisDb.StringGet(Constants.TOOLS_CONF_KEY); + if (!string.IsNullOrEmpty(rawData)) + { + redisToolsConf = JsonConvert.DeserializeObject>(rawData); + // se ho i parametri... + if (redisToolsConf != null) + { + // ciclo x ogni valore ricevuto da message service... + foreach (var item in toolsList) + { + // cerco il parametro corrispondente... + var currToolVal = redisToolsConf.FirstOrDefault(x => x.Title == item.Key); + if (currToolVal != null) + { + currToolVal.ValueNum = item.Value; + currToolVal.Value = $"{item.Value.ToString(currToolVal.DisplFormat)}"; + } + } + // verifico NON ci sia veto di scrittura... DbSampleInt (60 sec...) + if (adesso.Subtract(lastExecTools).TotalSeconds > DbSampleInt) + { + lastExecTools = adesso; + if (dbController != null) + { + // verifico x ogni parametro se sia completato il periodo di campionamento... + var val2save = toolsMan.processData(toolsList, redisToolsConf); + if (val2save.Count > 0) + { + // salvo sul DB + _ = dbController.DataLogInsertMany(val2save).Result; + Log.Info($"Tools | DB | {val2save.Count} rec inserted"); + } + } + } + } + } + + // invio sulla message pipeline corretta TUTTI i parametri aggiornati serializzati + string updRawVal = JsonConvert.SerializeObject(redisToolsConf); + toolsSendPipe.saveAndSendMessage(Constants.TOOLS_CURR_KEY, updRawVal); + if (redisToolsConf != null) + { + if (adesso.Subtract(lastLogDetail).TotalSeconds > 5 || numSendTools > 10) + { + Log.Info($"TOOLS | {redisToolsConf.Count} data transmitted x {numSendTools}"); + lastLogDetail = adesso; + numSendTools = 0; + } + else + { + numSendTools++; + } + } + } + } + catch (Exception exc) + { + Log.Error($"Eccezione in ToolsRecvPipe_EA_NewMessage:{Environment.NewLine}{exc}{Environment.NewLine}{currArgs.newMessage}"); + } + } +} + + /// /// Gestione evento ricezione messaggi parametri /// diff --git a/MP.MONO.DECODER/ToolsManager.cs b/MP.MONO.DECODER/ToolsManager.cs new file mode 100644 index 0000000..9b360c6 --- /dev/null +++ b/MP.MONO.DECODER/ToolsManager.cs @@ -0,0 +1,155 @@ +using MP.MONO.Core; +using MP.MONO.Core.DTO; +using MP.MONO.Data.DbModels; +using NLog; +using NLua; + +namespace MP.MONO.DECODER +{ + public class ToolsManager + { + #region Private Fields + + /// + /// Dizionario dei valori accumulati sulle variabili + /// + private Dictionary VarAccumulator = new Dictionary(); + + #endregion Private Fields + + #region Protected Fields + + protected static Logger Log = LogManager.GetCurrentClassLogger(); + protected static string luaPath = ""; + protected static Lua state = new Lua(); + protected List AlarmList = new List(); + + #endregion Protected Fields + + #region Public Fields + + public static string alarmStatus = ""; + public static bool valueChanged = false; + + #endregion Public Fields + + #region Public Constructors + + public ToolsManager() + { + // preparo variabile x avvisare script che il modo è da NLua + state["callMode"] = "NLua"; + state["vcFunct"] = "AVG"; + + // carico il file (derivato da quello dei parametri) + luaPath = Path.Combine(Directory.GetCurrentDirectory(), "lua", "ToolsDecoder.lua"); + state.DoFile(luaPath); + + Log.Info("ToolsManager OK"); + Console.WriteLine("ToolsManager OK"); + } + + #endregion Public Constructors + + #region Public Methods + + /// + /// Funzione chiamata LUA x calcolo degli eventuali parametri con periodi "scaduti" + /// + /// + /// + /// + public List processData(Dictionary paramsList, List redisParamConf) + { + List answ = new List(); + DateTime adesso = DateTime.Now; + + // vado ad "accumulare i dati" a quelli presenti... + foreach (var item in paramsList) + { + var currParam = redisParamConf.FirstOrDefault(x => x.Title == item.Key); + // cerco nelle variabili accomulatori... + if (!VarAccumulator.ContainsKey(item.Key)) + { + if (currParam != null) + { + var dataList = new List(); + dataList.Add(item.Value); + VCData newSet = new VCData() + { + dataArray = dataList, + DTStart = adesso, + Funzione = currParam.VcFunc, + Period = currParam.SamplePeriod + }; + // se non ci fosse creo + VarAccumulator.Add(item.Key, newSet); + } + } + else + { + // altrimenti aggiorno + VarAccumulator[item.Key].dataArray.Add(item.Value); + } + + // effettuo verifiche scadenza + bool calcOk = false; + double calcVal = 0; + if (VarAccumulator.ContainsKey(item.Key)) + { + if (VarAccumulator[item.Key].isElapsed) + { + string funcMode = $"{VarAccumulator[item.Key].Funzione}"; + // se scaduto --> mando a LUA x calcolo + state["valList"] = VarAccumulator[item.Key].dataArray; + state["numRec"] = VarAccumulator[item.Key].dataArray.Count; + state["vcFunct"] = funcMode; + + // effettuo calcolo + state.DoString("doProcess()"); + + // recupero valore calcolato + bool.TryParse(state.GetString("calcOk"), out calcOk); + if (calcOk) + { + try + { + var stringVal = state.GetString("calcVal"); + if (!string.IsNullOrEmpty(stringVal)) + { + calcVal = state.GetNumber("calcVal"); + Log.Trace($"calcVal: {calcVal}"); + } + } + catch (Exception exc) + { + Log.Error($"exception during processData for {item.Key}{Environment.NewLine}{exc}"); + } + } + + // aggiungo alla lista finale... + var dbRecord = new DataLogModel() + { + DtRif = adesso, + FluxType = item.Key, + MachineId = 1, + DataType = Enums.DataLogType.Tools, + ValNum = calcVal, + ValStr = $"{calcVal:N3}" + + }; + answ.Add(dbRecord); + + // elimino dai valori accumulati... + VarAccumulator.Remove(item.Key); + } + } + } + + + return answ; + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/MP.MONO.DECODER/lua/CountersDecoder.lua b/MP.MONO.DECODER/lua/CountersDecoder.lua index b56e76c..8ce917a 100644 --- a/MP.MONO.DECODER/lua/CountersDecoder.lua +++ b/MP.MONO.DECODER/lua/CountersDecoder.lua @@ -1,10 +1,10 @@ --[[--------------------------------------------------- -Procedura calcolo statistiche parametri: +Procedura calcolo statistiche counters (derivato dai parametri): Variabili IN: - vcFunct(string): tipo di processing da effettuare tra [POINT/AVG/MEDIAN/MIN/MAX] - valList(): elenco VALORI double da processare -- numRec(int): conteggio numero recorda da processare +- numRec(int): conteggio numero record da processare Variabili OUT: - calcVal(double): valore calcolato finale diff --git a/MP.MONO.DECODER/lua/ParamsDecoder.lua b/MP.MONO.DECODER/lua/ParamsDecoder.lua index b56e76c..2b76d18 100644 --- a/MP.MONO.DECODER/lua/ParamsDecoder.lua +++ b/MP.MONO.DECODER/lua/ParamsDecoder.lua @@ -4,7 +4,7 @@ Procedura calcolo statistiche parametri: Variabili IN: - vcFunct(string): tipo di processing da effettuare tra [POINT/AVG/MEDIAN/MIN/MAX] - valList(): elenco VALORI double da processare -- numRec(int): conteggio numero recorda da processare +- numRec(int): conteggio numero record da processare Variabili OUT: - calcVal(double): valore calcolato finale diff --git a/MP.MONO.DECODER/lua/ToolsDecoder.lua b/MP.MONO.DECODER/lua/ToolsDecoder.lua new file mode 100644 index 0000000..0296c8d --- /dev/null +++ b/MP.MONO.DECODER/lua/ToolsDecoder.lua @@ -0,0 +1,105 @@ +--[[--------------------------------------------------- +Procedura calcolo statistiche TOOLS: + +Variabili IN: +- vcFunct(string): tipo di processing da effettuare tra [POINT/AVG/MEDIAN/MIN/MAX] +- valList(): elenco VALORI double da processare +- numRec(int): conteggio numero record da processare + +Variabili OUT: +- calcVal(double): valore calcolato finale +-----------------------------------------------------]] + + +-- Per eventuale debug +local ZBS = "c:/ZeroBraneStudio" +if not package.path:find(ZBS,1,true) then + package.path = ZBS .. "/lualibs/?/?.lua;" .. ZBS .. "/lualibs/?.lua;" .. package.path + package.cpath = ZBS .. "/bin/?.dll;" .. ZBS .. "/bin/clibs53/?.dll;" .. package.cpath +end + +-- se non è da NLua inizializzo variabili accessorie +local function checkInit() + if (callMode ~= 'NLua') then + -- imposto valori test + valList = { 4467, 4468, 4467, 4467, 4467, 4467 } + numRec = #valList + --valList = { 4.0, 5.0, 3.0, 6.0, 1.0, 2.0 } + vcFunct = 'AVG' + --POINT AVG MEDIAN MIN MAX + end +end + +local function setupTable() + if numRec > 0 and valList[0] ~= nil then + for i = numRec, 1, -1 do + valListTable[i] = valList[i-1] + end + else + valListTable = valList + end +end + + +local function doCalc() + if(numRec > 0) then + -- verifica il tipo di richiesta + if(vcFunct == 'AVG') then + s = 0 + for i,v in ipairs(valListTable) do + s = s + v + end + calcVal = s / numRec + elseif(vcFunct == 'POINT') then + calcVal = valListTable[numRec] + elseif(vcFunct == 'MEDIAN') then + table.sort(valListTable) + calcVal = valListTable[numRec/2] + elseif(vcFunct == 'MIN') then + table.sort(valListTable) + calcVal = valListTable[1] + elseif(vcFunct == 'MAX') then + table.sort(valListTable) + calcVal = valListTable[numRec] + end + calcOk = true + else + calcVal = -999999 + numRec = 1 + calcOk = false + end +end + +local function displayTestInfo() + if (callMode ~= 'NLua') then + print('------------------------------') + print('calcOk: ' .. tostring(calcOk) .. ' | vcFunct: ' .. vcFunct) + for i,val in pairs(valList) do + print("v_"..i.." | "..val) + end + print('calcVal: ' .. calcVal) + print('------------------------------') + end +end + + +-- MAIN +function doProcess() + -- variabile semaforo callMode (locali o remote da NLua) + callMode = callMode or '' + calcVal = -999 + vcFunct = vcFunct or '' + valList = valList or {} + numRec = numRec or 1 + calcOk = false + valListTable = {} + + checkInit() + setupTable() + doCalc() + displayTestInfo() +end + +if (callMode ~= 'NLua') then + doProcess() +end diff --git a/MP.MONO.Data/Controllers/MpDbController.cs b/MP.MONO.Data/Controllers/MpDbController.cs index eadd62a..e06bc76 100644 --- a/MP.MONO.Data/Controllers/MpDbController.cs +++ b/MP.MONO.Data/Controllers/MpDbController.cs @@ -495,11 +495,12 @@ namespace MP.MONO.Data.Controllers /// Recupero record DataLog data condizione filtro /// /// + /// Tipologia di dato richiesto da enum /// /// /// /// - public List DataLogGetFilt(int machineId, string fluxType, DateTime inizio, DateTime fine) + public List DataLogGetFilt(int machineId, DataLogType dataType, string fluxType, DateTime inizio, DateTime fine) { List dbResult = new List(); using (MapoMonoContext localDbCtx = new MapoMonoContext()) @@ -508,7 +509,7 @@ namespace MP.MONO.Data.Controllers { dbResult = localDbCtx .DbSetDataLog - .Where(x => x.MachineId == machineId && x.FluxType == fluxType && x.DtRif >= inizio && x.DtRif <= fine) + .Where(x => (x.MachineId == machineId) && (x.FluxType == fluxType) && (x.DataType == dataType || dataType == DataLogType.ND) && (x.DtRif >= inizio && x.DtRif <= fine)) .Include(m => m.MachineNav) .OrderByDescending(x => x.DataLogId) .ToList(); diff --git a/MP.MONO.SIM/Program.cs b/MP.MONO.SIM/Program.cs index 97760ce..6fa510f 100644 --- a/MP.MONO.SIM/Program.cs +++ b/MP.MONO.SIM/Program.cs @@ -513,7 +513,8 @@ void simTools() // recupero uno stato simulato var newVal = currSimGen.getTools(); string rawData = JsonConvert.SerializeObject(newVal); - saveAndSendMessage(Constants.TOOLS_CURR_KEY, Constants.TOOLS_M_QUEUE, rawData); + saveAndSendMessage(Constants.TOOLS_CURR_KEY, Constants.TOOLS_RAW_QUEUE, rawData); + //saveAndSendMessage(Constants.TOOLS_CURR_KEY, Constants.TOOLS_M_QUEUE, rawData); // attesa random Thread.Sleep(rand.Next(minPeriod, maxPeriod)); diff --git a/MP.MONO.UI/Data/CurrentDataService.cs b/MP.MONO.UI/Data/CurrentDataService.cs index 4bf970c..42a20fe 100644 --- a/MP.MONO.UI/Data/CurrentDataService.cs +++ b/MP.MONO.UI/Data/CurrentDataService.cs @@ -235,11 +235,20 @@ namespace MP.MONO.UI.Data return await Task.FromResult(dbResult); } - public async Task> DataLogGetFilt(int machineId, string fluxType, DateTime inizio, DateTime fine) + /// + /// TimeSearie in formato DataLogModel + /// + /// ID macchina + /// Tipologia di dato richiesto da enum + /// Tipo di Flusso + /// DT Inizio estrazione + /// DT Fine estrazione + /// + public async Task> DataLogGetFilt(int machineId, DataLogType dataType, string fluxType, DateTime inizio, DateTime fine) { string source = "DB"; List dbResult = new List(); - string currKey = $"{Constants.DATA_LOG_KEY}:{machineId}:{fluxType.Replace(" ", "_")}:{inizio:yyyyMMdd}:{fine:yyyyMMdd}"; + string currKey = $"{Constants.DATA_LOG_KEY}:{machineId}:{dataType}:{fluxType.Replace(" ", "_")}:{inizio:yyyyMMdd}:{fine:yyyyMMdd}"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string rawData = await redisDb.StringGetAsync(currKey); @@ -258,14 +267,14 @@ namespace MP.MONO.UI.Data } else { - dbResult = dbController.DataLogGetFilt(machineId, fluxType, inizio, fine); + dbResult = dbController.DataLogGetFilt(machineId, dataType, fluxType, inizio, fine); // salvo per 2 min... rawData = JsonConvert.SerializeObject(dbResult); await redisDb.StringSetAsync(currKey, rawData, TimeSpan.FromSeconds(120)); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; - Log.Info($"DataLogGetFilt | {machineId} | {fluxType} | {inizio:yyyyMMdd}-{fine:yyyyMMdd} | {source} | {ts.TotalMilliseconds} ms | {rawData.Length / 1024} kb"); + Log.Info($"DataLogGetFilt | {machineId} | {dataType} | {fluxType} | {inizio:yyyyMMdd}-{fine:yyyyMMdd} | {source} | {ts.TotalMilliseconds} ms | {rawData.Length / 1024} kb"); return dbResult; } ///