using Microsoft.Extensions.Configuration; using MP.MONO.Core; using MP.MONO.Core.CONF; using MP.MONO.Core.DTO; using Newtonsoft.Json; using NLog; using Opc.Ua; using StackExchange.Redis; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Reflection; using System.Threading; using System.Threading.Tasks; using static MP.MONO.Core.Enums; namespace MP.MONO.ADAPTER.OPC { /// /// The program. /// public static class Program { #region Public Methods /// /// Main entry point. /// public static async Task Main(string[] args) { await Task.Delay(1); TextWriter output = Console.Out; output.WriteLine(lineSep); output.WriteLine("Egalware | MP.MONO.ADAPTER | OPC UA Console Client"); output.WriteLine($"vers.{Assembly.GetExecutingAssembly().GetName().Version}"); output.WriteLine(lineSep); output.WriteLine(); output.WriteLine("OPC UA library: {0} @ {1} -- {2}", Utils.GetAssemblyBuildNumber(), Utils.GetAssemblyTimestamp().ToString("G", CultureInfo.InvariantCulture), Utils.GetAssemblySoftwareVersion()); // init parte config, vedere https://blog.hildenco.com/2020/05/configuration-in-net-core-console.html var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); var builder = new ConfigurationBuilder() .AddJsonFile($"appsettings.json", true, true) .AddJsonFile($"appsettings.{env}.json", true, true) .AddEnvironmentVariables(); IConfigurationRoot config = builder.Build(); // imposto variabili di base redisConf = config.GetConnectionString("Redis"); confPath = Path.Combine(Directory.GetCurrentDirectory(), "conf"); Random rand = new Random(); List? statusList = new List(); List? modeList = new List(); // fix numero minimo dei thread pool x evitare collasso chiamate redis ThreadPool.SetMinThreads(10, 10); logInfo(lineSep, true, true); logInfo($"Starting Machine ADAPTER", true, true); logInfo($"Redis server param: {redisConf.Substring(0, 20)}...", false, true); logInfo(lineSep, true, true); logInfo("", true, true); // Setup REDIS ConnectionMultiplexer.SetFeatureFlag("preventthreadtheft", true); ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(redisConf); sub = redis.GetSubscriber(); redisDb = redis.GetDatabase(); // salvo configurazioni in redis setupConfRedis(config); // avvio il vero e proprio programma di comunicaizone OPC-UA var currIob = new IobOpcUa(confPath, config); logInfo($"Started IOB at path {confPath}", true, true); logInfo("Running - press CTRL-C to stop ADAPTER", false, true); logInfo("", false, true); // wait for timeout or Ctrl-C var quitEvent = ConsoleUtils.CtrlCHandler(); bool quit = false; DateTime start = DateTime.UtcNow; int waitTime = int.MaxValue; // Ciclo infinito x attesa chiusura con CTRL-C do { // se non fosse connesso... riprovo la connessione... currIob.tryConnect(); // attesa... Thread.Sleep(100); // aggiunta condizioni check dati "recenti" x ri-connessione: se NON si fosse // aggiornato entro limite indicato --> disconnect/reconnect if (currIob.dataIsStale) { currIob.tryDisconnect(); Thread.Sleep(500); currIob.tryConnect(); } // verifico se c'è evento quit quit = quitEvent.WaitOne(Math.Min(1_000, waitTime)); } while (!quit); // disconnetto alla fine... if (currIob.connectionOk) { currIob.tryDisconnect(); } } #endregion Public Methods #region Private Fields private static AlarmReportingMode alarmMode = AlarmReportingMode.ND; private static string confPath = ""; private static DateTime lastLog = DateTime.Now.AddMinutes(-1); private static Dictionary LastSend = new Dictionary(); private static string lineSep = "---------------------------------------------"; private static Logger Log = LogManager.GetCurrentClassLogger(); private static Dictionary LogSimulator = new Dictionary(); private static bool logWriting = false; private static string redisConf = ""; private static bool verboseLog = false; #endregion Private Fields #region Private Properties /// /// Redis DB /// private static IDatabase? redisDb { get; set; } /// /// Redis channel manager /// private static ISubscriber sub { get; set; } #endregion Private Properties #region Private Methods /// /// verifica esistenza file oppure lo crea... /// private static void checkFilePresent(string filePath) { // verific presenza file log... if (!File.Exists(filePath)) { File.WriteAllText(filePath, $"{filePath} created!"); } } /// /// Effettua log ERROR su file e se richiesto su console /// private static void logError(string msg, bool log2file = true, bool log2console = false) { if (log2console) { Console.WriteLine(msg); } if (log2file) { Log.Error(msg); } } /// /// Effettua log INFO su file e se richiesto su console /// private static void logInfo(string msg, bool log2file = true, bool log2console = false) { if (log2console) { Console.WriteLine(msg); } if (log2file) { Log.Info(msg); } } /// /// Setup e salvataggio redis delle conf (es modi/stati) /// private static void setupConfRedis(IConfigurationRoot appConf) { // fix configuraizoni di base MachineDTO currMach = new MachineDTO() { Manufacturer = appConf.GetValue("Machine:Manufacturer"), Model = appConf.GetValue("Machine:Model"), SerNumber = appConf.GetValue("Machine:SerialNumber"), Name = appConf.GetValue("Machine:Name"), ModeId = 0, StatusId = 0 }; redisDb.StringSet(Constants.MACHINE_CONF_PLATE, JsonConvert.SerializeObject(currMach)); // allarmi alarmMode = appConf.GetValue("OptPar:AlarmMode"); redisDb.StringSet(Constants.ALARMS_MODE_KEY, JsonConvert.SerializeObject(alarmMode)); // gestore specifico configurazioni ConfigManager configManager = new ConfigManager(redisConf, confPath); if (alarmMode == AlarmReportingMode.RawList) { _ = configManager.getAlarmsRawConf(); } else { _ = configManager.getAlarmsBankConf(); } // altre conf _ = configManager.getMachineModeConf(); _ = configManager.getMachineStatusConf(); _ = configManager.getPalletStatusConf(); _ = configManager.getParamsConf(); } #endregion Private Methods } }