diff --git a/csharp/App/SaliMax/src/DataTypes/AlarmOrWarning.cs b/csharp/App/SaliMax/src/DataTypes/AlarmOrWarning.cs new file mode 100644 index 000000000..e316d977f --- /dev/null +++ b/csharp/App/SaliMax/src/DataTypes/AlarmOrWarning.cs @@ -0,0 +1,9 @@ +namespace InnovEnergy.App.SaliMax.DataTypes; + +public class AlarmOrWarning +{ + public String? Date { get; set; } + public String? Time { get; set; } + public String? Description { get; set; } + public String? CreatedBy { get; set; } +} \ No newline at end of file diff --git a/csharp/App/SaliMax/src/MiddlewareClasses/Configuration.cs b/csharp/App/SaliMax/src/DataTypes/Configuration.cs similarity index 82% rename from csharp/App/SaliMax/src/MiddlewareClasses/Configuration.cs rename to csharp/App/SaliMax/src/DataTypes/Configuration.cs index 0a3fd986c..f50589446 100644 --- a/csharp/App/SaliMax/src/MiddlewareClasses/Configuration.cs +++ b/csharp/App/SaliMax/src/DataTypes/Configuration.cs @@ -1,6 +1,6 @@ using InnovEnergy.App.SaliMax.SystemConfig; -namespace InnovEnergy.App.SaliMax.MiddlewareClasses; +namespace InnovEnergy.App.SaliMax.DataTypes; public class Configuration { diff --git a/csharp/App/SaliMax/src/MiddlewareClasses/StatusMessage.cs b/csharp/App/SaliMax/src/DataTypes/StatusMessage.cs similarity index 90% rename from csharp/App/SaliMax/src/MiddlewareClasses/StatusMessage.cs rename to csharp/App/SaliMax/src/DataTypes/StatusMessage.cs index f5b51fab6..15169c2b2 100644 --- a/csharp/App/SaliMax/src/MiddlewareClasses/StatusMessage.cs +++ b/csharp/App/SaliMax/src/DataTypes/StatusMessage.cs @@ -1,7 +1,6 @@ - using InnovEnergy.App.SaliMax.Ess; -namespace InnovEnergy.App.SaliMax.MiddlewareClasses; +namespace InnovEnergy.App.SaliMax.DataTypes; public class StatusMessage { diff --git a/csharp/App/SaliMax/src/MiddlewareClasses/AlarmOrWarning.cs b/csharp/App/SaliMax/src/MiddlewareClasses/AlarmOrWarning.cs deleted file mode 100644 index 9c27c52e1..000000000 --- a/csharp/App/SaliMax/src/MiddlewareClasses/AlarmOrWarning.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace InnovEnergy.App.SaliMax.MiddlewareClasses; - -public class AlarmOrWarning -{ - public String Date { get; set; } - public String Time { get; set; } - public String Description { get; set; } - public String CreatedBy { get; set; } -} \ No newline at end of file diff --git a/csharp/App/SaliMax/src/MiddlewareClasses/MiddlewareAgent.cs b/csharp/App/SaliMax/src/MiddlewareClasses/MiddlewareAgent.cs new file mode 100644 index 000000000..0f33a4d62 --- /dev/null +++ b/csharp/App/SaliMax/src/MiddlewareClasses/MiddlewareAgent.cs @@ -0,0 +1,78 @@ +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Text; +using System.Text.Json; +using InnovEnergy.App.SaliMax.DataTypes; +using InnovEnergy.App.SaliMax.Ess; +namespace InnovEnergy.App.SaliMax.MiddlewareClasses; + +public static class MiddlewareAgent +{ + public static UdpClient UdpListener = null!; + private static IPAddress? _controllerIpAddress; + + public static void InitializeCommunicationToMiddleware() + { + _controllerIpAddress = FindVpnIp(); + if (Equals(IPAddress.None, _controllerIpAddress)) + { + Console.WriteLine("There is no VPN interface, exiting..."); + } + + const Int32 udpPort = 9000; + var endPoint = new IPEndPoint(_controllerIpAddress, udpPort); + + UdpListener = new UdpClient(); + UdpListener.Client.Blocking = false; + UdpListener.Client.Bind(endPoint); + } + + private static IPAddress FindVpnIp() + { + const String interfaceName = "innovenergy"; + + var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); + + foreach (var networkInterface in networkInterfaces) + { + if (networkInterface.Name == interfaceName) + { + var ipProps = networkInterface.GetIPProperties(); + var uniCastIPs = ipProps.UnicastAddresses; + var controllerIpAddress = uniCastIPs[0].Address; + + Console.WriteLine("VPN IP is: "+ uniCastIPs[0].Address); + return controllerIpAddress; + } + } + + return IPAddress.None; + } + + public static Configuration? SetConfigurationFile() + { + if (UdpListener.Available > 0) + { + IPEndPoint? serverEndpoint = null; + + var replyMessage = "ACK"; + var replyData = Encoding.UTF8.GetBytes(replyMessage); + + var udpMessage = UdpListener.Receive(ref serverEndpoint); + var message = Encoding.UTF8.GetString(udpMessage); + + Configuration? config = JsonSerializer.Deserialize(message); + + Console.WriteLine($"Received a configuration message: GridSetPoint is " + config.GridSetPoint + ", MinimumSoC is " + config.MinimumSoC + " and ForceCalibrationCharge is " + config.ForceCalibrationCharge); + + // Send the reply to the sender's endpoint + UdpListener.Send(replyData, replyData.Length, serverEndpoint); + Console.WriteLine($"Replied to {serverEndpoint}: {replyMessage}"); + return config; + } + + return null; + } + +} \ No newline at end of file diff --git a/csharp/App/SaliMax/src/MiddlewareClasses/RabbitMQManager.cs b/csharp/App/SaliMax/src/MiddlewareClasses/RabbitMQManager.cs new file mode 100644 index 000000000..35931424e --- /dev/null +++ b/csharp/App/SaliMax/src/MiddlewareClasses/RabbitMQManager.cs @@ -0,0 +1,61 @@ +using System.Text; +using System.Text.Json; +using InnovEnergy.App.SaliMax.DataTypes; +using RabbitMQ.Client; + +namespace InnovEnergy.App.SaliMax.MiddlewareClasses; + +public static class RabbitMqManager +{ + public static ConnectionFactory? Factory ; + public static IConnection ? Connection; + public static IModel? Channel; + + public static Boolean SubscribeToQueue(StatusMessage currentSalimaxState, String? s3Bucket,String VpnServerIp) + { + try + { + //_factory = new ConnectionFactory { HostName = VpnServerIp }; + + Factory = new ConnectionFactory + { + HostName = VpnServerIp, + Port = 5672, + VirtualHost = "/", + UserName = "producer", + Password = "b187ceaddb54d5485063ddc1d41af66f", + + }; + + Connection = Factory.CreateConnection(); + Channel = Connection.CreateModel(); + Channel.QueueDeclare(queue: "statusQueue", durable: true, exclusive: false, autoDelete: false, arguments: null); + + Console.WriteLine("The controller sends its status to the middleware for the first time"); + if (s3Bucket != null) InformMiddleware(currentSalimaxState); + + + } + catch (Exception ex) + { + Console.WriteLine("An error occurred while connecting to the RabbitMQ queue: " + ex.Message); + return false; + } + return true; + } + + public static void InformMiddleware(StatusMessage status) + { + var message = JsonSerializer.Serialize(status); + var body = Encoding.UTF8.GetBytes(message); + + Channel.BasicPublish(exchange: string.Empty, + routingKey: "statusQueue", + basicProperties: null, + body: body); + + Console.WriteLine($"Producer sent message: {message}"); + } + + +} \ No newline at end of file diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index 175546e0c..cf1f6b8f8 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -4,7 +4,6 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reactive.Linq; using System.Reactive.Threading.Tasks; -using System.Security.Cryptography.X509Certificates; using System.Text; using Flurl.Http; using InnovEnergy.App.SaliMax.Devices; @@ -26,7 +25,7 @@ using InnovEnergy.Lib.Protocols.Modbus.Channels; using InnovEnergy.Lib.Units; using InnovEnergy.Lib.Utils; using System.Text.Json; -using RabbitMQ.Client; +using InnovEnergy.App.SaliMax.DataTypes; using static System.Double; using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.SystemConfig; using DeviceState = InnovEnergy.App.SaliMax.Devices.DeviceState; @@ -52,14 +51,7 @@ internal static class Program private static readonly Channel RelaysChannel ; private static readonly Channel BatteriesChannel ; - //private const String VpnServerIp = "194.182.190.208"; private const String VpnServerIp = "10.2.0.11"; - - private static IPAddress? _controllerIpAddress; - private static UdpClient _udpListener = null!; - private static ConnectionFactory? _factory ; - private static IConnection ? _connection; - private static IModel? _channel; private static Boolean _subscribedToQueue = false; private static Boolean _subscribeToQueueForTheFirstTime = false; private static SalimaxAlarmState _prevSalimaxState = SalimaxAlarmState.Green; @@ -95,7 +87,7 @@ internal static class Program { //Do not await HourlyDataAggregationManager(); - InitializeCommunicationToMiddleware(); + MiddlewareAgent.InitializeCommunicationToMiddleware(); while (true) { try @@ -109,21 +101,7 @@ internal static class Program } } - private static void InitializeCommunicationToMiddleware() - { - _controllerIpAddress = FindVpnIp(); - if (Equals(IPAddress.None, _controllerIpAddress)) - { - Console.WriteLine("There is no VPN interface, exiting..."); - } - - const Int32 udpPort = 9000; - var endPoint = new IPEndPoint(_controllerIpAddress, udpPort); - - _udpListener = new UdpClient(); - _udpListener.Client.Blocking = false; - _udpListener.Client.Bind(endPoint); - } + private static async Task Run() { @@ -262,8 +240,8 @@ internal static class Program // ReSharper disable once FunctionNeverReturns } - - private static void SendSalimaxStateAlarm(StatusMessage currentSalimaxState, StatusRecord record) + + public static void SendSalimaxStateAlarm(StatusMessage currentSalimaxState, StatusRecord record) { var s3Bucket = Config.Load().S3?.Bucket; @@ -274,14 +252,14 @@ internal static class Program if (_subscribeToQueueForTheFirstTime==false) { _subscribeToQueueForTheFirstTime = true; - SubscribeToQueue(currentSalimaxState, s3Bucket); + _subscribedToQueue = RabbitMqManager.SubscribeToQueue(currentSalimaxState, s3Bucket, VpnServerIp); } //If already subscribed to the queue and the status has been changed, update the queue if (_subscribedToQueue && currentSalimaxState.Status != _prevSalimaxState) { _prevSalimaxState = currentSalimaxState.Status; if (s3Bucket != null) - InformMiddleware(currentSalimaxState); + RabbitMqManager.InformMiddleware(currentSalimaxState); } else if (_subscribedToQueue && _heartBitInterval>=15) { @@ -291,97 +269,16 @@ internal static class Program currentSalimaxState.Type = MessageType.Heartbit; if (s3Bucket != null) - InformMiddleware(currentSalimaxState); + RabbitMqManager.InformMiddleware(currentSalimaxState); } //If there is an available message from the RabbitMQ Broker, apply the configuration file - if (_udpListener.Available > 0) + Configuration? config = MiddlewareAgent.SetConfigurationFile(); + if (config != null) { - IPEndPoint? serverEndpoint = null; - - var replyMessage = "ACK"; - var replyData = Encoding.UTF8.GetBytes(replyMessage); - - var udpMessage = _udpListener.Receive(ref serverEndpoint); - var message = Encoding.UTF8.GetString(udpMessage); - - Configuration config = JsonSerializer.Deserialize(message); - - Console.WriteLine($"Received a configuration message: GridSetPoint is "+config.GridSetPoint +", MinimumSoC is "+config.MinimumSoC+ " and ForceCalibrationCharge is "+config.ForceCalibrationCharge); - - // Send the reply to the sender's endpoint - _udpListener.Send(replyData, replyData.Length, serverEndpoint); - Console.WriteLine($"Replied to {serverEndpoint}: {replyMessage}"); - record.ApplyConfigFile(config); - } - } - - private static void SubscribeToQueue(StatusMessage currentSalimaxState, String? s3Bucket) - { - try - { - //_factory = new ConnectionFactory { HostName = VpnServerIp }; - - _factory = new ConnectionFactory - { - HostName = VpnServerIp, - Port = 5672, - VirtualHost = "/", - UserName = "producer", - Password = "b187ceaddb54d5485063ddc1d41af66f", - - }; - - _connection = _factory.CreateConnection(); - _channel = _connection.CreateModel(); - _channel.QueueDeclare(queue: "statusQueue", durable: true, exclusive: false, autoDelete: false, arguments: null); - - Console.WriteLine("The controller sends its status to the middleware for the first time"); - if (s3Bucket != null) InformMiddleware(currentSalimaxState); - - _subscribedToQueue = true; - } - catch (Exception ex) - { - Console.WriteLine("An error occurred while connecting to the RabbitMQ queue: " + ex.Message); - } - } - - private static IPAddress FindVpnIp() - { - const String interfaceName = "innovenergy"; - - var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); - - foreach (var networkInterface in networkInterfaces) - { - if (networkInterface.Name == interfaceName) - { - var ipProps = networkInterface.GetIPProperties(); - var uniCastIPs = ipProps.UnicastAddresses; - var controllerIpAddress = uniCastIPs[0].Address; - - Console.WriteLine("VPN IP is: "+ uniCastIPs[0].Address); - return controllerIpAddress; - } - } - - return IPAddress.None; - } - - private static void InformMiddleware(StatusMessage status) - { - var message = JsonSerializer.Serialize(status); - var body = Encoding.UTF8.GetBytes(message); - - _channel.BasicPublish(exchange: string.Empty, - routingKey: "statusQueue", - basicProperties: null, - body: body); - - Console.WriteLine($"Producer sent message: {message}"); + } private static StatusMessage GetSalimaxStateAlarm(StatusRecord record) @@ -774,8 +671,12 @@ internal static class Program //Create a new file to folder "Hourly Aggregated Data and push it to S3" Console.WriteLine("-----------------------------------------------------------------------------------------------------------------"); + + + } + // Custom method to check if a string is numeric private static bool IsSoc(string value) { @@ -792,7 +693,7 @@ internal static class Program return value == "/Battery/Dc/Power"; } - private static void ApplyConfigFile(this StatusRecord status, Configuration config) + private static void ApplyConfigFile(this StatusRecord status, Configuration? config) { status.Config.MinSoc = config.MinimumSoC; status.Config.GridSetPoint = config.GridSetPoint * 1000; // converted from kW to W