Removed complexity from program.cs, created classes for rabbitmq management and middleware communication
This commit is contained in:
parent
907f8b66c6
commit
a871693ba8
|
@ -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; }
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using InnovEnergy.App.SaliMax.SystemConfig;
|
using InnovEnergy.App.SaliMax.SystemConfig;
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.MiddlewareClasses;
|
namespace InnovEnergy.App.SaliMax.DataTypes;
|
||||||
|
|
||||||
public class Configuration
|
public class Configuration
|
||||||
{
|
{
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
using InnovEnergy.App.SaliMax.Ess;
|
using InnovEnergy.App.SaliMax.Ess;
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.MiddlewareClasses;
|
namespace InnovEnergy.App.SaliMax.DataTypes;
|
||||||
|
|
||||||
public class StatusMessage
|
public class StatusMessage
|
||||||
{
|
{
|
|
@ -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; }
|
|
||||||
}
|
|
|
@ -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<Configuration>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Threading.Tasks;
|
using System.Reactive.Threading.Tasks;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Flurl.Http;
|
using Flurl.Http;
|
||||||
using InnovEnergy.App.SaliMax.Devices;
|
using InnovEnergy.App.SaliMax.Devices;
|
||||||
|
@ -26,7 +25,7 @@ using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||||
using InnovEnergy.Lib.Units;
|
using InnovEnergy.Lib.Units;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using RabbitMQ.Client;
|
using InnovEnergy.App.SaliMax.DataTypes;
|
||||||
using static System.Double;
|
using static System.Double;
|
||||||
using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.SystemConfig;
|
using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.SystemConfig;
|
||||||
using DeviceState = InnovEnergy.App.SaliMax.Devices.DeviceState;
|
using DeviceState = InnovEnergy.App.SaliMax.Devices.DeviceState;
|
||||||
|
@ -52,14 +51,7 @@ internal static class Program
|
||||||
private static readonly Channel RelaysChannel ;
|
private static readonly Channel RelaysChannel ;
|
||||||
private static readonly Channel BatteriesChannel ;
|
private static readonly Channel BatteriesChannel ;
|
||||||
|
|
||||||
//private const String VpnServerIp = "194.182.190.208";
|
|
||||||
private const String VpnServerIp = "10.2.0.11";
|
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 _subscribedToQueue = false;
|
||||||
private static Boolean _subscribeToQueueForTheFirstTime = false;
|
private static Boolean _subscribeToQueueForTheFirstTime = false;
|
||||||
private static SalimaxAlarmState _prevSalimaxState = SalimaxAlarmState.Green;
|
private static SalimaxAlarmState _prevSalimaxState = SalimaxAlarmState.Green;
|
||||||
|
@ -95,7 +87,7 @@ internal static class Program
|
||||||
{
|
{
|
||||||
//Do not await
|
//Do not await
|
||||||
HourlyDataAggregationManager();
|
HourlyDataAggregationManager();
|
||||||
InitializeCommunicationToMiddleware();
|
MiddlewareAgent.InitializeCommunicationToMiddleware();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
try
|
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()
|
private static async Task Run()
|
||||||
{
|
{
|
||||||
|
@ -262,8 +240,8 @@ internal static class Program
|
||||||
|
|
||||||
// ReSharper disable once FunctionNeverReturns
|
// 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;
|
var s3Bucket = Config.Load().S3?.Bucket;
|
||||||
|
|
||||||
|
@ -274,14 +252,14 @@ internal static class Program
|
||||||
if (_subscribeToQueueForTheFirstTime==false)
|
if (_subscribeToQueueForTheFirstTime==false)
|
||||||
{
|
{
|
||||||
_subscribeToQueueForTheFirstTime = true;
|
_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 already subscribed to the queue and the status has been changed, update the queue
|
||||||
if (_subscribedToQueue && currentSalimaxState.Status != _prevSalimaxState)
|
if (_subscribedToQueue && currentSalimaxState.Status != _prevSalimaxState)
|
||||||
{
|
{
|
||||||
_prevSalimaxState = currentSalimaxState.Status;
|
_prevSalimaxState = currentSalimaxState.Status;
|
||||||
if (s3Bucket != null)
|
if (s3Bucket != null)
|
||||||
InformMiddleware(currentSalimaxState);
|
RabbitMqManager.InformMiddleware(currentSalimaxState);
|
||||||
}
|
}
|
||||||
else if (_subscribedToQueue && _heartBitInterval>=15)
|
else if (_subscribedToQueue && _heartBitInterval>=15)
|
||||||
{
|
{
|
||||||
|
@ -291,97 +269,16 @@ internal static class Program
|
||||||
currentSalimaxState.Type = MessageType.Heartbit;
|
currentSalimaxState.Type = MessageType.Heartbit;
|
||||||
|
|
||||||
if (s3Bucket != null)
|
if (s3Bucket != null)
|
||||||
InformMiddleware(currentSalimaxState);
|
RabbitMqManager.InformMiddleware(currentSalimaxState);
|
||||||
}
|
}
|
||||||
|
|
||||||
//If there is an available message from the RabbitMQ Broker, apply the configuration file
|
//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<Configuration>(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);
|
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)
|
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"
|
//Create a new file to folder "Hourly Aggregated Data and push it to S3"
|
||||||
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------");
|
Console.WriteLine("-----------------------------------------------------------------------------------------------------------------");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Custom method to check if a string is numeric
|
// Custom method to check if a string is numeric
|
||||||
private static bool IsSoc(string value)
|
private static bool IsSoc(string value)
|
||||||
{
|
{
|
||||||
|
@ -792,7 +693,7 @@ internal static class Program
|
||||||
return value == "/Battery/Dc/Power";
|
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.MinSoc = config.MinimumSoC;
|
||||||
status.Config.GridSetPoint = config.GridSetPoint * 1000; // converted from kW to W
|
status.Config.GridSetPoint = config.GridSetPoint * 1000; // converted from kW to W
|
||||||
|
|
Loading…
Reference in New Issue