Merge branch 'release/UpdateBlinkAlarms' into main

This commit is contained in:
Samuele E. Locatelli
2022-10-23 18:11:30 +02:00
32 changed files with 1240 additions and 148 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>AnyCPU;x86;x64</Platforms>
<Version>1.2.2210.2018</Version>
<Version>1.2.2210.2318</Version>
</PropertyGroup>
<ItemGroup>
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>MAPO-MONO</i>
<h4>Version: 1.2.2210.2018</h4>
<h4>Version: 1.2.2210.2318</h4>
<br /> Release Note:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
1.2.2210.2018
1.2.2210.2318
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.2.2210.2018</version>
<version>1.2.2210.2318</version>
<url>http://nexus.steamware.net/repository/SWS/MP.MONO.ANALYZER/stable/LAST/MP.Mon.zip</url>
<changelog>http://nexus.steamware.net/repository/SWS/MP.MONO.ANALYZER/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
+8 -7
View File
@@ -10,7 +10,8 @@ namespace MP.MONO.Core.CONF
#region Public Constructors
public MachDataItem()
{ }
{
}
#endregion Public Constructors
@@ -19,32 +20,32 @@ namespace MP.MONO.Core.CONF
/// <summary>
/// Categoria oggetto
/// </summary>
public DataItemCategory Category { get; set; }
public DataItemCategory Category { get; set; } = DataItemCategory.EVENT;
/// <summary>
/// Nome / descrizione
/// </summary>
public string Name { get; set; }
public string Name { get; set; } = "";
/// <summary>
/// Tipologia specifica
/// </summary>
public string SubType { get; set; }
public string SubType { get; set; } = "";
/// <summary>
/// Tipologia principale
/// </summary>
public string Type { get; set; }
public string Type { get; set; } = "";
/// <summary>
/// Unità di misura
/// </summary>
public string Units { get; set; }
public string Units { get; set; } = "";
/// <summary>
/// ID generico
/// </summary>
public string uuid { get; set; }
public string uuid { get; set; } = "";
#endregion Public Properties
}
+2 -1
View File
@@ -43,8 +43,9 @@ namespace MP.MONO.Core
public static readonly string ACT_LOG_CURR_KEY = $"{BASE_HASH}:Current:ActivityLog";
public static readonly string ALARM_ADAPTER_ACT_KEY = $"{BASE_HASH}:Current:AdapterAlarm";
public static readonly string ALARM_ACT_KEY = $"{BASE_HASH}:Current:AlarmsVal";
public static readonly string ALARM_CURR_KEY = $"{BASE_HASH}:Current:Alarms";
public static readonly string ALARM_BLINK_CURR_KEY = $"{BASE_HASH}:Current:AlarmsBlink";
public static readonly string ALARM_CURR_KEY = $"{BASE_HASH}:Current:Alarms";
public static readonly string ALARM_RECEIV_KEY = $"{BASE_HASH}:Current:AlarmsReceived";
public static readonly string EVENT_LOG_CURR_KEY = $"{BASE_HASH}:Current:EventsLog";
public static readonly string MACH_STATS_CURR_KEY = $"{BASE_HASH}:Current:MachStats";
public static readonly string MAINT_STATS_CURR_KEY = $"{BASE_HASH}:Current:Maintenance";
+6 -1
View File
@@ -55,7 +55,12 @@
/// <summary>
/// Modalità di invio di un elenco di allarmi attivi in un dato istante
/// </summary>
RawList
RawList,
/// <summary>
/// Modalità di invio di un elenco di allarmi attivi in un dato istante con BLINK ogni 10 sec (come amcchina multiax)
/// </summary>
RawListBlink
}
/// <summary>
+1 -1
View File
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
+325
View File
@@ -0,0 +1,325 @@
using Microsoft.Extensions.Configuration;
using MP.MONO.Core;
using Newtonsoft.Json;
using NLog;
using StackExchange.Redis;
namespace MP.MONO.DECODER
{
public class AlarmsBlinkManager
{
#region Protected Fields
protected static Logger Log = LogManager.GetCurrentClassLogger();
#endregion Protected Fields
#region Private Fields
private static ConnectionMultiplexer? redisConn = null;
private static IDatabase? redisDb = null;
#endregion Private Fields
#region Public Constructors
public AlarmsBlinkManager()
{
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var builder = new ConfigurationBuilder()
.AddJsonFile($"appsettings.json", true, true)
.AddJsonFile($"appsettings.{env}.json", true, true)
.AddEnvironmentVariables();
var config = builder.Build();
redisConn = ConnectionMultiplexer.Connect(config.GetConnectionString("Redis"));
redisDb = redisConn.GetDatabase();
Log.Info("AlarmsBlinkManager OK");
Console.WriteLine("AlarmsBlinkManager OK");
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Funzione chiamata x verifica allarmi:
/// - fornisce elenco allarmi correnti aggiornati
/// - fornisce elenco dei NUOVI come ref
/// - fornisce elenco dei CESSATI come ref
/// </summary>
/// <param name="alarmListReceived"></param>
/// <param name="alarmListCurrent"></param>
/// <param name="alarmListAdded"></param>
/// <param name="alarmListCeased"></param>
/// <returns>Boolean che indica se ci siano state variazioni</returns>
public static bool processData(List<string> alarmListReceived, ref List<string> alarmListCurrent, ref List<string> alarmListAdded, ref List<string> alarmListCeased)
{
bool answ = false;
// verifico se sono zero e prima > 0...
answ = (alarmListReceived.Count == 0 && alarmListCurrent.Count > 0);
// primo step: verifico gli allarmi ricevuti siano > 0 e NON contengano duplicati...
List<string> alarmListReceivedOk = new List<string>();
if (alarmListReceived.Count > 0)
{
alarmListReceivedOk = alarmListReceived
.GroupBy(x => x)
.Select(grp => grp.First())
.OrderBy(x => x)
.ToList();
Log.Info($"Ricezione update allarmi | {alarmListReceived.Count} --> {alarmListReceivedOk.Count} distinct");
}
else
{
Log.Info($"Ricezione ZERO allarmi | {alarmListReceived.Count}");
}
// salvo set allarmi ricevuti...
setAlarms("LastReceived", alarmListReceivedOk);
Log.Debug($"Salvataggio LastReceived | count {alarmListReceivedOk.Count}");
// elenco allarmi confermati
var alarmListConf = alarmListCurrent.Intersect(alarmListReceivedOk);
// copio oggetti x allarmi NUOVI e cessati
alarmListAdded = new List<string>(alarmListReceivedOk);
alarmListCeased = new List<string>(alarmListCurrent);
foreach (var item in alarmListConf)
{
// calcolo allarmi nuovi/cessati eliminando eventuali elementi comuni
alarmListAdded.Remove(item);
alarmListCeased.Remove(item);
}
// aggiungo i nuovi a current
alarmListCurrent.AddRange(alarmListAdded);
// riordino
alarmListCurrent = alarmListCurrent.OrderBy(x => x).ToList();
// ...e salvo subito
setAlarms("Current", alarmListCurrent);
// loggo controllo
Log.Debug($"Esito controllo | {alarmListReceivedOk.Count} ricevuti | {alarmListAdded.Count} aggiunti | {alarmListCeased.Count} cessati");
#if false
// gestione allarmi muted
List<AlarmListModel>? mutedAlarmsList = new List<AlarmListModel>();
string rawData = redisDb.StringGet(Constants.ALARMS_SETT_RLIST_KEY);
if (!string.IsNullOrEmpty(rawData))
{
mutedAlarmsList = JsonConvert.DeserializeObject<List<AlarmListModel>>(rawData);
}
if (mutedAlarmsList == null)
{
mutedAlarmsList = dbController.AlarmListGetAll();
}
// rileggo da REDIS la conf attuale allarmi già attivi da area ALARM_CURR_KEY
// FIXME TODO !!! usare una lista thread safe?!?!?
List<string> lastAlarms = getAlarms("Current");
List<string> startedAlarms = new List<string>();
List<string> ceasedAlarms = new List<string>();
string serAlarms = "";
// ciclo x ogni allarme ricevuto x vedere se sia INIZIATO o vada filtrato x muted
if (alarmList != null)
{
// ciclo x ogni allarme attivo x verificare se si sia CHIUSO
foreach (var newAlarm in alarmList)
{
var currNewAlarm = newAlarm;
// se ho valori trim pre/post li applica...
if (!string.IsNullOrEmpty(AlarmCleanPre))
{
currNewAlarm = currNewAlarm.Replace(AlarmCleanPre, "");
}
if (!string.IsNullOrEmpty(AlarmCleanPost))
{
currNewAlarm = currNewAlarm.Replace(AlarmCleanPost, "");
}
// se AlarmIgnoreEmpty=true + vuoto --> salto
if (AlarmIgnoreEmpty && string.IsNullOrWhiteSpace(currNewAlarm))
{
alarmList.Remove(currNewAlarm);
alarmList.Remove(newAlarm);
}
else
{
// in primis... se è muted --> lo escludo...
bool isMuted = false;
var maybeMuted = mutedAlarmsList.Where(x => x.FullValue == currNewAlarm).FirstOrDefault();
if (maybeMuted != null)
{
isMuted = maybeMuted.Muted;
}
// cerco l'allarme nell'elenco degli allarmi dal DB
AlarmListModel? foundAlarm = getAlarmModel(currNewAlarm);
if (!isMuted)
{
if (!lastAlarms.Contains(currNewAlarm))
{
if (foundAlarm != null)
{
// segno come iniziato...
AlarmRecModel newAlarmRec = new AlarmRecModel()
{
MachineId = MachineId,
DtStart = adesso,
DtEnd = adesso.AddMinutes(-1),
AlarmId = foundAlarm.AlarmId
};
alarmRecList.Add(newAlarmRec);
startedAlarms.Add(currNewAlarm);
lastAlarms.Add(currNewAlarm);
needsWrite = true;
}
}
}
else
{
// rimuovo da alarmList perché muted...
alarmList.Remove(currNewAlarm);
alarmList.Remove(newAlarm);
}
}
}
}
// salvo
serAlarms = JsonConvert.SerializeObject(lastAlarms);
// invio sulla message pipeline corretta TUTTI gli allarmi serializzati
alarmsSendPipe.saveAndSendMessage(Constants.ALARM_CURR_KEY, serAlarms);
// calcolo allarmi cessati...
if (lastAlarms != null)
{
// ciclo x ogni allarme attivo x verificare se si sia CHIUSO
foreach (var oldData in lastAlarms)
{
bool trovato = false;
if (alarmList != null)
{
trovato = alarmList.Contains(oldData);
}
// se non c'è... segno cessato
if (!trovato)
{
ceasedAlarms.Add(oldData);
await Task.Run(async () =>
{
await checkCeasedAlarm(oldData);
});
}
}
}
Log.Debug($"Stato lastAlarms | count {lastAlarms.Count}");
// gli allarmi cessati avvio un task di verifica dopo periodo di blink
if (needsWrite)
{
Log.Debug($"Preparazione AlarmLogRecord | count {lastAlarms.Count}");
// preparo dati x alarmLog
AlarmLogModel newAlarmLog = new AlarmLogModel()
{
MachineId = MachineId,
DtRif = adesso,
MemAddress = "ND",
Index = 0,
// usare alarmList o lastAlarms
Status = (uint)alarmList.Count,
ValDecoded = alarmList.Count > 0 ? string.Join(", ", alarmList) : "All OK"
};
alarmLogList.Add(newAlarmLog);
}
if (lastAlarms != null)
{
lastAlarms = lastAlarms.OrderBy(x => x).ToList();
// serializzo l'elenco allarmi...
serAlarms = JsonConvert.SerializeObject(lastAlarms);
// se vuoto metto controllo x chiusura
if (lastAlarms.Count() == 0)
{
await Task.Run(async () =>
{
await checkCloseAllAlarm();
});
}
// invio sulla message pipeline corretta TUTTI gli allarmi serializzati
alarmsSendPipe.saveAndSendMessage(Constants.ALARM_CURR_KEY, serAlarms);
Log.Debug($"Salvataggio/invio allarmi | serAlarms | count {lastAlarms.Count}");
}
#endif
// restituisco esito esecuzione
answ = answ || (alarmListAdded.Count > 0 || alarmListCeased.Count > 0);
return answ;
}
#endregion Public Methods
#region Private Methods
/// <summary>
/// Recupero da redis gli allarmi secondo tipo LastReceived / Current
/// </summary>
private static List<string> getAlarms(string tipo)
{
// rileggo da REDIS la conf attuale allarmi già attivi da area ALARM_CURR_KEY
List<string> lastAlarms = new List<string>();
// in base al tipo leggo una chiave redis o l'altra...
string rawData = "";
if (redisDb != null)
{
if (tipo == "LastReceived")
{
rawData = redisDb.StringGet(Constants.ALARM_RECEIV_KEY);
}
else
{
rawData = redisDb.StringGet(Constants.ALARM_CURR_KEY);
}
}
// se trovati uso questi...
if (!string.IsNullOrEmpty(rawData))
{
var rawLastAlarms = JsonConvert.DeserializeObject<List<string>>(rawData);
lastAlarms = rawLastAlarms != null ? rawLastAlarms : new List<string>();
Log.Debug($"Lettura allarmi | tipo: {tipo} | num: {lastAlarms.Count}");
}
return lastAlarms;
}
/// <summary>
/// Salvo in redis gli allarmi secondo tipo LastReceived / Sent
/// </summary>
private static bool setAlarms(string tipo, List<string> listAlarm)
{
bool fatto = false;
string rawData = JsonConvert.SerializeObject(listAlarm);
if (redisDb != null)
{
if (tipo == "LastReceived")
{
fatto = redisDb.StringSet(Constants.ALARM_RECEIV_KEY, rawData);
}
else
{
fatto = redisDb.StringSet(Constants.ALARM_CURR_KEY, rawData);
}
}
Log.Debug($"Scrittura allarmi | tipo: {tipo} | num: {listAlarm.Count}");
return fatto;
}
#endregion Private Methods
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>AnyCPU;x86;x64</Platforms>
<Version>1.2.2210.2018</Version>
<Version>1.2.2210.2318</Version>
</PropertyGroup>
<ItemGroup>
+17 -18
View File
@@ -6,29 +6,29 @@
throwExceptions="false"
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
<!-- optional, add some variables
<!-- optional, add some variables
https://github.com/nlog/NLog/wiki/Configuration-file#variables
-->
<variable name="myvar" value="myvalue" />
<variable name="myvar" value="myvalue" />
<!--
<!--
See https://github.com/nlog/nlog/wiki/Configuration-file
for information on customizing logging rules and outputs.
-->
<targets>
<targets>
<!--
<!--
add your targets here
See https://github.com/nlog/NLog/wiki/Targets for possible targets.
See https://github.com/nlog/NLog/wiki/Layout-Renderers for the possible layout renderers.
-->
<!--
<!--
Write events to a file with the date in the filename.
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
layout="${longdate} ${uppercase:${level}} ${message}" />
-->
<target xsi:type="File"
<target xsi:type="File"
name="fileTarget"
fileName="${basedir}/logs/${shortdate}.log"
layout="${longdate} | ${uppercase:${level}} | ${logger:shortName=false} | ${message}"
@@ -37,22 +37,21 @@
archiveAboveSize="1024000"
maxArchiveFiles="90"
enableArchiveFileCompression="true"
keepFileOpen="false"
/>
<target xsi:type="ColoredConsole"
keepFileOpen="false" />
<target xsi:type="ColoredConsole"
name="consoleTarget"
layout="${longdate} | ${uppercase:${level}} | ${logger:shortName=true}| ${message}" />
</targets>
</targets>
<rules>
<!-- add your logging rules here -->
<rules>
<!-- add your logging rules here -->
<!--
<!--
Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace) to "f"
<logger name="*" minlevel="Debug" writeTo="f" />
-->
<!--<logger name="Microsoft.*" maxlevel="Info" final="true" />-->
<!--<logger name="*" minlevel="Trace" writeTo="consoleTarget" />-->
<logger name="*" minlevel="Info" writeTo="fileTarget" />
</rules>
<!--<logger name="Microsoft.*" maxlevel="Info" final="true" />-->
<logger name="*" minlevel="Info" writeTo="consoleTarget" />
<logger name="*" minlevel="Info" writeTo="fileTarget" />
</rules>
</nlog>
+468 -9
View File
@@ -8,6 +8,7 @@ using MP.MONO.Data.DbModels;
using MP.MONO.DECODER;
using Newtonsoft.Json;
using NLog;
using Org.BouncyCastle.Asn1.Pkcs;
using StackExchange.Redis;
using System.Diagnostics;
using System.Reflection;
@@ -92,6 +93,7 @@ bool AlarmIgnoreEmpty = true;
string AlarmCleanPre = "";
string AlarmCleanPost = "";
int DbSampleInt = 60;
int BlinkPeriodMSec = 1000;
setupConf();
// datetime dell'inizio esecuzione task... x usare un semaforo di veto doppia esecuzione entro 30 sec
@@ -152,6 +154,7 @@ paramsRecvPipe.EA_NewMessage += ParamsValPipe_EA_NewMessage;
* --------------------------------*/
// init classe gestione allarmi con LUA
AlarmsManager alarmsMan = new AlarmsManager();
AlarmsBlinkManager alarmsBlinkMan = new AlarmsBlinkManager();
// inizializzo gestione messagePipe da Redis x allarmi
MessagePipe alarmsSendPipe = new MessagePipe(redisConn, Constants.ALARM_M_QUEUE);
MessagePipe alarmsRecvPipe = new MessagePipe(redisConn, Constants.ALARM_RAW_QUEUE);
@@ -159,10 +162,189 @@ MessagePipe alarmsRecvPipe = new MessagePipe(redisConn, Constants.ALARM_RAW_QUEU
DateTime lastExecAlarms = DateTime.Now.AddHours(-1);
// registro gestione eventi
alarmsRecvPipe.EA_NewMessage += AlarmsValPipe_EA_NewMessage;
setupAlarmState();
/* --------------------------------
* Funzioni / metodi accessori
* --------------------------------*/
/// <summary>
/// Setup iniziale allarmi
/// </summary>
void setupAlarmState()
{
// setup preliminare allarmi da DB
var actAlarmsList = dbController.AlarmRecGetActive().Select(x => x.AlarmListNav.FullValue).Distinct().ToList();
setAlarms("Current", actAlarmsList);
setAlarms("LastReceived", new List<string>());
Log.Debug($"Setup Stato allarmi | act: {actAlarmsList.Count}");
}
/// <summary>
/// Recupero da redis gli allarmi secondo tipo LastReceived / Sent
/// </summary>
List<string> getAlarms(string tipo)
{
// rileggo da REDIS la conf attuale allarmi già attivi da area ALARM_CURR_KEY
List<string> lastAlarms = new List<string>();
// in base al tipo leggo una chiave redis o l'altra...
string rawData = "";
if (redisDb != null)
{
if (tipo == "LastReceived")
{
rawData = redisDb.StringGet(Constants.ALARM_RECEIV_KEY);
}
else
{
rawData = redisDb.StringGet(Constants.ALARM_CURR_KEY);
}
}
// se trovati uso questi...
if (!string.IsNullOrEmpty(rawData))
{
var rawLastAlarms = JsonConvert.DeserializeObject<List<string>>(rawData);
lastAlarms = rawLastAlarms != null ? rawLastAlarms : new List<string>();
Log.Debug($"Lettura allarmi | tipo: {tipo} | num: {lastAlarms.Count}");
}
return lastAlarms;
}
/// <summary>
/// Salvo in redis gli allarmi secondo tipo LastReceived / Sent
/// </summary>
bool setAlarms(string tipo, List<string> listAlarm)
{
bool fatto = false;
string rawData = JsonConvert.SerializeObject(listAlarm);
if (redisDb != null)
{
if (tipo == "LastReceived")
{
fatto = redisDb.StringSet(Constants.ALARM_RECEIV_KEY, rawData);
}
else
{
fatto = redisDb.StringSet(Constants.ALARM_CURR_KEY, rawData);
}
}
Log.Debug($"Scrittura allarmi | tipo: {tipo} | num: {listAlarm.Count}");
return fatto;
}
AlarmListModel? getAlarmModel(string alarmFullCode)
{
// cerco l'allarme nell'elenco degli allarmi dal DB
AlarmListModel? foundAlarm = null;
if (alarmsRecorded != null)
{
foundAlarm = alarmsRecorded
.Where(x => x.FullValue == alarmFullCode)
.FirstOrDefault();
}
// se non lo trovo --> chiamo procedura che verifica su DB, eventualmente inserisce, restituisce nuovo elenco
if (foundAlarm == null)
{
// salvo sul DB
foundAlarm = dbController.AlarmListInsert(alarmFullCode);
// ora rileggo ed aggiorno redis e cerco di nuovo record...
alarmsRecorded = dbController.AlarmListGetAll();
if (redisDb != null)
{
redisDb.StringSet(Constants.ALARMS_SETT_RLIST_KEY, JsonConvert.SerializeObject(alarmsRecorded));
}
}
return foundAlarm;
}
/// <summary>
/// Verifica un allarme se sia x caso cessato dopo il periodo di pausa e quindi
/// </summary>
async Task<bool> checkCeasedAlarm(string alarmFullCode)
{
bool answ = false;
Log.Debug($"checkCeasedAlarm 01 | Verifica scadenza allarmi | cod: {alarmFullCode}");
// attendo periodo pausa...
await Task.Delay(BlinkPeriodMSec);
// cerco allarme da valore REDIS ultimi ricevuti
var alarmListRecev = getAlarms("LastReceived");
if (alarmListRecev != null)
{
// ...SE mancasse
if (!alarmListRecev.Contains(alarmFullCode))
{
Log.Debug($"checkCeasedAlarm 02 | Allarme ancora mancante | cod: {alarmFullCode}");
// recupero allarme...
// se non lo trovo
var foundAlarm = alarmsRecorded
.Where(x => x.FullValue == alarmFullCode)
.FirstOrDefault();
// --> chiudo
if (foundAlarm != null)
{
// salvo sul DB
_ = dbController.AlarmRecCloseActive(foundAlarm.AlarmId);
Log.Info($"Chiusura allarme | Id: {foundAlarm.AlarmId}");
Log.Debug($"checkCeasedAlarm 03 | Chiusura allarme | cod: {alarmFullCode}");
}
// --> rimuovo da elenco attivi!
var alarmListSent = getAlarms("Current");
int numPre = alarmListSent.Count();
alarmListSent.Remove(alarmFullCode);
int numPost = alarmListSent.Count();
Log.Debug($"checkCeasedAlarm 04 | Salvataggio Sent alarms | num: {numPre} --> {numPost}");
// invio attivi...
string serAlarms = JsonConvert.SerializeObject(alarmListSent);
// invio sulla message pipeline corretta TUTTI gli allarmi serializzati
alarmsSendPipe.saveAndSendMessage(Constants.ALARM_CURR_KEY, serAlarms);
}
answ = true;
}
return answ;
}
/// <summary>
/// Verifica x TUTTI gli allarmi SE siano cessati topo 4 * periodo di controllo... zero ora e zero dopo...
/// </summary>
async Task<bool> checkCloseAllAlarm()
{
bool answ = false;
Log.Debug($"Verifica checkCloseAllAlarm");
// cerco allarme da valore REDIS ultimi ricevuti
var alarmSent = getAlarms("Current");
if (alarmSent != null)
{
bool isZero = alarmSent.Count() == 0;
// solo SE ora sono zero...
if (isZero)
{
// attendo periodo pausa...
await Task.Delay(BlinkPeriodMSec * 2);
// rileggo stato
alarmSent = getAlarms("Current");
isZero = alarmSent.Count() == 0;
// ...SE fossero sempre zero
if (isZero)
{
Log.Debug($"Verifica zero allarmi confermata, chiamo chiusura");
// chiudo sul DB
_ = dbController.AlarmRecCloseStarving();
// invio resettati...
string serAlarms = JsonConvert.SerializeObject(alarmSent);
// invio sulla message pipeline corretta TUTTI gli allarmi serializzati
alarmsSendPipe.saveAndSendMessage(Constants.ALARM_CURR_KEY, serAlarms);
}
}
answ = true;
}
return answ;
}
/// <summary>
/// Recupero da redis le conf (es modi,stati,allarmi)
/// </summary>
@@ -179,6 +361,9 @@ void setupConf()
bool.TryParse(rConf, out AlarmIgnoreEmpty);
AlarmCleanPre = config["OptPar:AlarmCleanPre"];
AlarmCleanPost = config["OptPar:AlarmCleanPost"];
// gestione blink allarmi
rConf = config["OptPar:BlinkPeriodMSec"];
int.TryParse(rConf, out BlinkPeriodMSec);
// recupero valori e deserializzo
string rawData = "";
@@ -223,6 +408,10 @@ void setupConf()
{
alarmsRListConf = JsonConvert.DeserializeObject<List<BaseAlarmRawConf>>(rawData);
}
else if (alarmMode == AlarmReportingMode.RawListBlink)
{
alarmsRListConf = JsonConvert.DeserializeObject<List<BaseAlarmRawConf>>(rawData);
}
else
{
alarmsBankBitConf = JsonConvert.DeserializeObject<List<BaseAlarmBankConf>>(rawData);
@@ -233,13 +422,17 @@ void setupConf()
/// <summary>
/// Gestione evento ricezione messaggi allarmi secondo tipologia attiva...
/// </summary>
void AlarmsValPipe_EA_NewMessage(object? sender, EventArgs e)
async void AlarmsValPipe_EA_NewMessage(object? sender, EventArgs e)
{
PubSubEventArgs currArgs = (PubSubEventArgs)e;
// conversione on-the-fly List<string> --> allarmi
if (!string.IsNullOrEmpty(currArgs.newMessage))
{
DateTime adesso = DateTime.Now;
// variabili accessorie x persistenza su DB
List<AlarmRecModel> alarmRecList = new List<AlarmRecModel>();
List<AlarmLogModel> alarmLogList = new List<AlarmLogModel>();
if (alarmMode == AlarmReportingMode.RawList)
{
try
@@ -256,9 +449,6 @@ void AlarmsValPipe_EA_NewMessage(object? sender, EventArgs e)
.Select(grp => grp.First())
.ToList();
}
List<AlarmRecModel> alarmRecList = new List<AlarmRecModel>();
List<AlarmLogModel> alarmLogList = new List<AlarmLogModel>();
// gestione allarmi muted
List<AlarmListModel>? mutedAlarmsList = new List<AlarmListModel>();
string rawData = redisDb.StringGet(Constants.ALARMS_SETT_RLIST_KEY);
@@ -324,9 +514,11 @@ void AlarmsValPipe_EA_NewMessage(object? sender, EventArgs e)
isMuted = maybeMuted.Muted;
}
// cerco l'allarme nell'elenco degli allarmi dal DB
AlarmListModel? foundAlarm = getAlarmModel(currNewAlarm);
#if false
var foundAlarm = alarmsRecorded
.Where(x => x.FullValue == currNewAlarm)
.FirstOrDefault();
.Where(x => x.FullValue == currNewAlarm)
.FirstOrDefault();
// se non lo trovo --> chiamo procedura che verifica su DB,
// eventualmente inserisce, restituisce nuovo elenco
if (foundAlarm == null)
@@ -337,6 +529,7 @@ void AlarmsValPipe_EA_NewMessage(object? sender, EventArgs e)
alarmsRecorded = dbController.AlarmListGetAll();
redisDb.StringSet(Constants.ALARMS_SETT_RLIST_KEY, JsonConvert.SerializeObject(alarmsRecorded));
}
#endif
if (!isMuted)
{
if (!lastAlarms.Contains(currNewAlarm))
@@ -455,8 +648,14 @@ void AlarmsValPipe_EA_NewMessage(object? sender, EventArgs e)
alarmsSendPipe.saveAndSendMessage(Constants.ALARM_CURR_KEY, serAlarms);
// salvo sul DB
_ = dbController.AlarmRecInsertMany(alarmRecList).Result;
_ = dbController.AlarmLogInsertMany(alarmLogList).Result;
if (alarmRecList.Count > 0)
{
_ = dbController.AlarmRecInsertMany(alarmRecList).Result;
}
if (alarmLogList.Count > 0)
{
_ = dbController.AlarmLogInsertMany(alarmLogList).Result;
}
// salvo nuovo elenco allarmi
lastAlarms = alarmList;
@@ -464,6 +663,266 @@ void AlarmsValPipe_EA_NewMessage(object? sender, EventArgs e)
catch
{ }
}
else if (alarmMode == AlarmReportingMode.RawListBlink)
{
bool needsWrite = false;
try
{
// decodifico allarmi ricevuti
var alarmListRaw = JsonConvert.DeserializeObject<List<string>>(currArgs.newMessage);
// allarmi correnti
List<string> alarmListCurrent = getAlarms("Current");
// init classi helper
List<string> addedAlarms = new List<string>();
List<string> ceasedAlarms = new List<string>();
// chiamo procedura in blocco...
bool fatto = AlarmsBlinkManager.processData(alarmListRaw, ref alarmListCurrent, ref addedAlarms, ref ceasedAlarms);
// salvo ed invio subito i current...
string serAlarms = JsonConvert.SerializeObject(alarmListCurrent);
alarmsSendPipe.saveAndSendMessage(Constants.ALARM_CURR_KEY, serAlarms);
// se cambiato --> preparo record LOG e salvo
if (fatto)
{
// preparo dati x alarmLog
AlarmLogModel newAlarmLog = new AlarmLogModel()
{
MachineId = MachineId,
DtRif = adesso,
MemAddress = "ND",
Index = 0,
Status = (uint)alarmListCurrent.Count,
ValDecoded = alarmListCurrent.Count > 0 ? string.Join(", ", alarmListCurrent) : "All OK"
};
alarmLogList.Add(newAlarmLog);
_ = dbController.AlarmLogInsertMany(alarmLogList).Result;
Log.Info("Inserito Record AlarmLogModel");
}
if (addedAlarms.Count > 0)
{
// preparo lista NEW x inserimento su DB
foreach (var item in addedAlarms)
{
// cerco l'allarme nell'elenco degli allarmi dal DB
AlarmListModel? foundAlarm = getAlarmModel(item);
if (foundAlarm != null)
{
// segno come iniziato...
AlarmRecModel newAlarmRec = new AlarmRecModel()
{
MachineId = MachineId,
DtStart = adesso,
DtEnd = adesso.AddMinutes(-1),
AlarmId = foundAlarm.AlarmId
};
alarmRecList.Add(newAlarmRec);
}
}
// salvo sul DB
_ = dbController.AlarmRecInsertMany(alarmRecList).Result;
Log.Info($"Inseriti {alarmRecList.Count} Records AlarmRecModel");
}
if (ceasedAlarms.Count > 0)
{
// chiamo task x verifica chiusura ritardata
foreach (var item in ceasedAlarms)
{
await Task.Run(async () =>
{
await checkCeasedAlarm(item);
});
await Task.Delay(10);
}
// Loggo quanto fatto
Log.Debug($"Chiamato controllo differito per {ceasedAlarms.Count} allarmi cessati");
}
#if false
// effettuo selezione dei SOLI allarmi distinct (in caso di cambio posizione...)
List<string> alarmList = new List<string>();
if (alarmListRaw != null && alarmListRaw.Count > 0)
{
alarmList = alarmListRaw
.GroupBy(x => x)
.Select(grp => grp.First())
.OrderBy(x => x)
.ToList();
}
Log.Info($"Ricezione update allarmi | {alarmListRaw.Count} --> {alarmList.Count}");
// salvo set allarmi correnti...
setAlarms("LastReceived", alarmList);
Log.Debug($"Salvataggio LastReceived | count {alarmList.Count}");
// gestione allarmi muted
List<AlarmListModel>? mutedAlarmsList = new List<AlarmListModel>();
string rawData = redisDb.StringGet(Constants.ALARMS_SETT_RLIST_KEY);
if (!string.IsNullOrEmpty(rawData))
{
mutedAlarmsList = JsonConvert.DeserializeObject<List<AlarmListModel>>(rawData);
}
if (mutedAlarmsList == null)
{
mutedAlarmsList = dbController.AlarmListGetAll();
}
// rileggo da REDIS la conf attuale allarmi già attivi da area ALARM_CURR_KEY
// FIXME TODO !!! usare una lista thread safe?!?!?
List<string> lastAlarms = getAlarms("Current");
List<string> startedAlarms = new List<string>();
List<string> ceasedAlarms = new List<string>();
string serAlarms = "";
// ciclo x ogni allarme ricevuto x vedere se sia INIZIATO o vada filtrato x muted
if (alarmList != null)
{
// ciclo x ogni allarme attivo x verificare se si sia CHIUSO
foreach (var newAlarm in alarmList)
{
var currNewAlarm = newAlarm;
// se ho valori trim pre/post li applica...
if (!string.IsNullOrEmpty(AlarmCleanPre))
{
currNewAlarm = currNewAlarm.Replace(AlarmCleanPre, "");
}
if (!string.IsNullOrEmpty(AlarmCleanPost))
{
currNewAlarm = currNewAlarm.Replace(AlarmCleanPost, "");
}
// se AlarmIgnoreEmpty=true + vuoto --> salto
if (AlarmIgnoreEmpty && string.IsNullOrWhiteSpace(currNewAlarm))
{
alarmList.Remove(currNewAlarm);
alarmList.Remove(newAlarm);
}
else
{
// in primis... se è muted --> lo escludo...
bool isMuted = false;
var maybeMuted = mutedAlarmsList.Where(x => x.FullValue == currNewAlarm).FirstOrDefault();
if (maybeMuted != null)
{
isMuted = maybeMuted.Muted;
}
// cerco l'allarme nell'elenco degli allarmi dal DB
AlarmListModel? foundAlarm = getAlarmModel(currNewAlarm);
if (!isMuted)
{
if (!lastAlarms.Contains(currNewAlarm))
{
if (foundAlarm != null)
{
// segno come iniziato...
AlarmRecModel newAlarmRec = new AlarmRecModel()
{
MachineId = MachineId,
DtStart = adesso,
DtEnd = adesso.AddMinutes(-1),
AlarmId = foundAlarm.AlarmId
};
alarmRecList.Add(newAlarmRec);
startedAlarms.Add(currNewAlarm);
lastAlarms.Add(currNewAlarm);
needsWrite = true;
}
}
}
else
{
// rimuovo da alarmList perché muted...
alarmList.Remove(currNewAlarm);
alarmList.Remove(newAlarm);
}
}
}
}
// salvo
serAlarms = JsonConvert.SerializeObject(lastAlarms);
// invio sulla message pipeline corretta TUTTI gli allarmi serializzati
alarmsSendPipe.saveAndSendMessage(Constants.ALARM_CURR_KEY, serAlarms);
// calcolo allarmi cessati...
if (lastAlarms != null)
{
// ciclo x ogni allarme attivo x verificare se si sia CHIUSO
foreach (var oldData in lastAlarms)
{
bool trovato = false;
if (alarmList != null)
{
trovato = alarmList.Contains(oldData);
}
// se non c'è... segno cessato
if (!trovato)
{
ceasedAlarms.Add(oldData);
await Task.Run(async () =>
{
await checkCeasedAlarm(oldData);
});
}
}
}
Log.Debug($"Stato lastAlarms | count {lastAlarms.Count}");
// gli allarmi cessati avvio un task di verifica dopo periodo di blink
if (needsWrite)
{
Log.Debug($"Preparazione AlarmLogRecord | count {lastAlarms.Count}");
// preparo dati x alarmLog
AlarmLogModel newAlarmLog = new AlarmLogModel()
{
MachineId = MachineId,
DtRif = adesso,
MemAddress = "ND",
Index = 0,
// usare alarmList o lastAlarms
Status = (uint)alarmList.Count,
ValDecoded = alarmList.Count > 0 ? string.Join(", ", alarmList) : "All OK"
};
alarmLogList.Add(newAlarmLog);
}
if (lastAlarms != null)
{
lastAlarms = lastAlarms.OrderBy(x => x).ToList();
// serializzo l'elenco allarmi...
serAlarms = JsonConvert.SerializeObject(lastAlarms);
// se vuoto metto controllo x chiusura
if (lastAlarms.Count() == 0)
{
await Task.Run(async () =>
{
await checkCloseAllAlarm();
});
}
// invio sulla message pipeline corretta TUTTI gli allarmi serializzati
alarmsSendPipe.saveAndSendMessage(Constants.ALARM_CURR_KEY, serAlarms);
Log.Debug($"Salvataggio/invio allarmi | serAlarms | count {lastAlarms.Count}");
}
// salvo sul DB
_ = dbController.AlarmRecInsertMany(alarmRecList).Result;
_ = dbController.AlarmLogInsertMany(alarmLogList).Result;
Log.Debug($"Effettuato salvataggio su DB | alarmRecList {alarmRecList.Count} | alarmLogList {alarmLogList.Count}");
#endif
}
catch
{ }
}
else
{
try
@@ -474,7 +933,7 @@ void AlarmsValPipe_EA_NewMessage(object? sender, EventArgs e)
{
// variabili accessorie
List<string> activeAlarmList = new List<string>();
List<AlarmLogModel> alarmLogList = new List<AlarmLogModel>();
alarmLogList = new List<AlarmLogModel>();
// rileggo da REDIS la conf attuale allarmi da area ALARMS_SETT_KEY, altrimenti
// uso quella letta inizialmente da conf base
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>MAPO-MONO</i>
<h4>Version: 1.2.2210.2018</h4>
<h4>Version: 1.2.2210.2318</h4>
<br /> Release Note:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
1.2.2210.2018
1.2.2210.2318
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.2.2210.2018</version>
<version>1.2.2210.2318</version>
<url>http://nexus.steamware.net/repository/SWS/MP.MONO.DECODER/stable/LAST/MP.Mon.zip</url>
<changelog>http://nexus.steamware.net/repository/SWS/MP.MONO.DECODER/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
+4 -3
View File
@@ -8,7 +8,7 @@
"AllowedHosts": "*",
"ConnectionStrings": {
"Redis": "nkcredis.steamware.net:6379,DefaultDatabase=7,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false,password=BtN9Py1wtLfLRvmzWnOPJ7RytDM+CLiVsJ/16zduNTlV8IOPGNrtzJSXPUnImA5PqmUMhKaUqo9NdHIG",
"AuthConnection": "Server=localhost;port=3306;database=GWMS;user=GWMS;pwd=GWMS_secret_pwd;sslmode=None;",
"AuthConnection": "Server=localhost;port=3306;database=GWMS;user=GWMS;pwd=GWMS_secret_pwd;sslmode=None;",
"DefaultConnection": "Server=localhost;port=3306;database=MAPO.MONO;user=GWMS;pwd=GWMS_secret_pwd;sslmode=None;",
"AdminConnection": "Server=localhost;port=3306;database=MAPO.MONO;user=root;pwd=Egalware_24068!;sslmode=None;",
"MP.MONO.Data": "Server=localhost;port=3306;database=MAPO.MONO;user=GWMS;pwd=GWMS_secret_pwd;sslmode=None;"
@@ -39,7 +39,8 @@
"AlarmMode": "RawList",
"AlarmRegexp": "^{[\\d\\w\\:\\ \\.\\/\\(\\)]*}",
//"AlarmRegexp": "^{.*}",
"BlinkCount": 0,
"DbSampleInt": 60
"BlinkCount": 3,
"DbSampleInt": 60,
"BlinkPeriodMSec": 3000
}
}
+7 -1
View File
@@ -33,6 +33,12 @@
}
},
"OptPar": {
"AlarmMode": "RawList"
"AlarmCleanPre": "",
"AlarmCleanPost": "",
"AlarmIgnoreEmpty": true,
"AlarmMode": "RawList",
"AlarmRegexp": "^{[\\d\\w\\:\\ \\.\\/\\(\\)]*}",
"BlinkCount": 10,
"DbSampleInt": 60
}
}
+148 -42
View File
@@ -3,7 +3,6 @@ using MP.MONO.Core.DTO;
using MP.MONO.Data.DbModels;
using MP.MONO.Data.DTO;
using NLog;
using StackExchange.Redis;
using System.Diagnostics;
using static MP.MONO.Core.Enums;
@@ -11,6 +10,12 @@ namespace MP.MONO.Data.Controllers
{
public class MpDbController : IDisposable
{
#region Private Fields
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
#endregion Private Fields
#region Public Constructors
public MpDbController()
@@ -127,6 +132,7 @@ namespace MP.MONO.Data.Controllers
{
dbResult = localDbCtx
.DbSetAlarmLog
.AsNoTracking()
.Where(x => x.MachineId == MachineId)
.Include(m => m.MachineNav)
.OrderByDescending(x => x.AlarmLogId)
@@ -154,6 +160,7 @@ namespace MP.MONO.Data.Controllers
{
dbResult = localDbCtx
.DbSetAlarmLog
.AsNoTracking()
.Where(x => (x.MachineId == MachineId) && (x.DtRif <= dtRif))
.Include(m => m.MachineNav)
.OrderByDescending(x => x.AlarmLogId)
@@ -194,7 +201,6 @@ namespace MP.MONO.Data.Controllers
}
return fatto;
}
/// <summary>
/// Inserimento di una lista record AlarmLog
@@ -208,16 +214,19 @@ namespace MP.MONO.Data.Controllers
{
try
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
await localDbCtx
.DbSetAlarmLog
.AddRangeAsync(newItems);
await localDbCtx.SaveChangesAsync();
fatto = true;
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Info($"AlarmLogInsertMany| DB insert | {newItems.Count} rec | {ts.TotalMilliseconds} ms");
if (newItems.Count > 0)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
await localDbCtx
.DbSetAlarmLog
.AddRangeAsync(newItems);
await localDbCtx.SaveChangesAsync();
fatto = true;
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Info($"AlarmLogInsertMany| DB insert | {newItems.Count} rec | {ts.TotalMilliseconds} ms");
}
}
catch (Exception exc)
{
@@ -259,6 +268,63 @@ namespace MP.MONO.Data.Controllers
return fatto;
}
/// <summary>
/// Chiude ultimo record di allarmi aperti (avendo verificato zia zero da un pò...)
/// </summary>
/// <returns></returns>
public async Task<bool> AlarmRecCloseStarving()
{
bool fatto = false;
using (MapoMonoContext localDbCtx = new MapoMonoContext())
{
try
{
DateTime adesso = DateTime.Now;
var candList = localDbCtx
.DbSetAlarmRec
.Where(x => x.DtStart >= x.DtEnd)
.ToList();
foreach (var item in candList)
{
item.DtEnd = adesso;
}
await localDbCtx.SaveChangesAsync();
fatto = true;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante AlarmRecCloseStarving{Environment.NewLine}{exc}");
}
}
return fatto;
}
/// <summary>
/// Recupero elenco allarmi Rec ATTIVI (non chiusi)
/// </summary>
/// <returns></returns>
public List<AlarmRecModel> AlarmRecGetActive()
{
List<AlarmRecModel> dbResult = new List<AlarmRecModel>();
using (MapoMonoContext localDbCtx = new MapoMonoContext())
{
try
{
dbResult = localDbCtx
.DbSetAlarmRec
.AsNoTracking()
.Where(x => x.DtStart >= x.DtEnd)
.Include(m => m.AlarmListNav)
.ToList();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante AlarmRecGetActive{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Recupero elenco allarmi Rec (ultimi dato "skip")
/// </summary>
@@ -275,6 +341,7 @@ namespace MP.MONO.Data.Controllers
{
dbResult = localDbCtx
.DbSetAlarmRec
.AsNoTracking()
.Where(x => x.MachineId == MachineId)
.Include(m => m.MachineNav)
.Include(m => m.AlarmListNav)
@@ -303,6 +370,7 @@ namespace MP.MONO.Data.Controllers
{
dbResult = localDbCtx
.DbSetAlarmRec
.AsNoTracking()
.Where(x => (x.MachineId == MachineId) && (x.DtStart <= dtRif))
.Include(m => m.MachineNav)
.Include(m => m.AlarmListNav)
@@ -465,16 +533,54 @@ namespace MP.MONO.Data.Controllers
{
try
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
await localDbCtx
.DbSetAlarmRec
.AddRangeAsync(newItems);
await localDbCtx.SaveChangesAsync();
fatto = true;
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Info($"AlarmRecInsertMany| DB insert | {newItems.Count} rec | {ts.TotalMilliseconds} ms");
if (newItems.Count > 0)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
// verifico eventuali items già aperti da NON dover aggiungere...
List<int>? stillOpenAlarms = localDbCtx
.DbSetAlarmRec
.Where(x => x.DtStart >= x.DtEnd)
.Select(x => x.AlarmId)
.ToList();
// costruisco l'elenco degli ID allarmi da inserire
List<int>? listNewId = newItems
.Select(x => x.AlarmId)
.Distinct()
.ToList();
var alarm2rem = listNewId.Intersect(stillOpenAlarms).ToList();
// andrò ad inserire solo gli item NON già presenti...
foreach (var item in alarm2rem)
{
var item2del = newItems.FirstOrDefault(x => x.AlarmId == item);
if (item2del != null)
{
newItems.Remove(item2del);
}
}
if (newItems.Count > 0)
{
// aggiungo
await localDbCtx
.DbSetAlarmRec
.AddRangeAsync(newItems);
// salvo!
await localDbCtx.SaveChangesAsync();
fatto = true;
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Info($"AlarmRecInsertMany| DB insert | {newItems.Count} rec | {ts.TotalMilliseconds} ms");
}
else
{
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Info($"Allarmi già presenti non reinseriti | {ts.TotalMilliseconds} ms");
}
}
}
catch (Exception exc)
{
@@ -836,18 +942,21 @@ namespace MP.MONO.Data.Controllers
.DbSetPMTask
.Where(x => x.PMTaskId == currRec.PMTaskId)
.FirstOrDefault();
// se effettivo delete
if (forceDelete)
if (currVal != null)
{
localDbCtx
.DbSetPMTask
.Remove(currVal);
// se effettivo delete
if (forceDelete)
{
localDbCtx
.DbSetPMTask
.Remove(currVal);
}
else
{
currVal.IsDisabled = true;
}
await localDbCtx.SaveChangesAsync();
}
else
{
currVal.IsDisabled = true;
}
await localDbCtx.SaveChangesAsync();
fatto = true;
}
catch (Exception exc)
@@ -874,12 +983,15 @@ namespace MP.MONO.Data.Controllers
.DbSetPMTask
.Where(x => x.PMTaskId == currRec.PMTaskId)
.FirstOrDefault();
// se effettivo delete
if (currRec.IsDisabled)
if (currVal != null)
{
currVal.IsDisabled = false;
// se effettivo delete
if (currRec.IsDisabled)
{
currVal.IsDisabled = false;
}
await localDbCtx.SaveChangesAsync();
}
await localDbCtx.SaveChangesAsync();
fatto = true;
}
catch (Exception exc)
@@ -1225,11 +1337,5 @@ namespace MP.MONO.Data.Controllers
}
#endregion Public Methods
#region Private Fields
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
#endregion Private Fields
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>AnyCPU;x86;x64</Platforms>
<Version>1.2.2210.2018</Version>
<Version>1.2.2210.2318</Version>
</PropertyGroup>
<ItemGroup>
+186 -5
View File
@@ -141,6 +141,10 @@ void setupConf()
{
alarmsRawConf = configManager.getAlarmsRawConf("SimAlarmRawList.json");
}
else if (alarmMode == AlarmReportingMode.RawListBlink)
{
alarmsRawConf = configManager.getAlarmsRawConf("SimAlarmRawList.json");
}
else
{
alarmsBankBitConf = configManager.getAlarmsBankConf();
@@ -255,16 +259,193 @@ void saveAndSendMessage(string memKey, string notifyChannel, string message)
}
}
// Effettua salvataggio allarmi attivi
void sendActiveAlarm(Dictionary<string, DateTime> CurrActiveAlarm)
{
// serializzo ed invio l'elenco dei soli allarmi attivi
List<string> actAlarmList = CurrActiveAlarm.Select(x => x.Key).OrderBy(x => x).ToList();
string rawDataVal = JsonConvert.SerializeObject(actAlarmList);
saveAndSendMessage(Constants.ALARM_ACT_KEY, Constants.ALARM_RAW_QUEUE, rawDataVal);
}
void simAlarms()
{
int minPeriod = 2000;
int maxPeriod = 8000;
// periodo minimo tra check allarmi
int minPeriod = 1000;
// periodo massimo tra check allarmi
int maxPeriod = 5000;
int percAllarmi = config.GetValue<int>("SimPar:PercAllarmi");
int MaxAddAllarmi = config.GetValue<int>("SimPar:MaxAddAllarmi");
double MaxDurationAllarmi = config.GetValue<int>("SimPar:MaxDurationAllarmi");
//--------------------------------
// Parametri x SIM BLINK
//--------------------------------
// indica se l'ultimo allarme simulato fosse breve
bool lastAlarmWasShort = true;
// soglia (sec) tra interruzioni/allarmi
int sogliaSecAllarmi = config.GetValue<int>("SimPar:SogliaAllarmi");
// periodo (sec) ogni cui fare refresh allarmi (toglie 1:1 e rimette 1:1)
int perRefresh = config.GetValue<int>("SimPar:PeriodRefresh");
// periodo in secondi dopo cui è si generano allarmi o interruzioni (alternando)
int minOkPeriod = config.GetValue<int>("SimPar:PeriodOk");
// in base alla modalità configurata effettuo la simulazione...
if (alarmMode == AlarmReportingMode.RawList)
if (alarmMode == AlarmReportingMode.RawListBlink)
{
// controllo se devo fare (se ho valori da simulare...)
if (alarmsRawConf.Count > 0 && alarmsRawConf[0].messages.Count > 0)
{
DateTime lastOk = DateTime.Now;
DateTime lastAlarm = DateTime.Now.AddMilliseconds(-1);
int stdPeriod = 1000;
/* Modalità simulazione blink...
* - verifico da quanto non ho allarmi
* - se supero soglia minima ok --> simulo allarme o interruzione (alternati)
* - vado in simulazione inizio/fine per le interruzioni (brevi)
* - vado in simulazione inizio/fine per gli allarmi (che dovranno sparire e tornare ogni 10 sec)
*/
// Dict allarmi attivi (e da quando)
Dictionary<string, DateTime> CurrActiveAlarm = new Dictionary<string, DateTime>();
do
{
DateTime adesso = DateTime.Now;
Dictionary<string, DateTime> NewActiveAlarm = new Dictionary<string, DateTime>();
bool newAlarm = false;
// verifico SE ho superato la soglia minima x "tirare i dadi" e simulare allarmi
if (adesso.Subtract(lastOk).TotalSeconds > minOkPeriod)
{
// simulo allarmi insorti
foreach (var alarmGroup in alarmsRawConf)
{
// simulo e limito insorgenza NUOVI allarmi al percAllarmi/100 dei casi
newAlarm = rand.Next(0, 100) <= percAllarmi;
if (newAlarm)
{
int numNew = rand.Next(1, MaxAddAllarmi);
// ciclo x aggiungere il numero di allarmi indicato
for (int i = 0; i < numNew; i++)
{
// seleziono uno degli allarmi del banco.. dando + peso agli "allarmi bassi"
int alarmIndex = 0;
int msgBlock = rand.Next(1, 5);
switch (msgBlock)
{
case 1:
alarmIndex = rand.Next(0, alarmGroup.messages.Count / 4);
break;
case 2:
alarmIndex = rand.Next(0, alarmGroup.messages.Count / 2);
break;
case 3:
alarmIndex = rand.Next(0, alarmGroup.messages.Count * 3 / 4);
break;
case 4:
default:
alarmIndex = rand.Next(0, alarmGroup.messages.Count);
break;
}
string rndNewAlarm = alarmGroup.messages[alarmIndex];
if (!NewActiveAlarm.ContainsKey(rndNewAlarm))
{
NewActiveAlarm.Add(rndNewAlarm, DateTime.Now);
}
}
}
}
// se ho allarmi...
if (NewActiveAlarm.Count > 0)
{
// verifico ultimo tipo allarmi breve/veloce
if (lastAlarmWasShort)
{
Dictionary<string, DateTime> currAlarm = new Dictionary<string, DateTime>();
// aggiungo 1:1 ed invio
foreach (var item in NewActiveAlarm)
{
Thread.Sleep(rand.Next(400, 700));
currAlarm.Add(item.Key, item.Value);
sendActiveAlarm(currAlarm);
}
// CICLO 01: aspetto periodo blink... tra 80 e 110% periodo
Thread.Sleep(rand.Next(800 * perRefresh, 1100 * perRefresh));
// tolgo tutti ed invio
currAlarm = new Dictionary<string, DateTime>();
sendActiveAlarm(currAlarm);
// riaggiungo 1:1 ed invio
foreach (var item in NewActiveAlarm)
{
Thread.Sleep(rand.Next(400, 700));
currAlarm.Add(item.Key, item.Value);
sendActiveAlarm(currAlarm);
}
Thread.Sleep(rand.Next(800 * perRefresh, 1000 * perRefresh));
// CICLO 02: aspetto periodo blink... tra 80 e 110% periodo
// tolgo tutti ed invio
currAlarm = new Dictionary<string, DateTime>();
sendActiveAlarm(currAlarm);
// riaggiungo 1:1 ed invio
foreach (var item in NewActiveAlarm)
{
Thread.Sleep(rand.Next(400, 700));
currAlarm.Add(item.Key, item.Value);
sendActiveAlarm(currAlarm);
}
Thread.Sleep(rand.Next(800 * perRefresh, 1000 * perRefresh));
// CICLO 03: aspetto periodo blink... tra 80 e 110% periodo
// tolgo tutti ed invio
currAlarm = new Dictionary<string, DateTime>();
sendActiveAlarm(currAlarm);
// riaggiungo 1:1 ed invio
foreach (var item in NewActiveAlarm)
{
Thread.Sleep(rand.Next(400, 700));
currAlarm.Add(item.Key, item.Value);
sendActiveAlarm(currAlarm);
}
Thread.Sleep(rand.Next(800 * perRefresh, 1000 * perRefresh));
// svuoto
NewActiveAlarm = new Dictionary<string, DateTime>();
// invio update
sendActiveAlarm(NewActiveAlarm);
}
else
{
// invio allarmi
sendActiveAlarm(NewActiveAlarm);
// aspetto poco
Thread.Sleep(rand.Next(100, 1000 * sogliaSecAllarmi));
// svuoto
NewActiveAlarm = new Dictionary<string, DateTime>();
// invio update
sendActiveAlarm(NewActiveAlarm);
}
// resetto/svuoto allarmi correnti...
NewActiveAlarm = new Dictionary<string, DateTime>();
// inverto tipo simulato...
lastAlarmWasShort = !lastAlarmWasShort;
// indico che ora è INIZIATO periodo OK...
lastOk = DateTime.Now;
}
}
// copio i nuovi allarmi nella memoria principale...
CurrActiveAlarm = NewActiveAlarm;
// invio
sendActiveAlarm(CurrActiveAlarm);
// attesa random
Thread.Sleep(rand.Next(minPeriod, maxPeriod));
} while (true);
}
}
else if (alarmMode == AlarmReportingMode.RawList)
{
// controllo se devo fare (se ho valori da simulare...)
if (alarmsRawConf.Count > 0 && alarmsRawConf[0].messages.Count > 0)
@@ -503,8 +684,8 @@ void simMaint()
void simTools()
{
int minPeriod = 3000;
int maxPeriod = 10000;
int minPeriod = 30000;
int maxPeriod = 120000;
// controllo se devo fare (se ho valori da simulare...)
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>MAPO-MONO</i>
<h4>Version: 1.2.2210.2018</h4>
<h4>Version: 1.2.2210.2318</h4>
<br /> Release Note:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
1.2.2210.2018
1.2.2210.2318
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.2.2210.2018</version>
<version>1.2.2210.2318</version>
<url>http://nexus.steamware.net/repository/SWS/MP.MONO.SIM/stable/LAST/MP.Mon.zip</url>
<changelog>http://nexus.steamware.net/repository/SWS/MP.MONO.SIM/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
+9 -4
View File
@@ -39,12 +39,17 @@
"SerialNumber": "1521"
},
"OptPar": {
"AlarmMode": "RawList"
"AlarmMode": "RawListBlink"
},
"SimPar": {
"MinSaveIntSec": 5,
"PercAllarmi": 10,
"MaxAddAllarmi": 4,
"MaxDurationAllarmi": 10
"PercAllarmi": 60,
//"PercAllarmi": 20,
"MaxAddAllarmi": 6,
"MaxDurationAllarmi": 30,
"PeriodRefresh": 10,
"PeriodOk": 10,
//"PeriodOk": 30,
"SogliaAllarmi": 4
}
}
+32 -32
View File
@@ -2,43 +2,43 @@
{
"source": "NC Alarm",
"messages": [
"NC Alarm 001",
"NC Alarm 002",
"NC Alarm 003",
"NC Alarm 004",
"NC Alarm 005",
"NC Alarm 006",
"NC Alarm 007",
"NC Alarm 008",
"NC Alarm 009",
"NC Alarm 010",
"NC Alarm 011",
"NC Alarm 012",
"NC Alarm 013",
"NC Alarm 014",
"NC Alarm 015",
"NC Alarm 016"
"NC Alarm 001 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 002 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 003 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 004 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 005 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 006 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 007 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 008 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 009 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 010 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 011 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 012 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 013 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 014 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 015 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case",
"NC Alarm 016 - this is a long text made for simulate real alarm text data and so create a bad looking UI like on production case"
]
},
{
"source": "PLC Alarm",
"messages": [
"PLC Warning 001",
"PLC Warning 002",
"PLC Warning 003",
"PLC Warning 004",
"PLC Warning 005",
"PLC Warning 006",
"PLC Warning 007",
"PLC Warning 008",
"PLC Warning 009",
"PLC Warning 010",
"PLC Warning 011",
"PLC Warning 012",
"PLC Warning 013",
"PLC Warning 014",
"PLC Warning 015",
"PLC Warning 016"
"PLC Warning 001 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 002 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 003 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 004 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 005 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 006 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 007 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 008 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 009 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 010 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 011 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 012 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 013 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 014 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 015 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI",
"PLC Warning 016 - this is a medium text made for simulate real warning and create a bad looking UI like on real UI"
]
}
]
+8 -6
View File
@@ -9,18 +9,20 @@
{
if (@ListRecords.Count == 0)
{
<div class="alert alert-success text-center display-4">All OK</div>
<div class="alert alert-success text-center display-4">All OK</div>
}
else
{
<ul class="list-group">
@foreach (var item in ListRecords)
{
<li class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between small" title="order">
<div class="text-wrap">@item.Title</div>
<div class="textConsensed">
<b>@item.Value</b>
<li class="list-group-item alarms list-group-item-action text-warning bg-danger">
<div class="textConsensed w-100 small" title="order">
<div class="small">
@item.Title
</div>
<div class="">
<span class="text-break">@item.Value</span>
</div>
</div>
</li>
+1 -1
View File
@@ -40,7 +40,7 @@
<li class="list-group-item">
<div class="d-flex w-100 justify-content-between" title="Current Cycle Time">
<div><i class="fa-solid fa-stopwatch fa-2x"></i></div>
<div class="h2" title="">
<div class="h3" title="">
<b>@($"{currProd.CycleTime.Hours:00}:{currProd.CycleTime.Minutes:00}:{currProd.CycleTime.Seconds:00}")</b>
</div>
</div>
+1 -1
View File
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Platforms>AnyCPU;x86;x64</Platforms>
<Version>1.2.2210.2018</Version>
<Version>1.2.2210.2318</Version>
</PropertyGroup>
<ItemGroup>
+2 -1
View File
@@ -128,7 +128,7 @@ namespace MP.MONO.UI.Pages
protected override async Task OnInitializedAsync()
{
//StartTimer();
#if false
if (setLogRec)
{
SearchRecords = await MMDataService.AlarmLogGetFilt(MachineId, 0, MaxRecord);
@@ -140,6 +140,7 @@ namespace MP.MONO.UI.Pages
SearchRecordsREC = await MMDataService.AlarmRecGetFilt(MachineId, 0, MaxRecord);
ListRecordsREC = SearchRecordsREC.Skip(numRecord * (currPage - 1)).Take(numRecord).ToList();
}
#endif
await ReloadData(true);
}
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>MAPO-MONO</i>
<h4>Version: 1.2.2210.2018</h4>
<h4>Version: 1.2.2210.2318</h4>
<br /> Release Note:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
1.2.2210.2018
1.2.2210.2318
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.2.2210.2018</version>
<version>1.2.2210.2318</version>
<url>http://nexus.steamware.net/repository/SWS/MP.MONO.UI/stable/LAST/MP.Mon.zip</url>
<changelog>http://nexus.steamware.net/repository/SWS/MP.MONO.UI/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>