From bb50053fa899d05b0bdd49f8fda987dc06c4a97f Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Mon, 7 Mar 2022 12:06:41 +0100 Subject: [PATCH] OK display sim parameters in HOME --- MP.MONO.Data/Controllers/MpDbController.cs | 27 --- MP.MONO.Data/Controllers/SimController.cs | 179 ++++++++++++++++++ MP.MONO.Data/MessagePipe.cs | 6 +- MP.MONO.UI/Components/AlarmsOverview.razor.cs | 2 +- MP.MONO.UI/Components/CmpTop.razor.cs | 2 +- MP.MONO.UI/Components/ParamOverview.razor | 17 -- MP.MONO.UI/Components/ParamOverview.razor.cs | 60 ++++++ MP.MONO.UI/Data/CurrentDataService.cs | 72 +++++-- MachineSim/Program.cs | 89 +++++---- 9 files changed, 345 insertions(+), 109 deletions(-) create mode 100644 MP.MONO.UI/Components/ParamOverview.razor.cs diff --git a/MP.MONO.Data/Controllers/MpDbController.cs b/MP.MONO.Data/Controllers/MpDbController.cs index 37c7408..111cc1a 100644 --- a/MP.MONO.Data/Controllers/MpDbController.cs +++ b/MP.MONO.Data/Controllers/MpDbController.cs @@ -26,33 +26,6 @@ namespace MP.MONO.Data.Controllers //Log.Info("Dispose di GWMSController"); } - /// - /// Restituisce stato Macchina - /// - /// - public MachineDTO MachineGetStatus() - { - // !!!FIXME TODO... è fake... - - Random rand = new Random(); - int maxRun = 5; - int maxExe = 7; - - MachineDTO currMachDto = new MachineDTO() - { - Manufacturer = "Egalware", - Model = "SIM Machine", - Name = "DEMO 01", - SerNumber = "2022-0001", - Mode = $"{(Enums.MachRunMode)rand.Next(0, maxRun)}", - Status = $"{(Enums.MachExeStatus)rand.Next(0, maxExe)}" - }; - - Task.Delay(200).Wait(); - - return currMachDto; - } - public ProductionDTO MachineGetProd() { // !!!FIXME TODO... è fake... diff --git a/MP.MONO.Data/Controllers/SimController.cs b/MP.MONO.Data/Controllers/SimController.cs index 971e8a4..9e1e1f3 100644 --- a/MP.MONO.Data/Controllers/SimController.cs +++ b/MP.MONO.Data/Controllers/SimController.cs @@ -44,5 +44,184 @@ namespace MP.MONO.Data.Controllers return currMachDto; } + + + public ProductionDTO MachineGetProd() + { + // !!!FIXME TODO... è fake... + + Random rand = new Random(); + int stdCycle = 5; + + ProductionDTO currMachDto = new ProductionDTO() + { + Order = "ODL Test", + ItemCode = "ART.0000123", + ProgName = "P000012", + CurrQty = DateTime.Now.Minute + rand.Next(1, 40), + OrderQty = 100, + CycleTimeMin = rand.NextDouble() * stdCycle, + Message = "...simulated data..." + }; + + Task.Delay(400).Wait(); + + return currMachDto; + } + + public List MachineGetParameters() + { + List answ = new List(); + + // !!!FIXME TODO... è fake... + + Random rand = new Random(); + int stdCycle = 5; + +#if false + var currVal = rand.NextDouble(); + DisplayDataDTO displ01 = new DisplayDataDTO() + { + Order = 0, + Title = "OEE", + ValueNum = currVal, + IsNumeric = true, + Value = currVal.ToString("P1"), + Type = "OEE-75-90" + }; + answ.Add(displ01); + + currVal = rand.NextDouble(); + DisplayDataDTO displ02 = new DisplayDataDTO() + { + Order = 0, + Title = "Avail", + ValueNum = currVal, + IsNumeric = true, + Value = currVal.ToString("P1"), + Type = "AVAIL-50-80" + }; + answ.Add(displ02); + + currVal = rand.NextDouble(); + DisplayDataDTO displ03 = new DisplayDataDTO() + { + Order = 0, + Title = "Order fulfill", + ValueNum = currVal, + IsNumeric = true, + Value = currVal.ToString("P1"), + Type = "ORDER" + }; + answ.Add(displ03); + + double minTCiclo = stdCycle * rand.NextDouble(); + TimeSpan durTCycle = TimeSpan.FromMinutes(minTCiclo); + DisplayDataDTO displ04 = new DisplayDataDTO() + { + Order = 0, + Title = "Cycle time", + ValueNum = 0, + IsNumeric = false, + Value = $"{durTCycle.Hours:00}:{durTCycle.Minutes:00}:{durTCycle.Seconds:00}", + Type = "TCycle" + }; + answ.Add(displ04); +#endif + double currVal = 0; + currVal = rand.Next(10, 120) * 100; + DisplayDataDTO displ01 = new DisplayDataDTO() + { + Order = 0, + Title = "SPEED", + ValueNum = currVal, + IsNumeric = true, + Value = currVal.ToString("N0"), + Type = "SPEED-5000-10000" + }; + answ.Add(displ01); + + currVal = rand.Next(10, 100) * 100; + DisplayDataDTO displ02 = new DisplayDataDTO() + { + Order = 0, + Title = "FEED", + ValueNum = currVal, + IsNumeric = true, + Value = currVal.ToString("N0"), + Type = "FEED-3000-5000" + }; + answ.Add(displ02); + + currVal = rand.NextDouble() * 1.2; + DisplayDataDTO displ03 = new DisplayDataDTO() + { + Order = 0, + Title = "SPINDLE LOAD", + ValueNum = currVal, + IsNumeric = true, + Value = currVal.ToString("P0"), + Type = "ORDER" + }; + answ.Add(displ03); + + currVal = rand.NextDouble() * 5000; + DisplayDataDTO displ04 = new DisplayDataDTO() + { + Order = 0, + Title = "X POS", + ValueNum = currVal, + IsNumeric = true, + Value = currVal.ToString("N1"), + Type = "POS" + }; + answ.Add(displ04); + + currVal = rand.NextDouble() * 10000; + DisplayDataDTO displ05 = new DisplayDataDTO() + { + Order = 0, + Title = "Y POS", + ValueNum = currVal, + IsNumeric = true, + Value = currVal.ToString("N1"), + Type = "POS" + }; + answ.Add(displ05); + + currVal = rand.NextDouble() * -3000; + DisplayDataDTO displ06 = new DisplayDataDTO() + { + Order = 0, + Title = "Z POS", + ValueNum = currVal, + IsNumeric = true, + Value = currVal.ToString("N1"), + Type = "POS" + }; + answ.Add(displ06); + + + Task.Delay(200).Wait(); + + return answ; + } + + public Dictionary GetCurrentParameters() + { + Dictionary? ParametersList = new Dictionary(); + ParametersList.Add("Speed", $"{Random.Shared.Next(0, 5000)}"); + ParametersList.Add("Feed", $"{Random.Shared.Next(0, 10000)}"); + ParametersList.Add("Load", $"{Random.Shared.Next(0, 100)}"); + //return ParametersList; + + var newParamList = Enumerable.Range(1, 10) + .ToDictionary(x => $"Par{x:00}", x => $"{Random.Shared.Next(0, 1000)}"); + foreach (var item in newParamList) + { + ParametersList.Add(item.Key, item.Value); + } + return ParametersList; + } } } diff --git a/MP.MONO.Data/MessagePipe.cs b/MP.MONO.Data/MessagePipe.cs index 1753c22..d859fb0 100644 --- a/MP.MONO.Data/MessagePipe.cs +++ b/MP.MONO.Data/MessagePipe.cs @@ -36,7 +36,7 @@ namespace MP.MONO.Data { //Output received message Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {message}"); - MessageEventArgs mea = new MessageEventArgs(message); + PubSubEventArgs mea = new PubSubEventArgs(message); // se qualcuno ascolta sollevo evento nuovo valore... if (EA_NewMessage != null) { @@ -62,11 +62,11 @@ namespace MP.MONO.Data } } - public class MessageEventArgs : EventArgs + public class PubSubEventArgs : EventArgs { public string newMessage { get; set; } = ""; - public MessageEventArgs(string messaggio) + public PubSubEventArgs(string messaggio) { this.newMessage = messaggio; } diff --git a/MP.MONO.UI/Components/AlarmsOverview.razor.cs b/MP.MONO.UI/Components/AlarmsOverview.razor.cs index fa719d5..33c89bc 100644 --- a/MP.MONO.UI/Components/AlarmsOverview.razor.cs +++ b/MP.MONO.UI/Components/AlarmsOverview.razor.cs @@ -31,7 +31,7 @@ namespace MP.MONO.UI.Components private void AlarmPipe_EA_NewMessage(object? sender, EventArgs e) { - MessageEventArgs currArgs = (MessageEventArgs)e; + PubSubEventArgs currArgs = (PubSubEventArgs)e; if (currArgs.newMessage == "reset") { ListRecords = new List(); diff --git a/MP.MONO.UI/Components/CmpTop.razor.cs b/MP.MONO.UI/Components/CmpTop.razor.cs index d3c685c..af8822f 100644 --- a/MP.MONO.UI/Components/CmpTop.razor.cs +++ b/MP.MONO.UI/Components/CmpTop.razor.cs @@ -32,7 +32,7 @@ namespace MP.MONO.UI.Components private void StatusPipe_EA_NewMessage(object? sender, EventArgs e) { - MessageEventArgs currArgs = (MessageEventArgs)e; + PubSubEventArgs currArgs = (PubSubEventArgs)e; if (!string.IsNullOrEmpty(currArgs.newMessage)) { try diff --git a/MP.MONO.UI/Components/ParamOverview.razor b/MP.MONO.UI/Components/ParamOverview.razor index 7397c45..5aa1994 100644 --- a/MP.MONO.UI/Components/ParamOverview.razor +++ b/MP.MONO.UI/Components/ParamOverview.razor @@ -30,21 +30,4 @@ else } -@code { - protected bool dataLoaded = false; - private List? ListRecords { get; set; } = null; - protected override async Task OnInitializedAsync() - { - await ReloadData(); - } - - protected async Task ReloadData() - { - await Task.Delay(10); - ListRecords = await MMDataService.MachineDisplay(); - await Task.Delay(500); - dataLoaded = true; - } - -} diff --git a/MP.MONO.UI/Components/ParamOverview.razor.cs b/MP.MONO.UI/Components/ParamOverview.razor.cs new file mode 100644 index 0000000..77828d3 --- /dev/null +++ b/MP.MONO.UI/Components/ParamOverview.razor.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using System.Net.Http; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.AspNetCore.Components.Forms; +using Microsoft.AspNetCore.Components.Routing; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.Components.Web.Virtualization; +using Microsoft.JSInterop; +using MP.MONO.Core.DTO; +using MP.MONO.Data; +using MP.MONO.UI; +using MP.MONO.UI.Shared; +using MP.MONO.UI.Components; +using MP.MONO.UI.Data; +using Newtonsoft.Json; + +namespace MP.MONO.UI.Components +{ + public partial class ParamOverview + { + protected bool dataLoaded = false; + private List? ListRecords { get; set; } = null; + protected override async Task OnInitializedAsync() + { + await ReloadData(); + MMDataService.parametersPipe.EA_NewMessage += ParametersPipe_EA_NewMessage; + } + + private void ParametersPipe_EA_NewMessage(object? sender, EventArgs e) + { + PubSubEventArgs currArgs = (PubSubEventArgs)e; + if (!string.IsNullOrEmpty(currArgs.newMessage)) + { + try + { + ListRecords = JsonConvert.DeserializeObject>(currArgs.newMessage); + } + catch + { } + } + InvokeAsync(() => + { + StateHasChanged(); + }); + } + + protected async Task ReloadData() + { + await Task.Delay(10); + ListRecords = await MMDataService.MachineDisplay(); + await Task.Delay(500); + dataLoaded = true; + } + } +} \ No newline at end of file diff --git a/MP.MONO.UI/Data/CurrentDataService.cs b/MP.MONO.UI/Data/CurrentDataService.cs index 6513755..86dea0a 100644 --- a/MP.MONO.UI/Data/CurrentDataService.cs +++ b/MP.MONO.UI/Data/CurrentDataService.cs @@ -8,6 +8,7 @@ using NLog; using StackExchange.Redis; using System.Diagnostics; using System.Text; +using StackExchange.Redis; namespace MP.MONO.UI.Data { @@ -19,6 +20,15 @@ namespace MP.MONO.UI.Data private static ILogger _logger; private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); private readonly IDistributedCache distributedCache; + /// + /// Oggetto per connessione a REDIS + /// + private ConnectionMultiplexer redisConn = null!; + //ISubscriber sub = redis.GetSubscriber(); + /// + /// Oggetto DB redis da impiegare x chiamate R/W + /// + private IDatabase redisDb = null!; /// /// Durata assoluta massima della cache IN SECONDI @@ -42,12 +52,13 @@ namespace MP.MONO.UI.Data /// /// Controller dati simulati /// - public static SimController simController; + public static SimController simGen; #endregion Public Fields public MessagePipe alarmPipe { get; set; } = null!; + public MessagePipe parametersPipe { get; set; } = null!; public MessagePipe statusPipe { get; set; } = null!; #region Public Constructors @@ -56,10 +67,18 @@ namespace MP.MONO.UI.Data { _logger = logger; _configuration = configuration; + + // setup compoenti REDIS + this.redisConn = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("Redis")); + this.redisDb = this.redisConn.GetDatabase(); + // setup canali pub/sub alarmPipe = new MessagePipe(redisConn, "allarms"); + parametersPipe = new MessagePipe(redisConn, "parameters"); statusPipe = new MessagePipe(redisConn, "status"); + // conf cache this.distributedCache = distributedCache; + // conf DB string connStr = _configuration.GetConnectionString("MP.MONO.Data"); if (string.IsNullOrEmpty(connStr)) @@ -71,7 +90,7 @@ namespace MP.MONO.UI.Data dbController = new MpDbController(configuration); _logger.LogInformation("DbController OK"); } - simController = new SimController(); + simGen = new SimController(); } #endregion Public Constructors @@ -114,25 +133,38 @@ namespace MP.MONO.UI.Data public async Task> GetCurrentParameters() { ParametersList = new Dictionary(); - ParametersList.Add("Speed", $"{Random.Shared.Next(0, 5000)}"); - ParametersList.Add("Feed", $"{Random.Shared.Next(0, 10000)}"); - ParametersList.Add("Load", $"{Random.Shared.Next(0, 100)}"); - //return ParametersList; - - var newParamList = Enumerable.Range(1, 10) - .ToDictionary(x => $"Par{x:00}", x => $"{Random.Shared.Next(0, 1000)}"); - foreach (var item in newParamList) + string cacheKey = mHash("Machine:Parameters:Current"); + string rawData = await redisDb.StringGetAsync(cacheKey); + if (!string.IsNullOrEmpty(rawData)) { - ParametersList.Add(item.Key, item.Value); + ParametersList = JsonConvert.DeserializeObject>(rawData); + } + else + { + ParametersList = simGen.GetCurrentParameters(); + rawData = JsonConvert.SerializeObject(ParametersList); + await redisDb.StringSetAsync(cacheKey, rawData); } - await Task.Delay(1); return ParametersList; } public async Task> MachineDisplay() { List? dbResult = new List(); - string cacheKey = mHash("Machine:DisplayData"); + string cacheKey = mHash("Machine:Parameters:Current"); + string rawData = await redisDb.StringGetAsync(cacheKey); + if (!string.IsNullOrEmpty(rawData)) + { + dbResult = JsonConvert.DeserializeObject>(rawData); + } + else + { + dbResult = simGen.MachineGetParameters(); + rawData = JsonConvert.SerializeObject(dbResult); + await redisDb.StringSetAsync(cacheKey, rawData); + } +#if false + string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) @@ -156,7 +188,8 @@ namespace MP.MONO.UI.Data if (dbResult == null) { dbResult = new List(); - } + } +#endif return await Task.FromResult(dbResult); } @@ -195,19 +228,16 @@ namespace MP.MONO.UI.Data { MachineDTO? dbResult = new MachineDTO(); string cacheKey = mHash("Machine:Status:Current"); - string rawData; - var redisDataList = await distributedCache.GetAsync(cacheKey); - if (redisDataList != null) + string rawData = await redisDb.StringGetAsync(cacheKey); + if (!string.IsNullOrEmpty(rawData)) { - rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject(rawData); } else { - dbResult = simController.MachineGetStatus(); + dbResult = simGen.MachineGetStatus(); rawData = JsonConvert.SerializeObject(dbResult); - redisDataList = Encoding.UTF8.GetBytes(rawData); - //await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); + redisDb.StringSetAsync(cacheKey, rawData); } if (dbResult == null) { diff --git a/MachineSim/Program.cs b/MachineSim/Program.cs index d8f4973..306618a 100644 --- a/MachineSim/Program.cs +++ b/MachineSim/Program.cs @@ -2,7 +2,6 @@ using MP.MONO.Data.Controllers; using Newtonsoft.Json; using StackExchange.Redis; -using System.Configuration; string lineSep = "------------------------------------------------------"; string redisConf = "127.0.0.1:6379"; @@ -22,45 +21,24 @@ ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(redisConf); ISubscriber sub = redis.GetSubscriber(); IDatabase? redisDb = redis.GetDatabase(); - // avvio tutti i thread... Thread threadStatus = new Thread(simStatus); Thread threadAlarms = new Thread(simAlarms); +Thread threadParams = new Thread(simParameters); threadStatus.Start(); threadAlarms.Start(); +threadParams.Start(); - - -void simStatus() +/// +/// Hash Redis contenente i dati MP di una specifico TYPE (es StatusMacchina, StateMachineIngressi, ...) +/// +/// +/// +string mHash(string dataType) { - int minPeriod = 2000; - int maxPeriod = 3000; - - do { - // recupero uno stato simulato - var newStatus = simGen.MachineGetStatus(); - string rawData = JsonConvert.SerializeObject(newStatus); - saveAndSendMessage(mHash("Machine:Status:Current"), rawData, "status", rawData); - - // attesa random - Thread.Sleep(rand.Next(minPeriod, maxPeriod)); - } while (true); + return $"MAPO-MONO:{dataType}"; } -void simAlarms() -{ - int minPeriod = 1000; - int maxPeriod = 2000; - - do - { - var alarmCode = rand.Next(1, 100); - saveAndSendMessage(mHash("Machine:Alarms:Current"), $"{alarmCode:000} | Allarme PLC {alarmCode}", "allarms", $"{alarmCode:000}"); - // attesa random - Thread.Sleep(rand.Next(minPeriod, maxPeriod)); - } while (true); -} - void saveAndSendMessage(string memKey, string value, string notifyChannel, string message) { @@ -73,13 +51,46 @@ void saveAndSendMessage(string memKey, string value, string notifyChannel, strin sub.Publish(notifyChannel, message); Console.WriteLine($"[{notifyChannel}] key: {memKey} | val: {value} | message: {message}"); } - -/// -/// Hash Redis contenente i dati MP di una specifico TYPE (es StatusMacchina, StateMachineIngressi, ...) -/// -/// -/// -string mHash(string dataType) +void simAlarms() { - return $"MAPO-MONO:{dataType}"; + int minPeriod = 1000; + int maxPeriod = 2000; + + do + { + var alarmCode = rand.Next(1, 100); + saveAndSendMessage(mHash("Machine:Alarms:Current"), $"{alarmCode:000} | Allarme PLC {alarmCode}", "allarms", $"{alarmCode:000}"); + // attesa random + Thread.Sleep(rand.Next(minPeriod, maxPeriod)); + } while (true); +} +void simParameters() +{ + int minPeriod = 100; + int maxPeriod = 500; + + do + { + var newParams = simGen.MachineGetParameters(); + string rawData = JsonConvert.SerializeObject(newParams); + saveAndSendMessage(mHash("Machine:Parameters:Current"), rawData, "parameters", rawData); + // attesa random + Thread.Sleep(rand.Next(minPeriod, maxPeriod)); + } while (true); +} +void simStatus() +{ + int minPeriod = 2000; + int maxPeriod = 3000; + + do + { + // recupero uno stato simulato + var newStatus = simGen.MachineGetStatus(); + string rawData = JsonConvert.SerializeObject(newStatus); + saveAndSendMessage(mHash("Machine:Status:Current"), rawData, "status", rawData); + + // attesa random + Thread.Sleep(rand.Next(minPeriod, maxPeriod)); + } while (true); } \ No newline at end of file