1260 lines
40 KiB
C#
1260 lines
40 KiB
C#
using IOB_UT;
|
|
using MapoSDK;
|
|
using MTConnect.Clients;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net.NetworkInformation;
|
|
using System.Threading;
|
|
using MTConnectDevices = MTConnect.MTConnectDevices;
|
|
using MTConnectStreams = MTConnect.MTConnectStreams;
|
|
|
|
namespace IOB_WIN
|
|
{
|
|
public class IobMTC : IobGeneric
|
|
{
|
|
|
|
/// <summary>
|
|
/// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO
|
|
/// </summary>
|
|
Dictionary<string, string> signLUT = new Dictionary<string, string>();
|
|
/// <summary>
|
|
/// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing
|
|
/// </summary>
|
|
Dictionary<string, MtcDataItemExt> dataItemMem = new Dictionary<string, MtcDataItemExt>();
|
|
/// <summary>
|
|
/// Oggetto MAIN x connessione MTC
|
|
/// </summary>
|
|
protected MTConnectClient MTC_ref;
|
|
/// <summary>
|
|
/// Gestione filtraggio dati
|
|
/// </summary>
|
|
protected bool enableDataFilter = false;
|
|
/// <summary>
|
|
/// Determina se ha effettuata lettura items in memoria x confronto...
|
|
/// </summary>
|
|
protected bool hasReadItems = false;
|
|
/// <summary>
|
|
/// Veto controllos tatus x log...
|
|
/// </summary>
|
|
protected DateTime vetoCheckStatus = DateTime.Now;
|
|
/// <summary>
|
|
/// Ultimo current received x gestione update periodico...
|
|
/// </summary>
|
|
protected DateTime lastCurrent = DateTime.Now;
|
|
/// <summary>
|
|
/// Abilitazione restart (da opt par...)
|
|
/// </summary>
|
|
protected bool enableMtcRestart = false;
|
|
/// <summary>
|
|
/// URL x salvataggio elenco dataItems MTC
|
|
/// </summary>
|
|
protected string urlSaveDataItems
|
|
{
|
|
get
|
|
{
|
|
string answ = "";
|
|
try
|
|
{
|
|
string machineName = Environment.MachineName;
|
|
answ = string.Format(@"http://{0}{1}{2}/saveDataItems/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError(exc, "Errore in composizione urlSaveDataItems");
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Estende l'init della classe base, impiegando il pacchetto Nuget TrackHound
|
|
/// https://github.com/TrakHound/MTConnect.NET
|
|
/// </summary>
|
|
/// <param name="caller"></param>
|
|
/// <param name="adpConf"></param>
|
|
public IobMTC(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
|
{
|
|
// gestione invio ritardato contapezzi
|
|
pzCountDelay = utils.CRI("pzCountDelay");
|
|
// gestione data filtering...
|
|
if (!string.IsNullOrEmpty(getOptPar("ENABLE_DATA_FILTER")))
|
|
{
|
|
bool.TryParse(getOptPar("ENABLE_DATA_FILTER"), out enableDataFilter);
|
|
}
|
|
// gestione restart MTC client...
|
|
if (!string.IsNullOrEmpty(getOptPar("ENABLE_MTC_RESTART")))
|
|
{
|
|
bool.TryParse(getOptPar("ENABLE_MTC_RESTART"), out enableMtcRestart);
|
|
}
|
|
// init datetime counters
|
|
DateTime adesso = DateTime.Now;
|
|
lastPzCountSend = adesso;
|
|
lastWarnODL = adesso;
|
|
lastCurrent = adesso;
|
|
}
|
|
/// <summary>
|
|
/// Processo i task richiesti e li elimino dalla coda 1:1
|
|
/// </summary>
|
|
/// <param name="task2exe"></param>
|
|
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
|
|
{
|
|
// uso metodo base x ora
|
|
return base.executeTasks(task2exe);
|
|
}
|
|
/// <summary>
|
|
/// Effettua reset del contapezzi, in questo caso il conteggio dei KG
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override bool resetContapezziCNC()
|
|
{
|
|
bool answ = false;
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Effettua IMPOSTAZIONE FORZATA del contapezzi, in questo caso il conteggio dei KG
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override bool setContapezziCNC(int newPzCount)
|
|
{
|
|
bool answ = false;
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Effettua log di un devices (ed eventualmente dei sub-devices...
|
|
/// </summary>
|
|
/// <param name="elencoDevices"></param>
|
|
protected void logDevicesList(List<MTConnectDevices.Device> elencoDevices)
|
|
{
|
|
if (elencoDevices != null)
|
|
{
|
|
// loggo devices principali...
|
|
foreach (var item in elencoDevices)
|
|
{
|
|
lgInfo($"Device data | ID: {item.Id} | Name: {item.Name} | UUID: {item.Uuid} | # items: {item.DataItems.Count}");
|
|
// se ho subItems descrivo pure loro...
|
|
if (item.DataItems.Count > 0)
|
|
{
|
|
logDataItemList(item.DataItems);
|
|
}
|
|
if (item.Components.Components.Count > 0)
|
|
{
|
|
logComponentsList(item.Components.Components);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Effettua log di un elenco componenti
|
|
/// </summary>
|
|
/// <param name="elencoComponenti"></param>
|
|
protected void logComponentsList(List<MTConnectDevices.Component> elencoComponenti)
|
|
{
|
|
if (elencoComponenti != null)
|
|
{
|
|
foreach (var item in elencoComponenti)
|
|
{
|
|
lgInfo($"Component data | ID: {item.Id} | Name: {item.Name} | Type: {item.Type} | # items: {item.DataItems.Count}");
|
|
// se ho sottocomponenti richiamo...
|
|
if (item.SubComponents != null)
|
|
{
|
|
if (item.SubComponents.Components.Count > 0)
|
|
{
|
|
logComponentsList(item.SubComponents.Components);
|
|
}
|
|
}
|
|
if (item.DataItems.Count > 0)
|
|
{
|
|
logDataItemList(item.DataItems);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Log elenco DataItems
|
|
/// </summary>
|
|
/// <param name="elencoItems"></param>
|
|
protected void logDataItemList(List<MTConnectDevices.DataItem> elencoItems)
|
|
{
|
|
if (elencoItems != null)
|
|
{
|
|
// loggo devices principali...
|
|
foreach (var item in elencoItems)
|
|
{
|
|
lgInfo($"Device data | ID: {item.Id} | Name: {item.Name} | Category: {item.Category} | # Type: {item.Type}");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Vera connessione ad MTC
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private short doConnect()
|
|
{
|
|
short esitoLink = 0;
|
|
// reset memoria dataItem..
|
|
dataItemMem = new Dictionary<string, MtcDataItemExt>();
|
|
// avvio un oggetto di comunicazione MTC
|
|
#if false
|
|
MTC_ref = new MTConnectClient($"http://{cIobConf.cncIpAddr}:{port}");
|
|
#endif
|
|
short port = 5000;
|
|
short.TryParse(cIobConf.cncPort, out port);
|
|
// test probe!
|
|
try
|
|
{
|
|
var probe = new Probe($"http://{cIobConf.cncIpAddr}:{port}").Execute();
|
|
// se valido loggo!
|
|
if (probe != null)
|
|
{
|
|
lgInfo($"Effettuata correttamente PROBE per device MTC all'URL {probe.Url} | vers: {probe.Version} | send: {probe.Header.Sender}");
|
|
lgInfo($"---------------- Elenco Devices ----------------");
|
|
// loggo devices principali...
|
|
logDevicesList(probe.Devices);
|
|
#if false
|
|
// chiamo il device succesful!
|
|
DevicesSuccessful(probe);
|
|
#endif
|
|
}
|
|
}
|
|
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: {cIobConf.cncIpAddr}:{port}");
|
|
MTC_ref = new MTConnectClient($"http://{cIobConf.cncIpAddr}:{port}");
|
|
// Subscribe to the Event handlers to receive the MTConnect documents
|
|
MTC_ref.ProbeReceived += DevicesSuccessful;
|
|
MTC_ref.CurrentReceived += CurrentSuccessful;
|
|
MTC_ref.SampleReceived += StreamsSuccessful;
|
|
|
|
// attendo 1 sec...
|
|
Thread.Sleep(1000);
|
|
MTC_ref.Start();
|
|
esitoLink = 1;
|
|
|
|
// fix tempi!
|
|
DateTime adesso = DateTime.Now;
|
|
lastPzCountSend = adesso;
|
|
lastWarnODL = adesso;
|
|
lastCurrent = adesso;
|
|
}
|
|
catch
|
|
{ }
|
|
return esitoLink;
|
|
}
|
|
protected void DevicesSuccessful(MTConnectDevices.Document document)
|
|
{
|
|
lgInfo("STEP 01 DevicesSuccessful reached!");
|
|
MtcDataItemExt currDataItem = null;
|
|
machDataItem currMapoDataItem = null;
|
|
List<machDataItem> elencoDataItems = new List<machDataItem>();
|
|
int dSamplePeriod = 0;
|
|
int threshDBand = 0;
|
|
string uuid = "";
|
|
if (document != null)
|
|
{
|
|
foreach (var device in document.Devices)
|
|
{
|
|
List<MTConnectDevices.DataItem> dataItems = device.GetDataItems();
|
|
lgInfo($"Inizio STEP 02 per caricare {dataItems.Count} dataItems");
|
|
foreach (var dataItem in dataItems)
|
|
{
|
|
#if false
|
|
string sVal = $"STEP 03 | Category: {dataItem.Category} | Type: {dataItem.Type} | Id: {dataItem.Id} | Name: {dataItem.Name}";
|
|
lgInfo(sVal);
|
|
#endif
|
|
try
|
|
{
|
|
currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, dataItem);
|
|
// aggiungo se non c'è...
|
|
if (!dataItemMem.ContainsKey(dataItem.Id))
|
|
{
|
|
dataItemMem.Add(dataItem.Id, currDataItem);
|
|
}
|
|
// salvo oggetto x registrazione su server MP-IO
|
|
currMapoDataItem = new machDataItem()
|
|
{
|
|
uuid = dataItem.Id,
|
|
Category = (DataItemCategory)dataItem.Category,
|
|
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 04 invio dati di {elencoDataItems.Count} records");
|
|
sendDataItemsList(elencoDataItems);
|
|
}
|
|
hasReadItems = true;
|
|
lgInfo($"STEP 05: memorizzati {dataItemMem.Count} oggetti in memoria");
|
|
}
|
|
else
|
|
{
|
|
lgError("STEP 02 error: document null!");
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Formatta un dataitem da uno stream SAMPLE
|
|
/// </summary>
|
|
/// <param name="dSamplePeriod"></param>
|
|
/// <param name="threshDBand"></param>
|
|
/// <param name="uuid"></param>
|
|
/// <param name="DISample"></param>
|
|
/// <returns></returns>
|
|
private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectStreams.Sample DISample)
|
|
{
|
|
// creo il nuovo dataitem da sample...
|
|
MTConnectDevices.DataItem newDataItem = new MTConnectDevices.DataItem()
|
|
{
|
|
Category = DISample.Category,
|
|
Id = DISample.DataItemId,
|
|
Name = DISample.Name,
|
|
SampleRate = DISample.SampleRate,
|
|
Statistic = DISample.Statistic,
|
|
SubType = DISample.SubType,
|
|
Type = DISample.Type
|
|
};
|
|
return formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newDataItem);
|
|
}
|
|
/// <summary>
|
|
/// Formatta un dataitem da uno stream GENERICO
|
|
/// </summary>
|
|
/// <param name="dSamplePeriod"></param>
|
|
/// <param name="threshDBand"></param>
|
|
/// <param name="uuid"></param>
|
|
/// <param name="DIGen"></param>
|
|
/// <returns></returns>
|
|
private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectStreams.DataItem DIGen)
|
|
{
|
|
// creo il nuovo dataitem da sample...
|
|
MTConnectDevices.DataItem newDataItem = new MTConnectDevices.DataItem()
|
|
{
|
|
Category = DIGen.Category,
|
|
Id = DIGen.DataItemId,
|
|
Name = DIGen.Name,
|
|
SubType = DIGen.SubType,
|
|
Type = DIGen.Type
|
|
};
|
|
return formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newDataItem);
|
|
}
|
|
/// <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>
|
|
/// <returns></returns>
|
|
private MtcDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, MTConnectDevices.DataItem dataItem)
|
|
{
|
|
MtcDataItemExt currDataItem;
|
|
// uuid e parametri secondo categoria...
|
|
switch (dataItem.Category)
|
|
{
|
|
case MTConnect.DataItemCategory.CONDITION:
|
|
uuid = $"C_{dataItem.Id}";
|
|
threshDBand = 0;
|
|
dSamplePeriod = 0;
|
|
break;
|
|
case MTConnect.DataItemCategory.EVENT:
|
|
uuid = $"E_{dataItem.Id}";
|
|
threshDBand = 0;
|
|
dSamplePeriod = 0;
|
|
break;
|
|
case MTConnect.DataItemCategory.SAMPLE:
|
|
uuid = $"S_{dataItem.Id}";
|
|
// SOLOS E è abilitato il datafiltering...
|
|
if (enableDataFilter)
|
|
{
|
|
threshDBand = 1;
|
|
if (dataItem.Id.EndsWith("PosAct") || dataItem.Id.EndsWith("PosTgt") || dataItem.Id.EndsWith("InvDDone"))
|
|
{
|
|
threshDBand = 50;
|
|
}
|
|
}
|
|
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
|
|
};
|
|
// 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 invio a MP/IO dell'elenco serializzato dei dataItems
|
|
/// </summary>
|
|
/// <param name="dataItems"></param>
|
|
private void sendDataItemsList(List<machDataItem> dataItems)
|
|
{
|
|
string rawData = JsonConvert.SerializeObject(dataItems);
|
|
utils.callUrlNow($"{urlSaveDataItems}", rawData);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua traduzione ITEM da LUT recuperata da json configurazione (SPECIFICO MTC)
|
|
/// </summary>
|
|
/// <param name="tipo"></param>
|
|
/// <param name="id"></param>
|
|
/// <returns></returns>
|
|
protected string itemTranslation(string tipo, string id)
|
|
{
|
|
// !!!FARE!!! tradurre CORRETTAMENTE da lookuptable... x ora fake acccoda..
|
|
string answ = $"{tipo}_{id}";
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica / Salva valore generico (NON SAMPLE)
|
|
/// </summary>
|
|
/// <param name="newValue"></param>
|
|
/// <returns></returns>
|
|
protected bool checkSaveItem(MTConnectStreams.DataItem newValue)
|
|
{
|
|
bool answ = !enableDataFilter;
|
|
|
|
if (newValue != null)
|
|
{
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo($"Richiesta checkSaveItem per {newValue} | id: {newValue.DataItemId} | CDATA: {newValue.CDATA}");
|
|
}
|
|
// verifico in memoria se ho l'oggetto condition ed il suo valore..
|
|
if (dataItemMem.ContainsKey(newValue.DataItemId))
|
|
{
|
|
// salvo sempre!
|
|
dataItemMem[newValue.DataItemId].value = newValue.CDATA;
|
|
dataItemMem[newValue.DataItemId].valueTimestamp = newValue.Timestamp;
|
|
answ = true;
|
|
}
|
|
else
|
|
{
|
|
// registro non trovato da aggiungere...
|
|
lgInfo($"DataItem non trovato in checkSaveItem: {newValue.DataItemId}");
|
|
try
|
|
{
|
|
// provo a creare oggetot in memoria...
|
|
List<machDataItem> elencoDataItems = new List<machDataItem>();
|
|
int dSamplePeriod = 0;
|
|
int threshDBand = 0;
|
|
string uuid = "";
|
|
var currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newValue);
|
|
// aggiungo
|
|
dataItemMem.Add(newValue.DataItemId, currDataItem);
|
|
// salvo oggetto x registrazione su server MP-IO
|
|
var currMapoDataItem = new machDataItem()
|
|
{
|
|
uuid = newValue.DataItemId,
|
|
Category = (DataItemCategory)newValue.Category,
|
|
Name = newValue.Name,
|
|
Type = newValue.Type,
|
|
SubType = newValue.SubType,
|
|
//Units = newValue.Units
|
|
};
|
|
// aggiungo
|
|
elencoDataItems.Add(currMapoDataItem);
|
|
// invio il dataItem serializzato...
|
|
sendDataItemsList(elencoDataItems);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in checkSaveSample{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("Attenzione: checkSaveItem con newValue null!");
|
|
}
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Verifica / Salva valore SAMPLE e restitusice SE sia variato (e quindi da inviare...)
|
|
/// </summary>
|
|
/// <param name="newValue"></param>
|
|
/// <returns></returns>
|
|
protected bool checkSaveSample(MTConnectStreams.Sample newValue)
|
|
{
|
|
bool answ = !enableDataFilter;
|
|
double oldVal = 0;
|
|
double newVal = 0;
|
|
if (newValue != null)
|
|
{
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo($"Richiesta checkSaveSample per {newValue} | id: {newValue.DataItemId} | CDATA: {newValue.CDATA}");
|
|
}
|
|
// verifico in memoria se ho l'oggetto condition ed il suo valore..
|
|
if (dataItemMem.ContainsKey(newValue.DataItemId))
|
|
{
|
|
MtcDataItemExt currDataItemMem = dataItemMem[newValue.DataItemId];
|
|
// controllo SE SIA scaduto il tempo massimo...
|
|
if (Math.Abs(dataItemMem[newValue.DataItemId].valueTimestamp.Subtract(newValue.Timestamp).TotalSeconds) > currDataItemMem.samplePeriod)
|
|
//if (dataItemMem[newValue.DataItemId].valueTimestamp.AddSeconds(currDataItemMem.samplePeriod) < newValue.Timestamp)
|
|
{
|
|
answ = true;
|
|
}
|
|
else
|
|
{
|
|
// ALTRIMENTI controllo SE diverso
|
|
if (dataItemMem[newValue.DataItemId].value != newValue.CDATA)
|
|
{
|
|
// controllo SE ho DeadBand...
|
|
if (dataItemMem[newValue.DataItemId].thresholdDeadBand > 0)
|
|
{
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo($"Test deadband: oldVal: {oldVal} | newVal: {newVal}");
|
|
}
|
|
// recupero i valori e testo DeadBand...
|
|
double.TryParse(dataItemMem[newValue.DataItemId].value.Replace(".", ","), out oldVal);
|
|
double.TryParse(newValue.CDATA.Replace(".", ","), out newVal);
|
|
// test deadband!
|
|
if (Math.Abs(newVal - oldVal) > dataItemMem[newValue.DataItemId].thresholdDeadBand)
|
|
{
|
|
// indico da salvare..
|
|
answ = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (answ)
|
|
{
|
|
// salvo!
|
|
dataItemMem[newValue.DataItemId].value = newValue.CDATA;
|
|
dataItemMem[newValue.DataItemId].valueTimestamp = newValue.Timestamp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// registro non trovato da aggiungere...
|
|
lgInfo($"DataItem non trovato in checkSaveSample: {newValue.DataItemId}");
|
|
// provo a creare oggetot in memoria...
|
|
try
|
|
{
|
|
List<machDataItem> elencoDataItems = new List<machDataItem>();
|
|
int dSamplePeriod = 0;
|
|
int threshDBand = 0;
|
|
string uuid = "";
|
|
var currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, newValue);
|
|
// aggiungo
|
|
dataItemMem.Add(newValue.DataItemId, currDataItem);
|
|
// salvo oggetto x registrazione su server MP-IO
|
|
var currMapoDataItem = new machDataItem()
|
|
{
|
|
uuid = newValue.DataItemId,
|
|
Category = (DataItemCategory)newValue.Category,
|
|
Name = newValue.Name,
|
|
Type = newValue.Type,
|
|
SubType = newValue.SubType,
|
|
//Units = newValue.Units
|
|
};
|
|
// aggiungo
|
|
elencoDataItems.Add(currMapoDataItem);
|
|
// invio il dataItem serializzato...
|
|
sendDataItemsList(elencoDataItems);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in checkSaveSample{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("Attenzione: checkSaveItem con newValue null!");
|
|
}
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Effettuata discovery iniziale
|
|
/// </summary>
|
|
/// <param name="document"></param>
|
|
/// <param name="forceSend"></param>
|
|
protected void CurrentSuccessful(MTConnectStreams.Document document)
|
|
{
|
|
if (document != null)
|
|
{
|
|
lgInfo($"DiscoverySuccessful: discovery per {document.Url}");
|
|
if (document.DeviceStreams != null)
|
|
{
|
|
lgInfo($"DiscoverySuccessful: trovati {document.DeviceStreams.Count} streams");
|
|
}
|
|
checkAndSend(document, true);
|
|
}
|
|
else
|
|
{
|
|
lgError("StreamsSuccessful ERROR: document è null");
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Ricevuta modifica come stream
|
|
/// </summary>
|
|
/// <param name="document"></param>
|
|
protected void StreamsSuccessful(MTConnectStreams.Document document)
|
|
{
|
|
checkAndSend(document, false);
|
|
}
|
|
/// <summary>
|
|
/// Verifica ed invia variazioni
|
|
/// </summary>
|
|
/// <param name="document"></param>
|
|
/// <param name="forceSend"></param>
|
|
private void checkAndSend(MTConnectStreams.Document document, bool forceSend)
|
|
{
|
|
if (document != null)
|
|
{
|
|
foreach (var deviceStream in document.DeviceStreams)
|
|
{
|
|
string sVal = "";
|
|
string descr = "";
|
|
DateTime locTStamp = DateTime.Now;
|
|
// check su Conditions
|
|
try
|
|
{
|
|
// check su dataItems (conditions + events + samples)
|
|
foreach (var dataItem in deviceStream.Conditions)
|
|
{
|
|
descr = itemTranslation("C", dataItem.DataItemId);
|
|
locTStamp = dataItem.Timestamp.ToLocalTime();
|
|
sVal = $"CONDITION: {locTStamp.ToString()} | descr: {descr} | Id: {dataItem.DataItemId} | | Name: {dataItem.Name} | Val: {dataItem.CDATA}";
|
|
// condizion verboso SEMPRE!
|
|
lgInfo(sVal);
|
|
DateTime tStamp = dataItem.Timestamp;
|
|
var time2 = tStamp.ToLocalTime();
|
|
// verifico se salvare
|
|
bool changed = checkSaveItem(dataItem);
|
|
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, dataItem.CDATA));
|
|
//accodaAlarmLog(sVal, qEncodeFLog(locTStamp, descr, dataItem.CDATA));
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in decodifica Conditions x StreamSuccesfull{Environment.NewLine}{exc}", false);
|
|
}
|
|
// check su events
|
|
try
|
|
{
|
|
// check su dataItems (conditions + events + samples)
|
|
foreach (var dataItem in deviceStream.Events)
|
|
{
|
|
descr = itemTranslation("E", dataItem.DataItemId);
|
|
locTStamp = dataItem.Timestamp.ToLocalTime();
|
|
sVal = $"EVENT: {locTStamp.ToString()} | descr: {descr} | Id: {dataItem.DataItemId} | Name: {dataItem.Name} | Val: {dataItem.CDATA}";
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo(sVal);
|
|
}
|
|
DateTime tStamp = dataItem.Timestamp;
|
|
var time2 = tStamp.ToLocalTime();
|
|
// verifico se salvare
|
|
bool changed = checkSaveItem(dataItem);
|
|
if (changed || forceSend)
|
|
{
|
|
accodaFLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA));
|
|
//accodaFLog(sVal, qEncodeFLog(locTStamp, descr, dataItem.CDATA));
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in decodifica Events x StreamSuccesfull{Environment.NewLine}{exc}", false);
|
|
}
|
|
|
|
// check su samples
|
|
try
|
|
{
|
|
// check su dataItems (conditions + events + samples)
|
|
foreach (var dataItem in deviceStream.Samples)
|
|
{
|
|
descr = itemTranslation("S", dataItem.DataItemId);
|
|
locTStamp = dataItem.Timestamp.ToLocalTime();
|
|
sVal = $"SAMPLE: {locTStamp.ToString()} | descr: {descr} | Id: {dataItem.DataItemId} | | Name: {dataItem.Name} | Val: {dataItem.CDATA}";
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo(sVal);
|
|
}
|
|
DateTime tStamp = dataItem.Timestamp;
|
|
var time2 = tStamp.ToLocalTime();
|
|
// verifico se salvare
|
|
bool changed = checkSaveSample(dataItem);
|
|
if (changed || forceSend)
|
|
{
|
|
accodaFLog(sVal, qEncodeFLog(time2, descr, dataItem.CDATA));
|
|
//accodaFLog(sVal, qEncodeFLog(locTStamp, descr, dataItem.CDATA));
|
|
}
|
|
else
|
|
{
|
|
if (isVerboseLog)
|
|
{
|
|
lgInfo($"NON ACCODATO sample poiché verifica variazione SAMPLE ha dato esito negativo", false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgError($"Eccezione in decodifica Samples x StreamSuccesfull{Environment.NewLine}{exc}");
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("StreamsSuccessful ERROR: document è null");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override disconnessione
|
|
/// </summary>
|
|
public override void tryDisconnect()
|
|
{
|
|
if (connectionOk)
|
|
{
|
|
string szStatusConnection = "";
|
|
try
|
|
{
|
|
MTC_ref.Stop();
|
|
connectionOk = false;
|
|
lgInfo(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...");
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Override connessione
|
|
/// </summary>
|
|
public override void tryConnect()
|
|
{
|
|
if (!connectionOk)
|
|
{
|
|
// controllo che il ping sia stato tentato almeno pingTestSec fa...
|
|
if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
|
|
{
|
|
if (verboseLog || periodicLog)
|
|
{
|
|
lgInfo("MTC: ConnKO - tryConnect");
|
|
}
|
|
// in primis salvo data ping...
|
|
lastPING = DateTime.Now;
|
|
// se passa il ping faccio il resto...
|
|
if (testPingMachine == IPStatus.Success)
|
|
{
|
|
string szStatusConnection = "";
|
|
try
|
|
{
|
|
// ora provo connessione...
|
|
parentForm.commPlcActive = true;
|
|
short esitoLink = doConnect();
|
|
lgInfo($"szStatusConnection MTC, esitoLink: {esitoLink}");
|
|
parentForm.commPlcActive = false;
|
|
connectionOk = true;
|
|
// refresh stato allarmi!!!
|
|
if (connectionOk)
|
|
{
|
|
if (adpRunning)
|
|
{
|
|
// carico status allarmi (completo)
|
|
lgInfo("Inizio refresh completo stato allarmi...");
|
|
forceAlarmCheck();
|
|
lgInfo("Completato refresh completo stato allarmi!");
|
|
}
|
|
else
|
|
{
|
|
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 {cIobConf.cncIpAddr}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
needRefresh = true;
|
|
}
|
|
// se non è ancora connesso faccio procesisng memoria caso disconnesso...
|
|
if (!connectionOk)
|
|
{
|
|
// processo semafori ed invio...
|
|
processMemoryDiscon();
|
|
}
|
|
}
|
|
|
|
#region Metodi specifici (da verificare/completare in implementazione)
|
|
|
|
/// <summary>
|
|
/// controllo allarmi
|
|
/// </summary>
|
|
public override void forceAlarmCheck()
|
|
{
|
|
// controllo tutta la memoria allarmi SE richiesto
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua vero processing contapezzi
|
|
/// </summary>
|
|
public override void processContapezzi()
|
|
{
|
|
if (utils.CRB("enableContapezzi"))
|
|
{
|
|
// cerco parametro contapezzi...
|
|
string currPzCount = "";
|
|
string currPartId = "";
|
|
string currProg = "";
|
|
try
|
|
{
|
|
var currDataItem = dataItemMem["Path_01_PZ_TOT"];
|
|
currPzCount = currDataItem.value;
|
|
}
|
|
catch
|
|
{ }
|
|
try
|
|
{
|
|
var currDataItem = dataItemMem["Path_01_PartId"];
|
|
currPartId = currDataItem.value;
|
|
}
|
|
catch
|
|
{ }
|
|
try
|
|
{
|
|
var currDataItem = dataItemMem["Path_01_CurrProg"];
|
|
currProg = currDataItem.value;
|
|
}
|
|
catch
|
|
{ }
|
|
|
|
// se ho un contapezzi... processo...
|
|
if (!string.IsNullOrEmpty(currPzCount))
|
|
{
|
|
int newVal = -1;
|
|
Int32.TryParse(currPzCount, out newVal);
|
|
lastCountCNC = newVal > -1 ? newVal : lastCountCNC;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua lettura semafori principale
|
|
/// <paramref name="currDispData">Parametri da aggiornare x display in form</paramref>
|
|
/// </summary>
|
|
public override void readSemafori(ref newDisplayData currDispData)
|
|
{
|
|
base.readSemafori(ref currDispData);
|
|
try
|
|
{
|
|
if (verboseLog)
|
|
{
|
|
lgInfo("inizio read semafori");
|
|
}
|
|
|
|
currDispData.semIn = Semaforo.SV;
|
|
|
|
// decodifica e gestione
|
|
decodeToBaseBitmap();
|
|
reportRawInput(ref currDispData);
|
|
}
|
|
catch
|
|
{
|
|
currDispData.semIn = Semaforo.SR;
|
|
}
|
|
}
|
|
/// <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.DataItemCategory.CONDITION)
|
|
{
|
|
// se ha valore !="" --> allarmi attivi
|
|
if (!string.IsNullOrEmpty(item.Value.value))
|
|
{
|
|
answ = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
|
|
/// </summary>
|
|
private void decodeToBaseBitmap()
|
|
{
|
|
// init a zero...
|
|
B_input = 0;
|
|
|
|
|
|
/* -----------------------------------------------------
|
|
* bitmap MAPO
|
|
* B0: POWER_ON
|
|
* B1: RUN
|
|
* B2: pzCount
|
|
* B3: allarme
|
|
* B4: manuale
|
|
*
|
|
*
|
|
* contapezzi: Path_01_PZ_TOT
|
|
*
|
|
*
|
|
* E_Path_01_RUN_MODE
|
|
* public enum MtcRunMode
|
|
* {
|
|
* UNDEFINED = 0,
|
|
* AUTOMATIC,
|
|
* EDIT,
|
|
* MANUAL_DATA_INPUT,
|
|
* MANUAL,
|
|
* SEMI_AUTO
|
|
* }
|
|
*
|
|
*
|
|
* E_Path_01_EXE_MODE
|
|
* /// <summary>
|
|
* /// ENUM degli stati EXE del path MTC
|
|
* /// </summary>
|
|
* public enum MtcExeMode
|
|
* {
|
|
* UNDEFINED = 0,
|
|
* ACTIVE,
|
|
* READY,
|
|
* STOPPED,
|
|
* FEED_HOLD,
|
|
* OPTIONAL_STOP,
|
|
* PROGRAM_STOPPED,
|
|
* PROGRAM_COMPLETED
|
|
* }
|
|
*
|
|
*
|
|
* LAVORA SOLO SE
|
|
* Path_01_EXE_MODE = ACTIVE
|
|
* Path_01_RUN_MODE = AUTOMATIC
|
|
* ST_Abilitaz_Abrasivo = ACTIVE
|
|
* ST_Getto_On = ACTIVE
|
|
* ST_UnOp_01_Status = ACTIVE
|
|
*
|
|
----------------------------------------------------- */
|
|
|
|
// Controllo booleano PING e POWERON...
|
|
bool checkPing = (testPingMachine == IPStatus.Success);
|
|
string currPowerOn = "";
|
|
MtcDataItemExt currMTC_DI = null;
|
|
try
|
|
{
|
|
currMTC_DI = dataItemMem["POWER"];
|
|
currPowerOn = currMTC_DI.value;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
//lgError($"Eccezione in decodifica currPowerOn: {Environment.NewLine}{exc}");
|
|
}
|
|
|
|
bool checkPowerOn = (currPowerOn == "ON");
|
|
|
|
// bit 0 (poweron) imposto a 1 SE pingo o PowerOn=="ON"...
|
|
B_input = (checkPing || checkPowerOn) ? 1 : 0;
|
|
|
|
|
|
// variabili appoggio...
|
|
string currExe = "";
|
|
string currRun = "";
|
|
string currUnOpStatus = "";
|
|
try
|
|
{
|
|
currMTC_DI = dataItemMem["Path_01_EXE_MODE"];
|
|
currExe = currMTC_DI.value;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
//lgError($"Eccezione in decodifica exeMode: {Environment.NewLine}{exc}");
|
|
}
|
|
try
|
|
{
|
|
currMTC_DI = dataItemMem["Path_01_RUN_MODE"];
|
|
currRun = currMTC_DI.value;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
//lgError($"Eccezione in decodifica runMode: {Environment.NewLine}{exc}");
|
|
}
|
|
try
|
|
{
|
|
currMTC_DI = dataItemMem["ST_UnOp_01_Status"];
|
|
currUnOpStatus = currMTC_DI.value;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
//lgError($"Eccezione in decodifica UnOp_Status: {Environment.NewLine}{exc}");
|
|
}
|
|
|
|
// controllo lavora...
|
|
if (currRun == "AUTOMATIC" || currRun == "SEMI_AUTO")
|
|
{
|
|
if (currExe == "ACTIVE")
|
|
{
|
|
if (currUnOpStatus == "ACTIVE")
|
|
{
|
|
// RUN = LAVORA!
|
|
B_input += (1 << 1);
|
|
}
|
|
}
|
|
}
|
|
// se ho almeno 1 allarme E NON SONO IN AUTO --> ALARM!
|
|
else if (hasError)
|
|
{
|
|
B_input += (1 << 3);
|
|
}
|
|
else
|
|
{
|
|
// se ho run mode != auto --> manual
|
|
B_input += (1 << 4);
|
|
}
|
|
|
|
|
|
DateTime adesso = DateTime.Now;
|
|
int vFactor = 1;
|
|
// controllo SE HO dati per fare verifiche...
|
|
if (string.IsNullOrEmpty(currRun) || string.IsNullOrEmpty(currExe) || string.IsNullOrEmpty(currUnOpStatus))
|
|
{
|
|
// 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(1000);
|
|
// 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} | currExe: {currExe} | currUnOpStatus: {currUnOpStatus}");
|
|
// imposto veto per vetoSeconds...
|
|
vetoCheckStatus = adesso.AddSeconds(vetoSeconds * vFactor);
|
|
}
|
|
#if false
|
|
|
|
// process ODL e contapezzi
|
|
string currODL = "";
|
|
try
|
|
{
|
|
currODL = utils.callUrl(urlGetCurrODL);
|
|
// solo SE HO un ODL...
|
|
if (currODL == "" || currODL == "0")
|
|
{
|
|
if (periodicLog)
|
|
{
|
|
lgInfo(string.Format("MTC | Lettura ODL andata a vuoto: currODL: {0}", currODL));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// se variato o scaduto timeout log...
|
|
if (periodicLog || (currIdxODL.ToString() != currODL))
|
|
{
|
|
lgInfo(string.Format("MTC | Lettura ODL, currODL: {0} --> currIdxODL prec: {1}", currODL, currIdxODL));
|
|
}
|
|
// provo a salvare nuovo ODL
|
|
int.TryParse(currODL, out currIdxODL);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
if (DateTime.Now.Subtract(lastWarnODL).TotalSeconds > 15)
|
|
{
|
|
lgError(exc, "Errore in fase di chiamata URL x ODL corrente | URL chiamato: {0}", urlGetCurrODL);
|
|
lastWarnODL = DateTime.Now;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// log opzionale!
|
|
if (verboseLog)
|
|
{
|
|
lgInfo($"Trasformazione B_input: {B_input} | currRun = {currRun} | currExe = {currExe} | currUnOpStatus {currUnOpStatus}");
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Verifica un DataItem e se il valore corrisponde a quello indicato come "true value" 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>
|
|
/// Recupero dati dinamici...
|
|
/// </summary>
|
|
public override Dictionary<string, string> getDynData()
|
|
{
|
|
// valore non presente in vers default... se gestito fare override
|
|
Dictionary<string, string> outVal = new Dictionary<string, string>();
|
|
return outVal;
|
|
}
|
|
/// <summary>
|
|
/// OVerride metodo x scrittura parametri su PLC
|
|
/// </summary>
|
|
/// <param name="updatedPar"></param>
|
|
protected override void plcWriteParams(List<objItem> updatedPar)
|
|
{
|
|
int valInt = 0;
|
|
if (updatedPar != null)
|
|
{
|
|
// controllo i parametri... ne gestisco 4...
|
|
foreach (var item in updatedPar)
|
|
{
|
|
#if false
|
|
switch (item.uid)
|
|
{
|
|
case "kgRich":
|
|
int.TryParse(item.reqValue, out valInt);
|
|
pesoRichiesto = valInt;
|
|
break;
|
|
case "kgLotto":
|
|
int.TryParse(item.reqValue, out valInt);
|
|
quantitaLotto = valInt;
|
|
break;
|
|
case "portata":
|
|
int.TryParse(item.reqValue, out valInt);
|
|
portata = valInt;
|
|
break;
|
|
case "setComm":
|
|
commessa = item.reqValue;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|