8bb0f158b5
- proj di base con le 2 form da ereditare - progetto globale che contiene TUTTI gli adapter (pronto a venire spezzettato - gettate le basi x "portare fuori" i vari componenti oppure fare compilazione condizonale
661 lines
26 KiB
C#
661 lines
26 KiB
C#
using IOB_UT_NEXT;
|
|
using MapoSDK;
|
|
using Opc.Ua;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net.NetworkInformation;
|
|
|
|
namespace IOB_WIN_NEXT.IobOpc
|
|
{
|
|
public enum IcoelStatus
|
|
{
|
|
Allarme = 0,
|
|
Stop = 1,
|
|
Manuale = 2,
|
|
Automatico = 3
|
|
}
|
|
|
|
public class DatiMesIcoel
|
|
{
|
|
#region Public Constructors
|
|
|
|
/// <summary>
|
|
/// Inizializzazione classe con dati RAW da byte[]
|
|
/// </summary>
|
|
/// <param name="rawData">Flusso di dati RAW da tradurre...</param>
|
|
public DatiMesIcoel(byte[] rawData)
|
|
{
|
|
// solo se i dati sono esattamente 115...
|
|
|
|
if (rawData.Length >= 115)
|
|
{
|
|
Calibratrice_L1 = new MesItemStatus(rawData.Skip(0).Take(7).ToArray());
|
|
Calibratrice_L2 = new MesItemStatus(rawData.Skip(7).Take(7).ToArray());
|
|
Dewatering_L1 = new MesItemStatus(rawData.Skip(14).Take(7).ToArray());
|
|
Dewatering_L2 = new MesItemStatus(rawData.Skip(21).Take(7).ToArray());
|
|
Precalibro_L1 = new MesItemStatus(rawData.Skip(28).Take(7).ToArray());
|
|
Precalibro_L2 = new MesItemStatus(rawData.Skip(35).Take(7).ToArray());
|
|
Taglierina_L1 = new MesItemStatus(rawData.Skip(42).Take(7).ToArray());
|
|
Taglierina_L2 = new MesItemStatus(rawData.Skip(49).Take(7).ToArray());
|
|
NastroTaglierina_L1 = new MesItemStatus(rawData.Skip(56).Take(7).ToArray());
|
|
NastroTaglierina_L2 = new MesItemStatus(rawData.Skip(63).Take(7).ToArray());
|
|
Elevatore_L1 = new MesItemStatus(rawData.Skip(70).Take(7).ToArray());
|
|
Elevatore_L2 = new MesItemStatus(rawData.Skip(77).Take(7).ToArray());
|
|
ImmergitoreBins_L1 = new MesItemStatus(rawData.Skip(84).Take(7).ToArray());
|
|
ImmergitoreBins_L2 = new MesItemStatus(rawData.Skip(91).Take(7).ToArray());
|
|
ImmergitoreCasse_L1 = new MesItemStatus(rawData.Skip(98).Take(7).ToArray());
|
|
ImmergitoreCasse_L2 = new MesItemStatus(rawData.Skip(105).Take(7).ToArray());
|
|
Varie = new PlantStatus(rawData.Skip(112).Take(3).ToArray());
|
|
}
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Properties
|
|
|
|
public MesItemStatus Calibratrice_L1 { get; set; }
|
|
public MesItemStatus Calibratrice_L2 { get; set; }
|
|
public MesItemStatus Dewatering_L1 { get; set; }
|
|
public MesItemStatus Dewatering_L2 { get; set; }
|
|
public MesItemStatus Elevatore_L1 { get; set; }
|
|
public MesItemStatus Elevatore_L2 { get; set; }
|
|
public MesItemStatus ImmergitoreBins_L1 { get; set; }
|
|
public MesItemStatus ImmergitoreBins_L2 { get; set; }
|
|
public MesItemStatus ImmergitoreCasse_L1 { get; set; }
|
|
public MesItemStatus ImmergitoreCasse_L2 { get; set; }
|
|
public MesItemStatus NastroTaglierina_L1 { get; set; }
|
|
public MesItemStatus NastroTaglierina_L2 { get; set; }
|
|
public MesItemStatus Precalibro_L1 { get; set; }
|
|
public MesItemStatus Precalibro_L2 { get; set; }
|
|
public MesItemStatus Taglierina_L1 { get; set; }
|
|
public MesItemStatus Taglierina_L2 { get; set; }
|
|
public PlantStatus Varie { get; set; }
|
|
|
|
#endregion Public Properties
|
|
|
|
#region Public Methods
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
// Object is not a GaugeModel instance
|
|
if (!(obj is DatiMesIcoel item))
|
|
return false;
|
|
|
|
if (Calibratrice_L1 != item.Calibratrice_L1)
|
|
return false;
|
|
if (Calibratrice_L2 != item.Calibratrice_L2)
|
|
return false;
|
|
if (Dewatering_L1 != item.Dewatering_L1)
|
|
return false;
|
|
if (Dewatering_L2 != item.Dewatering_L2)
|
|
return false;
|
|
if (Precalibro_L1 != item.Precalibro_L1)
|
|
return false;
|
|
if (Precalibro_L2 != item.Precalibro_L2)
|
|
return false;
|
|
if (Taglierina_L1 != item.Taglierina_L1)
|
|
return false;
|
|
if (Taglierina_L2 != item.Taglierina_L2)
|
|
return false;
|
|
if (NastroTaglierina_L1 != item.NastroTaglierina_L1)
|
|
return false;
|
|
if (NastroTaglierina_L2 != item.NastroTaglierina_L2)
|
|
return false;
|
|
if (Elevatore_L1 != item.Elevatore_L1)
|
|
return false;
|
|
if (Elevatore_L2 != item.Elevatore_L2)
|
|
return false;
|
|
if (ImmergitoreBins_L1 != item.ImmergitoreBins_L1)
|
|
return false;
|
|
if (ImmergitoreBins_L2 != item.ImmergitoreBins_L2)
|
|
return false;
|
|
if (ImmergitoreCasse_L1 != item.ImmergitoreCasse_L1)
|
|
return false;
|
|
if (ImmergitoreCasse_L2 != item.ImmergitoreCasse_L2)
|
|
return false;
|
|
if (Varie != item.Varie)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return base.GetHashCode();
|
|
}
|
|
|
|
#endregion Public Methods
|
|
}
|
|
|
|
public class MesItemStatus
|
|
{
|
|
#region Public Constructors
|
|
|
|
public MesItemStatus(byte[] rawData)
|
|
{
|
|
Stato = (IcoelStatus)BitConverter.ToUInt16(rawData, 0);
|
|
Velocita = BitConverter.ToUInt16(rawData, 2);
|
|
Termico = !rawData.Skip(4).Take(1).FirstOrDefault().Equals(0);
|
|
MagnetoTermico = !rawData.Skip(5).Take(1).FirstOrDefault().Equals(0);
|
|
AvariaInverter = !rawData.Skip(6).Take(1).FirstOrDefault().Equals(0);
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Properties
|
|
|
|
public bool AvariaInverter { get; set; } = false;
|
|
public bool MagnetoTermico { get; set; } = false;
|
|
public IcoelStatus Stato { get; set; } = 0;
|
|
public bool Termico { get; set; } = false;
|
|
public UInt16 Velocita { get; set; } = 0;
|
|
|
|
#endregion Public Properties
|
|
|
|
#region Public Methods
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
// Object is not a GaugeModel instance
|
|
if (!(obj is MesItemStatus item))
|
|
return false;
|
|
|
|
if (Stato != item.Stato)
|
|
return false;
|
|
if (Velocita != item.Velocita)
|
|
return false;
|
|
if (Termico != item.Termico)
|
|
return false;
|
|
if (MagnetoTermico != item.MagnetoTermico)
|
|
return false;
|
|
if (AvariaInverter != item.AvariaInverter)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return base.GetHashCode();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converte un singolo item in un array di byte per scrittura su PLC S7
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public byte[] serialize()
|
|
{
|
|
byte[] answ = new byte[7];
|
|
Buffer.BlockCopy(BitConverter.GetBytes((short)Stato), 0, answ, 0, 2);
|
|
Buffer.BlockCopy(BitConverter.GetBytes(Velocita), 0, answ, 2, 2);
|
|
Buffer.BlockCopy(BitConverter.GetBytes(Termico), 0, answ, 4, 1);
|
|
Buffer.BlockCopy(BitConverter.GetBytes(MagnetoTermico), 0, answ, 5, 1);
|
|
Buffer.BlockCopy(BitConverter.GetBytes(AvariaInverter), 0, answ, 6, 1);
|
|
return answ;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
}
|
|
|
|
public class OpcUaOmronIcoel : OpcUaOmron
|
|
{
|
|
#region Public Constructors
|
|
|
|
/// <summary>
|
|
/// Estende l'init della classe base, impiegando il pacchetto Nuget OPC-UA foundation con la
|
|
/// gestione specifica per Omron (es ICOEL) https://github.com/OPCFoundation/UA-.NETStandard
|
|
/// </summary>
|
|
/// <param name="caller"></param>
|
|
/// <param name="IOBConf"></param>
|
|
public OpcUaOmronIcoel(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
|
{
|
|
// inizializzo classe base...
|
|
if (!string.IsNullOrEmpty(getOptPar("CHANGE_ODL_MODE")))
|
|
{
|
|
CHANGE_ODL_MODE = getOptPar("CHANGE_ODL_MODE");
|
|
}
|
|
sendKeyRichiesta = true;
|
|
doByteRead = true;
|
|
lgInfo($"Avviato IobOpcUaOmronIcoel | encodeReadData: {doByteRead}");
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#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>
|
|
/// Effettua vero processing contapezzi
|
|
/// </summary>
|
|
public override void processContapezzi()
|
|
{
|
|
#if false
|
|
if (utils.CRB("enableContapezzi"))
|
|
{
|
|
// check condizione validazione
|
|
if (checkMultiCondition(opcUaParams.condCountEnabled) || opcUaParams.condCountEnabled.checkList.Count == 0)
|
|
{
|
|
// cerco parametro contapezzi...
|
|
string currPzCount = getDataItemValue(opcUaParams.keyPartCount);
|
|
|
|
// se ho un contapezzi... processo...
|
|
if (!string.IsNullOrEmpty(currPzCount))
|
|
{
|
|
int newVal = -1;
|
|
bool fatto = Int32.TryParse(currPzCount, out newVal);
|
|
|
|
if (fatto)
|
|
{
|
|
// gestione decremento contapezzi: viene "messo via" solo SE c'è un
|
|
// effettivo decremento contapezzi...
|
|
if (newVal < contapezziPLC)
|
|
{
|
|
pzCountResetted = true;
|
|
// incremento contatore richiesta
|
|
countKeyRichiesta = countKeyRichiesta + 1;
|
|
// log
|
|
lgInfo("Contapezzi resettato (PLC) --> pzCountResetted = true");
|
|
}
|
|
|
|
// salvo nuovo valore contapezziPLC
|
|
contapezziPLC = newVal > -1 ? newVal : contapezziPLC;
|
|
}
|
|
else
|
|
{
|
|
lgError($"Errore in decodifica valore contapezzi, valore rilevato: {currPzCount}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("Errore in decodifica valore contapezzi, valore vuoto!");
|
|
}
|
|
}
|
|
|
|
if (CHANGE_ODL_MODE == "PZCOUNT_RESET")
|
|
{
|
|
// controllo comunque, se è ZERO il contapezzi, e sul server è maggiore il
|
|
// valore x ODL e NON abilitato il trigger reset --> abilito trigger...
|
|
if (!pzCountResetted && contapezziPLC == 0 && contapezziIOB > 0)
|
|
{
|
|
pzCountResetted = true;
|
|
// incremento contatore richiesta
|
|
countKeyRichiesta = countKeyRichiesta + 1;
|
|
// log
|
|
lgInfo("Contapezzi resettato (PLC==0 e IOB>PLC) --> pzCountResetted = true");
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/// <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;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Internal Methods
|
|
|
|
/// <summary>
|
|
/// Verifica ed invia variazioni DAL FORMATO RAW data (byte[]) --> esplode oggetti e li
|
|
/// testa 1:1
|
|
/// </summary>
|
|
/// <param name="MonIt"></param>
|
|
/// <param name="NotifyValue"></param>
|
|
/// <param name="forceSend"></param>
|
|
internal override bool checkAndSendRaw(Opc.Ua.Client.MonitoredItem MonIt, byte[] NotifyValue, bool forceSend)
|
|
{
|
|
bool changed = false;
|
|
if (MonIt != null)
|
|
{
|
|
if (NotifyValue != null && NotifyValue.Length > 0)
|
|
{
|
|
// verifico variazione "globale"
|
|
if (!lastData.Equals(currData))
|
|
{
|
|
// effettuo test/invio x ogni info
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "Calibratrice_L1", lastData.Calibratrice_L1, currData.Calibratrice_L1, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "Calibratrice_L2", lastData.Calibratrice_L2, currData.Calibratrice_L2, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "Dewatering_L1", lastData.Dewatering_L1, currData.Dewatering_L1, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "Dewatering_L2", lastData.Dewatering_L2, currData.Dewatering_L2, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "Elevatore_L1", lastData.Elevatore_L1, currData.Elevatore_L1, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "Elevatore_L2", lastData.Elevatore_L2, currData.Elevatore_L2, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "ImmergitoreBins_L1", lastData.ImmergitoreBins_L1, currData.ImmergitoreBins_L1, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "ImmergitoreBins_L2", lastData.ImmergitoreBins_L2, currData.ImmergitoreBins_L2, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "ImmergitoreCasse_L1", lastData.ImmergitoreCasse_L1, currData.ImmergitoreCasse_L1, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "ImmergitoreCasse_L2", lastData.ImmergitoreCasse_L2, currData.ImmergitoreCasse_L2, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "NastroTaglierina_L1", lastData.NastroTaglierina_L1, currData.NastroTaglierina_L1, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "NastroTaglierina_L2", lastData.NastroTaglierina_L2, currData.NastroTaglierina_L2, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "Precalibro_L1", lastData.Precalibro_L1, currData.Precalibro_L1, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "Precalibro_L2", lastData.Precalibro_L2, currData.Precalibro_L2, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "Taglierina_L1", lastData.Taglierina_L1, currData.Taglierina_L1, forceSend);
|
|
changed = changed || testSendDataBlock(MonIt.StartNodeId, "Taglierina_L2", lastData.Taglierina_L2, currData.Taglierina_L2, forceSend);
|
|
// salvo lastData...
|
|
lastData = currData;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError($"checkAndSend ERROR | MonIt: {MonIt.DisplayName} | NotifyValue Null!!!");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("checkAndSend ERROR: MonIt null");
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
internal override void UA_ref_eh_MonItChange(object sender, opcUaMonitItemChange e)
|
|
{
|
|
base.UA_ref_eh_MonItChange(sender, e);
|
|
}
|
|
|
|
#endregion Internal Methods
|
|
|
|
#region Protected Properties
|
|
|
|
/// <summary>
|
|
/// Valore corrente dei dati ICOEL (traduzione JIT da byte[])
|
|
/// </summary>
|
|
protected DatiMesIcoel currData
|
|
{
|
|
get
|
|
{
|
|
byte[] rawByte = new byte[115];
|
|
// se ho dati raw decodifico...
|
|
if (byteRawData != null)
|
|
{
|
|
if (byteRawData.Length >= 115)
|
|
{
|
|
rawByte = byteRawData;
|
|
}
|
|
}
|
|
DatiMesIcoel answ = new DatiMesIcoel(rawByte);
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Indica se abbia stato POWER ON (multicondizione)
|
|
/// </summary>
|
|
protected override bool hasPowerOn
|
|
{
|
|
get
|
|
{
|
|
// da rivedere
|
|
return true;
|
|
//return checkMultiCondition(opcUaParams.condPowerOn);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Indica se abbia stato MANUAL (condizioni varie, es stopped)
|
|
/// </summary>
|
|
protected override bool isManual
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
//return checkMultiCondition(opcUaParams.condManual);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Indica se abbia stato READY (condizioni varie, es ausiliari OK)
|
|
/// </summary>
|
|
protected override bool isReady
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
//return checkMultiCondition(opcUaParams.condReady);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ultima versione validata delle info x confronto
|
|
/// </summary>
|
|
protected DatiMesIcoel lastData { get; set; } = new DatiMesIcoel(new byte[115]);
|
|
|
|
#endregion Protected Properties
|
|
|
|
#region Protected Methods
|
|
|
|
/// <summary>
|
|
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
|
|
/// </summary>
|
|
protected override 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 / setup
|
|
* B7: emergenza ARMATA (1=ok, 0 = premuta)
|
|
---------------------------------------------------- */
|
|
|
|
// se valido il check ping lo eseguo... altrimenti lo do x buono
|
|
bool checkPing = !opcUaParams.pingAsPowerOn;
|
|
string currRun = "N.A.";
|
|
if (!checkPing)
|
|
{
|
|
checkPing = (testPingMachine == IPStatus.Success);
|
|
}
|
|
// bit 0 (poweron) imposto a 1 SE pingo + PowerOn=="ON"...
|
|
bool powerOnOk = checkPing && hasPowerOn;
|
|
// procedo SOLO SE mi da ping OK...
|
|
if (checkPing)
|
|
{
|
|
B_input = powerOnOk ? 1 : 0;
|
|
|
|
// decodifico da currData
|
|
if (!currData.Varie.InEmergenza)
|
|
{
|
|
B_input += (1 << 7);
|
|
}
|
|
if (currData.Varie.InMarcia)
|
|
{
|
|
B_input += (1 << 1);
|
|
}
|
|
if (currData.Varie.InStop)
|
|
{
|
|
B_input += (1 << 3);
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
lgDebug($"Stato variabili checkPing: {testPingMachine}");
|
|
// imposto veto per vetoSeconds...
|
|
vetoCheckStatus = adesso.AddSeconds(vetoSeconds * vFactor);
|
|
}
|
|
|
|
// log opzionale!
|
|
if (verboseLog)
|
|
{
|
|
lgDebug($"Trasformazione checkPing: {checkPing} | hasPowerOn: {hasPowerOn} | B_input: {B_input} | currRun = {currRun}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua vera scrittura parametri
|
|
/// </summary>
|
|
/// <param name="updatedPar"></param>
|
|
protected override void plcWriteParams(ref List<objItem> updatedPar)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// effettua verifica del datablock icoel inviando eventualmente i dati variati
|
|
/// </summary>
|
|
/// <param name="startNodeId"></param>
|
|
/// <param name="blockName"></param>
|
|
/// <param name="currBlock"></param>
|
|
/// <param name="newBlock"></param>
|
|
/// <param name="forceSend"></param>
|
|
/// <returns></returns>
|
|
protected bool testSendDataBlock(NodeId startNodeId, string blockName, MesItemStatus currBlock, MesItemStatus newBlock, bool forceSend)
|
|
{
|
|
bool changed = false;
|
|
// verifica globale blocchi old/new...
|
|
if (!currBlock.Equals(newBlock))
|
|
{
|
|
// creo un nuovo monitoredItem se non ci fosse x ogni variabile dell'oggetto...
|
|
changed = changed || testSendProperty(new Opc.Ua.Client.MonitoredItem() { DisplayName = $"{blockName}_Stato", NodeClass = NodeClass.Variable, StartNodeId = startNodeId }, $"{newBlock.Stato}", forceSend);
|
|
changed = changed || testSendProperty(new Opc.Ua.Client.MonitoredItem() { DisplayName = $"{blockName}_Velocita", NodeClass = NodeClass.Variable, StartNodeId = startNodeId }, $"{newBlock.Velocita}", forceSend);
|
|
changed = changed || testSendProperty(new Opc.Ua.Client.MonitoredItem() { DisplayName = $"{blockName}_Termico", NodeClass = NodeClass.Variable, StartNodeId = startNodeId }, $"{newBlock.Termico}", forceSend);
|
|
changed = changed || testSendProperty(new Opc.Ua.Client.MonitoredItem() { DisplayName = $"{blockName}_MagnetoTermico", NodeClass = NodeClass.Variable, StartNodeId = startNodeId }, $"{newBlock.MagnetoTermico}", forceSend);
|
|
changed = changed || testSendProperty(new Opc.Ua.Client.MonitoredItem() { DisplayName = $"{blockName}_AvariaInverter", NodeClass = NodeClass.Variable, StartNodeId = startNodeId }, $"{newBlock.AvariaInverter}", forceSend);
|
|
|
|
// spostare sotto in checkAndSendRaw ??? FIXME todo
|
|
if (changed)
|
|
{
|
|
lgTrace($"Invio variazione dataitem per {dataItemMem.Count} elementi");
|
|
sendDataItemListToServer(startNodeId);
|
|
}
|
|
else
|
|
{
|
|
lgTrace("Nessuna variazione DataItem da trasmettere");
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifico se salvare e inviare proprietà specificata
|
|
/// </summary>
|
|
/// <param name="MonIt"></param>
|
|
protected bool testSendProperty(Opc.Ua.Client.MonitoredItem MonIt, string NotifyValue, bool forceSend)
|
|
{
|
|
bool changed = false;
|
|
DateTime locTStamp = DateTime.Now;
|
|
string sVal = "";
|
|
string descr = "";
|
|
string uuid = calcID($"{MonIt.StartNodeId.Identifier}", $"{MonIt.DisplayName}");
|
|
descr = itemTranslation("OPC", uuid);
|
|
sVal = $"Change: {locTStamp.ToString()} | descr: {descr} | Id: {MonIt.StartNodeId} | Val: {NotifyValue}";
|
|
lgDebug($"TSP | {sVal}");
|
|
|
|
changed = checkSaveValue(MonIt, NotifyValue, false);
|
|
// cerco se non sia un dato filtrato in FLUXLOG...
|
|
bool isFiltered = opcUaParams.fluxLogVeto.Contains(uuid);
|
|
if (isFiltered)
|
|
{
|
|
lgTrace($"TSP | NON ACCODATO sample per {MonIt.DisplayName} - trovato VETO in fluxLogVeto", false);
|
|
}
|
|
else
|
|
{
|
|
if (changed || forceSend)
|
|
{
|
|
accodaFLog(sVal, qEncodeFLog(descr, $"{NotifyValue}"));
|
|
}
|
|
else
|
|
{
|
|
lgTrace($"TSP | NON ACCODATO sample per {uuid} - verifica variazione ha dato esito negativo", false);
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
#endregion Protected Methods
|
|
}
|
|
|
|
public class PlantStatus
|
|
{
|
|
#region Public Constructors
|
|
|
|
public PlantStatus(byte[] rawData)
|
|
{
|
|
InMarcia = !rawData.Skip(0).Take(1).FirstOrDefault().Equals(0);
|
|
InEmergenza = !rawData.Skip(1).Take(1).FirstOrDefault().Equals(0);
|
|
InStop = !rawData.Skip(2).Take(1).FirstOrDefault().Equals(0);
|
|
|
|
//var valore = BitConverter.ToUInt16(rawData, 0);
|
|
|
|
//byte b = rawData.Skip(0).Take(1).FirstOrDefault();
|
|
//InMarcia = (b & (1 << (1 - 1))) != 0;
|
|
//InEmergenza = (b & (1 << (2 - 1))) != 0;
|
|
//InStop = (b & (1 << (3 - 1))) != 0;
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Properties
|
|
|
|
public bool InEmergenza { get; set; } = false;
|
|
public bool InMarcia { get; set; } = false;
|
|
public bool InStop { get; set; } = false;
|
|
|
|
#endregion Public Properties
|
|
|
|
#region Public Methods
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
// Object is not a GaugeModel instance
|
|
if (!(obj is PlantStatus item))
|
|
return false;
|
|
|
|
if (InMarcia != item.InMarcia)
|
|
return false;
|
|
if (InEmergenza != item.InEmergenza)
|
|
return false;
|
|
if (InStop != item.InStop)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return base.GetHashCode();
|
|
}
|
|
|
|
#endregion Public Methods
|
|
}
|
|
} |