diff --git a/csharp/App/SaliMax/src/Ess/StatusRecord.cs b/csharp/App/SaliMax/src/Ess/StatusRecord.cs index cf6ca2b31..bc67de3f2 100644 --- a/csharp/App/SaliMax/src/Ess/StatusRecord.cs +++ b/csharp/App/SaliMax/src/Ess/StatusRecord.cs @@ -21,6 +21,7 @@ public record StatusRecord public required AmptStatus? PvOnAcGrid { get; init; } public required AmptStatus? PvOnAcIsland { get; init; } public required AcPowerDevice? AcGridToAcIsland { get; init; } + public required DcPowerDevice? AcDcToDcLink { get; init; } public required DcPowerDevice? LoadOnDc { get; init; } public required RelaysRecord? Relays { get; init; } public required AmptStatus? PvOnDc { get; init; } diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index a0a86e8e6..d23041ae2 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -72,6 +72,7 @@ internal static class Program { while (true) { + //CreateAverage(); try { await Run(); @@ -120,14 +121,18 @@ internal static class Program var pvOnAcIsland = pvOnAcIslandDevice.Read(); var gridBusToIslandBus = Topology.CalculateGridBusToIslandBusPower(pvOnAcIsland, loadOnAcIsland, acDc); - - var gridBusLoad = devices.LoadOnAcGrid.DeviceState == DeviceState.Disabled ? - new AcPowerDevice { Power = 0 } : - Topology.CalculateGridBusLoad(gridMeter, pvOnAcGrid, gridBusToIslandBus); - - var dcLoad = devices.LoadOnDc.DeviceState == DeviceState.Disabled ? - new DcPowerDevice() { Power = 0 } : - Topology.CalculateDcLoad(acDc, pvOnDc, dcDc); + + var gridBusLoad = devices.LoadOnAcGrid.DeviceState == DeviceState.Disabled + ? new AcPowerDevice { Power = 0 } + : Topology.CalculateGridBusLoad(gridMeter, pvOnAcGrid, gridBusToIslandBus); + + var dcLoad = devices.LoadOnDc.DeviceState == DeviceState.Disabled + ? new DcPowerDevice { Power = 0 } + : Topology.CalculateDcLoad(acDc, pvOnDc, dcDc); + + var acDcToDcLink = devices.LoadOnDc.DeviceState == DeviceState.Disabled ? + Topology.CalculateAcDcToDcLink(pvOnDc, dcDc, acDc) + : new DcPowerDevice{ Power = acDc.Dc.Power}; return new StatusRecord { @@ -136,32 +141,31 @@ internal static class Program Battery = battery, Relays = relays, GridMeter = gridMeter, - PvOnAcGrid = pvOnAcGrid, PvOnAcIsland = pvOnAcIsland, PvOnDc = pvOnDc, - AcGridToAcIsland = gridBusToIslandBus, + AcDcToDcLink = acDcToDcLink, LoadOnAcGrid = gridBusLoad, LoadOnAcIsland = loadOnAcIsland, LoadOnDc = dcLoad, - - StateMachine = StateMachine.Default, + + StateMachine = StateMachine.Default, EssControl = EssControl.Default, - Log = new SystemLog{Led = LedState.Green, Message = null}, //TODO: Put real stuff + Log = new SystemLog { Led = LedState.Green, Message = null }, //TODO: Put real stuff Config = config // load from disk every iteration, so config can be changed while running }; } - + void WriteControl(StatusRecord r) { if (r.Relays is not null) saliMaxRelaysDevice.Write(r.Relays); - + acDcDevices.Write(r.AcDc); dcDcDevices.Write(r.DcDc); } - + Console.WriteLine("press ctrl-c to stop"); while (true) @@ -180,23 +184,23 @@ internal static class Program Watchdog.NotifyAlive(); var record = ReadStatus(); + - /* - var i = 2; - if (record.Battery is not null) - { - foreach (var r in record.Battery.Devices) - { - var y = r.BusCurrentHex; - var x = r.CellsCurrentHex; - - r.SerialNumber.WriteLine(" serial number " + i); - - ("--------------").WriteLine(); - - i++; - } - }*/ + // var i = 2; + // if (record.Battery is not null) + // { + // foreach (var r in record.Battery.Devices) + // { + // //var y = r.BusCurrentHex; + // //var x = r.CellsCurrentHex; + // + // r.FwVersion.WriteLine(" serial number " + i); + // + // ("--------------").WriteLine(); + // + // i++; + // } + // }i //record.Log = new SystemLog @@ -215,8 +219,9 @@ internal static class Program record.ControlConstants(); record.ControlSystemState(); - $"{DateTime.Now.ToUnixTime()} : {record.StateMachine.State}: {record.StateMachine.Message}".WriteLine().LogInfo(); - + $"{DateTime.Now.Round(UpdateInterval).ToUnixTime()} : {record.StateMachine.State}: {record.StateMachine.Message}".WriteLine() + .LogInfo(); + var essControl = record.ControlEss().WriteLine().LogInfo(); record.EssControl = essControl; @@ -366,6 +371,107 @@ internal static class Program return true; } + + private static void CreateAverage() + { + string myDirectory = "LogDirectoryNew"; + List> csvDataList = new List>(); + + // Get all CSV files in the specified directory + string[] csvFiles = Directory.GetFiles(myDirectory, "*.csv"); + + List socList = new List(); + List pvPowerList = new List(); + List batteryPowerList = new List(); + + foreach (var csvFile in csvFiles) + { + using (var reader = new StreamReader(csvFile)) + { + // Read the CSV file and store data in dictionary + Dictionary csvData = new Dictionary(); + + while (!reader.EndOfStream) + { + var line = reader.ReadLine(); + var values = line?.Split(';'); + + // Assuming there are always three columns (variable name and its value) + if (values is { Length: 3 }) + { + String variableName = values[0].Trim(); + String variableValue = values[1].Trim(); + + // Check if variableValue is a valid number + if (IsSoc(variableName)) + { + // Add to the dictionary only if variableValue is a number + socList.Add(double.TryParse(variableValue, out double v)? v: 0); + } + if (IsPvPower(variableName)) + { + // Add to the dictionary only if variableValue is a number + pvPowerList.Add(double.TryParse(variableValue, out double v)? v: 0); + } + if (IsBatteryPower(variableName)) + { + // Add to the dictionary only if variableValue is a number + batteryPowerList.Add(double.TryParse(variableValue, out double v)? v: 0); + } + else + { + // Handle cases where variableValue is not a valid number + // Console.WriteLine($"Invalid numeric value for variable {variableName}: {variableValue}"); + } + } + else + { + // Handle invalid CSV format + //Console.WriteLine($"Invalid format in file: {csvFile}"); + //break; + } + } + } + } + + + double socAverage = CalculateAverage(socList); + double pvPowerAverage = CalculateAverage(pvPowerList); + double batteryPowerAverage = CalculateAverage(batteryPowerList); + + // Print the stored CSV data for verification + + Console.WriteLine($"SOC: {socAverage}"); + Console.WriteLine($"PvPower: {pvPowerAverage}"); + Console.WriteLine($"Battery: {batteryPowerAverage}"); + + Console.WriteLine("----------"); + + Console.WriteLine("CSV data reading and storage completed."); + } + // Custom method to check if a string is numeric + private static bool IsSoc(string value) + { + return value == "/Battery/Soc"; + } + private static bool IsPvPower(string value) + { + return value == "/PvOnDc/Dc/Power"; + } + + private static bool IsBatteryPower(string value) + { + return value == "/Battery/Dc/Power"; + } + + + // Method to calculate average for a variableValue in a dictionary + static double CalculateAverage( List data) + { + // Calculate and return the moving average + double movingAverage = data.Average(); + return movingAverage; + } } \ No newline at end of file diff --git a/csharp/App/SaliMax/src/Topology.cs b/csharp/App/SaliMax/src/Topology.cs index 923693bbd..859ac69f6 100644 --- a/csharp/App/SaliMax/src/Topology.cs +++ b/csharp/App/SaliMax/src/Topology.cs @@ -54,8 +54,9 @@ namespace InnovEnergy.App.SaliMax; // DC side // h + i - j - k = 0 [eq3] // -// g = h assuming no losses in ACDC -// k = l assuming no losses in DCDC +// if Dc load not existing, h = i - k [eq4] + +// k = l assuming no losses in DCDC // this is changed now l is equal total battery power // j = h + i - k [eq3] @@ -69,7 +70,7 @@ public static class Topology var e = status.PvOnAcIsland?.Dc.Power.Value; var f = status.LoadOnAcIsland?.Ac.Power.Active; var g = status.AcDc.Dc.Power.Value; - var h = g; + var h = status.AcDcToDcLink.Power.Value; var i = status.PvOnDc?.Dc.Power.Value; var k = status.DcDc.Dc.Link.Power.Value; var l = status.Battery is not null ? status.Battery.Dc.Power.Value : 0; @@ -483,6 +484,23 @@ public static class Topology return new AcPowerDevice { Power = c }; } + //We are fake using the ampt instead of PvOnAc, We dont have a Pv on Ac at the moment and we don't have it classes :TODO + public static DcPowerDevice? CalculateAcDcToDcLink(AmptStatus? pvOnDc, DcDcDevicesRecord? dcDc, AcDcDevicesRecord acDc) + { + var i = pvOnDc?.Dc.Power; + var k = dcDc?.Dc.Link.Power; // We dont check on the DcDc because this device is mandatory + var g = acDc?.Dc.Power; + + if (i is null || k is null ) + { + return new DcPowerDevice { Power = g }; + } + + var h = -(i - k); // [eq4] + + return new DcPowerDevice { Power = h }; + } + //We are fake using the ampt instead of PvOnAc, We dont have a Pv on Ac at the moment and we don't have it classes :TODO public static AcPowerDevice? CalculateGridBusToIslandBusPower(AmptStatus? pvOnAcIsland, EmuMeterRegisters? loadOnAcIsland, AcDcDevicesRecord? acDc) { @@ -511,40 +529,5 @@ public static class Topology return new DcPowerDevice { Power = j}; } - - // public static (AcPowerDevice? acGridToAcIsland, AcPowerDevice? loadOnAcGrid, DcPowerDevice? dcPowerDevice) - // - // CalculateEnergyFlow(EmuMeterRegisters? gridMeter, - // AcPowerDevice pvOnAcGrid, - // AcPowerDevice pvOnAcIsland, - // EmuMeterRegisters? loadOnAcIsland, - // AcDcDevicesRecord acDc, - // AmptStatus? pvOnDc, - // DcDcDevicesRecord dcDc) - // { - // var gridPower = gridMeter?.Ac.Power.Active; - // var islandLoadPower = loadOnAcIsland?.Ac.Power.Active; - // var inverterAcPower = acDc.Ac.Power.Active; - // var inverterDcPower = acDc.Dc.Power; - // - // var a = gridPower; - // var b = pvOnAcGrid.Power.Active; - // var e = pvOnAcIsland.Power.Active; - // var f = islandLoadPower; - // var g = inverterAcPower; - // var h = inverterDcPower; - // var i = pvOnDc?.Dc.Power; - // var k = dcDc.Dc.Link.Power; - // var j = Sum(h, i, -k); - // var d = Sum(f, g, -e); - // var c = Sum(a, b, -d); - // - // var acGridToAcIsland = d is null ? null : new AcPowerDevice { Power = d.Value }; - // var loadOnAcGrid = c is null ? null : new AcPowerDevice { Power = c.Value }; - // var dcPowerDevice = j is null ? null : new DcPowerDevice { Power = j }; - // - // return (acGridToAcIsland, loadOnAcGrid, dcPowerDevice); - // } - }