688 lines
36 KiB
C#
688 lines
36 KiB
C#
using ProEdge.Model;
|
|
using ProEdge.Model.Report;
|
|
using ProEdge.Model.Report.MachineEvents;
|
|
using ProEdge.Report;
|
|
using Schneider.PLC;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Configuration;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Xml;
|
|
using TeamDev.SDK;
|
|
using TeamDev.SDK.MVVM;
|
|
|
|
namespace ProEdge.IOT
|
|
{
|
|
public class RedisManager
|
|
{
|
|
private enum Status
|
|
{
|
|
EXE,
|
|
READY,
|
|
AZZERAMENTO, // Stato aggiuntivo da non inviare a Redis
|
|
RISCALDAMENTO, // Stato aggiuntivo da non inviare a Redis
|
|
SETUP,
|
|
FAIL,
|
|
POWER_OFF
|
|
}
|
|
|
|
private static Dictionary<Type, Dictionary<string, string>> _mappingProperties;
|
|
private static Dictionary<Type, Type> _nonPlcGroupsMappingTypes;
|
|
private static Dictionary<Type, Dictionary<int, int>> _axisToTypeMapping;
|
|
private static Dictionary<Type, Dictionary<int, string>> _activeTimesToTypeMapping;
|
|
private static Dictionary<Type, Dictionary<int, string>> _loadsToTypeMapping;
|
|
|
|
private Dictionary<string, string>[] _mappingGroups;
|
|
private Dictionary<int, List<int>> _mappingNonPLCGroupsToPLCGroups;
|
|
private Dictionary<int, string> _mappingLoads;
|
|
private Dictionary<int, string> _mappingActiveTimes;
|
|
private Dictionary<int, string> _mappingAxes;
|
|
|
|
private int[] ActiveAlarms;
|
|
private int[] ActiveWarnings;
|
|
private int[] ActiveMessages;
|
|
private bool[] ActiveStatuses = new bool[Enum.GetNames(typeof(Status)).Length];
|
|
static RedisManager()
|
|
{
|
|
_mappingProperties = new Dictionary<Type, Dictionary<string, string>>();
|
|
_nonPlcGroupsMappingTypes = new Dictionary<Type, Type>();
|
|
_loadsToTypeMapping = new Dictionary<Type, Dictionary<int, string>>();
|
|
_activeTimesToTypeMapping = new Dictionary<Type, Dictionary<int, string>>();
|
|
_axisToTypeMapping = new Dictionary<Type, Dictionary<int, int>>();
|
|
// PREFIX
|
|
var subgroups = "Subgroups:";
|
|
// SUFFIXES
|
|
var distance = ":Distance";
|
|
var feedrate = ":FeedRate";
|
|
var activetime = ":ActiveTime";
|
|
var repetition = ":Repetition";
|
|
var value = ":Value";
|
|
var load = ":Load";
|
|
|
|
Dictionary<string, string> dict;
|
|
Dictionary<int, string> loadDict;
|
|
Dictionary<int, string> activeTimeDict;
|
|
Dictionary<int, int> axisDict;
|
|
|
|
// BASE MACCHINA
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.BaseMacchina.KmCingolo), $"{subgroups}01{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.BaseMacchina.VelocitaCingolo), $"{subgroups}01{feedrate}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.BaseMacchina.ActiveTimeCingolo), $"{subgroups}01{activetime}");
|
|
_mappingProperties.Add(typeof(BaseMacchina), dict);
|
|
loadDict = new Dictionary<int, string>();
|
|
loadDict.Add(1, $"{subgroups}01{load}");
|
|
_loadsToTypeMapping.Add(typeof(BaseMacchina), loadDict);
|
|
axisDict = new Dictionary<int, int>();
|
|
axisDict.Add(1, 2);
|
|
axisDict.Add(2, 3);
|
|
_axisToTypeMapping.Add(typeof(BaseMacchina), axisDict);
|
|
|
|
// RETTIFICATORE 2 INVERTER
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.Rettificatore2Inverter.MetriFresaAnteriore), $"{subgroups}05{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Rettificatore2Inverter.MetriFresaPosteriore), $"{subgroups}06{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Rettificatore2Inverter.NumeroPannelloAnteriore), $"{subgroups}07{repetition}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Rettificatore2Inverter.NumeroPannelliPosteriore), $"{subgroups}08{repetition}");
|
|
_mappingProperties.Add(typeof(Rettificatore2Inverter), dict);
|
|
loadDict = new Dictionary<int, string>();
|
|
loadDict.Add(2, $"{subgroups}01{load}");
|
|
loadDict.Add(8, $"{subgroups}02{load}");
|
|
_loadsToTypeMapping.Add(typeof(Rettificatore2Inverter), loadDict);
|
|
activeTimeDict = new Dictionary<int, string>();
|
|
activeTimeDict.Add(3, $"{subgroups}03{activetime}");
|
|
activeTimeDict.Add(4, $"{subgroups}04{activetime}");
|
|
_activeTimesToTypeMapping.Add(typeof(Rettificatore2Inverter), activeTimeDict);
|
|
axisDict = new Dictionary<int, int>();
|
|
axisDict.Add(4, 9);
|
|
_axisToTypeMapping.Add(typeof(Rettificatore2Inverter), axisDict);
|
|
|
|
// INCOLLAGGIO VC1000
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.IncollaggioVC1000.NumeroPannelliLavorati), "Repetition");
|
|
dict.Add(nameof(ProEdge.Model.IOT.IncollaggioVC1000.NumeroInterventiCesoia), $"{subgroups}04{repetition}");
|
|
_mappingProperties.Add(typeof(IncollatoreVC1000), dict);
|
|
loadDict = new Dictionary<int, string>();
|
|
loadDict.Add(5, $"{subgroups}02{load}");
|
|
_loadsToTypeMapping.Add(typeof(IncollatoreVC1000), loadDict);
|
|
activeTimeDict = new Dictionary<int, string>();
|
|
activeTimeDict.Add(15, $"{subgroups}03{activetime}");
|
|
_activeTimesToTypeMapping.Add(typeof(IncollatoreVC1000), activeTimeDict);
|
|
axisDict = new Dictionary<int, int>();
|
|
axisDict.Add(4, 1);
|
|
axisDict.Add(25, 1);
|
|
_axisToTypeMapping.Add(typeof(IncollatoreVC1000), axisDict);
|
|
|
|
// PREFUSORE
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.Prefusore.TemperaturaPrefusore), $"{subgroups}01{value}");
|
|
_mappingProperties.Add(typeof(Prefusore), dict);
|
|
|
|
// VASCA COLLA VC1000
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.VascaCollaVC1000.TemperaturaVasca), $"{subgroups}01{value}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.VascaCollaVC1000.TemperaturaRullo), $"{subgroups}02{value}");
|
|
_mappingProperties.Add(typeof(VascaCollaVC1000), dict);
|
|
loadDict = new Dictionary<int, string>();
|
|
loadDict.Add(4, $"{subgroups}04{load}");
|
|
_loadsToTypeMapping.Add(typeof(VascaCollaVC1000), loadDict);
|
|
activeTimeDict = new Dictionary<int, string>();
|
|
activeTimeDict.Add(14, $"{subgroups}05{activetime}");
|
|
_activeTimesToTypeMapping.Add(typeof(VascaCollaVC1000), activeTimeDict);
|
|
axisDict = new Dictionary<int, int>();
|
|
axisDict.Add(17, 2);
|
|
_axisToTypeMapping.Add(typeof(VascaCollaVC1000), axisDict);
|
|
|
|
// AIR FUSION
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.AirFusion.TemperaturaLeister1), $"{subgroups}01{value}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.AirFusion.TemperaturaLeister2), $"{subgroups}02{value}");
|
|
_mappingProperties.Add(typeof(AirFusion), dict);
|
|
|
|
// LAMPADE
|
|
_nonPlcGroupsMappingTypes.Add(typeof(Lampada), typeof(IncollatoreVC1000));
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.IncollaggioVC1000.TempoAccensioneLampade), $"ActiveTime");
|
|
_mappingProperties.Add(typeof(Lampada), dict);
|
|
|
|
// INTESTATORE KSEL
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.IntestatoreKSEL.MetriLamaAnteriore), $"{subgroups}04{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.IntestatoreKSEL.MetriLamaPosteriore), $"{subgroups}05{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.IntestatoreKSEL.NumeroPannelliAnteriore), $"{subgroups}06{repetition}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.IntestatoreKSEL.NumeroPannelliPosteriore), $"{subgroups}07{repetition}");
|
|
_mappingProperties.Add(typeof(IntestatoreKSEL), dict);
|
|
loadDict = new Dictionary<int, string>();
|
|
loadDict.Add(6, $"{subgroups}01{load}");
|
|
_loadsToTypeMapping.Add(typeof(IntestatoreKSEL), loadDict);
|
|
activeTimeDict = new Dictionary<int, string>();
|
|
activeTimeDict.Add(3, $"{subgroups}02{activetime}");
|
|
activeTimeDict.Add(4, $"{subgroups}03{activetime}");
|
|
_activeTimesToTypeMapping.Add(typeof(IntestatoreKSEL), activeTimeDict);
|
|
|
|
// REFILATORE RSINV
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.RefilatoreRSINV.MetriFresaSuperiore), $"{subgroups}04{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.RefilatoreRSINV.MetriFresaInferiore), $"{subgroups}05{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.RefilatoreRSINV.NumeroPannelliSuperiore), $"{subgroups}06{repetition}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.RefilatoreRSINV.NumeroPannelliInferiore), $"{subgroups}07{repetition}");
|
|
_mappingProperties.Add(typeof(RefilatoreRSINV), dict);
|
|
loadDict = new Dictionary<int, string>();
|
|
loadDict.Add(3, $"{subgroups}01{load}");
|
|
_loadsToTypeMapping.Add(typeof(RefilatoreRSINV), loadDict);
|
|
activeTimeDict = new Dictionary<int, string>();
|
|
activeTimeDict.Add(6, $"{subgroups}02{activetime}");
|
|
activeTimeDict.Add(5, $"{subgroups}03{activetime}");
|
|
_activeTimesToTypeMapping.Add(typeof(RefilatoreRSINV), activeTimeDict);
|
|
|
|
// SPIGOLATORE 6 ASSI
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.Spigolatore6Assi.MetriFresaSuperiore1), $"{subgroups}09{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Spigolatore6Assi.MetriFresaInferiore1), $"{subgroups}05{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Spigolatore6Assi.MetriFresaSuperiore2), $"{subgroups}10{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Spigolatore6Assi.MetriFresaInferiore2), $"{subgroups}06{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Spigolatore6Assi.MetriFresaSuperiore3), $"{subgroups}11{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Spigolatore6Assi.MetriFresaInferiore3), $"{subgroups}07{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Spigolatore6Assi.MetriFresaSuperiore4), $"{subgroups}12{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Spigolatore6Assi.MetriFresaInferiore4), $"{subgroups}08{distance}");
|
|
// TODO
|
|
//dict.Add(nameof(ProEdge.Model.IOT.Spigolatore6Assi.NumeroPannelliSuperiore), $"{subgroups}04{repetition}");
|
|
//dict.Add(nameof(ProEdge.Model.IOT.Spigolatore6Assi.NumeroPannelliInferiore), $"{subgroups}05{repetition}");
|
|
_mappingProperties.Add(typeof(Spigolatore6Assi), dict);
|
|
loadDict = new Dictionary<int, string>();
|
|
loadDict.Add(9, $"{subgroups}01{load}");
|
|
loadDict.Add(12, $"{subgroups}02{load}");
|
|
_loadsToTypeMapping.Add(typeof(Spigolatore6Assi), loadDict);
|
|
activeTimeDict = new Dictionary<int, string>();
|
|
activeTimeDict.Add(7, $"{subgroups}03{activetime}");
|
|
activeTimeDict.Add(8, $"{subgroups}04{activetime}");
|
|
_activeTimesToTypeMapping.Add(typeof(Spigolatore6Assi), activeTimeDict);
|
|
axisDict = new Dictionary<int, int>();
|
|
axisDict.Add(7, 13);
|
|
axisDict.Add(8, 15);
|
|
axisDict.Add(9, 17);
|
|
axisDict.Add(10, 14);
|
|
axisDict.Add(11, 16);
|
|
axisDict.Add(12, 18);
|
|
_axisToTypeMapping.Add(typeof(Spigolatore6Assi), axisDict);
|
|
|
|
// ROUND SK2
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.RoundSK2.MetriFresaSuperiore), $"{subgroups}06{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.RoundSK2.MetriFresaInferiore), $"{subgroups}05{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.RoundSK2.NumeroCicliLavorazione1Superiore), $"{subgroups}09{repetition}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.RoundSK2.NumeroCicliLavorazione1Inferiore), $"{subgroups}07{repetition}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.RoundSK2.NumeroCicliLavorazione2Superiore), $"{subgroups}10{repetition}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.RoundSK2.NumeroCicliLavorazione2Inferiore), $"{subgroups}08{repetition}");
|
|
_mappingProperties.Add(typeof(RoundSK2), dict);
|
|
loadDict = new Dictionary<int, string>();
|
|
loadDict.Add(10, $"{subgroups}01{load}");
|
|
_loadsToTypeMapping.Add(typeof(RoundSK2), loadDict);
|
|
activeTimeDict = new Dictionary<int, string>();
|
|
activeTimeDict.Add(9, $"{subgroups}02{activetime}");
|
|
activeTimeDict.Add(10, $"{subgroups}03{activetime}");
|
|
_activeTimesToTypeMapping.Add(typeof(RoundSK2), activeTimeDict);
|
|
axisDict = new Dictionary<int, int>();
|
|
axisDict.Add(15, 10);
|
|
axisDict.Add(16, 11);
|
|
_axisToTypeMapping.Add(typeof(RoundSK2), axisDict);
|
|
|
|
// RASCHIABORDO 4 ASSI
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiabordo4Assi.MetriColtelloSuperiore1), $"{subgroups}05{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiabordo4Assi.MetriColtelloInferiore1), $"{subgroups}01{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiabordo4Assi.MetriColtelloSuperiore2), $"{subgroups}06{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiabordo4Assi.MetriColtelloInferiore2), $"{subgroups}02{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiabordo4Assi.MetriColtelloSuperiore3), $"{subgroups}07{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiabordo4Assi.MetriColtelloInferiore3), $"{subgroups}03{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiabordo4Assi.MetriColtelloSuperiore4), $"{subgroups}08{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiabordo4Assi.MetriColtelloInferiore4), $"{subgroups}04{distance}");
|
|
// TODO
|
|
//dict.Add(nameof(ProEdge.Model.IOT.Raschiabordo4Assi.NumeroPannelliSuperiore), $"{subgroups}06{distance}");
|
|
//dict.Add(nameof(ProEdge.Model.IOT.Raschiabordo4Assi.NumeroPannelliInferiore), $"{subgroups}05{distance}");
|
|
_mappingProperties.Add(typeof(Raschiabordo4Assi), dict);
|
|
axisDict = new Dictionary<int, int>();
|
|
axisDict.Add(19, 11);
|
|
axisDict.Add(20, 13);
|
|
axisDict.Add(22, 12);
|
|
axisDict.Add(23, 14);
|
|
_axisToTypeMapping.Add(typeof(Raschiabordo4Assi), axisDict);
|
|
|
|
// TOUPIE
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.Toupie.MetriLavorati), $"{subgroups}03{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Toupie.NumeroPannelli), $"{subgroups}04{repetition}");
|
|
_mappingProperties.Add(typeof(Toupie), dict);
|
|
loadDict = new Dictionary<int, string>();
|
|
loadDict.Add(7, $"{subgroups}01{load}");
|
|
_loadsToTypeMapping.Add(typeof(Toupie), loadDict);
|
|
activeTimeDict = new Dictionary<int, string>();
|
|
activeTimeDict.Add(13, $"{subgroups}02{activetime}");
|
|
_activeTimesToTypeMapping.Add(typeof(Toupie), activeTimeDict);
|
|
|
|
// RASCHIACOLLA
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiacolla.MetriLavoratiSuperiore), $"{subgroups}02{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiacolla.MetriLavoratiInferiore), $"{subgroups}01{distance}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiacolla.NumeroPannelliSuperiore), $"{subgroups}04{repetition}");
|
|
dict.Add(nameof(ProEdge.Model.IOT.Raschiacolla.NumeroPannelliInferiore), $"{subgroups}03{repetition}");
|
|
_mappingProperties.Add(typeof(RCA), dict);
|
|
|
|
// SPAZZOLE
|
|
dict = new Dictionary<string, string>();
|
|
dict.Add(nameof(ProEdge.Model.IOT.Spazzole.MetriLavorati), $"Distance");
|
|
_mappingProperties.Add(typeof(SpazzoleSPK), dict);
|
|
}
|
|
|
|
public static RedisManager Current { get; set; } = new RedisManager();
|
|
private RedisManager() { }
|
|
|
|
// Indica se lo scambio di dati con Redis è attivo
|
|
private bool Active { get; set; }
|
|
|
|
public void Init(GruppoBase[] groups)
|
|
{
|
|
Active = true;
|
|
if (!Active) return;
|
|
|
|
initMapping(groups);
|
|
|
|
// Messaggio per terminare l'heartbeat e le comunicazioni in generale
|
|
MessageServices.Current.Subscribe("REDIS_END_COMUNICATION", (o1, o2) => { Active = false; });
|
|
|
|
// Ricezione stato di allarme
|
|
MessageServices.Current.Subscribe<StatoMacchina>("CLIENTNOTIFY_UPDATED_STATUS_MACHINE", (o, status) =>
|
|
{
|
|
Write("Machine:Power", (status.Stato > 50 && status.Stato < 54) || (status.Stato > 60 && status.Stato < 64) ? "true" : "false");
|
|
Write("Machine:Alarm", status.Alarms ? "true" : "false");
|
|
});
|
|
|
|
// resetto TUTTE le aree di competenza
|
|
redUtil.man.redFlushKey(redUtil.man.redHash("AdpVeto*"));
|
|
redUtil.man.redFlushKey(redUtil.man.redHash("AdpConf*"));
|
|
redUtil.man.redFlushKey(redUtil.man.redHash("Adp*"));
|
|
|
|
// Imposto CONF
|
|
Write("Adp:Vers", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
|
|
|
Write("Adp:Status", "started");
|
|
|
|
// Thread per l'heartbeat
|
|
new Thread(() =>
|
|
{
|
|
// una volta al secondo
|
|
while (Active)
|
|
{
|
|
Write("Adp:Heartbeat", DateTime.UtcNow.ToString("yyyy-MM-dd\\THH:mm:ss.fffK"));
|
|
Thread.Sleep(1000);
|
|
}
|
|
redUtil.man.setRSV(redUtil.man.redHash("Adp:Status"), "stopped");
|
|
}).Start();
|
|
|
|
// Scrittura datamodel
|
|
var datamodelPath = Path.Combine(AppContext.BaseDirectory, ConfigurationManager.AppSettings["DataModelFile"]);
|
|
if (File.Exists(datamodelPath))
|
|
{
|
|
using (StreamReader sr = new StreamReader(new FileStream(datamodelPath, FileMode.Open, FileAccess.Read)))
|
|
{
|
|
var datamodel = xmlSanitize(sr.ReadToEnd());
|
|
WriteConf("DataModel", datamodel);
|
|
}
|
|
}
|
|
|
|
// imposto VETO (codici allarme da ignorare)
|
|
WriteVeto("Hmi:Condition", "000000000000|000");
|
|
WriteVeto("Plc:Condition", "000000000000|000");
|
|
|
|
// Versione PLC
|
|
Write("Machine:Plc:Version", PlcStatus.PLCVersion());
|
|
|
|
// Versione HMI (TODO: Aggiorna con la versione del client)
|
|
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetEntryAssembly();
|
|
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
|
|
Write("Machine:Hmi:Version", fvi.FileVersion);
|
|
|
|
// Utente Collegato
|
|
Write("Machine:Hmi:User", "null");
|
|
MessageServices.Current.Subscribe<DbOperator>("LOGGED_IN", (o, u) => Write("Machine:Hmi:User", u.User));
|
|
MessageServices.Current.Subscribe("LOGGED_OUT", (o, u) => Write("Machine:Hmi:User", "null"));
|
|
|
|
// STATUS
|
|
/*
|
|
EXE=Macchina piena cingolo in moto ===> MachineWorkPieces
|
|
READY=Macchina in work e (cingolo in moto e vuota o cingolo fermo e abilitato ma mancano consensi esterni) ===> MachineWorkNoPieces/MachineStopTrackWithPieces
|
|
SETUP=Azzeramento assi in corso e/o riscaldamento colla ===> stati vari, non c'è in eventi (e se AirFusion?)
|
|
FAIL=Macchina in allarme ===> MachineInAlarm
|
|
POWER_OFF=Macchina in stop" ===> !(quelli sopra)
|
|
*/
|
|
Write("Machine:Status", "POWER_OFF");
|
|
ActiveStatuses[(int)Status.POWER_OFF] = true;
|
|
WriteStatus();
|
|
Action<string, bool> updateStatusArray = (s, b) =>
|
|
{
|
|
switch (s)
|
|
{
|
|
case nameof(MachineEventTypeIds.General.MachineInAlarm):
|
|
ActiveStatuses[(int)Status.FAIL] = b;
|
|
break;
|
|
case nameof(MachineEventTypeIds.General.MachineWorkNoPieces):
|
|
case nameof(MachineEventTypeIds.General.MachineStopTrackWithPieces):
|
|
ActiveStatuses[(int)Status.READY] = b;
|
|
break;
|
|
case nameof(MachineEventTypeIds.General.MachineWorkPieces):
|
|
ActiveStatuses[(int)Status.EXE] = b;
|
|
break;
|
|
default: return;
|
|
}
|
|
WriteStatus();
|
|
};
|
|
MessageServices.Current.Subscribe<Event>("CLIENTNOTIFY_UPDATED_NEW_EVENT", (o, e) => updateStatusArray(e.Description, true));
|
|
MessageServices.Current.Subscribe<Event>("CLIENTNOTIFY_UPDATED_EVENT_CLOSED", (o, e) => updateStatusArray(e.Description, false));
|
|
var vc = groups.Where(g => g is IVascaColla).FirstOrDefault();
|
|
if (vc != null)
|
|
MessageServices.Current.Subscribe<StatoVascaColla>("CLIENTNOTIFY_UPDATED_STATUS_" + vc.UniqueID, (o, s) =>
|
|
{
|
|
ActiveStatuses[(int)Status.RISCALDAMENTO] = s.Stato == 3 && !s.ConsensoVascaColla;
|
|
ActiveStatuses[(int)Status.SETUP] = ActiveStatuses[(int)Status.AZZERAMENTO] || ActiveStatuses[(int)Status.RISCALDAMENTO];
|
|
WriteStatus();
|
|
});
|
|
MessageServices.Current.Subscribe<StatoComandiManuali>("CLIENTNOTIFY_UPDATED_STATUS_MANUAL", (o, s) =>
|
|
{
|
|
ActiveStatuses[(int)Status.AZZERAMENTO] = s.AzzeramentoAssiInCorso;
|
|
ActiveStatuses[(int)Status.SETUP] = ActiveStatuses[(int)Status.AZZERAMENTO] || ActiveStatuses[(int)Status.RISCALDAMENTO];
|
|
WriteStatus();
|
|
});
|
|
}
|
|
|
|
private void initMapping(GruppoBase[] groups)
|
|
{
|
|
_mappingGroups = new Dictionary<string, string>[groups.Max(g => g.Id)];
|
|
_mappingNonPLCGroupsToPLCGroups = new Dictionary<int, List<int>>();
|
|
_mappingLoads = new Dictionary<int, string>();
|
|
_mappingActiveTimes = new Dictionary<int, string>();
|
|
_mappingAxes = new Dictionary<int, string>();
|
|
|
|
foreach (var g in groups)
|
|
{
|
|
var gType = g.GetType();
|
|
// Dati dei gruppi
|
|
if (_mappingProperties.ContainsKey(gType))
|
|
_mappingGroups[g.Id] = _mappingProperties[gType];
|
|
// Carico inverter
|
|
if (_loadsToTypeMapping.ContainsKey(gType))
|
|
foreach (var l in _loadsToTypeMapping[gType])
|
|
_mappingLoads[l.Key] = $"{g.Id:00}:{l.Value}";
|
|
// Active Time mandrini
|
|
if (_activeTimesToTypeMapping.ContainsKey(gType))
|
|
foreach (var l in _activeTimesToTypeMapping[gType])
|
|
_mappingActiveTimes[l.Key] = $"{g.Id:00}:{l.Value}";
|
|
// Dati assi
|
|
if (_axisToTypeMapping.ContainsKey(gType))
|
|
foreach (var l in _axisToTypeMapping[gType])
|
|
_mappingAxes[l.Key] = $"{g.Id:00}:Subgroups:{l.Value:00}";
|
|
}
|
|
|
|
// GRUPPI NON PLC
|
|
foreach (var g in groups)
|
|
{
|
|
var gType = g.GetType();
|
|
if (_nonPlcGroupsMappingTypes.ContainsKey(gType))
|
|
{
|
|
var plcType = _nonPlcGroupsMappingTypes[gType];
|
|
var realGroupId = groups.Where(gr => gr.GetType() == plcType).Select(gr => gr.Id).First();
|
|
if (!_mappingNonPLCGroupsToPLCGroups.ContainsKey(realGroupId))
|
|
_mappingNonPLCGroupsToPLCGroups.Add(realGroupId, new List<int>());
|
|
_mappingNonPLCGroupsToPLCGroups[realGroupId].Add(g.Id);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void WriteAlarmsList()
|
|
{
|
|
string result = "000000000000|000";
|
|
if (ActiveAlarms != null)
|
|
lock (ActiveAlarms)
|
|
foreach (var alm in ActiveAlarms)
|
|
result += $",000A{alm:0000}|900";
|
|
if (ActiveWarnings != null)
|
|
lock (ActiveWarnings)
|
|
foreach (var wrn in ActiveWarnings)
|
|
result += $",000W{wrn:0000}|500";
|
|
if (ActiveMessages != null)
|
|
lock (ActiveMessages)
|
|
foreach (var msg in ActiveMessages)
|
|
result += $",000M{msg:0000}|100";
|
|
Write("Machine:Plc:Condition", result);
|
|
}
|
|
|
|
private void WriteStatus()
|
|
{
|
|
Status result = Status.POWER_OFF;
|
|
if (ActiveStatuses[(int)Status.SETUP]) result = Status.SETUP;
|
|
if (ActiveStatuses[(int)Status.READY]) result = Status.READY;
|
|
if (ActiveStatuses[(int)Status.EXE]) result = Status.EXE;
|
|
if (ActiveStatuses[(int)Status.FAIL]) result = Status.FAIL;
|
|
|
|
Write("Machine:Status", result.ToString());
|
|
}
|
|
|
|
private void WriteConf(string key, string value)
|
|
{
|
|
Write($"AdpConf:{key}", value);
|
|
}
|
|
|
|
private void WriteVeto(string key, string value)
|
|
{
|
|
Write($"AdpVeto:{key}", value);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Metodo di sanitizzazione XML
|
|
/// - elimina commenti
|
|
/// - formatta
|
|
/// </summary>
|
|
/// <param name="xmlOrig"></param>
|
|
/// <returns></returns>
|
|
private string xmlSanitize(string xmlOrig)
|
|
{
|
|
string sXml = xmlOrig;
|
|
bool xmlSanitize = false;
|
|
#if DEBUG
|
|
xmlSanitize = true;// utils.CRB("xmlSanitize");
|
|
#endif
|
|
// se richeisto faccio sanitize xml (pulizia commenti...)
|
|
if (xmlSanitize)
|
|
{
|
|
// primo step: converto stringa in dox XML
|
|
XmlDocument xmlDoc = new XmlDocument();
|
|
xmlDoc.PreserveWhitespace = false;
|
|
xmlDoc.LoadXml(sXml);
|
|
// ora lo parso come lista eliminando i commenti
|
|
XmlNodeList list = xmlDoc.SelectNodes("//comment()");
|
|
foreach (XmlNode node in list)
|
|
{
|
|
node.ParentNode.RemoveChild(node);
|
|
}
|
|
// fix formattazione "riscrivendo" indentazione...
|
|
StringWriter string_writer = new StringWriter();
|
|
XmlTextWriter xml_text_writer = new XmlTextWriter(string_writer);
|
|
xml_text_writer.Formatting = Formatting.Indented;
|
|
xmlDoc.WriteTo(xml_text_writer);
|
|
sXml = string_writer.ToString();
|
|
}
|
|
// restituisco
|
|
return sXml;
|
|
}
|
|
|
|
public bool Write(string key, string value)
|
|
{
|
|
// TODO: se non connesso, attendi che si riconnetta
|
|
|
|
if (Active && redUtil.connRedis.IsConnected)
|
|
{
|
|
string hashKey = redUtil.man.redHash(key);
|
|
string hashVal = string.Format(value);
|
|
redUtil.man.setRSV(hashKey, hashVal);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Scrive la lista di tutti i possibili allarmi/warning/messaggi con la loro traduzione nella lingua corrente, in inglese ed in italiano
|
|
public void WriteAlarms(string currentLanguage, Dictionary<string, string> curr, Dictionary<string, string> en, Dictionary<string, string> it)
|
|
{
|
|
if (!Active) return;
|
|
|
|
// Scrivo la lingua attuale
|
|
Write("Machine:Hmi:Language", currentLanguage);
|
|
|
|
//var listCNC_curr = new List<KeyValuePair<string, string>>();
|
|
var listPLC_curr = new List<KeyValuePair<string, string>>();
|
|
var listHMI_curr = new List<KeyValuePair<string, string>>();
|
|
//var listCNC_it = new List<KeyValuePair<string, string>>();
|
|
var listPLC_it = new List<KeyValuePair<string, string>>();
|
|
var listHMI_it = new List<KeyValuePair<string, string>>();
|
|
//var listCNC_en = new List<KeyValuePair<string, string>>();
|
|
var listPLC_en = new List<KeyValuePair<string, string>>();
|
|
var listHMI_en = new List<KeyValuePair<string, string>>();
|
|
// imposto valori "empty" di default....
|
|
//listCNC_curr.Add(new KeyValuePair<string, string>("000A0001|900", "NONE")); // Allarmi: 900, Warning: 500, Messaggi: 100
|
|
//listCNC_en.Add(new KeyValuePair<string, string>("000000000000|000", "NONE"));
|
|
//listCNC_it.Add(new KeyValuePair<string, string>("000000000000|000", "NONE"));
|
|
listHMI_curr.Add(new KeyValuePair<string, string>("000000000000|000", "NONE"));
|
|
listHMI_en.Add(new KeyValuePair<string, string>("000000000000|000", "NONE"));
|
|
listHMI_it.Add(new KeyValuePair<string, string>("000000000000|000", "NONE"));
|
|
listPLC_curr.Add(new KeyValuePair<string, string>("000000000000|000", "NONE"));
|
|
listPLC_en.Add(new KeyValuePair<string, string>("000000000000|000", "NONE"));
|
|
listPLC_it.Add(new KeyValuePair<string, string>("000000000000|000", "NONE"));
|
|
|
|
foreach (var key in curr.Keys)
|
|
{
|
|
string type = key.StartsWith("SCH_A") ? "900" : key.StartsWith("SCH_W") ? "500" : key.StartsWith("SCH_M") ? "100" : null;
|
|
if (type == null) continue;
|
|
int number = -1;
|
|
if (int.TryParse(key.Substring(5), out number))
|
|
{
|
|
string prefix = type == "900" ? "000A" : type == "500" ? "000W" : "000M";
|
|
var almKey = $"{prefix}{number:0000}|{type}";
|
|
listPLC_curr.Add(new KeyValuePair<string, string>(almKey, !curr.ContainsKey(key) || string.IsNullOrEmpty(curr[key]) ? number.ToString() : curr[key]));
|
|
listPLC_en.Add(new KeyValuePair<string, string>(almKey, !en.ContainsKey(key) || string.IsNullOrEmpty(en[key]) ? number.ToString() : en[key]));
|
|
listPLC_it.Add(new KeyValuePair<string, string>(almKey, !it.ContainsKey(key) || string.IsNullOrEmpty(it[key]) ? number.ToString() : it[key]));
|
|
//listPLC_curr.Add(new KeyValuePair<string, string>(almKey, curr[key]));
|
|
//listPLC_en.Add(new KeyValuePair<string, string>(almKey, en[key]));
|
|
//listPLC_it.Add(new KeyValuePair<string, string>(almKey, it[key]));
|
|
}
|
|
}
|
|
|
|
// salvo vettori lingua CURR
|
|
//var hashKey = redUtil.man.redHash("AdpConf:Cnc:Condition:Curr");
|
|
//redUtil.man.redFlushKey(hashKey);
|
|
//redUtil.man.redSaveHashList(hashKey, listCNC_curr);
|
|
var hashKey = redUtil.man.redHash("AdpConf:Hmi:Condition:Curr");
|
|
redUtil.man.redFlushKey(hashKey);
|
|
redUtil.man.redSaveHashList(hashKey, listHMI_curr);
|
|
hashKey = redUtil.man.redHash("AdpConf:Plc:Condition:Curr");
|
|
redUtil.man.redFlushKey(hashKey);
|
|
redUtil.man.redSaveHashList(hashKey, listPLC_curr);
|
|
// salvo vettori lingua EN
|
|
//hashKey = redUtil.man.redHash("AdpConf:Cnc:Condition:En");
|
|
//redUtil.man.redFlushKey(hashKey);
|
|
//redUtil.man.redSaveHashList(hashKey, listCNC_en);
|
|
hashKey = redUtil.man.redHash("AdpConf:Hmi:Condition:En");
|
|
redUtil.man.redFlushKey(hashKey);
|
|
redUtil.man.redSaveHashList(hashKey, listHMI_en);
|
|
hashKey = redUtil.man.redHash("AdpConf:Plc:Condition:En");
|
|
redUtil.man.redFlushKey(hashKey);
|
|
redUtil.man.redSaveHashList(hashKey, listPLC_en);
|
|
// salvo vettori lingua IT
|
|
//hashKey = redUtil.man.redHash("AdpConf:Cnc:Condition:It");
|
|
//redUtil.man.redFlushKey(hashKey);
|
|
//redUtil.man.redSaveHashList(hashKey, listCNC_it);
|
|
hashKey = redUtil.man.redHash("AdpConf:Hmi:Condition:It");
|
|
redUtil.man.redFlushKey(hashKey);
|
|
redUtil.man.redSaveHashList(hashKey, listHMI_it);
|
|
hashKey = redUtil.man.redHash("AdpConf:Plc:Condition:It");
|
|
redUtil.man.redFlushKey(hashKey);
|
|
redUtil.man.redSaveHashList(hashKey, listPLC_it);
|
|
|
|
// Valori di default
|
|
Write("Machine:Hmi:Condition", "000000000000|000");
|
|
Write("Machine:Plc:Condition", "000000000000|000");
|
|
|
|
// Scritto l'elenco di allarmi, comincio a ricevere le variazioni degli allarmi
|
|
MessageServices.Current.Subscribe<AlarmWarningList>("CLIENTNOTIFY_UPDATED_MESSAGES", (o, msgs) => { ActiveMessages = msgs.List.Select(m => m.ID).ToArray(); WriteAlarmsList(); });
|
|
MessageServices.Current.Subscribe<AlarmWarningList>("CLIENTNOTIFY_UPDATED_WARNINGS", (o, wrns) => { ActiveWarnings = wrns.List.Select(m => m.ID).ToArray(); WriteAlarmsList(); });
|
|
MessageServices.Current.Subscribe<AlarmWarningList>("CLIENTNOTIFY_UPDATED_ALARMS", (o, alms) => { ActiveAlarms = alms.List.Select(m => m.ID).ToArray(); WriteAlarmsList(); });
|
|
|
|
}
|
|
|
|
// Dati dei gruppi
|
|
public void WriteGroupData(int idGroup, string property, string value)
|
|
{
|
|
// Lo stato di emergenza è contenuto nel gruppo Base Macchina
|
|
if (property == nameof(ProEdge.Model.IOT.BaseMacchina.Emergenza))
|
|
Write("Machine:Emergency", value);
|
|
|
|
if (_mappingGroups != null && _mappingGroups[idGroup] != null && _mappingGroups[idGroup].ContainsKey(property))
|
|
{
|
|
string key = $"Machine:OperatingGroups:{idGroup:00}:{_mappingGroups[idGroup][property]}";
|
|
Write(key, value.ToString());
|
|
}
|
|
else if (_mappingNonPLCGroupsToPLCGroups != null && _mappingNonPLCGroupsToPLCGroups.ContainsKey(idGroup))
|
|
{
|
|
foreach (var i in _mappingNonPLCGroupsToPLCGroups[idGroup])
|
|
WriteGroupData(i, property, value);
|
|
}
|
|
}
|
|
|
|
// Assorbimenti inverter
|
|
public void WriteLoad(int id, string value)
|
|
{
|
|
if (_mappingLoads != null && _mappingLoads.ContainsKey(id))
|
|
{
|
|
Write("Machine:OperatingGroups:" + _mappingLoads[id], value.ToString());
|
|
}
|
|
}
|
|
|
|
// Active Time motori
|
|
public void WriteActiveTime(int id, string value)
|
|
{
|
|
if (_mappingActiveTimes != null && _mappingActiveTimes.ContainsKey(id))
|
|
{
|
|
Write("Machine:OperatingGroups:" + _mappingActiveTimes[id], value.ToString());
|
|
}
|
|
}
|
|
|
|
// Dati Assi
|
|
public void WriteAxis(int id, string distance, string repetition)
|
|
{
|
|
if (_mappingAxes != null && _mappingAxes.ContainsKey(id))
|
|
{
|
|
Write("Machine:OperatingGroups:" + _mappingAxes[id] + ":Distance", distance.ToString());
|
|
Write("Machine:OperatingGroups:" + _mappingAxes[id] + ":Repetition", repetition.ToString());
|
|
}
|
|
}
|
|
|
|
public void WriteTotalActiveTime(TimeSpan value)
|
|
{
|
|
Write("Machine:ActiveTime", Math.Truncate(value.TotalHours).ToString());
|
|
}
|
|
|
|
public void WriteActualActiveTime(TimeSpan value)
|
|
{
|
|
Write("Machine:Hmi:ActiveTimeSession", Math.Truncate(value.TotalHours).ToString());
|
|
}
|
|
|
|
public void WriteActualSection(string section)
|
|
{
|
|
Write("Machine:Hmi:ActiveSection", section);
|
|
}
|
|
}
|
|
}
|