Files
OPC-UA-REDIS/Varie/Thiene/RedisManager.cs
T
2019-02-07 11:11:48 +01:00

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);
}
}
}