1163 lines
47 KiB
C#
1163 lines
47 KiB
C#
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using MP.Core.Objects;
|
|
using MP.Data.DbModels;
|
|
using MP.Data.Repository.IOC;
|
|
using Newtonsoft.Json;
|
|
using NLog;
|
|
using StackExchange.Redis;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using ZiggyCreatures.Caching.Fusion;
|
|
using static MP.Core.Objects.Enums;
|
|
|
|
namespace MP.Data.Services.IOC
|
|
{
|
|
public class IocService : BaseServ, IIocService
|
|
{
|
|
#region Public Constructors
|
|
|
|
public IocService(
|
|
IConfiguration config,
|
|
IConnectionMultiplexer redis,
|
|
IIocRepository repo,
|
|
IServiceScopeFactory scopeFactory,
|
|
//Microsoft.Extensions.Caching.Memory.IMemoryCache cache
|
|
IFusionCache cache) : base(config, redis)
|
|
{
|
|
_className = "IocServ";
|
|
int.TryParse(config.GetValue<string>("ServerConf:redisLongTimeCache"), out redisLongTimeCache);
|
|
int.TryParse(config.GetValue<string>("ServerConf:redisShortTimeCache"), out redisShortTimeCache);
|
|
_repo = repo;
|
|
_scopeFactory = scopeFactory;
|
|
_cache = cache;
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Methods
|
|
|
|
/// <inheritdoc />
|
|
public async Task<bool> CheckCambiaStatoBatchAsync(tipoInputEvento tipoInput, string IdxMacchina, DateTime InizioStato, int IdxTipo, string CodArt, string Value, int MatrOpr, string pallet)
|
|
{
|
|
bool success = await _repo.CheckCambiaStatoBatchAsync(tipoInput, IdxMacchina, InizioStato, IdxTipo, CodArt, Value, MatrOpr, pallet);
|
|
return success;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<bool> ClearFusionCache()
|
|
{
|
|
bool fatto = false;
|
|
await _cache.ClearAsync();
|
|
fatto = true;
|
|
return fatto;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<bool> EvListMicroStatoInsertAsync(MicroStatoMacchinaModel newRecMsm, EventListModel newRecEv)
|
|
{
|
|
bool success = await _repo.EvListMicroStatoInsertAsync(newRecMsm, newRecEv);
|
|
return success;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<string> GetCurrOdlAsync(string idxMacchina)
|
|
{
|
|
string result = "";
|
|
string currKey = $"{MP.Data.Utils.redisOdlCurrByMac}:{idxMacchina}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = _redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = $"{rawData}";
|
|
}
|
|
else
|
|
{
|
|
result = await GetCurrOdlByProdAsync(idxMacchina);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
_redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<Dictionary<string, string>> GetTask2ExeMacchinaAsync(string idxMacchina)
|
|
{
|
|
var currHash = MP.Data.Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
|
|
return await RedisGetHashDictAsync(currHash);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<bool> IobInsEnabAsync(string idxMacchina)
|
|
{
|
|
string cacheKey = $"IOC_IobInsEnab_{idxMacchina}";
|
|
return await GetOrFetchAsync(cacheKey, async () =>
|
|
{
|
|
var key = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
|
|
|
string? val = await _redisDb.HashGetAsync(key, "insEnabled");
|
|
|
|
if (val == null)
|
|
{
|
|
var data = await ResetDatiMacchinaAsync(idxMacchina);
|
|
data.TryGetValue("insEnabled", out val);
|
|
}
|
|
|
|
return val != null && (val == "1" || val.ToLower() == "true");
|
|
}, TimeSpan.FromSeconds(5));
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<bool> MicroStatoMacchinaUpsertAsync(MicroStatoMacchinaModel newRec)
|
|
{
|
|
bool success = await _repo.MicroStatoMacchinaUpsertAsync(newRec);
|
|
return success;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<string> ProcessInputAsync(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore)
|
|
{
|
|
string answ = "";
|
|
if (ValidateInputParams(idxMacchina, valore, dtEve, dtCurr))
|
|
{
|
|
DateTime dataOraEvento = ParseEventTime(dtEve, dtCurr);
|
|
|
|
// se abilitato registro evento sul DB
|
|
if (await IobSLogEnabAsync(idxMacchina))
|
|
{
|
|
int cntVal = 0;
|
|
int.TryParse(contatore, out cntVal);
|
|
await saveSigLogAsync(idxMacchina, valore, dataOraEvento, cntVal);
|
|
}
|
|
// continuo col resto
|
|
try
|
|
{
|
|
// scrivo keep alive!!! (se necessario, altrimenti è in cache...)
|
|
await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
|
|
// Cache dati macchina per evitare lookup ridondanti
|
|
Dictionary<string, string> datiMacc = await mDatiMacchineAsync(idxMacchina);
|
|
// verifico se sia una macchina MULTI....
|
|
if (isMulti(idxMacchina, datiMacc))
|
|
{
|
|
// inizio preprocessing
|
|
string newVal = "";
|
|
// processo OGNI macchina a stati dell'impianto... (KEY:IdxMacchina / IdxMacchina#qualcosa, Val = IdxFamIn)
|
|
foreach (var item in await mTabMSMIAsync(idxMacchina))
|
|
{
|
|
newVal = preProcInput(item.Key, valore, datiMacc);
|
|
// ora processo e salvo il valOut del microstato...
|
|
// INTERNAMENTE gestisce i casi DB/REDIS secondo necessità
|
|
await CheckMicroStatoAsync(item.Key, newVal, dataOraEvento, contatore, datiMacc);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ora processo e salvo il valOut del microstato... INTERNAMENTE
|
|
// gestisce i casi DB/REDIS secondo necessità
|
|
await CheckMicroStatoAsync(idxMacchina, valore, dataOraEvento, contatore, datiMacc);
|
|
}
|
|
// forzo RESET dati macchina...
|
|
await ResetDatiMacchinaAsync(idxMacchina);
|
|
// registro in risposta che è andato tutto bene...
|
|
answ = "OK";
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
string errore = $"Errore: {Environment.NewLine}{exc}";
|
|
Log.Error(errore);
|
|
answ = errore;
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<int> PzCounterTcAsync(string idxMacchina)
|
|
{
|
|
int answ = -1;
|
|
DateTime dataRif = DateTime.Now;
|
|
var datiProd = await StatoProdMacchinaAsync(idxMacchina, dataRif);
|
|
if (datiProd != null)
|
|
{
|
|
answ = datiProd.PzTotODL;
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<string> SaveCounterAsync(string idxMacchina, string counter)
|
|
{
|
|
string answ = "0";
|
|
// inizio processing vero e proprio INPUT...
|
|
if (string.IsNullOrEmpty(idxMacchina))
|
|
{
|
|
string errore = "Errore: parametro macchina vuoto";
|
|
Log.Warn(errore);
|
|
answ = errore;
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrEmpty(counter))
|
|
{
|
|
string errore = "Errore: parametro counter vuoto";
|
|
Log.Warn(errore);
|
|
answ = errore;
|
|
}
|
|
else
|
|
{
|
|
int newCounter = -1;
|
|
int.TryParse(counter, out newCounter);
|
|
// se il conteggio è >= 0 SALVO come nuovo conteggio...
|
|
if (newCounter >= 0)
|
|
{
|
|
var currKey = MP.Data.Utils.RedKeyPzCount(idxMacchina, MpIoNS);
|
|
RedisValue rawData = await _redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
// salvo per + tempo...
|
|
await _redisDb.StringSetAsync(currKey, answ.ToString());
|
|
answ = counter;
|
|
}
|
|
else
|
|
{
|
|
int currCount = await PzCounterTcAsync(idxMacchina);
|
|
answ = currCount.ToString();
|
|
// salvo per meno tempo...
|
|
await _redisDb.StringSetAsync(currKey, answ);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task ScriviKeepAliveAsync(string IdxMacchina, DateTime oraMacchina)
|
|
{
|
|
// cerco se ho keep alive in redis,
|
|
var currKey = MP.Data.Utils.RedKeyHash($"KeepAlive:{IdxMacchina}");
|
|
bool keyPresent = await _redisDb.KeyExistsAsync(currKey);
|
|
// se NON presente salvo in REDIS con TTL 10 sec e sul DB...
|
|
if (!keyPresent)
|
|
{
|
|
DateTime adesso = DateTime.Now;
|
|
await _redisDb.StringSetAsync(currKey, adesso.ToString("s"), TimeSpan.FromSeconds(30));
|
|
// effettuo scrittura sul DB
|
|
await _repo.KeepAliveUpsertAsync(IdxMacchina, DateTime.Now, oraMacchina);
|
|
}
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Protected Fields
|
|
|
|
protected Random rand = new Random();
|
|
|
|
#endregion Protected Fields
|
|
|
|
#region Protected Methods
|
|
|
|
/// <summary>
|
|
/// Restituisce un timeout dai minuti richiesti + tempo random 1..60 sec
|
|
/// </summary>
|
|
/// <param name="stdMinutes"></param>
|
|
/// <returns></returns>
|
|
protected TimeSpan getRandTOut(double stdMinutes)
|
|
{
|
|
double rndValue = stdMinutes + (double)rand.Next(1, 60) / 60;
|
|
return TimeSpan.FromMinutes(rndValue);
|
|
}
|
|
|
|
#endregion Protected Methods
|
|
|
|
#region Private Fields
|
|
|
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
|
|
|
private readonly IFusionCache _cache;
|
|
|
|
private readonly string _className;
|
|
|
|
private readonly IIocRepository _repo;
|
|
private readonly IServiceScopeFactory _scopeFactory;
|
|
|
|
/// <summary>
|
|
/// Provider CultureInfo x parse valori(es dataora)
|
|
/// </summary>
|
|
private CultureInfo ciProvider = CultureInfo.InvariantCulture;
|
|
|
|
/// <summary>
|
|
/// Formato dataora standard x parsing
|
|
/// </summary>
|
|
private string dtFormat = "yyyyMMddHHmmssfff";
|
|
|
|
private int redisLongTimeCache = 5;
|
|
|
|
private int redisShortTimeCache = 2;
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Private Methods
|
|
|
|
/// <summary>
|
|
/// controlla se da il segnale di "microstato" deriva un evento da generare - modalità OFFLINE
|
|
/// </summary>
|
|
/// <param name="idxMacchina">idx macchina</param>
|
|
/// <param name="valore">valOut ingresso</param>
|
|
/// <param name="dtEve">data-ora evento (server)</param>
|
|
/// <param name="contatore">sequenza dati inviati</param>
|
|
/// <param name="datiMaccCache">dati macchina in cache (opzionale, se null fa lookup)</param>
|
|
/// <returns></returns>
|
|
private async Task<inputComandoMapo> CheckMicroStatoAsync(string idxMacchina, string valore, DateTime dtEve, string contatore, Dictionary<string, string>? datiMaccCache = null)
|
|
{
|
|
// recupero SE IMPIEGATO REDIS i valori del Dictionary della macchina...
|
|
Dictionary<string, string> datiMacc = datiMaccCache ?? await mDatiMacchineAsync(idxMacchina);
|
|
|
|
// processing
|
|
inputComandoMapo answ = new inputComandoMapo();
|
|
|
|
// SE no trovassi verifico se esista la macchina altrimenti la creo... REDIS compliant
|
|
if (!datiMacc.ContainsKey(idxMacchina))
|
|
{
|
|
await verificaIdxMacchinaAsync(idxMacchina);
|
|
}
|
|
|
|
// continuo processing...
|
|
string CodArticolo = datiMacc["CodArticolo"];
|
|
if (string.IsNullOrEmpty(CodArticolo))
|
|
{
|
|
var allDatiMacch = await _repo.DatiMacchineGetAllAsync();
|
|
var recMacc = allDatiMacch.FirstOrDefault(x => x.IdxMacchina == idxMacchina);
|
|
if (recMacc != null)
|
|
{
|
|
CodArticolo = recMacc.CodArticoloA;
|
|
}
|
|
}
|
|
// preparo gestione val ingresso
|
|
int? valINT = 0;
|
|
int idxTipoEv = 0;
|
|
int next_idxMS = 0;
|
|
try
|
|
{
|
|
valINT = int.Parse(valore, NumberStyles.HexNumber);
|
|
int idxFamIn = Convert.ToInt32(datiMacc["IdxFamIn"]);
|
|
int idxMicroStato = Convert.ToInt32(datiMacc["IdxMicroStato"]);
|
|
int valIOB = Convert.ToInt32(valINT);
|
|
next_idxMS = idxMicroStato;
|
|
// recupero singolo valOut (stringa) x chiave
|
|
string todoSMI = await ValoreSmiAsync(idxFamIn, idxMicroStato, valIOB);
|
|
// solo se ho trovato un risultato nella tab SMI della famiglia macchina...
|
|
if (!string.IsNullOrEmpty(todoSMI) && todoSMI.Contains("_"))
|
|
{
|
|
// splitto e salvo valori OUT...
|
|
string[] valori = todoSMI.Split('_');
|
|
idxTipoEv = Convert.ToInt32(valori[0]);
|
|
next_idxMS = Convert.ToInt32(valori[1]);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"[ChkMiSt_5a] - - Eccezione in recupero riga Trans ingressi | idxMacchina {idxMacchina} | valINT {valINT}:{Environment.NewLine}{exc}", Environment.NewLine, exc, valINT, idxMacchina);
|
|
}
|
|
|
|
// effettuo update vari SU DB!!!
|
|
MicroStatoMacchinaModel newRecMsm = new MicroStatoMacchinaModel()
|
|
{
|
|
IdxMacchina = idxMacchina,
|
|
IdxMicroStato = next_idxMS,
|
|
InizioStato = dtEve,
|
|
Value = valore
|
|
};
|
|
if (idxTipoEv > 0)
|
|
{
|
|
// preparo record
|
|
string valEsteso = string.Format("[{0}] {1}", contatore.PadLeft(3, '0'), valore);
|
|
// creo evento
|
|
EventListModel newRecEv = new EventListModel()
|
|
{
|
|
CodArticolo = CodArticolo,
|
|
IdxMacchina = idxMacchina,
|
|
IdxTipo = idxTipoEv,
|
|
InizioStato = dtEve,
|
|
MatrOpr = 0,
|
|
pallet = "-",
|
|
Value = valEsteso
|
|
};
|
|
// salva e processa evento + microstato
|
|
answ = await scriviRigaEventoAsync(newRecMsm, newRecEv);
|
|
}
|
|
else
|
|
{
|
|
await _repo.MicroStatoMacchinaUpsertAsync(newRecMsm);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco completo config da DB
|
|
/// </summary>
|
|
private async Task<List<ConfigModel>> ConfigGetAllAsync()
|
|
{
|
|
return await GetOrFetchAsync("IOC_ConfigAll", async () =>
|
|
{
|
|
List<ConfigModel>? result = new List<ConfigModel>();
|
|
// cerco in redis...
|
|
RedisValue rawData = await _redisDb.StringGetAsync(MP.Data.Utils.redisConfKey);
|
|
string source = "DB";
|
|
if (!string.IsNullOrEmpty($"{rawData}"))
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<ConfigModel>>($"{rawData}");
|
|
source = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await _repo.ConfigGetAllAsync();
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await _redisDb.StringSetAsync(MP.Data.Utils.redisConfKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
Log.Debug($"ConfigGetAllAsync Read from {source}");
|
|
if (result == null)
|
|
{
|
|
result = new List<ConfigModel>();
|
|
}
|
|
return result;
|
|
}, TimeSpan.FromMinutes(1));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper standardizzazione valOut dataora ricevuto da IOB remoti
|
|
/// </summary>
|
|
/// <param name="s"></param>
|
|
/// <returns></returns>
|
|
private string dtFormStd(string? s)
|
|
{
|
|
return s?.Length > 17 ? s[..17] : s?.PadRight(17, '0') ?? string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recupero info ODL corrente da dati prod macchina
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
private async Task<string> GetCurrOdlByProdAsync(string idxMacchina)
|
|
{
|
|
string answ = "";
|
|
// recupero stato...
|
|
var datiProd = await StatoProdMacchinaAsync(idxMacchina, DateTime.Now);
|
|
if (datiProd != null)
|
|
{
|
|
answ = datiProd.IdxOdl.ToString();
|
|
}
|
|
// ultimo controllo su idxOdl...
|
|
answ = answ == "" ? "0" : answ;
|
|
// restituisco!
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Implementa gestione recupero cache da memoria o da obj esterno + cache memoria
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="cacheKey"></param>
|
|
/// <param name="fetchFunc"></param>
|
|
/// <param name="expiration"></param>
|
|
/// <returns></returns>
|
|
private async Task<T> GetOrFetchAsync<T>(string cacheKey, Func<Task<T>> fetchFunc, TimeSpan expiration)
|
|
{
|
|
// GetOrSetAsync di Fusion cache:
|
|
// - TryGetValue, se mancasse crea un lock solo per QUELLA key
|
|
// - Esegue fetchFunc (la logica Redis + DB)
|
|
// - Salva in memoria e rilascia il lock
|
|
return await _cache.GetOrSetAsync<T>(
|
|
cacheKey,
|
|
async ct => await fetchFunc(),
|
|
options => options.SetDuration(expiration)
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valOut booleano se la macchina sia abilitata all'inserimento COMPLETO nel
|
|
/// Signal Log
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
private async Task<bool> IobSLogEnabAsync(string idxMacchina)
|
|
{
|
|
bool answ = false;
|
|
// ORA recupero da memoria redis...
|
|
try
|
|
{
|
|
var currHash = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
|
RedisValue rawData = await _redisDb.HashGetAsync(currHash, (RedisValue)"sLogEnabled");
|
|
// se è vuoto... leggo da DB e popolo!
|
|
if (!rawData.HasValue)
|
|
{
|
|
await ResetDatiMacchinaAsync(idxMacchina);
|
|
// riprovo
|
|
rawData = await _redisDb.HashGetAsync(currHash, (RedisValue)"sLogEnabled");
|
|
}
|
|
|
|
// provo conversione
|
|
bool.TryParse($"{rawData}", out answ);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore IobSLogEnabAsync | idxMacchina {idxMacchina}:{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valOut booleano se la macchina sia di tipo MULTI (con più state machine x INGRESSI)
|
|
/// usando dati macchina in cache per evitare lookup ridondanti
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="datiMacc"></param>
|
|
/// <returns></returns>
|
|
private bool isMulti(string idxMacchina, Dictionary<string, string> datiMacc)
|
|
{
|
|
bool answ = false;
|
|
try
|
|
{
|
|
answ = Convert.ToBoolean(datiMacc.ContainsKey("Multi") && datiMacc["Multi"] == "1");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in isMulti{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
private async Task<HashSet<string>> ListMasterAsync()
|
|
{
|
|
return await GetOrFetchAsync("IOC_ListMaster", async () =>
|
|
{
|
|
HashSet<string> result = new();
|
|
string currKey = $"{MP.Data.Utils.redisBaseAddr}:ListMaster";
|
|
RedisValue rawData = await _redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<HashSet<string>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
var fullList = await Macchine2SlaveGetAllAsync();
|
|
result = fullList.Select(x => x.IdxMacchina).ToHashSet<string>();
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await _redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
|
|
}
|
|
return result;
|
|
}, TimeSpan.FromMinutes(15));
|
|
}
|
|
|
|
private async Task<HashSet<string>> ListSlaveAsync()
|
|
{
|
|
return await GetOrFetchAsync("IOC_ListSlave", async () =>
|
|
{
|
|
HashSet<string> result = new();
|
|
string currKey = $"{MP.Data.Utils.redisBaseAddr}:ListSlave";
|
|
RedisValue rawData = await _redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<HashSet<string>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
var fullList = await Macchine2SlaveGetAllAsync();
|
|
result = fullList.Select(x => x.IdxMacchinaSlave).Distinct().ToHashSet<string>();
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await _redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
|
|
}
|
|
return result;
|
|
}, TimeSpan.FromMinutes(15));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco completo valori Macchine 2 Slave
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private async Task<List<Macchine2SlaveModel>> Macchine2SlaveGetAllAsync()
|
|
{
|
|
return await GetOrFetchAsync("IOC_M2SlaveGetAll", async () =>
|
|
{
|
|
List<Macchine2SlaveModel>? result = new List<Macchine2SlaveModel>();
|
|
string currKey = $"{MP.Data.Utils.redisBaseAddr}:M2STab";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = await _redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<Macchine2SlaveModel>>($"{rawData}");
|
|
}
|
|
else
|
|
{
|
|
result = await _repo.Macchine2SlaveAsync();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await _redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<Macchine2SlaveModel>();
|
|
}
|
|
return result;
|
|
}, TimeSpan.FromMinutes(30));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei campi DatiMacchine + StatoMacchine per l'impianto indicato
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
private async Task<Dictionary<string, string>> mDatiMacchineAsync(string idxMacchina)
|
|
{
|
|
// hard coded dimensione vettore DatiMacchine
|
|
Dictionary<string, string> answ = new Dictionary<string, string>();
|
|
// ORA recupero da memoria redis...
|
|
try
|
|
{
|
|
var currHash = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
|
answ = await RedisGetHashDictAsync(currHash);
|
|
// se è vuoto... leggo da DB e popolo!
|
|
if (answ.Count == 0)
|
|
{
|
|
answ = await ResetDatiMacchinaAsync(idxMacchina);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in compilazione dati Macchine x Redis - idxMacchina {idxMacchina}:{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP (async) per evitare blocchi quando chiamato da metodi asincroni
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
private async Task<KeyValuePair<string, string>[]> mTabMSMIAsync(string idxMacchina)
|
|
{
|
|
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[1];
|
|
answ[0] = new KeyValuePair<string, string>("0", "0");
|
|
try
|
|
{
|
|
var currHash = MP.Data.Utils.RedKeyMsmi(idxMacchina);
|
|
answ = await RedisGetHashAsync(currHash);
|
|
if (answ == null || answ.Length == 0)
|
|
{
|
|
answ = await resetMSMIAsync(idxMacchina);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in compilazione Tabella Multi State Machine Ingressi x Redis:{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calcola dataora evento da info dt ricevute
|
|
/// </summary>
|
|
/// <param name="dtEve"></param>
|
|
/// <param name="dtCurr"></param>
|
|
/// <returns></returns>
|
|
private DateTime ParseEventTime(string dtEve, string dtCurr)
|
|
{
|
|
DateTime dataOraEvento = DateTime.Now;
|
|
|
|
// fix formato dataora in ingresso
|
|
string stdEve = dtFormStd(dtEve);
|
|
string stdCurr = dtFormStd(dtCurr);
|
|
|
|
// 2. Se le stringhe normalizzate coincidono, skip dei calcoli
|
|
if (stdEve != stdCurr)
|
|
{
|
|
// 3. Parsing sicuro
|
|
if (DateTime.TryParseExact(stdEve, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtEvento) &&
|
|
DateTime.TryParseExact(stdCurr, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtCorrente))
|
|
{
|
|
TimeSpan diff = dtCorrente - dtEvento;
|
|
double ms = Math.Abs(diff.TotalMilliseconds);
|
|
|
|
// 4. Classificazione delta con switch expression (più leggibile e performante)
|
|
string deltaClass = ms switch
|
|
{
|
|
<= 10 => "0-10 ms",
|
|
<= 100 => "10-100 ms",
|
|
<= 1000 => "100-1000 ms",
|
|
<= 10000 => "1-10 sec",
|
|
_ => "> 10 sec"
|
|
};
|
|
|
|
Log.Debug($"Correzione delta {deltaClass}");
|
|
|
|
// 5. Correzione data/ora server: sottrao lo scarto calcolato
|
|
dataOraEvento = dataOraEvento.Subtract(diff);
|
|
}
|
|
else
|
|
{
|
|
Log.Error($"Errore parsing date: {stdEve} | {stdCurr}");
|
|
}
|
|
}
|
|
return dataOraEvento;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calcola l'effettivo valOut da passare alla macchina a stati INGRESSI usando dati macchina in cache
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="valore"></param>
|
|
/// <param name="datiMacc"></param>
|
|
/// <returns></returns>
|
|
private string preProcInput(string idxMacchina, string valore, Dictionary<string, string> datiMacc)
|
|
{
|
|
string newVal = "";
|
|
try
|
|
{
|
|
// variabili
|
|
int valINT = 0;
|
|
int BitFilt = 0;
|
|
int BSR = 0;
|
|
bool ExplodeBit = false;
|
|
int NumBit = 0;
|
|
int newValInt = 0;
|
|
// recupero parametri dalla cache...
|
|
int.TryParse(datiMacc.ContainsKey("BitFilt") ? datiMacc["BitFilt"] : "0", out BitFilt);
|
|
int.TryParse(datiMacc.ContainsKey("BSR") ? datiMacc["BSR"] : "0", out BSR);
|
|
Boolean.TryParse(datiMacc.ContainsKey("ExplodeBit") ? datiMacc["ExplodeBit"] : "false", out ExplodeBit);
|
|
// non usato (x ora)
|
|
int.TryParse(datiMacc.ContainsKey("NumBit") ? datiMacc["NumBit"] : "0", out NumBit);
|
|
|
|
// recupero valOut
|
|
valINT = int.Parse(valore, NumberStyles.HexNumber);
|
|
// filtro
|
|
newValInt = MP.Core.Utils.bMaskInt(valINT, BitFilt);
|
|
// effettuo eventuale BitShiftRight
|
|
if (BSR > 0)
|
|
{
|
|
newValInt = newValInt >> BSR;
|
|
}
|
|
// effettuo eventuale esplosione in BIT esclusivi
|
|
if (ExplodeBit)
|
|
{
|
|
newValInt = Convert.ToInt32(1 << newValInt);
|
|
}
|
|
// riconverto a STRING HEX!!!
|
|
newVal = newValInt.ToString("X");
|
|
}
|
|
catch
|
|
{
|
|
newVal = valore;
|
|
}
|
|
|
|
return newVal;
|
|
}
|
|
|
|
private async Task<KeyValuePair<string, string>[]> RedisGetHashAsync(RedisKey redKey)
|
|
{
|
|
HashEntry[] rawData = await _redisDb.HashGetAllAsync(redKey);
|
|
var result = rawData.Where(x => !x.Name.IsNull).Select(x => new KeyValuePair<string, string>($"{x.Name}", $"{x.Value}")).ToArray();
|
|
return result;
|
|
}
|
|
|
|
private async Task<Dictionary<string, string>> RedisGetHashDictAsync(RedisKey hashKey)
|
|
{
|
|
HashEntry[] rawData = await _redisDb.HashGetAllAsync(hashKey);
|
|
var result = rawData
|
|
.Where(x => !x.Name.IsNull)
|
|
.ToDictionary(x => x.Name.ToString(), x => x.Value.ToString());
|
|
return result;
|
|
}
|
|
|
|
private async Task RedisSetHashAsync(RedisKey redKey, KeyValuePair<string, string>[] valori, double expireSeconds = -1.0)
|
|
{
|
|
HashEntry[] redHash = valori.Select(x => new HashEntry(x.Key, x.Value)).ToArray();
|
|
await _redisDb.HashSetAsync(redKey, redHash);
|
|
if (expireSeconds > 0.0)
|
|
{
|
|
await _redisDb.KeyExpireAsync(redKey, DateTime.Now.AddSeconds(expireSeconds));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei campi DatiMacchine + StatoMacchine per l'impianto indicato
|
|
/// </summary>
|
|
/// <param name="idxMacc"></param>
|
|
/// <returns></returns>
|
|
private async Task<Dictionary<string, string>> ResetDatiMacchinaAsync(string idxMacc)
|
|
{
|
|
Dictionary<string, string> result = new Dictionary<string, string>();
|
|
VMSFDModel? dbResult = null;
|
|
dbResult = await _repo.VMSFDGetByMaccAsync(idxMacc);
|
|
if (dbResult == null) return new Dictionary<string, string>();
|
|
|
|
double numSecCache = redisLongTimeCache;
|
|
// converto in formato dizionario...
|
|
if (dbResult != null)
|
|
{
|
|
// salvo 1:1 i valori... STATO
|
|
result.Add("IdxMicroStato", $"{dbResult.IdxMicroStato}");
|
|
result.Add("IdxStato", $"{dbResult.IdxStato}");
|
|
result.Add("CodArticolo", $"{dbResult.CodArticolo}");
|
|
result.Add("insEnabled", $"{dbResult.InsEnabled}");
|
|
result.Add("sLogEnabled", $"{dbResult.SLogEnabled}");
|
|
result.Add("pallet", $"{dbResult.Pallet}");
|
|
result.Add("CodArticolo_A", $"{dbResult.CodArticoloA}");
|
|
result.Add("CodArticolo_B", $"{dbResult.CodArticoloB}");
|
|
result.Add("TempoCicloBase", $"{dbResult.TempoCicloBase}");
|
|
result.Add("PzPalletProd", $"{dbResult.PzPalletProd}");
|
|
result.Add("MatrOpr", $"{dbResult.MatrOpr}");
|
|
result.Add("lastVal", $"{dbResult.LastVal}");
|
|
result.Add("TCBase", $"{dbResult.TempoCicloBase}");
|
|
|
|
//...e SETUP
|
|
result.Add("CodMacc", $"{dbResult.Codmacchina}");
|
|
result.Add("IdxFamIn", $"{dbResult.IdxFamigliaIngresso}");
|
|
result.Add("Multi", $"{dbResult.Multi}");
|
|
result.Add("BitFilt", $"{dbResult.BitFilt}");
|
|
result.Add("MaxVal", $"{dbResult.MaxVal}");
|
|
result.Add("BSR", $"{dbResult.Bsr}");
|
|
result.Add("ExplodeBit", $"{dbResult.ExplodeBit}");
|
|
result.Add("NumBit", $"{dbResult.NumBit}");
|
|
result.Add("IdxFamMacc", $"{dbResult.IdxFamiglia}");
|
|
result.Add("simplePallet", $"{dbResult.SimplePallet}");
|
|
result.Add("palletChange", $"{dbResult.PalletChange}");
|
|
// durata cache in secondi dal valOut insEnabled...
|
|
//double numSecCache = ((result["insEnabled"].ToLower() == "true") ? redisShortTimeCache : redisLongTimeCache);
|
|
numSecCache = dbResult.InsEnabled ? redisShortTimeCache : redisLongTimeCache;
|
|
}
|
|
|
|
// dati master/slave
|
|
string isMaster = (await ListMasterAsync()).Contains(idxMacc) ? "1" : "0";
|
|
string isSlave = (await ListSlaveAsync()).Contains(idxMacc) ? "1" : "0";
|
|
result.Add("Master", isMaster);
|
|
result.Add("Slave", isSlave);
|
|
|
|
// Processing redis in transazoine...
|
|
var redKey = MP.Data.Utils.RedKeyDatiMacc(idxMacc, MpIoNS);
|
|
|
|
// variazione con redis transaction...
|
|
var transaction = _redisDb.CreateTransaction();
|
|
// 1. Eliminiamo la chiave (rimuove i vecchi campi)
|
|
_ = transaction.KeyDeleteAsync(redKey);
|
|
// 2. Prepariamo gli HashEntry per il batch (più efficiente di un Dictionary)
|
|
HashEntry[] entries = result.Select(kvp => new HashEntry(kvp.Key, kvp.Value)).ToArray();
|
|
// 3. Inseriamo i nuovi valori
|
|
_ = transaction.HashSetAsync(redKey, entries);
|
|
// 4. Impostiamo l'expiration in un unico colpo
|
|
_ = transaction.KeyExpireAsync(redKey, TimeSpan.FromSeconds(numSecCache));
|
|
// Eseguiamo tutto in un unico viaggio verso Redis
|
|
bool success = await transaction.ExecuteAsync();
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resetta (rileggendo) i dati della State Machine multi ingressi nel formato
|
|
/// currKey: IdxMacchina
|
|
/// value: IdxFamigliaIngresso
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
private async Task<KeyValuePair<string, string>[]> resetMSMIAsync(string idxMacchina)
|
|
{
|
|
var currHash = MP.Data.Utils.RedKeyMsmi(idxMacchina);
|
|
// recupero records
|
|
var tabMSMI = await _repo.VMSFDGetMultiByMaccAsync(idxMacchina);
|
|
|
|
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[tabMSMI.Count];
|
|
// salvo tutti i valori StateMachineIngressi...
|
|
int i = 0;
|
|
foreach (var item in tabMSMI)
|
|
{
|
|
answ[i] = new KeyValuePair<string, string>(item.IdxMacchina, item.IdxFamigliaIngresso.ToString());
|
|
i++;
|
|
}
|
|
// verifico il timeout (default 60 sec...)
|
|
var sTOutSmi = await tryGetConfigAsync("TmOut.MSMI");
|
|
int tOut = 60;
|
|
int.TryParse(sTOutSmi, out tOut);
|
|
tOut = tOut <= 60 ? 60 : tOut;
|
|
// salvo in redis!
|
|
await RedisSetHashAsync(currHash, answ, tOut);
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resetta (rileggendo) i dati della State Machine ingressi nel formato
|
|
/// currKey: cState_nVal (current MICRO-STATE + "_" + new Value)
|
|
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE)
|
|
/// </summary>
|
|
/// <param name="idxFamIn"></param>
|
|
/// <returns></returns>
|
|
private async Task<KeyValuePair<string, string>[]> resetSMIAsync(int idxFamIn)
|
|
{
|
|
var currHash = MP.Data.Utils.GetHashSMI(idxFamIn);
|
|
// leggo da DB...
|
|
var tabSMI = await _repo.StateMachineIngressiAsync(idxFamIn);
|
|
|
|
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[tabSMI.Count];
|
|
// salvo tutti i valori StateMachineIngressi...
|
|
int i = 0;
|
|
string key = "";
|
|
string val = "";
|
|
foreach (var item in tabSMI)
|
|
{
|
|
key = string.Format("{0}_{1}", item.IdxMicroStato, item.ValoreIngresso);
|
|
val = string.Format("{0}_{1}", item.IdxTipoEvento, item.NextIdxMicroStato);
|
|
answ[i] = new KeyValuePair<string, string>(key, val);
|
|
i++;
|
|
}
|
|
// verifico il timeout (default 60 sec...)
|
|
int tOut = 300;
|
|
var sTOutSmi = await tryGetConfigAsync("TmOut.SMI");
|
|
if (!string.IsNullOrEmpty(sTOutSmi))
|
|
{
|
|
int.TryParse(sTOutSmi, out tOut);
|
|
}
|
|
// salvo in redis!
|
|
await RedisSetHashAsync(currHash, answ, tOut);
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// salva il segnale di "microstato" (segnale) ASYNC
|
|
/// </summary>
|
|
/// <param name="idxMacchina">idx macchina</param>
|
|
/// <param name="valore">valOut ingresso</param>
|
|
/// <param name="dtEve">data-ora evento (server)</param>
|
|
/// <param name="contatore">contatore sequenza dati inviati</param>
|
|
/// <returns></returns>
|
|
private async Task<bool> saveSigLogAsync(string idxMacchina, string valore, DateTime dtEve, int contatore)
|
|
{
|
|
SignalLogModel newRec = new SignalLogModel()
|
|
{
|
|
IdxMacchina = idxMacchina,
|
|
DtCurr = DateTime.Now,
|
|
DtEve = dtEve,
|
|
Contatore = contatore,
|
|
Valore = valore
|
|
};
|
|
return await _repo.SignalLogInsertAsync(newRec);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scrive una riga evento + una riga microstato insieme, ed effettua verifica necessità cambio stato
|
|
/// </summary>
|
|
/// <param name="newRecMsm">Record MicroStatoMacchina</param>
|
|
/// <param name="newRecEv">record EventList</param>
|
|
/// <returns></returns>
|
|
private async Task<inputComandoMapo> scriviRigaEventoAsync(MicroStatoMacchinaModel newRecMsm, EventListModel newRecEv)
|
|
{
|
|
bool inserito = false;
|
|
|
|
// inserisco evento
|
|
inserito = await _repo.EvListMicroStatoInsertAsync(newRecMsm, newRecEv);
|
|
// faccio controllo per eventuale cambio stato da tab transizioni...
|
|
|
|
await _repo.CheckCambiaStatoBatchAsync(tipoInputEvento.hw, newRecEv.IdxMacchina, newRecEv.InizioStato ?? DateTime.Now, newRecEv.IdxTipo, newRecEv.CodArticolo, newRecEv.Value, newRecEv.MatrOpr, newRecEv.pallet);
|
|
|
|
// formatto output
|
|
inputComandoMapo answ = new inputComandoMapo();
|
|
answ.outValue = inserito.ToString();
|
|
answ.needStatusRefresh = true;
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei campi della State Machine ingressi nel formato
|
|
/// currKey: cState_nVal (current MICRO-STATE + "_" + new Value)
|
|
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE
|
|
/// </summary>
|
|
/// <param name="idxFamIn"></param>
|
|
/// <returns></returns>
|
|
private async Task<KeyValuePair<string, string>[]> StateMachInByKeyAsync(int idxFamIn)
|
|
{
|
|
// hard coded dimensione vettore DatiMacchine
|
|
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[1];
|
|
// iniziualizzo con un valOut... 0/0
|
|
answ[0] = new KeyValuePair<string, string>("0", "0");
|
|
// ORA recupero da memoria redis...
|
|
try
|
|
{
|
|
var currHash = MP.Data.Utils.GetHashSMI(idxFamIn);
|
|
answ = await RedisGetHashAsync(currHash);
|
|
// se è vuoto... leggo da DB e popolo!
|
|
if (answ.Length == 0)
|
|
{
|
|
answ = await resetSMIAsync(idxFamIn);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in compilazione State Machine Ingressi x Redis:{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stato prod macchina (completo)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="dtReq"></param>
|
|
/// <returns></returns>
|
|
private async Task<StatoProdModel> StatoProdMacchinaAsync(string idxMacchina, DateTime dtReq, bool forceDb = false)
|
|
{
|
|
string cacheKey = $"IOC_StatoProd_{idxMacchina}";
|
|
return await GetOrFetchAsync(cacheKey, async () =>
|
|
{
|
|
StatoProdModel? result = new StatoProdModel();
|
|
// cerco in _redisConn...
|
|
string currKey = $"{MP.Data.Utils.redisStatoProd}:{idxMacchina}:{dtReq:HHmm}";
|
|
RedisValue rawData = await _redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue && !forceDb)
|
|
{
|
|
result = JsonConvert.DeserializeObject<StatoProdModel>($"{rawData}");
|
|
}
|
|
else
|
|
{
|
|
result = await _repo.StatoProdMacchinaAsync(idxMacchina, dtReq);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await _redisDb.StringSetAsync(currKey, rawData, TimeSpan.FromSeconds(30));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new StatoProdModel();
|
|
}
|
|
return result;
|
|
}, TimeSpan.FromSeconds(3));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce valOut della stringa (SE disponibile)
|
|
/// </summary>
|
|
/// <param name="keyName"></param>
|
|
/// <returns></returns>
|
|
private async Task<string> tryGetConfigAsync(string keyName)
|
|
{
|
|
string answ = "";
|
|
// preselezione valori
|
|
var configData = await ConfigGetAllAsync();
|
|
var currRec = configData.FirstOrDefault(x => x.Chiave == keyName);
|
|
if (currRec != null)
|
|
{
|
|
answ = currRec.Valore;
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validazione preliminare valori input
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="valore"></param>
|
|
/// <param name="dtEve"></param>
|
|
/// <param name="dtCurr"></param>
|
|
/// <returns></returns>
|
|
private bool ValidateInputParams(string idxMacchina, string valore, string dtEve, string dtCurr)
|
|
{
|
|
bool isValid = false;
|
|
// preparo stringa valori correnti
|
|
string currVals = $"idxMacchina: {idxMacchina} | valOut: {valore} | dtEve: {dtEve} | dtCurr:{dtCurr}";
|
|
if (dtEve == null || dtCurr == null)
|
|
{
|
|
Log.Warn($"procInput: null found | {currVals}");
|
|
}
|
|
else if (dtEve.Length < 17 || dtCurr.Length < 17)
|
|
{
|
|
Log.Info($"procInput: invalid data | {currVals}");
|
|
}
|
|
else if (string.IsNullOrEmpty(idxMacchina))
|
|
{
|
|
Log.Info($"procInput: missing IdxMacchina | {currVals}");
|
|
}
|
|
else if (string.IsNullOrEmpty(valore))
|
|
{
|
|
Log.Info($"procInput: missing valOut | {currVals}");
|
|
}
|
|
else
|
|
{
|
|
isValid = true;
|
|
}
|
|
return isValid;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valore SPECIFICATO per la state machine ingressi
|
|
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE)
|
|
/// </summary>
|
|
/// <param name="idxFamIn"></param>
|
|
/// <param name="idxMicroStato"></param>
|
|
/// <param name="valoreIn"></param>
|
|
/// <returns></returns>
|
|
private async Task<string> ValoreSmiAsync(int idxFamIn, int idxMicroStato, int valoreIn)
|
|
{
|
|
string valOut = "";
|
|
var currHash = MP.Data.Utils.GetHashSMI(idxFamIn);
|
|
string field = $"{idxMicroStato}_{valoreIn}";
|
|
var searchVal = await _redisDb.HashGetAsync(currHash, field);
|
|
if (!searchVal.HasValue)
|
|
{
|
|
// ricarico tabella (salvando in redis x ricerca successiva)!
|
|
var valori = await StateMachInByKeyAsync(idxFamIn);
|
|
if (valori.Any(x => x.Key == field))
|
|
{
|
|
searchVal = valori.FirstOrDefault(x => x.Key == field).Value;
|
|
}
|
|
}
|
|
valOut = $"{searchVal}";
|
|
return valOut;
|
|
}
|
|
|
|
/// <summary>
|
|
/// cerca codice in anagrafica macchine ed eventualmente inserisce nuova macchina
|
|
/// </summary>
|
|
/// <param name="IdxMacchina"></param>
|
|
private async Task verificaIdxMacchinaAsync(string IdxMacchina)
|
|
{
|
|
// esecuzione in REDIS...cerco status macchina...
|
|
if ((await mDatiMacchineAsync(IdxMacchina)).Count == 0)
|
|
{
|
|
// verifico se esiste su DB
|
|
var dbRec = await _repo.MacchineGetByIdxAsync(IdxMacchina);
|
|
if (dbRec == null)
|
|
{
|
|
MacchineModel newRec = new MacchineModel()
|
|
{
|
|
IdxMacchina = IdxMacchina,
|
|
CodMacchina = "0000",
|
|
Nome = IdxMacchina,
|
|
Descrizione = "Macchina non codificata",
|
|
Note = "-",
|
|
locazione = "",
|
|
RecipeArchivePath = "",
|
|
RecipePath = ""
|
|
};
|
|
await _repo.MacchineUpsertAsync(newRec);
|
|
|
|
// verifico ci sia un microstato macchina...
|
|
var recMSM = await _repo.MicroStatoMacchinaGetByIdxMaccAsync(IdxMacchina);
|
|
if (recMSM.Count == 0)
|
|
{
|
|
// inserisco nuovo stato...
|
|
MicroStatoMacchinaModel msRec = new MicroStatoMacchinaModel()
|
|
{
|
|
IdxMacchina = IdxMacchina,
|
|
IdxMicroStato = 0,
|
|
InizioStato = DateTime.Now,
|
|
Value = "00"
|
|
};
|
|
await _repo.MicroStatoMacchinaUpsertAsync(msRec);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion Private Methods
|
|
}
|
|
} |