Files
Mapo-IOB-WIN/IOB-WIN-NEXT/IobOpcUa.cs
T
2021-12-15 09:54:32 +01:00

1126 lines
43 KiB
C#

using IOB_UT_NEXT;
using MapoSDK;
using MTConnect.Clients;
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;
using Opc.Ua;
using Opc.Ua.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Net.NetworkInformation;
using System.Threading;
using System.Windows.Forms;
using System.Linq;
namespace IOB_WIN_NEXT
{
public class IobOpcUa : IobGeneric
{
#region Private Fields
/// <summary>
/// Struttura dove vengono memorizzati i dataitem ed i rispettivi valori x processing
/// </summary>
protected Dictionary<string, OpcUaDataItemExt> dataItemMem = new Dictionary<string, OpcUaDataItemExt>();
/// <summary>
/// Elenco degli items da monitorare come risultato del browse iniziale
/// </summary>
private Dictionary<string, string> selectedItemList = new Dictionary<string, string>();
#endregion Private Fields
#region Protected Fields
/// <summary>
/// Abilitazione restart (da opt par...)
/// </summary>
protected bool enableCliRestart = false;
/// <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>
/// Ultimo current received x gestione update periodico...
/// </summary>
protected DateTime lastCurrent = DateTime.Now;
/// <summary>
/// Variabile numero errori controllo --> se supera soglia 20 --> disconnette
/// </summary>
protected int numErroriCheck = 0;
/// <summary>
/// Oggetto MAIN x connessione MTC
/// </summary>
protected UAClient UA_ref;
/// <summary>
/// Veto controllo status x log...
/// </summary>
protected DateTime vetoCheckStatus = DateTime.Now;
#endregion Protected Fields
#region Public Constructors
/// <summary>
/// Estende l'init della classe base, impiegando il pacchetto Nuget OPC-UA foundation
/// https://github.com/OPCFoundation/UA-.NETStandard
/// </summary>
/// <param name="caller"></param>
/// <param name="IOBConf"></param>
public IobOpcUa(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 OpcUa client...
if (!string.IsNullOrEmpty(getOptPar("ENABLE_CLI_RESTART")))
{
bool.TryParse(getOptPar("ENABLE_CLI_RESTART"), out enableCliRestart);
}
// init datetime counters
DateTime adesso = DateTime.Now;
lastPzCountSend = adesso;
lastWarnODL = adesso;
lastCurrent = adesso;
// ora leggo il file di conf specifico....
string jsonFileName = getOptPar("OPC_PARAM_CONF");
if (!string.IsNullOrEmpty(jsonFileName))
{
// leggo il file...
loadOpcUaConf(jsonFileName);
}
}
#endregion Public Constructors
#region Protected Properties
/// <summary>
/// Verifico se abbia ALMENO un errore...
/// </summary>
protected bool hasError
{
get
{
return checkMultiCondition(opcUaParams.condError.checkList, opcUaParams.condError.checkMode);
}
}
/// <summary>
/// Indica se abbia emergenza ARMATA (cond normale)
/// </summary>
protected bool hasEStopArmed
{
get
{
return checkMultiCondition(opcUaParams.condEStop.checkList, opcUaParams.condError.checkMode);
}
}
/// <summary>
/// Indica se abbia stato POWER ON (multicondizione)
/// </summary>
protected bool hasPowerOn
{
get
{
return checkMultiCondition(opcUaParams.condPowerOn.checkList, opcUaParams.condPowerOn.checkMode);
}
}
/// <summary>
/// Indica se abbia stato MANUAL (condizioni varie, es stopped)
/// </summary>
protected bool isManual
{
get
{
return checkMultiCondition(opcUaParams.condManual.checkList, opcUaParams.condManual.checkMode);
}
}
/// <summary>
/// Indica se abbia stato READY (condizioni varie, es ausiliari OK)
/// </summary>
protected bool isReady
{
get
{
return checkMultiCondition(opcUaParams.condReady.checkList, opcUaParams.condReady.checkMode);
}
}
/// <summary>
/// Indica se sia in stato WarmUp / CoolDown (riscaldamento/raffreddamento)
/// </summary>
protected bool isWarmUpCoolDown
{
get
{
return checkMultiCondition(opcUaParams.condWarmUpCoolDown.checkList, opcUaParams.condWarmUpCoolDown.checkMode);
}
}
/// <summary>
/// Indica se sia in stato Warning
/// </summary>
protected bool isWarning
{
get
{
return checkMultiCondition(opcUaParams.condWarning.checkList, opcUaParams.condWarning.checkMode);
}
}
/// <summary>
/// Indica se sia in stato Ssetup
/// </summary>
protected bool isSetup
{
get
{
return checkMultiCondition(opcUaParams.condSetup.checkList, opcUaParams.condSetup.checkMode);
}
}
/// <summary>
/// Indica se abbia stato READY (condizioni varie, es ausiliari OK)
/// </summary>
protected bool isWorking
{
get
{
return checkMultiCondition(opcUaParams.condWork, boolCheckMode.AND);
}
}
/// <summary>
/// Parametri specifici MTC
/// </summary>
protected OpcUaParamConf opcUaParams { get; set; }
/// <summary>
/// URL x salvataggio elenco dataItems OpcUa
/// </summary>
protected string urlSaveDataItems
{
get
{
string answ = "";
try
{
string machineName = Environment.MachineName;
answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/saveDataItems/{cIobConf.codIOB}";
}
catch (Exception exc)
{
lgError(exc, "Errore in composizione urlSaveDataItems");
}
return answ;
}
}
#endregion Protected Properties
#region Private Methods
/// <summary>
/// Verifica ed invia variazioni
/// </summary>
/// <param name="MonIt"></param>
/// <param name="NotifyValue"></param>
/// <param name="forceSend"></param>
private void checkAndSend(Opc.Ua.Client.MonitoredItem MonIt, string NotifyValue, bool forceSend)
{
if (MonIt != null)
{
if (!string.IsNullOrEmpty(NotifyValue))
{
string sVal = "";
string descr = "";
DateTime locTStamp = DateTime.Now;
descr = itemTranslation("OPC", MonIt.DisplayName);
sVal = $"Change: {locTStamp.ToString()} | descr: {descr} | Id: {MonIt.StartNodeId} | | Val: {NotifyValue}";
if (isVerboseLog)
{
lgInfo(sVal);
}
// verifico se salvare
bool changed = checkSaveValue(MonIt, NotifyValue);
// cerco se non sia un dato filtrato in FLUXLOG...
bool isFiltered = opcUaParams.fluxLogVeto.Contains(MonIt.DisplayName);
if (isFiltered)
{
if (isVerboseLog)
{
lgInfo($"NON ACCODATO sample per {MonIt.DisplayName} poiché trovato VETO in fluxLogVeto", false);
}
}
else
{
if (changed || forceSend)
{
accodaFLog(sVal, qEncodeFLog(descr, $"{NotifyValue}"));
}
else
{
if (isVerboseLog)
{
lgInfo($"NON ACCODATO sample per {MonIt.DisplayName} poiché verifica variazione ha dato esito negativo", false);
}
}
}
}
else
{
lgError($"checkAndSend ERROR | MonIt: {MonIt.DisplayName} | NotifyValue Null!!!");
}
}
else
{
lgError("checkAndSend ERROR: MonIt null");
}
}
/// <summary>
/// Vera connessione ad OpcUa
/// </summary>
/// <returns></returns>
private async Task<short> doConnect()
{
short esitoLink = 0;
// reset memoria dataItem..
dataItemMem = new Dictionary<string, OpcUaDataItemExt>();
// predisposizione conf oggetto di comunicazione MTC
int port = 4840;
int.TryParse(cIobConf.cncPort, out port);
// ora avvio
try
{
lgInfo("Start init OpcUa Client");
// Define the UA Client application
ApplicationInstance application = new ApplicationInstance();
application.ApplicationName = "Steamware IOB-WIN Client";
application.ApplicationType = ApplicationType.Client;
// load the application configuration.
string confPath = $"{Application.StartupPath}\\DATA\\CONF\\IobOpcUaClient.Config.xml";
await application.LoadApplicationConfiguration(confPath, silent: false).ConfigureAwait(false);
// check the application certificate.
await application.CheckApplicationInstanceCertificate(silent: false, minimumKeySize: 0).ConfigureAwait(false);
lgInfo($"Chiamata UAClient con configurazione standard: {application.ApplicationConfiguration.ApplicationName}");
UA_ref = new UAClient(application.ApplicationConfiguration, cIobConf.codIOB, isVerboseLog, ClientBase.ValidateResponse);
lgInfo($"Chiamata apertura OpcUa Client: {cIobConf.cncIpAddr}:{port}");
UA_ref.ServerUrl = $"opc.tcp://{cIobConf.cncIpAddr}:{port}";
var task = Task.Run(async () =>
{
return await UA_ref.ConnectAsync().ConfigureAwait(false);
});
bool connected = task.Result;
if (connected)
{
// faccio un primo browse dei dati...
Dictionary<string, string> nodeIdNameList = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(opcUaParams.BrowseFullVal))
{
UA_ref.Browse(opcUaParams.BrowseFullVal, opcUaParams.filterItemsNodeId, ref nodeIdNameList);
}
else
{
UA_ref.Browse(opcUaParams.BrowseNSIndex, opcUaParams.BrowseValue, opcUaParams.filterItemsNodeId, ref nodeIdNameList);
}
// loggo elenco degli item sottocrivibili...
lgInfo("---------- AVAILABLE FOR SUBSCRIBE ----------");
foreach (var item in nodeIdNameList)
{
lgInfo(item.Key);
}
lgInfo("---------- END LIST ----------");
// se ho un insieme non vuoto degli item sottoscritti carico solo quelli
if (opcUaParams.subscribedItems != null && opcUaParams.subscribedItems.Count > 0)
{
// cerco e aggiungo SOLO quelle indicati
foreach (var currItem in opcUaParams.subscribedItems)
{
var foundItems = nodeIdNameList.Where(x => x.Key.Contains(currItem)).ToList();
if (foundItems != null && foundItems.Count > 0)
{
foreach (var fItem in foundItems)
{
// verifico di NON duplicare...
if (!selectedItemList.ContainsKey(fItem.Key))
{
selectedItemList.Add(fItem.Key, fItem.Value);
}
}
}
else
{
lgInfo($"subscribedItems non trovato: {currItem}");
}
}
lgInfo($"Aggiunti {selectedItemList.Count} items!");
}
// altrimenti tutti!
else
{
selectedItemList = nodeIdNameList;
}
// loggo elenco degli item sottocrivibili...
lgInfo("---------- SUBSCRIBED NODES ----------");
foreach (var item in selectedItemList)
{
lgInfo(item.Key);
}
lgInfo("---------- END LIST ----------");
// sottoscrivo a rilevazione cambio dati solo l'incrocio degli insiemi
List<Opc.Ua.Client.MonitoredItem> subscribedItems = UA_ref.SubscribeToDataChanges(selectedItemList);
// aggiungo come DataItems
int dSamplePeriod = 0;
int threshDBand = 0;
string uuid = "";
foreach (var item in subscribedItems)
{
OpcUaDataItemExt newItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, item);
// controllo non sia già stato aggiunto
if (dataItemMem.ContainsKey(uuid))
{
lgInfo($"Item ALREADY subscribed: {uuid} | NOT re-adding");
}
else
{
dataItemMem.Add(uuid, newItem);
lgInfo($"Item subscribed: {uuid}");
string currVal = UA_ref.ReadNode(item.StartNodeId);
checkAndSend(item, currVal, true);
}
}
// gestione eventi change
UA_ref.eh_MonItChange += UA_ref_eh_MonItChange;
lgInfo("eh_MonItChange event registered");
}
esitoLink = 1;
// fix tempi!
DateTime adesso = DateTime.Now;
lastPzCountSend = adesso;
lastWarnODL = adesso;
lastCurrent = adesso;
}
catch (Exception exc)
{
lgError($"Eccezione in doConnect{Environment.NewLine}{exc}");
}
return esitoLink;
}
/// <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 OpcUaDataItemExt formatDataItem(ref int dSamplePeriod, ref int threshDBand, ref string uuid, Opc.Ua.Client.MonitoredItem dataItem)
{
OpcUaDataItemExt currDataItem;
// calcolo parametri
uuid = $"{dataItem.DisplayName}";
// SOLO SE è abilitato il datafiltering...
if (enableDataFilter)
{
threshDBand = 1;
// controllo SE ho conf x deadband...
if (opcUaParams.paramsEndThresh.Count > 0)
{
// ciclo su tutti i parametri indicati...
foreach (var item in opcUaParams.paramsEndThresh)
{
if (uuid.EndsWith(item.Key))
{
threshDBand = item.Value;
}
}
}
}
else
{
threshDBand = 0;
}
dSamplePeriod = 60;
// salvo oggetto x "uso interno"
currDataItem = new OpcUaDataItemExt(dataItem)
{
uid = uuid,
thresholdDeadBand = threshDBand,
samplePeriod = dSamplePeriod
};
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>
/// Evento rilevazione modifica valori --> chiamo checkSend
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void UA_ref_eh_MonItChange(object sender, opcUaMonitItemChange e)
{
checkAndSend(e.CurrMonitoredItem, $"{e.CurrNotify.Value}", false);
lastCurrent = DateTime.Now;
}
protected int WatchDog = 0;
#endregion Private Methods
#region Protected Methods
/// <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;
OpcUaDataItemExt 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="checkList"></param>
/// <returns></returns>
protected bool checkMultiCondition(List<diCheckCondition> checkList, boolCheckMode checkMode)
{
bool answ = false;
int numCondOk = 0;
int numCond = 0;
if (checkList != null && checkList.Count > 0)
{
numCond = checkList.Count;
// cerco nell'elenco delle condizioni che indicano lavora se sono ok faccio +1 conteggio......
foreach (var item in checkList)
{
if (string.IsNullOrEmpty(item.keyName))
{
lgError($"Attenzione: item vuoto in checkMultiCondition{Environment.NewLine}StackTrace: {Environment.StackTrace}");
}
else
{
if (getDataItemValue(item.keyName) == item.targetValue)
{
numCondOk++;
}
}
}
if (checkMode == boolCheckMode.AND)
{
answ = (numCond == numCondOk);
}
else if (checkMode == boolCheckMode.OR)
{
answ = numCondOk > 0;
}
}
else
{
answ = true;
}
return answ;
}
/// <summary>
/// Verifica / Salva valore e restitusice SE sia variato (e quindi da inviare...)
/// </summary>
/// <param name="newValue"></param>
/// <returns></returns>
protected bool checkSaveValue(Opc.Ua.Client.MonitoredItem dataItem, string NotifyValue)
{
bool answ = !enableDataFilter;
double oldVal = 0;
double newVal = 0;
if (dataItem != null)
{
if (!string.IsNullOrEmpty(NotifyValue))
{
if (isVerboseLog)
{
lgInfo($"Richiesta checkSaveSample per {dataItem.DisplayName} | id: {dataItem.StartNodeId} | Valore: {NotifyValue}");
}
// verifico in memoria se ho l'oggetto condition ed il suo valore..
string uuid = $"{dataItem.DisplayName}";
DateTime adesso = DateTime.Now;
if (dataItemMem.ContainsKey(uuid))
{
OpcUaDataItemExt currDataItemMem = dataItemMem[uuid];
// controllo SE SIA scaduto il tempo massimo...
if (Math.Abs(dataItemMem[uuid].valueTimestamp.Subtract(adesso).TotalSeconds) > currDataItemMem.samplePeriod)
{
answ = true;
}
else
{
// ALTRIMENTI controllo SE diverso
if (dataItemMem[uuid].value != $"{NotifyValue}")
{
if (isVerboseLog)
{
lgInfo($"Val uuid: {dataItemMem[uuid].value} | NotifyValue: {NotifyValue}");
}
// controllo SE ho DeadBand...
if (dataItemMem[uuid].thresholdDeadBand > 0)
{
// recupero i valori e testo DeadBand...
bool isNum01 = double.TryParse(dataItemMem[uuid].value.Replace(".", ","), out oldVal);
bool isNum02 = double.TryParse($"{NotifyValue}".Replace(".", ","), out newVal);
// test deadband!
if (!(isNum01 && isNum02))
{
answ = true;
}
else
{
if (Math.Abs(newVal - oldVal) > dataItemMem[uuid].thresholdDeadBand)
{
// indico da salvare..
answ = true;
}
}
if (isVerboseLog)
{
lgInfo($"Test deadband: oldVal: {oldVal} | newVal: {newVal}");
}
}
}
}
if (answ)
{
// salvo!
dataItemMem[uuid].value = $"{NotifyValue}";
dataItemMem[uuid].valueTimestamp = adesso;
}
}
else
{
// registro non trovato da aggiungere...
lgInfo($"DataItem non trovato in checkSaveSample: {dataItem.DisplayName}");
// provo a creare oggetto in memoria...
try
{
List<machDataItem> elencoDataItems = new List<machDataItem>();
int dSamplePeriod = 0;
int threshDBand = 0;
uuid = "";
var currDataItem = formatDataItem(ref dSamplePeriod, ref threshDBand, ref uuid, dataItem);
// sistemo valore/periodo
currDataItem.value = $"{NotifyValue}";
currDataItem.valueTimestamp = adesso;
// aggiungo
dataItemMem.Add(uuid, currDataItem);
// salvo oggetto x registrazione su server MP-IO
var currMapoDataItem = new machDataItem()
{
uuid = uuid,
Category = DataItemCategory.EVENT,
Name = dataItem.DisplayName,
Type = $"{dataItem.NodeClass}",
SubType = $"{dataItem.StartNodeId}"
};
// 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 Notify null!");
}
}
else
{
lgError("Attenzione: checkSaveItem con MonIt null!");
}
return answ;
}
/// <summary>
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
/// </summary>
protected virtual void decodeToBaseBitmap()
{
DateTime adesso = DateTime.Now;
// init a zero...
B_input = 0;
/* -----------------------------------------------------
* STATE MACHINE 60 STD / SIMULA
*------------------------------------------------------
* bitmap MAPO
* B0: POWER_ON
* B1: RUN
* B2: pzCount
* B3: allarme
* B4: manuale
* B5: SlowTC (NON gestito qui)
* B6: warm-up / cool-down
* B7: emergenza
---------------------------------------------------- */
// se valido il check ping lo eseguo... altrimenti lo do x buono
bool checkPing = !opcUaParams.pingAsPowerOn;
string currRun = "";
if (!checkPing)
{
checkPing = (testPingMachine == IPStatus.Success);
}
// bit 0 (poweron) imposto a 1 SE pingo + PowerOn=="ON"...
bool powerOnOk = checkPing && hasPowerOn;
// controllo se sono poweroff e se non ho dati buoni da > 2 minuti --> disconnetto
if (!powerOnOk && adesso.Subtract(lastCurrent).TotalMinutes > 2)
{
tryDisconnect();
}
// solo se non ho veto check
int vFactor = 2;
if (vetoCheckStatus < adesso)
{
lgInfo($"Stato variabili checkPing: {testPingMachine}");
// imposto veto per vetoSeconds...
vetoCheckStatus = adesso.AddSeconds(vetoSeconds * vFactor);
}
// se abilitato watchdog...
if (opcUaParams.WatchDog.IsEnabled)
{
lgInfo("WatchDog 01");
if (adesso.Subtract(lastWatchDogPLC).TotalSeconds > 2)
{
lastWatchDogPLC = adesso;
WatchDog++;
WatchDog = WatchDog > opcUaParams.WatchDog.MaxVal ? 0 : WatchDog;
lgInfo($"WatchDog val: {WatchDog}");
try
{
WriteValue commWriteVal = new WriteValue();
commWriteVal.NodeId = new NodeId(opcUaParams.WatchDog.MemConfWrite);
commWriteVal.AttributeId = Attributes.Value;
commWriteVal.Value = new DataValue();
commWriteVal.Value.Value = WatchDog;
List<WriteValue> nodes2Write = new List<WriteValue>();
nodes2Write.Add(commWriteVal);
UA_ref.WriteNodes(nodes2Write);
lgInfo("Effettuata scrittura WatchDog");
}
catch (Exception exc)
{
lgError($"Eccezione in gestione WatchDog, valore attuale {WatchDog}{Environment.NewLine}{exc}");
}
}
}
else
{
lgInfo("WatchDog disabilitato");
}
// log opzionale!
if (verboseLog)
{
lgInfo($"Trasformazione checkPing: {checkPing} | hasPowerOn: {hasPowerOn} | B_input: {B_input} | currRun = {currRun}");
}
}
/// <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 string itemTranslation(string tipo, string id)
{
string answ = "";
string lemma = id;
if (!string.IsNullOrEmpty(tipo))
{
lemma = $"{tipo}_{id}";
}
// cerco nel dizionario delle traduzioni SE esiste un valore e prendo quello, altrimenti uso il lemma...
if (opcUaParams.itemTranslation.ContainsKey(lemma))
{
answ = opcUaParams.itemTranslation[lemma];
}
else
{
answ = lemma;
}
return answ;
}
/// <summary>
/// Effettua lettura file di conf specifico OPC-UA da oggetto serializzato json
/// <paramref name="fileName">Nome file da cui leggere i parametri json</paramref>
/// </summary>
protected void loadOpcUaConf(string fileName)
{
string jsonFullPath = $"{Application.StartupPath}/DATA/CONF/{fileName}";
lgInfo($"Apertura file {jsonFullPath}");
using (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
{
opcUaParams = JsonConvert.DeserializeObject<OpcUaParamConf>(jsonData);
lgInfo($"Decodifica aree OpcUaParamConf: trovati {opcUaParams.paramsEndThresh.Count} valori paramsEndThresh");
// sistemo se ci sono dati memMap...
memMap = new plcMemMap();
if (opcUaParams.mMapWrite != null)
{
memMap.mMapWrite = opcUaParams.mMapWrite;
}
if (opcUaParams.mMapRead != null)
{
memMap.mMapRead = opcUaParams.mMapRead;
}
setupMemMap();
}
catch (Exception exc)
{
lgError($"Eccezione in decodifica conf json OPC-UA:{Environment.NewLine}{exc}");
}
}
else
{
lgError("Errore in loadOpcUaConf: file json vuoto!");
}
}
//reader.Dispose();
}
#endregion Protected Methods
#region Public Methods
/// <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>
/// Recupera uno specifico dataItem
/// </summary>
/// <param name="diKey"></param>
/// <returns></returns>
public string getDataItemValue(string diKey)
{
string answ = "";
if (string.IsNullOrEmpty(diKey))
{
lgError($"Attenzione: richiesta chiave vuota in getDataItemValue{Environment.NewLine}StackTrace: {Environment.StackTrace}");
}
else
{
DateTime adesso = DateTime.Now;
if (dataItemMem.Count == 0)
{
numErroriCheck++;
if (vetoCheckStatus < adesso)
{
lgError($"Errore in getDataItemValue per {diKey} | dataItemMem NON contiene valori");
// imposto veto per vetoSeconds...
vetoCheckStatus = adesso.AddSeconds(vetoSeconds * 2);
}
}
else
{
if (!dataItemMem.ContainsKey(diKey))
{
if (vetoCheckStatus < adesso)
{
lgError($"Errore in getDataItemValue per {diKey} | dataItemMem non contiene la chiave richiesta ma altri {dataItemMem.Count} valori");
// imposto veto per vetoSeconds...
vetoCheckStatus = adesso.AddSeconds(vetoSeconds * 2);
}
numErroriCheck++;
}
else
{
try
{
var currDataItem = dataItemMem[diKey];
answ = currDataItem.value;
}
catch (Exception exc)
{
lgError($"Errore in getDataItemValue per {diKey} | dataItemMem contiene {dataItemMem.Count} valori {Environment.NewLine}{exc}");
if (dataItemMem != null)
{
lgError($"dataItemMem contiene {dataItemMem.Count} valori");
int maxNum = 5;
foreach (var item in dataItemMem)
{
maxNum--;
if (maxNum < 0)
{
break;
}
lgInfo($"{item.Key} --> {item.Value.DisplayName} = {item.Value.value}");
}
}
}
}
}
// se supero soglia errori lettura --> disconnetto e resetto
if (numErroriCheck > 100)
{
lgInfo($"numErroriCheck: {numErroriCheck} --> richiesta disconnessione adapter con tryDisconnect");
numErroriCheck = 0;
tryDisconnect();
}
}
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 (utils.CRB("enableContapezzi"))
{
// da ridefinire la gestione base del contapezzi OPC-UA...
}
}
/// <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 (Exception exc)
{
currDispData.semIn = Semaforo.SR;
lgError($"Eccezione in readSemafori:{Environment.NewLine}{exc}");
}
}
/// <summary>
/// Effettua reset del contapezzi, NON POSSIBILE in questa versione
/// </summary>
/// <returns></returns>
public override bool resetcontapezziPLC()
{
bool answ = false;
return answ;
}
/// <summary>
/// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON POSSIBILE in questa versione
/// </summary>
/// <returns></returns>
public override bool setcontapezziPLC(int newPzCount)
{
bool answ = false;
return answ;
}
/// <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("OpcUa: 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;
var task = Task.Run(async () =>
{
return await doConnect().ConfigureAwait(false);
});
short esitoLink = task.Result; // use returned result from async method here
lgInfo($"szStatusConnection OpcUa, esitoLink: {esitoLink}");
parentForm.commPlcActive = false;
connectionOk = true;
// refresh stato allarmi!!!
if (connectionOk)
{
if (adpRunning)
{
lgInfo("Connessione OK");
}
}
else
{
lgError("Impossibile procedere, connessione mancante...");
}
}
catch (Exception exc)
{
lgFatal($"Errore nella connessione all'adapter OpcUa: {szStatusConnection}{Environment.NewLine}{exc}");
connectionOk = false;
lgInfo($"Eccezione in TryConnect, Adapter OpcUa 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: OpcUa 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();
}
}
/// <summary>
/// Override disconnessione
/// </summary>
public override void tryDisconnect()
{
if (connectionOk)
{
if (UA_ref != null)
{
string szStatusConnection = "";
try
{
UA_ref.Disconnect();
connectionOk = false;
lgInfo(szStatusConnection);
lgInfo("Effettuata disconnessione adapter OpcUa!");
}
catch (Exception exc)
{
lgFatal(exc, "Errore nella disconnessione dall'adapter OpcUa");
}
}
else
{
lgError("IMPOSSIBILE effettuare disconnessione OpcUa: UA_ref non disponibile...");
}
}
else
{
lgError("IMPOSSIBILE effettuare disconnessione OpcUa: Connessione non disponibile...");
}
}
#endregion Public Methods
}
}