2058 lines
80 KiB
C#
2058 lines
80 KiB
C#
using IOB_UT_NEXT;
|
|
using IOB_UT_NEXT.Config;
|
|
using IOB_UT_NEXT.Objects;
|
|
using IOB_UT_NEXT.Services.Files;
|
|
using IOB_UT_NEXT.Services.Networking;
|
|
using MapoSDK;
|
|
using MTConnect.Clients;
|
|
using MTConnect.Devices;
|
|
using MTConnect.Observations;
|
|
using MTConnect.Streams;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net.NetworkInformation;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
|
|
namespace IOB_WIN_MTC.Iob
|
|
{
|
|
public class MTConn : Iob.GenericNext
|
|
{
|
|
#region Public Constructors
|
|
|
|
/// <summary>
|
|
/// Estende l'init della classe base, impiegando il pacchetto Nuget TrackHound https://github.com/TrakHound/MTConnect.NET
|
|
/// </summary>
|
|
/// <param name="caller">Form chiamante</param>
|
|
/// <param name="IobConfFull">Configurazione (v 4.x)</param>
|
|
public MTConn(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
|
|
{
|
|
// gestione parametri da nuova IobConfFull
|
|
enableDataFilter = IobConfFull.FluxLog.EnableFilt;
|
|
MaxSecReload = IobConfFull.FluxLog.MaxSecReload;
|
|
readErrorMax = IobConfFull.Device.ReadErrorMax;
|
|
readErrorSleepTime = IobConfFull.Device.ReadErrorSleepTime;
|
|
enableCliRestart = IobConfFull.Device.Connect.EnableRestart;
|
|
|
|
// gestione data unavailable = poweroff...
|
|
if (!string.IsNullOrEmpty(getOptPar("UNAVAIL_POWEROFF")))
|
|
{
|
|
bool.TryParse(getOptPar("UNAVAIL_POWEROFF"), out unavailPoweroff);
|
|
}
|
|
// gestione restart MTC client...
|
|
if (!string.IsNullOrEmpty(getOptPar("ENABLE_MTC_RESTART")))
|
|
{
|
|
bool.TryParse(getOptPar("ENABLE_MTC_RESTART"), out enableMtcRestart);
|
|
}
|
|
// gestione parametri x sendDataItem
|
|
if (!string.IsNullOrEmpty(getOptPar("ENABLE_SEND_DATAITEM")))
|
|
{
|
|
bool.TryParse(getOptPar("ENABLE_SEND_DATAITEM"), out enableSendDataItem);
|
|
}
|
|
if (!string.IsNullOrEmpty(getOptPar("MIN_VETO_SEND_DATAITEM")))
|
|
{
|
|
int.TryParse(getOptPar("MIN_VETO_SEND_DATAITEM"), out minVetoSendDataItem);
|
|
}
|
|
|
|
|
|
// init datetime counters
|
|
DateTime adesso = DateTime.Now;
|
|
DtHelp.lastPzCountSend = adesso;
|
|
DtHelp.lastWarnODL = adesso;
|
|
lastCurrent = adesso;
|
|
// ora leggo il file di conf specifico....
|
|
string jsonFileName = getOptPar("MTC_PARAM_CONF");
|
|
if (!string.IsNullOrEmpty(jsonFileName))
|
|
{
|
|
// leggo il file...
|
|
loadMtcConf(jsonFileName);
|
|
}
|
|
|
|
// verifico SE ho dei bit "extra" configurati allora NON uso la state machine 54 ma 60...
|
|
if (mtcParams != null && mtcParams.bitSpecCond.Count > 0)
|
|
{
|
|
bitEmg = 7;
|
|
}
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Processo i task richiesti document li elimino dalla coda 1:1
|
|
/// </summary>
|
|
/// <param name="task2exe"></param>
|
|
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe, string codTav)
|
|
{
|
|
// uso metodo base x ora
|
|
return base.executeTasks(task2exe, codTav);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recupera uno specifico dataItem
|
|
/// </summary>
|
|
/// <param name="diKey"></param>
|
|
/// <returns></returns>
|
|
public string getDataItemValue(string diKey)
|
|
{
|
|
string answ = "";
|
|
if (queueInEnabCurr)
|
|
{
|
|
try
|
|
{
|
|
if (dataItemMem.ContainsKey(diKey))
|
|
{
|
|
var currDataItem = dataItemMem[diKey];
|
|
answ = currDataItem.value;
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Logging.Instance.Error($"Errore in getDataItemValue per {diKey}{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgDebug($"[VETO getDataItemValue] | veto attivo alle {DateTime.Now:yyyy.MM.dd HH:mm:ss}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recupero dati dinamici...
|
|
/// </summary>
|
|
public override Dictionary<string, string> getDynData()
|
|
{
|
|
Dictionary<string, string> outVal = new Dictionary<string, string>();
|
|
return outVal;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua vero processing contapezzi
|
|
/// </summary>
|
|
public override void processContapezzi()
|
|
{
|
|
if (enablePzCountByApp)
|
|
{
|
|
if (queueInEnabCurr)
|
|
{
|
|
// cerco parametro contapezzi...
|
|
string currPzCount = getDataItemValue(mtcParams.keyPartCount);
|
|
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo($"contapezzi: {mtcParams.keyPartCount} --> {currPzCount}");
|
|
}
|
|
|
|
// se ho un contapezzi... processo...
|
|
if (!string.IsNullOrEmpty(currPzCount))
|
|
{
|
|
int newVal = -1;
|
|
Int32.TryParse(currPzCount, out newVal);
|
|
contapezziPLC = newVal > -1 ? newVal : contapezziPLC;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgDebug($"[VETO processContapezzi] | veto attivo alle {DateTime.Now:yyyy.MM.dd HH:mm:ss}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgTrace($"processContapezzi escluso: enablePzCountByApp = {enablePzCountByApp} | disablePzCountByIob: {disablePzCountByIob}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua lettura semafori principale di default da FamIngressi 54 ma opzionalmente si può cambiare (es 60)
|
|
/// <paramref name="currDispData">Parametri da
|
|
/// aggiornare x display in form</paramref>
|
|
/// </summary>
|
|
public override void readSemafori(ref newDisplayData currDispData)
|
|
{
|
|
DateTime adesso = DateTime.Now;
|
|
DtHelp.lastReadPLC = adesso;
|
|
// verifico non sia in veto invio iniziale...
|
|
if (queueInEnabCurr)
|
|
{
|
|
try
|
|
{
|
|
if (verboseLog)
|
|
{
|
|
lgInfo("inizio read semafori");
|
|
}
|
|
|
|
currDispData.semIn = Semaforo.SV;
|
|
|
|
// decodifica document gestione
|
|
decodeToBaseBitmap();
|
|
reportRawInput(ref currDispData);
|
|
|
|
// controllo read error ed eventuale disconnect
|
|
if (readErrorCurr > readErrorMax)
|
|
{
|
|
lgError($"Effettuo disconnessione x superamento errori lettura UA_ref.ReadNodeString, sleetp 15 sec");
|
|
tryDisconnect();
|
|
Thread.Sleep(readErrorSleepTime);
|
|
readErrorCurr = 0;
|
|
}
|
|
else if (readErrorCurr > 0)
|
|
{
|
|
readErrorCurr--;
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
currDispData.semIn = Semaforo.SR;
|
|
lgError($"Eccezione in readSemafori:{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgDebug($"[VETO readSemafori] | veto attivo alle {adesso:yyyy.MM.dd HH:mm:ss}");
|
|
checkVetoQueueIn();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua reset del contapezzi, NON POSSIBILE per MTC (read only)
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override bool resetContapezziPLC(string codTav)
|
|
{
|
|
bool answ = true;
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE per MTC (read only)
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override bool setcontapezziPLC(int newPzCount, string codTav)
|
|
{
|
|
bool answ = true;
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override connessione
|
|
/// </summary>
|
|
public override void tryConnect()
|
|
{
|
|
if (!connectionOk)
|
|
{
|
|
// disattivo eventuali sottoscrizioni
|
|
DeactEvents();
|
|
// controllo che il ping sia stato tentato almeno pingTestSec fa...
|
|
if (DateTime.Now.Subtract(DtHelp.lastPING).TotalSeconds > utils.CRI("pingTestSec"))
|
|
{
|
|
if (verboseLog || periodicLog)
|
|
{
|
|
lgInfo("MTC: ConnKO - tryConnect");
|
|
}
|
|
// in primis salvo data ping...
|
|
DtHelp.lastPING = DateTime.Now;
|
|
// se passa il ping faccio il resto...
|
|
if (testPingMachine == IPStatus.Success)
|
|
{
|
|
string szStatusConnection = "";
|
|
try
|
|
{
|
|
// ora provo connessione...
|
|
parentForm.commPlcActive = true;
|
|
doConnect();
|
|
parentForm.commPlcActive = false;
|
|
// refresh stato allarmi!!!
|
|
if (connectionOk)
|
|
{
|
|
checkVetoQueueIn();
|
|
if (adpRunning)
|
|
{
|
|
lgInfo("Connessione OK");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("Impossibile procedere, connessione mancante...");
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgFatal($"Errore nella connessione all'adapter MTC: {szStatusConnection}{Environment.NewLine}{exc}");
|
|
connectionOk = false;
|
|
lgInfo($"Eccezione in TryConnect, Adapter MTC NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// loggo no risposta ping ...
|
|
connectionOk = false;
|
|
if (verboseLog || periodicLog)
|
|
{
|
|
lgInfo($"Attenzione: MTC controllo PING fallito per IP {IOBConfFull.Device.Connect.PingIpAddr}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
needRefresh = true;
|
|
}
|
|
// se non è ancora connesso faccio procesisng memoria caso disconnesso...
|
|
if (!connectionOk)
|
|
{
|
|
// processo semafori ed invio...
|
|
processMemoryDiscon();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override disconnessione
|
|
/// </summary>
|
|
public override void tryDisconnect()
|
|
{
|
|
try
|
|
{
|
|
queueInEnabCurr = false;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lg.Error($"eccezione in tryDisconnect | queueInEnabCurr = false{Environment.NewLine}{exc}");
|
|
}
|
|
// verifico che NON sia in fase di avvio MTC...
|
|
if (isConnecting && DateTime.Now.Subtract(startConnecting).TotalSeconds < 60)
|
|
{
|
|
lgInfo("Disconnessione non effettuata: connessione ancora in corso");
|
|
}
|
|
else
|
|
{
|
|
lgTrace("Richiesta tryDisconnect");
|
|
if (connectionOk)
|
|
{
|
|
string szStatusConnection = "";
|
|
try
|
|
{
|
|
// disattivo sottoscrizioni
|
|
DeactEvents();
|
|
// stop componente
|
|
MTC_ref.Stop();
|
|
connectionOk = false;
|
|
isConnecting = false;
|
|
lgInfo($"conn status: {szStatusConnection}");
|
|
lgInfo("Effettuata disconnessione adapter MTC!");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgFatal(exc, "Errore nella disconnessione dall'adapter MTC");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("IMPOSSIBILE effettuare disconnessione MTC: Connessione non disponibile...");
|
|
}
|
|
}
|
|
queueInEnabCurr = false;
|
|
needRefresh = true;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Protected Fields
|
|
|
|
/// <summary>
|
|
/// Gestione filtraggio dati
|
|
/// </summary>
|
|
protected bool enableDataFilter = false;
|
|
|
|
/// <summary>
|
|
/// Abilitazione restart (da opt par...)
|
|
/// </summary>
|
|
protected bool enableMtcRestart = false;
|
|
|
|
/// <summary>
|
|
/// Determina se ha effettuata lettura items in memoria x confronto...
|
|
/// </summary>
|
|
protected bool hasReadItems = false;
|
|
|
|
/// <summary>
|
|
/// Ultimo current received x gestione update periodico...
|
|
/// </summary>
|
|
protected DateTime lastCurrent = DateTime.Now;
|
|
|
|
/// <summary>
|
|
/// Oggetto MAIN x connessione MTC
|
|
/// </summary>
|
|
protected MTConnectHttpClient MTC_ref;
|
|
|
|
/// <summary>
|
|
/// Gestione valori unavailable come POWEROFF (es trevisan)
|
|
/// </summary>
|
|
protected bool unavailPoweroff = false;
|
|
|
|
/// <summary>
|
|
/// Veto controllos tatus x log...
|
|
/// </summary>
|
|
protected DateTime vetoCheckStatus = DateTime.Now;
|
|
|
|
#endregion Protected Fields
|
|
|
|
#region Protected Properties
|
|
|
|
/// <summary>
|
|
/// Verifico se abbia ALMENO un errore...
|
|
/// </summary>
|
|
protected bool hasError
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
// controllo TUTTE le conditions...
|
|
foreach (var item in dataItemMem)
|
|
{
|
|
// se NON HO GIA' allarmi attivi...
|
|
if (!answ)
|
|
{
|
|
// se è una condition...
|
|
if (item.Value.Category == MTConnect.Devices.DataItemCategory.CONDITION)
|
|
{
|
|
// se ha valore !="" --> allarmi attivi
|
|
if (!string.IsNullOrEmpty(item.Value.value))
|
|
{
|
|
answ = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Indica se abbia emergenza premuta
|
|
/// </summary>
|
|
protected bool hasEStopTriggered
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
if (queueInEnabCurr)
|
|
{
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(mtcParams.keyEStop))
|
|
{
|
|
string currEStop = getDataItemValue(mtcParams.keyEStop);
|
|
answ = (currEStop == "TRIGGERED");
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Logging.Instance.Error($"Errore in hasEStopTriggered{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgDebug($"[VETO hasEStopTriggered] | veto attivo alle {DateTime.Now:yyyy.MM.dd HH:mm:ss}");
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifico se abbia unavailable x le condizioni principali condPowerOn keyRunMode
|
|
/// </summary>
|
|
protected bool hasUnavailableData
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
if (queueInEnabCurr)
|
|
{
|
|
// verifico le condizioni: powerOn, run document work...
|
|
string currRun = getDataItemValue(mtcParams.keyRunMode);
|
|
bool unavRun = currRun.ToUpper() == "UNAVAILABLE";
|
|
string currPowerOn = getDataItemValue(mtcParams.condPowerOn.keyName);
|
|
bool checkPowerOn = (currPowerOn == mtcParams.condPowerOn.targetValue);
|
|
answ = unavRun && !checkPowerOn;
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
protected bool isConnecting { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Parametri specifici MTC
|
|
/// </summary>
|
|
protected MtcParamConf mtcParams { get; set; }
|
|
|
|
protected DateTime startConnecting { get; set; } = DateTime.Today;
|
|
|
|
#endregion Protected Properties
|
|
|
|
#region Protected Methods
|
|
|
|
/// <summary>
|
|
/// Verifica un DataItem document se il valore corrisponde a quello indicato come "true eValue"
|
|
/// restituisce true
|
|
/// </summary>
|
|
/// <param name="itemName"></param>
|
|
/// <param name="trueVal"></param>
|
|
/// <returns></returns>
|
|
protected bool checkDataItem(string itemName, string trueVal)
|
|
{
|
|
bool answ = false;
|
|
MtcDataItemExt currValue = null;
|
|
try
|
|
{
|
|
currValue = dataItemMem[itemName];
|
|
answ = (currValue.value.Equals(trueVal));
|
|
}
|
|
catch
|
|
{
|
|
lgError($"Errore in decodifica valore per {itemName} rispetto a {trueVal} | recuperato {currValue} / {currValue.value}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica condizione "multipla" secondo setup json
|
|
/// </summary>
|
|
/// <param name="reqCondition">Set condizioni da validare</param>
|
|
/// <returns></returns>
|
|
protected bool checkMultiCondition(diCheckCondSetup reqCondition)
|
|
{
|
|
bool answ = false;
|
|
int numCondTgt = 0;
|
|
int numCond = 0;
|
|
if (reqCondition.checkList != null && reqCondition.checkList.Count > 0)
|
|
{
|
|
numCond = reqCondition.checkList.Count;
|
|
// cerco nell'elenco delle condizioni che indicano lavora se sono ok faccio +1 conteggio......
|
|
foreach (var item in reqCondition.checkList)
|
|
{
|
|
if (string.IsNullOrEmpty(item.keyName))
|
|
{
|
|
lgError($"Attenzione: item vuoto in checkMultiCondition{Environment.NewLine}StackTrace: {Environment.StackTrace}");
|
|
}
|
|
else
|
|
{
|
|
// versione semplificata MTC
|
|
if (getDataItemValue(item.keyName) == item.targetValue)
|
|
{
|
|
numCondTgt++;
|
|
}
|
|
|
|
// versione completa OPC-UA
|
|
#if false
|
|
// verifico se ci sia richiesta x test bit...
|
|
if (item.bitNum >= 0)
|
|
{
|
|
if (getDataItemValueBit(item.keyName, item.bitNum) == item.targetValue)
|
|
{
|
|
numCondTgt++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (getDataItemValue(item.keyName) == item.targetValue)
|
|
{
|
|
numCondTgt++;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
if (reqCondition.checkMode == boolCheckMode.AND)
|
|
{
|
|
answ = (numCond == numCondTgt);
|
|
}
|
|
else if (reqCondition.checkMode == boolCheckMode.OR)
|
|
{
|
|
answ = numCondTgt > 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
answ = true;
|
|
}
|
|
// verifico se devo negare il valore...
|
|
answ = reqCondition.negateValue ? !answ : answ;
|
|
// restituisco
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica / Salva valore condition
|
|
/// </summary>
|
|
/// <param name="observ"></param>
|
|
/// <param name="cValue">Messaggio completo (livello + testo)</param>
|
|
/// <returns></returns>
|
|
protected bool checkSaveCondition(IObservation observ, string cValue)
|
|
{
|
|
bool answ = !enableDataFilter;
|
|
|
|
if (observ != null)
|
|
{
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo($"Richiesta checkSaveCondition per {observ} | id: {observ.DataItemId} | message: {cValue}");
|
|
}
|
|
// verifico in memoria se ho l'oggetto condition ed il suo valore..
|
|
if (dataItemMem.ContainsKey(observ.DataItemId))
|
|
{
|
|
// check variazione
|
|
if (dataItemMem[observ.DataItemId].value != cValue)
|
|
{
|
|
dataItemMem[observ.DataItemId].value = cValue;
|
|
answ = true;
|
|
}
|
|
dataItemMem[observ.DataItemId].valueTimestamp = observ.Timestamp;
|
|
}
|
|
else
|
|
{
|
|
// registro non trovato da aggiungere...
|
|
lgInfo($"DataItem non trovato in checkSaveCondition: {observ.DataItemId}");
|
|
try
|
|
{
|
|
// provo a creare oggetto in memoria...
|
|
List<machDataItem> elencoDataItems = new List<machDataItem>();
|
|
int dSamplePeriod = 0;
|
|
float threshDBand = 0;
|
|
string uuid = "";
|
|
var currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, observ, cValue);
|
|
// aggiungo
|
|
dataItemMem.Add(observ.DataItemId, currDataItem);
|
|
var thisCat = (MapoSDK.DataItemCategory)Enum.Parse(typeof(MapoSDK.DataItemCategory), $"{observ.Category}");
|
|
// salvo oggetto x registrazione su server MP-IO
|
|
var currMapoDataItem = new machDataItem()
|
|
{
|
|
uuid = observ.DataItemId,
|
|
Category = thisCat,
|
|
Name = observ.Name,
|
|
Type = observ.Type,
|
|
SubType = observ.SubType,
|
|
//Units = observ.Units
|
|
};
|
|
// aggiungo
|
|
elencoDataItems.Add(currMapoDataItem);
|
|
// invio il dataItem serializzato...
|
|
sendDataItemsList(elencoDataItems);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in checkSaveCondition{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("Attenzione: checkSaveCondition con observ null!");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica / Salva valore EVENT generico (NON SAMPLE)
|
|
/// </summary>
|
|
/// <param name="observ"></param>
|
|
/// <param name="iValue"></param>
|
|
/// <returns></returns>
|
|
protected bool checkSaveEvent(IObservation observ, string iValue)
|
|
{
|
|
bool answ = !enableDataFilter;
|
|
|
|
if (observ != null)
|
|
{
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo($"Richiesta checkSaveEvent per {observ} | id: {observ.DataItemId} | eValue: {iValue}");
|
|
}
|
|
// verifico in memoria se ho l'oggetto EVENT ed il suo valore..
|
|
if (dataItemMem.ContainsKey(observ.DataItemId))
|
|
{
|
|
// verifico SE sia cambiato...
|
|
if (dataItemMem[observ.DataItemId].value != iValue)
|
|
{
|
|
// verifico SE avessi una soglia deadBand...
|
|
if (dataItemMem[observ.DataItemId].thresholdDeadBand > 0)
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
dataItemMem[observ.DataItemId].value = iValue;
|
|
answ = true;
|
|
}
|
|
}
|
|
dataItemMem[observ.DataItemId].valueTimestamp = observ.Timestamp;
|
|
}
|
|
else
|
|
{
|
|
// registro non trovato da aggiungere...
|
|
lgInfo($"DataItem non trovato in checkSaveEvent: {observ.DataItemId}");
|
|
try
|
|
{
|
|
// provo a creare oggetot in memoria...
|
|
List<machDataItem> elencoDataItems = new List<machDataItem>();
|
|
int dSamplePeriod = 0;
|
|
float threshDBand = 0;
|
|
string uuid = "";
|
|
var currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, observ, iValue);
|
|
// aggiungo
|
|
dataItemMem.Add(observ.DataItemId, currDataItem);
|
|
var thisCat = (MapoSDK.DataItemCategory)Enum.Parse(typeof(MapoSDK.DataItemCategory), $"{observ.Category}");
|
|
// salvo oggetto x registrazione su server MP-IO
|
|
var currMapoDataItem = new machDataItem()
|
|
{
|
|
uuid = observ.DataItemId,
|
|
Category = thisCat,
|
|
Name = observ.Name,
|
|
Type = observ.Type,
|
|
SubType = observ.SubType,
|
|
//Units = observ.Units
|
|
};
|
|
// aggiungo
|
|
elencoDataItems.Add(currMapoDataItem);
|
|
// invio il dataItem serializzato...
|
|
sendDataItemsList(elencoDataItems);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in checkSaveEvent{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("Attenzione: checkSaveEvent con observ null!");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica / Salva valore SAMPLE document restitusice SE sia variato (document quindi da inviare...)
|
|
/// </summary>
|
|
/// <param name="observ"></param>
|
|
/// <returns></returns>
|
|
protected bool checkSaveSample(IObservation observ, string sValue)
|
|
{
|
|
bool answ = !enableDataFilter;
|
|
double oldVal = 0;
|
|
double newVal = 0;
|
|
if (observ != null)
|
|
{
|
|
// verifico in memoria se ho l'oggetto condition ed il suo valore..
|
|
if (dataItemMem.ContainsKey(observ.DataItemId))
|
|
{
|
|
MtcDataItemExt currDataItemMem = dataItemMem[observ.DataItemId];
|
|
// controllo SE SIA scaduto il tempo massimo...
|
|
if (Math.Abs(dataItemMem[observ.DataItemId].valueTimestamp.Subtract(observ.Timestamp).TotalSeconds) > currDataItemMem.samplePeriod)
|
|
{
|
|
answ = true;
|
|
}
|
|
else
|
|
{
|
|
// ALTRIMENTI controllo SE diverso
|
|
if (dataItemMem[observ.DataItemId].value != sValue)
|
|
{
|
|
// controllo SE ho DeadBand...
|
|
if (dataItemMem[observ.DataItemId].thresholdDeadBand > 0)
|
|
{
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo($"Test deadband: oldVal: {oldVal} | newVal: {newVal}");
|
|
}
|
|
// recupero i valori document testo DeadBand...
|
|
double.TryParse(dataItemMem[observ.DataItemId].value.Replace(".", ","), out oldVal);
|
|
double.TryParse(sValue.Replace(".", ","), out newVal);
|
|
// test deadband!
|
|
if (Math.Abs(newVal - oldVal) > dataItemMem[observ.DataItemId].thresholdDeadBand)
|
|
{
|
|
// indico da salvare..
|
|
answ = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (answ)
|
|
{
|
|
// salvo!
|
|
dataItemMem[observ.DataItemId].value = sValue;
|
|
dataItemMem[observ.DataItemId].valueTimestamp = observ.Timestamp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// registro non trovato da aggiungere...
|
|
lgInfo($"DataItem non trovato in checkSaveSample: {observ.DataItemId}");
|
|
// provo a creare oggetto in memoria...
|
|
try
|
|
{
|
|
List<machDataItem> elencoDataItems = new List<machDataItem>();
|
|
int dSamplePeriod = 0;
|
|
float threshDBand = 0;
|
|
string uuid = "";
|
|
var currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, observ, sValue);
|
|
// aggiungo
|
|
dataItemMem.Add(observ.DataItemId, currDataItem);
|
|
var thisCat = (MapoSDK.DataItemCategory)Enum.Parse(typeof(MapoSDK.DataItemCategory), $"{observ.Category}");
|
|
// salvo oggetto x registrazione su server MP-IO
|
|
var currMapoDataItem = new machDataItem()
|
|
{
|
|
uuid = observ.DataItemId,
|
|
Category = thisCat,
|
|
Name = observ.Name,
|
|
Type = observ.Type,
|
|
SubType = observ.SubType,
|
|
//Units = observ.Units
|
|
};
|
|
// aggiungo
|
|
elencoDataItems.Add(currMapoDataItem);
|
|
// invio il dataItem serializzato...
|
|
sendDataItemsList(elencoDataItems);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in checkSaveSample{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("Attenzione: checkSaveEvent con observ null!");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Indica se siano valide condizioni di bit speciali
|
|
/// </summary>
|
|
protected bool hasBitCondition(int bitNum)
|
|
{
|
|
bool answ = false;
|
|
if (queueInEnabCurr)
|
|
{
|
|
if (mtcParams.bitSpecCond.ContainsKey(bitNum))
|
|
{
|
|
answ = checkMultiCondition(mtcParams.bitSpecCond[bitNum]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgDebug($"[VETO hasWarmUpConditions] | veto attivo alle {DateTime.Now:yyyy.MM.dd HH:mm:ss}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua traduzione ITEM da LUT parametrica (key: tipo+id) del file di conf, se non
|
|
/// trovo uso key
|
|
/// </summary>
|
|
/// <param name="tipo"></param>
|
|
/// <param name="id"></param>
|
|
/// <returns></returns>
|
|
protected override string itemTranslation(string tipo, string id)
|
|
{
|
|
string answ = "";
|
|
string lemma = $"{tipo}_{id}";
|
|
// cerco nel dizionario delle traduzioni SE esiste un valore document prendo quello, altrimenti
|
|
// uso il lemma...
|
|
if (mtcParams.itemTranslation.ContainsKey(lemma))
|
|
{
|
|
answ = mtcParams.itemTranslation[lemma];
|
|
}
|
|
else
|
|
{
|
|
answ = lemma;
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua log di un elenco componenti
|
|
/// </summary>
|
|
/// <param name="elencoComponenti"></param>
|
|
protected int logComponentsList(List<IComponent> elencoComponenti)
|
|
{
|
|
int found = 0;
|
|
if (elencoComponenti != null)
|
|
{
|
|
foreach (var item in elencoComponenti)
|
|
{
|
|
lgTrace($"Component data | ID: {item.Id} | Name: {item.Name} | Type: {item.Type} | # items: {item.DataItems.Count()}");
|
|
found++;
|
|
// se ho sottocomponenti richiamo...
|
|
if (item.Components != null)
|
|
{
|
|
if (item.Components.Count() > 0)
|
|
{
|
|
found += logComponentsList(item.GetComponents().ToList());
|
|
}
|
|
}
|
|
if (item.DataItems.Count() > 0)
|
|
{
|
|
found += logDataItemList(item.GetDataItems().ToList());
|
|
}
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua log di un elenco composizioni
|
|
/// </summary>
|
|
/// <param name="elencoComposizioni"></param>
|
|
protected int logCompositionList(List<IComposition> elencoComposizioni)
|
|
{
|
|
int found = 0;
|
|
if (elencoComposizioni != null)
|
|
{
|
|
foreach (var item in elencoComposizioni)
|
|
{
|
|
lgTrace($"Composition data | ID: {item.Id} | Name: {item.Name} | Type: {item.Type} | # items: {item.DataItems.Count()} | path: {item.IdPath}");
|
|
found++;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Log elenco DataItems
|
|
/// </summary>
|
|
/// <param name="elencoItems"></param>
|
|
protected int logDataItemList(List<IDataItem> elencoItems)
|
|
{
|
|
int found = 0;
|
|
if (elencoItems != null)
|
|
{
|
|
// loggo devices principali...
|
|
foreach (var item in elencoItems)
|
|
{
|
|
lgTrace($"Device data | ID: {item.Id} | Name: {item.Name} | Category: {item.Category} | # Type: {item.Type} | Path: {item.IdPath}");
|
|
found++;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua log di un devices (ed eventualmente dei sub-devices...
|
|
/// </summary>
|
|
/// <param name="listDevices"></param>
|
|
protected void logProbeDevices(List<IDevice> listDevices)
|
|
{
|
|
if (listDevices != null)
|
|
{
|
|
int numCom = 0;
|
|
int numDev = 0;
|
|
int numItm = 0;
|
|
// loggo devices principali...
|
|
foreach (var device in listDevices)
|
|
{
|
|
lgTrace($"Device data | ID: {device.Id} | Name: {device.Name} | UUID: {device.Uuid} | # items: {device.DataItems.Count()}");
|
|
// se ho subItems descrivo pure loro...
|
|
if (device.DataItems.Count() > 0)
|
|
{
|
|
numItm += logDataItemList(device.GetDataItems().ToList());
|
|
}
|
|
if (device.Components.Count() > 0)
|
|
{
|
|
numCom += logComponentsList(device.GetComponents().ToList());
|
|
}
|
|
// All Compositions (traverse the entire Device model)
|
|
if (device.Compositions.Count() > 0)
|
|
{
|
|
numCom += logCompositionList(device.GetCompositions().ToList());
|
|
}
|
|
}
|
|
lgInfo(lineSep);
|
|
lgInfo($"Effettuata lettura | Components: {numCom} | Devices: {numDev} | DataItems: {numItm}");
|
|
lgInfo(lineSep);
|
|
}
|
|
}
|
|
|
|
#endregion Protected Methods
|
|
|
|
#region Private Fields
|
|
|
|
/// <summary>
|
|
/// Valore del bit usato x emergenza, default 5 x StateMach=54 , 7 se è StateMac=60
|
|
/// </summary>
|
|
private int bitEmg = 5;
|
|
|
|
/// <summary>
|
|
/// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing
|
|
/// </summary>
|
|
private Dictionary<string, MtcDataItemExt> dataItemMem = new Dictionary<string, MtcDataItemExt>();
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Private Methods
|
|
|
|
/// <summary>
|
|
/// Verifica ed invia variazioni
|
|
/// </summary>
|
|
/// <param name="document"></param>
|
|
/// <param name="forceSend"></param>
|
|
private void checkAndSend(IStreamsResponseDocument document, bool forceSend)
|
|
{
|
|
if (document != null)
|
|
{
|
|
foreach (var deviceStream in document.Streams)
|
|
{
|
|
// DeviceStream
|
|
lgTrace($"Stream: {deviceStream.Name}");
|
|
|
|
// Component Streams
|
|
foreach (var dataStream in deviceStream.ComponentStreams)
|
|
{
|
|
lgTrace($"Component {dataStream.Name} -->");
|
|
// DataItems (Samples, Events, and Conditions)
|
|
foreach (var observation in dataStream.Observations)
|
|
{
|
|
// cerco se non sia un dato filtrato in FLUXLOG...
|
|
bool isFiltered = mtcParams.fluxLogVeto.Where(x => x == observation.DataItemId).Count() > 0;
|
|
if (isFiltered)
|
|
{
|
|
traceObservation(observation);
|
|
}
|
|
else
|
|
{
|
|
processObservation(observation, forceSend);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("StreamsSuccessful ERROR: document è null");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disattivazione eventi sottoscritti
|
|
/// </summary>
|
|
private void DeactEvents()
|
|
{
|
|
if (MTC_ref != null)
|
|
{
|
|
// disconnetto metodi sottoscritti
|
|
MTC_ref.ClientStarted -= MTC_ref_ClientStarted;
|
|
MTC_ref.ClientStopped -= MTC_ref_ClientStopped;
|
|
MTC_ref.ConnectionError -= MTC_ref_ConnectionError;
|
|
MTC_ref.AssetsReceived -= MTC_ref_AssetsReceived;
|
|
MTC_ref.ProbeReceived -= MTC_ref_ProbeReceived;
|
|
MTC_ref.CurrentReceived -= MTC_ref_CurrentReceived;
|
|
// sample subscription
|
|
if (mtcParams.doSubsSample)
|
|
{
|
|
MTC_ref.SampleReceived -= MTC_ref_SampleReceived;
|
|
//MTC_ref.SampleReceived += StreamsSuccessful;
|
|
}
|
|
// observ subscription
|
|
if (mtcParams.doSubsObserv)
|
|
{
|
|
MTC_ref.ObservationReceived -= MTC_ref_ObservationReceived;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua decodifica aree memoria alla bitmap usata x MAPO (std 54, opzioanlmente 60)
|
|
/// </summary>
|
|
private void decodeToBaseBitmap()
|
|
{
|
|
/* -----------------------------------------------------
|
|
* Macchine a stati ammesse: tipicamente 54 (STD) opure 60 (SE ho configurazione 6° bit)
|
|
*
|
|
* -----------------------------------
|
|
* bitmap MAPO, STD 54 (6 bit)
|
|
* B0: POWER_ON
|
|
* B1: RUN
|
|
* B2: pzCount
|
|
* B3: allarme
|
|
* B4: manuale
|
|
* B5: emergenza (dipende da state machine se riportare 1 = armata/premuta, vedere conf mtcParams.emergencyArmedTrue)
|
|
* -----------------------------------
|
|
*
|
|
* -----------------------------------
|
|
* bitmap MAPO, OPZ 60 (8 bit)
|
|
* B0: POWER_ON
|
|
* B1: RUN
|
|
* B2: pzCount
|
|
* B3: allarme
|
|
* B4: manuale
|
|
* B5: emergenza (dipende da state machine se riportare 1 = armata/premuta, vedere conf mtcParams.emergencyArmedTrue)
|
|
----------------------------------------------------- */
|
|
|
|
// init a zero...
|
|
B_input = 0;
|
|
if (queueInEnabCurr)
|
|
{
|
|
DateTime adesso = DateTime.Now;
|
|
// controllo se non ho dati buoni da > MaxSecReload sec --> disconnetto
|
|
if (adesso.Subtract(lastCurrent).TotalSeconds > MaxSecReload)
|
|
{
|
|
if (enableCliRestart)
|
|
{
|
|
if (checkAdapterAlive())
|
|
{
|
|
lgInfo($"Mancanza innovazioni da oltre {MaxSecReload} sec | Alive Test Success | NON riavviamo, impostato lastCurrent");
|
|
lastCurrent = adesso;
|
|
}
|
|
else
|
|
{
|
|
|
|
lgInfo($"Timeout per mancata comunicazione da oltre {MaxSecReload} sec | Alive Test Failed | --> disconnessione adapter MTConnect!");
|
|
tryDisconnect();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
lgError($"Attenzione: superato periodo di mancata comunicazione da oltre {MaxSecReload} sec ma enableCliRestart non permesso");
|
|
}
|
|
}
|
|
|
|
// Controllo booleano PING document POWERON...
|
|
string currPowerOn = getDataItemValue(mtcParams.condPowerOn.keyName);
|
|
// se valido il check ping lo eseguo... altrimenti lo do x buono
|
|
bool isPingOk = mtcParams.pingAsPowerOn && (testPingMachine == IPStatus.Success);
|
|
|
|
// verifico da target eValue richiesto...
|
|
bool checkPowerOn = (currPowerOn == mtcParams.condPowerOn.targetValue);
|
|
|
|
// bit 0 (poweron) imposto a 1 SE pingo o PowerOn=="ON"...
|
|
B_input = (isPingOk || checkPowerOn) ? 1 : 0;
|
|
|
|
// variabili RUN...
|
|
string currRun = getDataItemValue(mtcParams.keyRunMode);
|
|
|
|
// controllo RUN MODE preliminare... CABLATO - è GENERALE x MTC
|
|
if (currRun == "AUTOMATIC" || currRun == "SEMI_AUTO" || currRun == "SEMI_AUTOMATIC")
|
|
{
|
|
int numCond = mtcParams.condWork.Count;
|
|
int numCondOk = 0;
|
|
// cerco nell'elenco delle condizioni che indicano lavora se sono ok faccio +1 conteggio......
|
|
foreach (var item in mtcParams.condWork)
|
|
{
|
|
if (getDataItemValue(item.keyName) == item.targetValue)
|
|
{
|
|
numCondOk++;
|
|
}
|
|
}
|
|
// se tutte condizioni rispettate --> lavora!
|
|
if (numCond == numCondOk)
|
|
{
|
|
// RUN = LAVORA!
|
|
B_input += (1 << 1);
|
|
}
|
|
}
|
|
// se ho almeno 1 allarme E NON SONO IN AUTO --> ALARM!
|
|
else if (hasError)
|
|
{
|
|
B_input += (1 << 3);
|
|
}
|
|
// 2024.01.90: gestione dati UNAVAILABLE che indicano poweroff...
|
|
else if (hasUnavailableData && unavailPoweroff)
|
|
{
|
|
B_input = 0;
|
|
}
|
|
else
|
|
{
|
|
// se ho run mode != auto --> manual
|
|
B_input += (1 << 4);
|
|
}
|
|
|
|
// gestione bit 5-6 se StateMach == 60...
|
|
if (bitEmg > 5)
|
|
{
|
|
// verifico condizioni per 6° bit = WarmUp/CoolDown...
|
|
if (hasBitCondition(6))
|
|
{
|
|
// resetto a 1 il segnale di base (solo poweron)...
|
|
B_input = 1;
|
|
// ed aggiungo warmup
|
|
B_input += (1 << 6);
|
|
}
|
|
// possibile miglioramento: gestione 5° bit slowTC come simula...
|
|
}
|
|
|
|
// emergenza armata da riportare con bit True/ 1
|
|
if (mtcParams.emergencyArmedTrue)
|
|
{
|
|
//se NON premuta lazo il bit
|
|
if (!hasEStopTriggered)
|
|
{
|
|
B_input += (1 << bitEmg);
|
|
}
|
|
}
|
|
// emergenza armata da riportare come False/0 (!mtcParams.emergencyArmedTrue)
|
|
else
|
|
{
|
|
// se premuta alzo il bit...
|
|
if (hasEStopTriggered)
|
|
{
|
|
B_input += (1 << bitEmg);
|
|
}
|
|
}
|
|
|
|
int vFactor = 1;
|
|
// controllo SE HO dati per fare verifiche...
|
|
if (string.IsNullOrEmpty(currRun))
|
|
{
|
|
// se ho parametro x gestione reset...
|
|
if (enableMtcRestart)
|
|
{
|
|
// controllo se ho ricevuto il current da OLTRE 1 minuto...
|
|
if (lastCurrent.AddMinutes(3) < adesso)
|
|
{
|
|
lastCurrent = adesso;
|
|
// stop...
|
|
lgInfo("Fermato MTC_ref per mancanza dati current");
|
|
MTC_ref.Stop();
|
|
Thread.Sleep(3000);
|
|
// restart
|
|
lgInfo("Riavviato MTC_ref per mancanza dati current");
|
|
MTC_ref.Start();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vFactor = 6;
|
|
}
|
|
|
|
// solo se non ho veto check
|
|
if (vetoCheckStatus < adesso)
|
|
{
|
|
lgInfo($"Stato variabili: currRun: {currRun}");
|
|
// imposto veto per vetoSeconds...
|
|
vetoCheckStatus = adesso.AddSeconds(vetoSeconds * vFactor);
|
|
}
|
|
// log opzionale!
|
|
if (verboseLog)
|
|
{
|
|
lgInfo($"Trasformazione B_input: {B_input} | currRun = {currRun}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgDebug($"[VETO getDataItemValue] | veto attivo alle {DateTime.Now:yyyy.MM.dd HH:mm:ss}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica stato Alive per adapter:
|
|
/// - test ping
|
|
/// - test probe
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private bool checkAdapterAlive()
|
|
{
|
|
bool isPingOk = testPingMachine == IPStatus.Success;
|
|
// test probe!
|
|
bool probeOk = TestProbe(mtcUrlCall, true);
|
|
return isPingOk && probeOk;
|
|
}
|
|
|
|
/// <summary>
|
|
/// URL completo x chiamate MTC
|
|
/// </summary>
|
|
private string mtcUrlCall
|
|
{
|
|
|
|
get
|
|
{
|
|
return $"{IOBConfFull.Device.Connect.IpAddr}:{mtcPort}";
|
|
}
|
|
}
|
|
|
|
private short mtcPort
|
|
{
|
|
|
|
get
|
|
{
|
|
short port = 5000;
|
|
short.TryParse(IOBConfFull.Device.Connect.Port, out port);
|
|
return port;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Vera connessione ad MTC
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private void doConnect()
|
|
{
|
|
isConnecting = true;
|
|
startConnecting = DateTime.Now;
|
|
// reset memoria dataItem..
|
|
dataItemMem = new Dictionary<string, MtcDataItemExt>();
|
|
// predisposizione conf oggetto di comunicazione MTC
|
|
string callUrl = mtcUrlCall;
|
|
// test probe!
|
|
try
|
|
{
|
|
|
|
// anche se non del tutto vero...
|
|
connectionOk = TestProbe(callUrl, true);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione durante test probe:{Environment.NewLine}{exc}");
|
|
}
|
|
// attendo 1 sec...
|
|
Thread.Sleep(1000);
|
|
// ora avvio
|
|
try
|
|
{
|
|
lgInfo($"Chiamata apertura MTC Client: {callUrl}");
|
|
MTC_ref = new MTConnectHttpClient(IOBConfFull.Device.Connect.IpAddr, mtcPort);
|
|
//MTC_ref = new MTConnectHttpClient(callUrl);
|
|
// sample interval
|
|
MTC_ref.Interval = mtcParams.clientSampleIntMs;
|
|
// timeout x richieste
|
|
MTC_ref.Timeout = mtcParams.reqTOutMs;
|
|
// timeout riconnessione
|
|
MTC_ref.ReconnectionInterval = mtcParams.reconnectIntMs;
|
|
|
|
// Sottoscrizioni base
|
|
MTC_ref.ClientStarted += MTC_ref_ClientStarted;
|
|
MTC_ref.ClientStopped += MTC_ref_ClientStopped;
|
|
MTC_ref.ConnectionError += MTC_ref_ConnectionError;
|
|
|
|
// Sottoscrizioni dati ricevuti !!!
|
|
MTC_ref.AssetsReceived += MTC_ref_AssetsReceived;
|
|
MTC_ref.ProbeReceived += MTC_ref_ProbeReceived;
|
|
MTC_ref.CurrentReceived += MTC_ref_CurrentReceived;
|
|
|
|
// sample subscription
|
|
if (mtcParams.doSubsSample)
|
|
{
|
|
MTC_ref.SampleReceived += MTC_ref_SampleReceived;
|
|
}
|
|
// observ subscription
|
|
if (mtcParams.doSubsObserv)
|
|
{
|
|
MTC_ref.ObservationReceived += MTC_ref_ObservationReceived;
|
|
}
|
|
|
|
MTC_ref.Start();
|
|
|
|
// fix tempi!
|
|
DateTime adesso = DateTime.Now;
|
|
DtHelp.lastPzCountSend = adesso;
|
|
DtHelp.lastWarnODL = adesso;
|
|
lastCurrent = adesso;
|
|
}
|
|
catch
|
|
{ }
|
|
isConnecting = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test di chiamata metodo PROBE con log info
|
|
/// </summary>
|
|
/// <param name="callUrl"></param>
|
|
private bool TestProbe(string callUrl, bool doLogDevices)
|
|
{
|
|
bool testOk = false;
|
|
lgInfo($"Test Probe MTC Client: {callUrl}");
|
|
try
|
|
{
|
|
var prbClient = new MTConnectHttpProbeClient(callUrl);
|
|
//var prbClient = new MTConnectHttpProbeClient(cIobConf.cncIpAddr, port);
|
|
prbClient.Timeout = mtcParams.reqTOutMs;
|
|
var prbDoc = prbClient.Get();
|
|
// se valido loggo!
|
|
if (prbDoc != null)
|
|
{
|
|
testOk = true;
|
|
lgInfo($"Effettuata correttamente PROBE per device MTC all'URL {callUrl}");
|
|
if (doLogDevices)
|
|
{
|
|
lgInfo($"---------------- Elenco Devices ----------------");
|
|
// loggo devices principali...
|
|
logProbeDevices(prbDoc.Devices.ToList());
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione durante TestProbe:{Environment.NewLine}{exc}");
|
|
}
|
|
return testOk;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Formatta un dataitem da uno stream SAMPLE
|
|
/// </summary>
|
|
/// <param name="dSamplePeriod"></param>
|
|
/// <param name="threshDBand"></param>
|
|
/// <param name="uuid"></param>
|
|
/// <param name="observ"></param>
|
|
/// <param name="fullMsg"></param>
|
|
/// <returns></returns>
|
|
private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref float threshDBand, ref string uuid, IObservation observ, string fullMsg)
|
|
{
|
|
DataItemStatistic currStat = DataItemStatistic.AVERAGE;
|
|
//cerco nei values...
|
|
if (observ.Values.Count() > 0)
|
|
{
|
|
foreach (var item in observ.Values)
|
|
{
|
|
if (item.Key == "Statistic")
|
|
{
|
|
currStat = (DataItemStatistic)Enum.Parse(typeof(DataItemStatistic), item.Value);
|
|
}
|
|
}
|
|
}
|
|
// creo il nuovo dataitem da sample...
|
|
DataItem newDataItem = new DataItem()
|
|
{
|
|
Category = observ.Category,
|
|
Id = observ.DataItemId,
|
|
Name = observ.Name,
|
|
//SampleRate = ,
|
|
Statistic = currStat,
|
|
SubType = observ.SubType,
|
|
Type = observ.Type
|
|
};
|
|
return formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newDataItem, fullMsg);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Formatta un dataitem x salvataggio in memoria locale
|
|
/// </summary>
|
|
/// <param name="dSamplePeriod"></param>
|
|
/// <param name="threshDBand"></param>
|
|
/// <param name="uuid"></param>
|
|
/// <param name="dataItem"></param>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref float threshDBand, ref string uuid, DataItem dataItem, string value)
|
|
{
|
|
MtcDataItemExt currDataItem;
|
|
// uuid document parametri secondo categoria...
|
|
switch (dataItem.Category)
|
|
{
|
|
case MTConnect.Devices.DataItemCategory.CONDITION:
|
|
uuid = $"C_{dataItem.Id}";
|
|
threshDBand = 0;
|
|
dSamplePeriod = 0;
|
|
break;
|
|
|
|
case MTConnect.Devices.DataItemCategory.EVENT:
|
|
uuid = $"E_{dataItem.Id}";
|
|
if (enableDataFilter)
|
|
{
|
|
threshDBand = 1;
|
|
// controllo SE ho conf x deadband...
|
|
if (mtcParams.paramsEndThresh.Count > 0)
|
|
{
|
|
// ciclo su tutti i parametri indicati...
|
|
foreach (var item in mtcParams.paramsEndThresh)
|
|
{
|
|
if (dataItem.Id.EndsWith(item.Key))
|
|
{
|
|
threshDBand = item.Value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
threshDBand = 0;
|
|
}
|
|
dSamplePeriod = 0;
|
|
break;
|
|
|
|
case MTConnect.Devices.DataItemCategory.SAMPLE:
|
|
uuid = $"S_{dataItem.Id}";
|
|
// SOLO SE è abilitato il datafiltering...
|
|
if (enableDataFilter)
|
|
{
|
|
threshDBand = 1;
|
|
// controllo SE ho conf x deadband...
|
|
if (mtcParams.paramsEndThresh.Count > 0)
|
|
{
|
|
// ciclo su tutti i parametri indicati...
|
|
foreach (var item in mtcParams.paramsEndThresh)
|
|
{
|
|
if (dataItem.Id.EndsWith(item.Key))
|
|
{
|
|
threshDBand = item.Value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
threshDBand = 0;
|
|
}
|
|
dSamplePeriod = 60;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
// salvo oggetto x "uso interno"
|
|
currDataItem = new MtcDataItemExt()
|
|
{
|
|
Id = dataItem.Id,
|
|
Category = dataItem.Category,
|
|
Constraints = dataItem.Constraints,
|
|
CoordinateSystem = dataItem.CoordinateSystem,
|
|
Name = dataItem.Name,
|
|
NativeScale = dataItem.NativeScale,
|
|
NativeUnits = dataItem.NativeUnits,
|
|
SampleRate = dataItem.SampleRate,
|
|
Representation = dataItem.Representation,
|
|
SignificantDigits = dataItem.SignificantDigits,
|
|
Source = dataItem.Source,
|
|
Statistic = dataItem.Statistic,
|
|
SubType = dataItem.SubType,
|
|
Type = dataItem.Type,
|
|
//TypePath = dataItem.TypePath,
|
|
Units = dataItem.Units,
|
|
//XPath = dataItem.XPath,
|
|
uid = uuid,
|
|
thresholdDeadBand = threshDBand,
|
|
samplePeriod = dSamplePeriod,
|
|
value = value
|
|
};
|
|
// log x capire COME ho chiamato alcune cosette...
|
|
if (dataItem.Id.Contains("EXE_MODE") || dataItem.Id.Contains("RUN_MODE") || dataItem.Id.Contains("POWER") || dataItem.Id.EndsWith("_Status"))
|
|
{
|
|
lgInfo($"DEBUG DATA | dataItem.Id : {dataItem.Id}");
|
|
}
|
|
|
|
return currDataItem;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Formatta un dataitem x salvataggio in memoria locale
|
|
/// </summary>
|
|
/// <param name="dSamplePeriod"></param>
|
|
/// <param name="threshDBand"></param>
|
|
/// <param name="uuid"></param>
|
|
/// <param name="dataItem"></param>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref float threshDBand, ref string uuid, IDataItem dataItem, string value)
|
|
{
|
|
MtcDataItemExt currDataItem;
|
|
// uuid document parametri secondo categoria...
|
|
switch (dataItem.Category)
|
|
{
|
|
case MTConnect.Devices.DataItemCategory.CONDITION:
|
|
uuid = $"C_{dataItem.Id}";
|
|
threshDBand = 0;
|
|
dSamplePeriod = 0;
|
|
break;
|
|
|
|
case MTConnect.Devices.DataItemCategory.EVENT:
|
|
uuid = $"E_{dataItem.Id}";
|
|
threshDBand = 0;
|
|
dSamplePeriod = 0;
|
|
break;
|
|
|
|
case MTConnect.Devices.DataItemCategory.SAMPLE:
|
|
uuid = $"S_{dataItem.Id}";
|
|
// SOLO SE è abilitato il datafiltering...
|
|
if (enableDataFilter)
|
|
{
|
|
threshDBand = 1;
|
|
// controllo SE ho conf x deadband...
|
|
if (mtcParams.paramsEndThresh.Count > 0)
|
|
{
|
|
// ciclo su tutti i parametri indicati...
|
|
foreach (var item in mtcParams.paramsEndThresh)
|
|
{
|
|
if (dataItem.Id.EndsWith(item.Key))
|
|
{
|
|
threshDBand = item.Value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
threshDBand = 0;
|
|
}
|
|
dSamplePeriod = 60;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// salvo oggetto x "uso interno"
|
|
currDataItem = new MtcDataItemExt()
|
|
{
|
|
Id = dataItem.Id,
|
|
Category = dataItem.Category,
|
|
Constraints = dataItem.Constraints,
|
|
CoordinateSystem = dataItem.CoordinateSystem,
|
|
Name = dataItem.Name,
|
|
NativeScale = dataItem.NativeScale,
|
|
NativeUnits = dataItem.NativeUnits,
|
|
SampleRate = dataItem.SampleRate,
|
|
Representation = dataItem.Representation,
|
|
SignificantDigits = dataItem.SignificantDigits,
|
|
Source = dataItem.Source,
|
|
Statistic = dataItem.Statistic,
|
|
SubType = dataItem.SubType,
|
|
Type = dataItem.Type,
|
|
//TypePath = dataItem.TypePath,
|
|
Units = dataItem.Units,
|
|
//XPath = dataItem.XPath,
|
|
uid = uuid,
|
|
thresholdDeadBand = threshDBand,
|
|
samplePeriod = dSamplePeriod,
|
|
value = value
|
|
};
|
|
// log x capire COME ho chiamato alcune cosette...
|
|
if (dataItem.Id.Contains("EXE_MODE") || dataItem.Id.Contains("RUN_MODE") || dataItem.Id.Contains("POWER") || dataItem.Id.EndsWith("_Status"))
|
|
{
|
|
lgInfo($"DEBUG DATA | dataItem.Id : {dataItem.Id}");
|
|
}
|
|
|
|
return currDataItem;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua lettura file di conf specifico MTC da oggetto serializzato json <paramref
|
|
/// name="fileName">Nome file da cui leggere i parametri json</paramref>
|
|
/// </summary>
|
|
private void loadMtcConf(string fileName)
|
|
{
|
|
string jsonFullPath = $"{Application.StartupPath}/DATA/CONF/{fileName}";
|
|
lgInfo($"Apertura file {jsonFullPath}");
|
|
StreamReader reader = new StreamReader(jsonFullPath);
|
|
string jsonData = reader.ReadToEnd().Replace("\n", "").Replace("\r", "");
|
|
if (!string.IsNullOrEmpty(jsonData))
|
|
{
|
|
lgInfo($"File json composto da {jsonData.Length} caratteri");
|
|
try
|
|
{
|
|
mtcParams = JsonConvert.DeserializeObject<MtcParamConf>(jsonData);
|
|
lgInfo($"Decodifica aree MtcParamConf | condPowerOn: {mtcParams.condPowerOn.keyName}={mtcParams.condPowerOn.targetValue} | condWork: {mtcParams.condWork.Count} | keyPartCount: {mtcParams.keyPartCount} | itemTranslation: {mtcParams.itemTranslation.Count} | fluxLogVeto: {mtcParams.fluxLogVeto.Count} | paramsEndThresh: {mtcParams.paramsEndThresh.Count} ");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in decodifica conf json MTC:{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("Errore in loadMtcConf: file json vuoto!");
|
|
}
|
|
reader.Dispose();
|
|
}
|
|
|
|
private void MTC_ref_AssetsReceived(object sender, MTConnect.Assets.IAssetsResponseDocument doc)
|
|
{
|
|
lgInfo("ASSET received");
|
|
queueInEnabCurr = true;
|
|
connectionOk = true;
|
|
lastCurrent = DateTime.Now;
|
|
int docSize = 0;
|
|
string rawVal = "";
|
|
foreach (var asset in doc.Assets)
|
|
{
|
|
// Print AssetId to the Console
|
|
lgInfo($"Asset: {asset.AssetId}");
|
|
rawVal = JsonConvert.SerializeObject(asset);
|
|
docSize += rawVal.Length;
|
|
}
|
|
// salvo dim caratteri ricevuti
|
|
trackExchData(docSize, 4096);
|
|
}
|
|
|
|
private void MTC_ref_ClientStarted(object sender, EventArgs e)
|
|
{
|
|
lgInfo($"Client Started!");
|
|
lastCurrent = DateTime.Now;
|
|
}
|
|
|
|
private void MTC_ref_ClientStopped(object sender, EventArgs e)
|
|
{
|
|
lgInfo($"Client Stopped! | {e}");
|
|
queueInEnabCurr = false;
|
|
connectionOk = false;
|
|
}
|
|
|
|
private void MTC_ref_ConnectionError(object sender, Exception exc)
|
|
{
|
|
lgError($"CONNECTION ERROR returned!{Environment.NewLine}{exc}");
|
|
queueInEnabCurr = false;
|
|
connectionOk = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettuata discovery iniziale valori CURRENT
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="document"></param>
|
|
private void MTC_ref_CurrentReceived(object sender, IStreamsResponseDocument document)
|
|
{
|
|
lgInfo("CURRENT received");
|
|
queueInEnabCurr = true;
|
|
connectionOk = true;
|
|
// se lastcurrent > MinRefreshPeriodSec sec --> forzo send...
|
|
bool forceSend = DateTime.Now.Subtract(lastCurrent).TotalSeconds > IOBConfFull.Device.MinRefreshPeriodSec;
|
|
lastCurrent = DateTime.Now;
|
|
if (document != null)
|
|
{
|
|
if (document.Streams != null)
|
|
{
|
|
lgInfo($"CurrentSuccessful: trovati {document.Streams.Count()} streams");
|
|
}
|
|
checkAndSend(document, forceSend);
|
|
}
|
|
else
|
|
{
|
|
lgError("MTC_ref_CurrentReceived ERROR: document è null");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processing singola observation ricevuta
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="observ"></param>
|
|
private void MTC_ref_ObservationReceived(object sender, IObservation observ)
|
|
{
|
|
connectionOk = true;
|
|
lastCurrent = DateTime.Now;
|
|
processObservation(observ, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettuata discovery iniziale valori PROBE
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="document"></param>
|
|
private void MTC_ref_ProbeReceived(object sender, IDevicesResponseDocument document)
|
|
{
|
|
queueInEnabCurr = true;
|
|
connectionOk = true;
|
|
lastCurrent = DateTime.Now;
|
|
lgInfo("STEP 01 DevicesSuccessful reached!");
|
|
MtcDataItemExt currDataItem = null;
|
|
machDataItem currMapoDataItem = null;
|
|
List<machDataItem> elencoDataItems = new List<machDataItem>();
|
|
int dSamplePeriod = 0;
|
|
float threshDBand = 0;
|
|
string uuid = "";
|
|
if (document != null)
|
|
{
|
|
foreach (var device in document.Devices)
|
|
{
|
|
List<IDataItem> dataItems = device.GetDataItems().ToList();
|
|
//List<DataItem> dataItems = device.GetDataItems();
|
|
lgInfo($"Inizio STEP 02 per caricare {dataItems.Count} dataItems");
|
|
foreach (var dataItem in dataItems)
|
|
{
|
|
try
|
|
{
|
|
currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, dataItem, "");
|
|
// aggiungo se non c'è...
|
|
if (!dataItemMem.ContainsKey(dataItem.Id))
|
|
{
|
|
dataItemMem.Add(dataItem.Id, currDataItem);
|
|
}
|
|
var thisCat = (MapoSDK.DataItemCategory)Enum.Parse(typeof(MapoSDK.DataItemCategory), $"{dataItem.Category}");
|
|
// salvo oggetto x registrazione su server MP-IO
|
|
currMapoDataItem = new machDataItem()
|
|
{
|
|
uuid = dataItem.Id,
|
|
Category = thisCat,
|
|
Name = dataItem.Name,
|
|
Type = dataItem.Type,
|
|
SubType = dataItem.SubType,
|
|
Units = dataItem.Units
|
|
};
|
|
// aggiungo se non ci fosse
|
|
if (!elencoDataItems.Contains(currMapoDataItem))
|
|
{
|
|
elencoDataItems.Add(currMapoDataItem);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in DevicesSuccessful / DataItem:{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
}
|
|
// invio IN BLOCCO il dataItem serializzati...
|
|
if (elencoDataItems.Count > 0)
|
|
{
|
|
lgInfo($"STEP 03 invio dati di {elencoDataItems.Count} records");
|
|
sendDataItemsList(elencoDataItems);
|
|
|
|
trackExchData(1024, 4096);
|
|
}
|
|
hasReadItems = true;
|
|
lgInfo($"STEP 04: memorizzati {dataItemMem.Count} oggetti in memoria");
|
|
}
|
|
else
|
|
{
|
|
lgError("STEP 05 error: document null!");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ricevuto SAMPLE stream da campionamenti ricevuti
|
|
/// </summary>
|
|
/// <param name="document"></param>
|
|
private void MTC_ref_SampleReceived(object sender, IStreamsResponseDocument document)
|
|
{
|
|
connectionOk = true;
|
|
lastCurrent = DateTime.Now;
|
|
lgTrace("SAMPLE received");
|
|
checkAndSend(document, false);
|
|
trackExchData(64, 4096);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processing di una singola observ in un datastream
|
|
/// </summary>
|
|
/// <param name="observ">Osservazione da processare</param>
|
|
/// <param name="forceSend">invio forzato</param>
|
|
private void processObservation(IObservation observ, bool forceSend)
|
|
{
|
|
string sVal = "";
|
|
string descr = "";
|
|
DateTime locTStamp = DateTime.Now;
|
|
// log msg
|
|
string sMsg = $" - {observ.DataItemId} | {observ.Category}";
|
|
switch (observ.Category)
|
|
{
|
|
case MTConnect.Devices.DataItemCategory.CONDITION:
|
|
string message = "OK";
|
|
string level = "";
|
|
string fullMsg = "";
|
|
bool doVeto = false;
|
|
try
|
|
{
|
|
descr = itemTranslation("C", observ.DataItemId);
|
|
locTStamp = observ.Timestamp.ToLocalTime();
|
|
sVal = $"CONDITION: {locTStamp.ToString()} | descr: {descr} | Id: {observ.DataItemId} | Name: {observ.Name}";
|
|
if (observ.Values.Count() > 0)
|
|
{
|
|
// se ho veto sui livelli di allarme li gestisco (e salto nel caso)
|
|
if (ListVetoCond.Count != 0)
|
|
{
|
|
// recupero level...
|
|
string cLevel = observ.Values.FirstOrDefault(x => x.Key.Equals("level", StringComparison.InvariantCultureIgnoreCase)).Value;
|
|
// verificos e è vietato il log ricevuto...
|
|
doVeto = ListVetoCond.Contains(cLevel);
|
|
}
|
|
foreach (var item in observ.Values)
|
|
{
|
|
sVal += $" | {item.Key}: {item.Value}";
|
|
if (item.Key == "Level")
|
|
{
|
|
level = item.Value;
|
|
}
|
|
else if (item.Key == "Message")
|
|
{
|
|
message = item.Value;
|
|
}
|
|
}
|
|
fullMsg = $"{level} | {message}";
|
|
}
|
|
// condition su debug
|
|
lgDebug(sVal);
|
|
DateTime tStamp = observ.Timestamp;
|
|
var time2 = tStamp.ToLocalTime();
|
|
// verifico veto...
|
|
if (!doVeto)
|
|
{
|
|
// verifico se sia variato valore e dataora da ultimo salvataggio redis...
|
|
string redKey = $"{redKeyLastCondition}:{observ.DataItemId}";
|
|
string redisLastCond = redisMan.getRSV(redKey);
|
|
string currCond = $"{observ.Timestamp}|{fullMsg}";
|
|
if (currCond.Equals(redisLastCond))
|
|
{
|
|
lgInfo($"Verifca condition | nessuna variazione da ultima registata | {redisLastCond}");
|
|
}
|
|
else
|
|
{
|
|
redisMan.setRSV(redKey, currCond);
|
|
// verifico se salvare
|
|
bool changed = checkSaveCondition(observ, fullMsg);
|
|
if (changed || forceSend)
|
|
{
|
|
// accodare ed invia nella coda ALARMS (che POI salva in document
|
|
// MongoDB anche ultimi x minuti di FluxLog...)
|
|
accodaAlarmLog(sVal, qEncodeFLog(time2, descr, fullMsg));
|
|
}
|
|
else
|
|
{
|
|
lgTrace(sVal);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgTrace(sVal);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in decodifica Conditions x StreamSuccesfull{Environment.NewLine}{exc}", false);
|
|
}
|
|
break;
|
|
|
|
case MTConnect.Devices.DataItemCategory.EVENT:
|
|
string eValue = "";
|
|
try
|
|
{
|
|
descr = itemTranslation("E", observ.DataItemId);
|
|
locTStamp = observ.Timestamp.ToLocalTime();
|
|
sVal = $"EVENT: {locTStamp.ToString()} | descr: {descr} | Id: {observ.DataItemId} | Name: {observ.Name}";
|
|
if (observ.Values.Count() > 0)
|
|
{
|
|
foreach (var item in observ.Values)
|
|
{
|
|
sVal += $" | {item.Key}: {item.Value}";
|
|
if (item.Key == "Result")
|
|
{
|
|
eValue = item.Value;
|
|
}
|
|
}
|
|
}
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo(sVal);
|
|
}
|
|
DateTime tStamp = observ.Timestamp;
|
|
var time2 = tStamp.ToLocalTime();
|
|
// verifico se salvare
|
|
bool changed = checkSaveEvent(observ, eValue);
|
|
if (changed || forceSend)
|
|
{
|
|
bool sent = accodaFLog(descr, sVal, qEncodeFLog(time2, descr, eValue));
|
|
if (sent)
|
|
{ // traccio valore DynData x analisi
|
|
trackDynData(descr, eValue);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in decodifica Events x StreamSuccesfull{Environment.NewLine}{exc}", false);
|
|
}
|
|
break;
|
|
|
|
case MTConnect.Devices.DataItemCategory.SAMPLE:
|
|
string sValue = "";
|
|
try
|
|
{
|
|
descr = itemTranslation("S", observ.DataItemId);
|
|
locTStamp = observ.Timestamp.ToLocalTime();
|
|
sVal = $"SAMPLE: {locTStamp.ToString()} | descr: {descr} | Id: {observ.DataItemId} | Name: {observ.Name}";
|
|
if (observ.Values.Count() > 0)
|
|
{
|
|
foreach (var item in observ.Values)
|
|
{
|
|
sVal += $" | {item.Key}: {item.Value}";
|
|
if (item.Key == "Result")
|
|
{
|
|
sValue = item.Value;
|
|
}
|
|
}
|
|
}
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo(sVal);
|
|
}
|
|
DateTime tStamp = observ.Timestamp;
|
|
var time2 = tStamp.ToLocalTime();
|
|
// verifico se salvare
|
|
bool changed = checkSaveSample(observ, sValue);
|
|
if (changed || forceSend)
|
|
{
|
|
bool sent = accodaFLog(descr, sVal, qEncodeFLog(time2, descr, sValue));
|
|
if (sent)
|
|
{ // traccio valore DynData x analisi
|
|
trackDynData(descr, sValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (isVerboseLog)
|
|
{
|
|
lgTrace($"NON ACCODATO sample per {observ.DataItemId} - verifica variazione SAMPLE ha dato esito negativo", false);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in decodifica Samples x StreamSuccesfull{Environment.NewLine}{exc}");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
if (observ.Values != null && observ.Values.Count() > 0)
|
|
{
|
|
foreach (var item in observ.Values)
|
|
{
|
|
sMsg += $" | {item.Key}: {item.Value}";
|
|
}
|
|
}
|
|
lgTrace(sMsg);
|
|
#if false
|
|
trackExchDataRaw(sMsg.Length, 1024);
|
|
#endif
|
|
trackExchData(64, 4096);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua invio a MP/IO dell'elenco serializzato dei dataItems
|
|
/// </summary>
|
|
/// <param name="dataItems"></param>
|
|
private void sendDataItemsList(List<machDataItem> dataItems)
|
|
{
|
|
// verifico abilitazione preliminare all'invio
|
|
if (enableSendDataItem)
|
|
{
|
|
// verifico veto ad invio (ogni 60 min...)
|
|
DateTime adesso = DateTime.Now;
|
|
if (adesso > DtHelp.dtVetoSenDataItem)
|
|
{
|
|
string rawData = JsonConvert.SerializeObject(dataItems);
|
|
var resp = HttpService.CallUrlPost($"{urlSaveDataItems}", rawData);
|
|
// imposto nuovo veto
|
|
DtHelp.dtVetoSenDataItem = adesso.AddMinutes(minVetoSendDataItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue log trace del valore che è filtrato in invio
|
|
/// </summary>
|
|
/// <param name="observation"></param>
|
|
private void traceObservation(IObservation observation)
|
|
{
|
|
#if DEBUG
|
|
// SOLO in debug...
|
|
trackExchData(64, 4096);
|
|
#endif
|
|
}
|
|
|
|
#endregion Private Methods
|
|
}
|
|
} |