diff --git a/csharp/App/SaliMax/Doc/AllStates.graphml b/csharp/App/SaliMax/Doc/AllStates.graphml index 2888ad499..5877679af 100644 --- a/csharp/App/SaliMax/Doc/AllStates.graphml +++ b/csharp/App/SaliMax/Doc/AllStates.graphml @@ -1,6 +1,6 @@ - + @@ -13,9 +13,8 @@ - + - @@ -32,14 +31,13 @@ K3 ✓ - 19 - K1 ✓ + K1 ✓ K2 ✓ K3 ✘ @@ -49,14 +47,13 @@ K3 ✘ - 3 - K1 ✓ + K1 ✓ K2 ✓ K3 ✘ @@ -66,14 +63,13 @@ K3 ✘ - 9 - K1 ✓ + K1 ✓ K2 ✘ K3 ✘ @@ -83,14 +79,13 @@ K3 ✘ - 1 - K1 ✓ + K1 ✓ K2 ✘ K3 ✘ @@ -100,14 +95,13 @@ K3 ✘ - 13 - K1 ✓ + K1 ✓ K2 ✘ K3 ✓ @@ -117,14 +111,13 @@ K3 ✓ - 29 - K1 ✓ + K1 ✓ K2 ✘ K3 ✓ @@ -134,14 +127,13 @@ K3 ✓ - 5 - K1 ✓ + K1 ✓ K2 ✘ K3 ✓ @@ -151,7 +143,6 @@ K3 ✓ - @@ -169,14 +160,13 @@ K3 ✓ - 11 - K1 ✓ + K1 ✓ K2 ✓ K3 ✘ @@ -187,13 +177,12 @@ K3 ✘ - - + - 15 + 15 K1 ✓ K2 ✓ K3 ✓ @@ -204,14 +193,13 @@ K3 ✓ - 21 - K1 ✓ + K1 ✓ K2 ✘ K3 ✓ @@ -221,14 +209,13 @@ K3 ✓ - 17 - K1 ✓ + K1 ✓ K2 ✘ K3 ✘ @@ -239,14 +226,13 @@ K3 ✘ - 25 - K1 ✓ + K1 ✓ K2 ✘ K3 ✘ @@ -257,14 +243,13 @@ K3 ✘ - - + 27 - K1 ✓ + K1 ✓ K2 ✓ K3 ✘ @@ -275,10 +260,9 @@ K3 ✘ - - + 31 @@ -292,14 +276,13 @@ K3 ✓ - 28 - K1 ✘ + K1 ✘ K2 ✘ K3 ✓ @@ -309,14 +292,13 @@ K3 ✓ - 24 - K1 ✘ + K1 ✘ K2 ✘ K3 ✘ @@ -326,14 +308,13 @@ K3 ✘ - 8 - K1 ✘ + K1 ✘ K2 ✘ K3 ✘ @@ -343,14 +324,13 @@ K3 ✘ - 6 - K1 ✘ + K1 ✘ K2 ✓ K3 ✓ @@ -360,14 +340,13 @@ K3 ✓ - 0 - K1 ✘ + K1 ✘ K2 ✘ K3 ✘ @@ -377,14 +356,13 @@ K3 ✘ - 4 - K1 ✘ + K1 ✘ K2 ✘ K3 ✓ @@ -394,14 +372,13 @@ K3 ✓ - 22 - K1 ✘ + K1 ✘ K2 ✓ K3 ✓ @@ -411,14 +388,13 @@ K3 ✓ - 16 - K1 ✘ + K1 ✘ K2 ✘ K3 ✘ @@ -428,14 +404,13 @@ K3 ✘ - 20 - K1 ✘ + K1 ✘ K2 ✘ K3 ✓ @@ -445,14 +420,13 @@ K3 ✓ - 18 - K1 ✘ + K1 ✘ K2 ✓ K3 ✘ @@ -462,14 +436,13 @@ K3 ✘ - 2 - K1 ✘ + K1 ✘ K2 ✓ K3 ✘ @@ -479,14 +452,13 @@ K3 ✘ - 10 - K1 ✘ + K1 ✘ K2 ✓ K3 ✘ @@ -496,14 +468,13 @@ K3 ✘ - 12 - K1 ✘ + K1 ✘ K2 ✘ K3 ✓ @@ -513,14 +484,13 @@ K3 ✓ - 14 - K1 ✘ + K1 ✘ K2 ✓ K3 ✓ @@ -530,14 +500,13 @@ K3 ✓ - - + 26 - K1 ✘ + K1 ✘ K2 ✓ K3 ✘ @@ -547,14 +516,13 @@ K3 ✘ - 30 - K1 ✘ + K1 ✘ K2 ✓ K3 ✓ @@ -569,14 +537,13 @@ K3 ✓ - turn off + turn off Inverters - @@ -589,19 +556,17 @@ grid tie - - K3's open + K3's open - @@ -613,7 +578,6 @@ grid tie - @@ -626,7 +590,6 @@ Inverters - @@ -638,7 +601,6 @@ Inverters - @@ -653,19 +615,17 @@ Inverters - - open K2 + open K2 - @@ -680,21 +640,19 @@ inverter - - + - + - turn off -inverters + turn off +inverters and open K2 - @@ -706,21 +664,19 @@ inverters - - + - + - turn off -inverters + turn off +inverters and open K2 - @@ -759,7 +715,6 @@ Inverters - @@ -772,7 +727,6 @@ island mode - @@ -808,7 +762,6 @@ Inverters - @@ -819,21 +772,21 @@ Inverters - - + - + + + - turn off -inverters + turn off +inverters and Open K2 - @@ -848,7 +801,6 @@ inverters - @@ -863,7 +815,6 @@ inverters - @@ -875,7 +826,6 @@ inverters - @@ -886,21 +836,21 @@ inverters - - + - + + + - turn off -inverters + turn off +inverters and open K2 - @@ -913,7 +863,6 @@ inverters - @@ -925,7 +874,6 @@ inverters - @@ -937,7 +885,6 @@ inverters - @@ -953,7 +900,6 @@ inverters - diff --git a/csharp/App/SaliMax/src/Devices/DeviceState.cs b/csharp/App/SaliMax/src/Devices/DeviceState.cs new file mode 100644 index 000000000..728e3c3f1 --- /dev/null +++ b/csharp/App/SaliMax/src/Devices/DeviceState.cs @@ -0,0 +1,8 @@ +namespace InnovEnergy.App.SaliMax.Devices; + +public enum DeviceState +{ + Disabled, + Measured, + Computed +} \ No newline at end of file diff --git a/csharp/App/SaliMax/src/Devices/SalimaxDevice.cs b/csharp/App/SaliMax/src/Devices/SalimaxDevice.cs new file mode 100644 index 000000000..ff7c8c6ca --- /dev/null +++ b/csharp/App/SaliMax/src/Devices/SalimaxDevice.cs @@ -0,0 +1,8 @@ +using InnovEnergy.Lib.Utils.Net; + +namespace InnovEnergy.App.SaliMax.Devices; + +public class SalimaxDevice : Ip4Address +{ + public required DeviceState DeviceState { get; init; } +} \ No newline at end of file diff --git a/csharp/App/SaliMax/src/Ess/StatusRecord.cs b/csharp/App/SaliMax/src/Ess/StatusRecord.cs index 0d0a1da63..cf6ca2b31 100644 --- a/csharp/App/SaliMax/src/Ess/StatusRecord.cs +++ b/csharp/App/SaliMax/src/Ess/StatusRecord.cs @@ -1,7 +1,7 @@ +using InnovEnergy.App.SaliMax.Devices; using InnovEnergy.App.SaliMax.SaliMaxRelays; using InnovEnergy.App.SaliMax.System; using InnovEnergy.App.SaliMax.SystemConfig; -using InnovEnergy.App.SaliMax.VirtualDevices; using InnovEnergy.Lib.Devices.AMPT; using InnovEnergy.Lib.Devices.Battery48TL; using InnovEnergy.Lib.Devices.EmuMeter; @@ -18,8 +18,8 @@ public record StatusRecord public required EmuMeterRegisters? GridMeter { get; init; } public required EmuMeterRegisters? LoadOnAcIsland { get; init; } public required AcPowerDevice? LoadOnAcGrid { get; init; } - public required AcPowerDevice? PvOnAcGrid { get; init; } - public required AcPowerDevice? PvOnAcIsland { get; init; } + public required AmptStatus? PvOnAcGrid { get; init; } + public required AmptStatus? PvOnAcIsland { get; init; } public required AcPowerDevice? AcGridToAcIsland { get; init; } public required DcPowerDevice? LoadOnDc { get; init; } public required RelaysRecord? Relays { get; init; } diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index e768cb80c..a0a86e8e6 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -1,11 +1,11 @@ using System.Reactive.Linq; using System.Reactive.Threading.Tasks; using Flurl.Http; +using InnovEnergy.App.SaliMax.Devices; using InnovEnergy.App.SaliMax.Ess; using InnovEnergy.App.SaliMax.SaliMaxRelays; using InnovEnergy.App.SaliMax.System; using InnovEnergy.App.SaliMax.SystemConfig; -using InnovEnergy.App.SaliMax.VirtualDevices; using InnovEnergy.Lib.Devices.AMPT; using InnovEnergy.Lib.Devices.Battery48TL; using InnovEnergy.Lib.Devices.EmuMeter; @@ -16,10 +16,10 @@ using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes; using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.Control; using InnovEnergy.Lib.Protocols.Modbus.Channels; -using InnovEnergy.Lib.Time.Unix; using InnovEnergy.Lib.Units; using InnovEnergy.Lib.Utils; using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.SystemConfig; +using DeviceState = InnovEnergy.App.SaliMax.Devices.DeviceState; #pragma warning disable IL2026 @@ -32,32 +32,40 @@ internal static class Program private static readonly IReadOnlyList BatteryNodes; - private static readonly TcpChannel TruConvertAcChannel ; - private static readonly TcpChannel TruConvertDcChannel ; - private static readonly TcpChannel GridMeterChannel ; - private static readonly TcpChannel IslandBusLoadChannel; - private static readonly TcpChannel AmptChannel ; - private static readonly TcpChannel RelaysChannel ; - private static readonly TcpChannel BatteriesChannel ; + private static readonly Channel TruConvertAcChannel ; + private static readonly Channel TruConvertDcChannel ; + private static readonly Channel GridMeterChannel ; + private static readonly Channel IslandBusLoadChannel; + private static readonly Channel PvOnDc ; + private static readonly Channel PvOnAcGrid ; + private static readonly Channel PvOnAcIsland ; + private static readonly Channel RelaysChannel ; + private static readonly Channel BatteriesChannel ; static Program() { var config = Config.Load(); var d = config.Devices; - - TruConvertAcChannel = new TcpChannel(d.TruConvertAcIp); - TruConvertDcChannel = new TcpChannel(d.TruConvertDcIp); - GridMeterChannel = new TcpChannel(d.GridMeterIp); - IslandBusLoadChannel = new TcpChannel(d.IslandBusLoadMeterIp); - AmptChannel = new TcpChannel(d.AmptIp); - RelaysChannel = new TcpChannel(d.RelaysIp); - BatteriesChannel = new TcpChannel(d.BatteryIp); - BatteryNodes = config - .Devices - .BatteryNodes - .Select(n => n.ConvertTo()) - .ToArray(config.Devices.BatteryNodes.Length); + Channel CreateChannel(SalimaxDevice device) => device.DeviceState == DeviceState.Disabled + ? new NullChannel() + : new TcpChannel(device); + + TruConvertAcChannel = CreateChannel(d.TruConvertAcIp); + TruConvertDcChannel = CreateChannel(d.TruConvertDcIp); + GridMeterChannel = CreateChannel(d.GridMeterIp); + IslandBusLoadChannel = CreateChannel(d.IslandBusLoadMeterIp); + PvOnDc = CreateChannel(d.PvOnDc); + PvOnAcGrid = CreateChannel(d.PvOnAcGrid); + PvOnAcIsland = CreateChannel(d.PvOnAcIsland); + RelaysChannel = CreateChannel(d.RelaysIp); + BatteriesChannel = CreateChannel(d.BatteryIp); + + BatteryNodes = config + .Devices + .BatteryNodes + .Select(n => n.ConvertTo()) + .ToArray(config.Devices.BatteryNodes.Length); } public static async Task Main(String[] args) @@ -91,26 +99,35 @@ internal static class Program var dcDcDevices = new TruConvertDcDcDevices(TruConvertDcChannel); var gridMeterDevice = new EmuMeterDevice(GridMeterChannel); var acIslandLoadMeter = new EmuMeterDevice(IslandBusLoadChannel); - var amptDevice = new AmptDevices(AmptChannel); + var pvOnDcDevice = new AmptDevices(PvOnDc); + var pvOnAcGridDevice = new AmptDevices(PvOnAcGrid); + var pvOnAcIslandDevice = new AmptDevices(PvOnAcIsland); var saliMaxRelaysDevice = new RelaysDevice(RelaysChannel); StatusRecord ReadStatus() { - + var config = Config.Load(); + var devices = config.Devices; var acDc = acDcDevices.Read(); var dcDc = dcDcDevices.Read(); var relays = saliMaxRelaysDevice.Read(); var loadOnAcIsland = acIslandLoadMeter.Read(); var gridMeter = gridMeterDevice.Read(); - var pvOnDc = amptDevice.Read(); + var pvOnDc = pvOnDcDevice.Read(); var battery = batteryDevices.Read(); - var pvOnAcGrid = new AcPowerDevice { Power = 0 }; // TODO - var pvOnAcIsland = new AcPowerDevice { Power = 0 }; // TODO + var pvOnAcGrid = pvOnAcGridDevice.Read(); + var pvOnAcIsland = pvOnAcIslandDevice.Read(); var gridBusToIslandBus = Topology.CalculateGridBusToIslandBusPower(pvOnAcIsland, loadOnAcIsland, acDc); - var gridBusLoad = Topology.CalculateGridBusLoad(gridMeter, pvOnAcGrid, gridBusToIslandBus); - var dcLoad = 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); return new StatusRecord { @@ -132,7 +149,7 @@ internal static class Program StateMachine = StateMachine.Default, EssControl = EssControl.Default, Log = new SystemLog{Led = LedState.Green, Message = null}, //TODO: Put real stuff - Config = Config.Load() // load from disk every iteration, so config can be changed while running + Config = config // load from disk every iteration, so config can be changed while running }; } @@ -152,28 +169,42 @@ internal static class Program await Observable .Interval(UpdateInterval) .Select(_ => RunIteration()) - .SelectMany(r => UploadCsv(r, DateTime.UtcNow)) + .SelectMany(r => UploadCsv(r, DateTime.Now.Round(UpdateInterval))) .SelectError() .ToTask(); } - // var iterations = from _ in Observable.Interval(UpdateInterval.ToTimeSpan()) - // let t = UnixTime.Now.RoundTo(UpdateInterval) - // let record = RunIteration() - // from uploaded in UploadCsv(record, t) - // select uploaded; - // - // using var running = iterations.Subscribe(); - - StatusRecord RunIteration() { 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; - // If control Special Error return true, we must stop the system.(break;) + r.SerialNumber.WriteLine(" serial number " + i); + + ("--------------").WriteLine(); + + i++; + } + }*/ + + + //record.Log = new SystemLog + //{ + // Led = alarmCondition is null ? LedState.Green : LedState.Orange, + // Message = alarmCondition + //}; + var alarmCondition = record.DetectAlarmStates(); if (alarmCondition is not null) @@ -184,7 +215,7 @@ internal static class Program record.ControlConstants(); record.ControlSystemState(); - $"{UnixTime.Now} : {record.StateMachine.State}: {record.StateMachine.Message}".WriteLine().LogInfo(); + $"{DateTime.Now.ToUnixTime()} : {record.StateMachine.State}: {record.StateMachine.Message}".WriteLine().LogInfo(); var essControl = record.ControlEss().WriteLine().LogInfo(); @@ -312,14 +343,14 @@ internal static class Program sc.ResetAlarmsAndWarnings = true; } - private static async Task UploadCsv(StatusRecord status, UnixTime timeStamp) + private static async Task UploadCsv(StatusRecord status, DateTime timeStamp) { var s3Config = status.Config.S3; var csv = status.ToCsv().LogInfo(); if (s3Config is null) return false; - var s3Path = timeStamp + ".csv"; + var s3Path = timeStamp.ToUnixTime() + ".csv"; var request = s3Config.CreatePutRequest(s3Path); var response = await request.PutAsync(new StringContent(csv)); diff --git a/csharp/App/SaliMax/src/System/Controller.cs b/csharp/App/SaliMax/src/System/Controller.cs index faf13533e..db0599143 100644 --- a/csharp/App/SaliMax/src/System/Controller.cs +++ b/csharp/App/SaliMax/src/System/Controller.cs @@ -54,18 +54,36 @@ public static class Controller { 0 => State0(s), 1 => State1(s), + 2 => State2(s), 3 => State3(s), 4 => State4(s), + 5 => State5(s), 6 => State6(s), + 7 => State7(s), 8 => State8(s), 9 => State9(s), + 10 => State10(s), + 11 => State11(s), + 12 => State12(s), 13 => State13(s), + 14 => State14(s), + 15 => State15(s), + 16 => State16(s), + 17 => State17(s), + 18 => State18(s), 19 => State19(s), + 20 => State20(s), + 21 => State21(s), 22 => State22(s), 23 => State23(s), 24 => State24(s), + 25 => State25(s), + 26 => State26(s), + 27 => State27(s), 28 => State28(s), 29 => State29(s), + 30 => State30(s), + 31 => State31(s), 101 => State101(s), @@ -95,20 +113,7 @@ public static class Controller // => 8 } - private static Boolean State9(StatusRecord s) - { - s.StateMachine.Message = "Ac/Dc are disconnected from Island Bus. Switching to GridTie Mode."; - s.DcDc.Disable(); - s.AcDc.Disable(); - s.AcDc.EnableGridTieMode(); - s.Relays.DisconnectIslandBusFromGrid(); - - return false; - - // => 1 - } - private static Boolean State1(StatusRecord s) { s.StateMachine.Message = "Grid Tied mode active, closing k2"; @@ -123,6 +128,20 @@ public static class Controller // => 3 } + private static Boolean State2(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableGridTieMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 0 + } + private static Boolean State3(StatusRecord s) { s.StateMachine.Message = "K2 closed, Turning on Ac/Dc"; @@ -136,6 +155,132 @@ public static class Controller // => 19 } + + + private static Boolean State4(StatusRecord s) + { + s.StateMachine.Message = "K2 is open, waiting K3 to open"; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableGridTieMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return true; + + // => 0 + } + + private static Boolean State5(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableGridTieMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => ? + } + + private static Boolean State6(StatusRecord s) + { + s.StateMachine.Message = "Inverters are off, opening K2"; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableGridTieMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return true; + + // => 4 + } + + private static Boolean State7(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableGridTieMode(); + s.Relays.ConnectIslandBusToGrid(); + + return false; + + // => ? + } + + private static Boolean State8(StatusRecord s) + { + s.StateMachine.Message = "Ac/Dc are off and in Island Mode."; + + s.DcDc.Enable(); + s.AcDc.Enable(); + s.AcDc.EnableIslandMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return true; + // => 24 + } + + private static Boolean State9(StatusRecord s) + { + s.StateMachine.Message = "Ac/Dc are disconnected from Island Bus. Switching to GridTie Mode."; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableGridTieMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 1 + } + + private static Boolean State10(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableIslandMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 8 + } + + private static Boolean State11(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableIslandMode(); + s.Relays.ConnectIslandBusToGrid(); + + return false; + + // => 9 + } + + private static Boolean State12(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableIslandMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 8 + } private static Boolean State13(StatusRecord s) { @@ -151,8 +296,80 @@ public static class Controller // => 9 } + private static Boolean State14(StatusRecord s) + { + s.StateMachine.Message = ""; + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableIslandMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + // => 12 + } + + + private static Boolean State15(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableIslandMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 13 + } + + + private static Boolean State16(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableGridTieMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 0 + } + + + private static Boolean State17(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableGridTieMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 1 + } + + + private static Boolean State18(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableGridTieMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 0 + } + private static Boolean State19(StatusRecord s) { s.StateMachine.Message = "Waiting for Ac/Dc to connect to Island Bus"; @@ -167,20 +384,33 @@ public static class Controller // => 23 } - - private static Boolean State23(StatusRecord s) + + private static Boolean State20(StatusRecord s) { - s.StateMachine.Message = "ESS"; - - s.DcDc.Enable(); - s.AcDc.Enable(); + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); s.AcDc.EnableGridTieMode(); - s.EnableDcLinkGridTie(); - s.Relays.ConnectIslandBusToGrid(); + s.Relays.DisconnectIslandBusFromGrid(); - return true; + return false; + + // => 4 + } + + private static Boolean State21(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableGridTieMode(); + s.Relays.DisconnectIslandBusFromGrid(); - // => 22 + return false; + + // => 5 } private static Boolean State22(StatusRecord s) @@ -196,49 +426,79 @@ public static class Controller // => 6 } - - - private static Boolean State6(StatusRecord s) + + private static Boolean State23(StatusRecord s) { - s.StateMachine.Message = "Inverters are off, opening K2"; + s.StateMachine.Message = "ESS"; - s.DcDc.Disable(); - s.AcDc.Disable(); + s.DcDc.Enable(); + s.AcDc.Enable(); s.AcDc.EnableGridTieMode(); - s.Relays.DisconnectIslandBusFromGrid(); + s.EnableDcLinkGridTie(); + s.Relays.ConnectIslandBusToGrid(); return true; - // => 4 + // => 22 } - private static Boolean State4(StatusRecord s) + + private static Boolean State24(StatusRecord s) { - s.StateMachine.Message = "K2 is open, waiting K3 to open"; - - s.DcDc.Disable(); - s.AcDc.Disable(); - s.AcDc.EnableGridTieMode(); - s.Relays.DisconnectIslandBusFromGrid(); - - return true; - - // => 0 - } - - private static Boolean State8(StatusRecord s) - { - s.StateMachine.Message = "Ac/Dc are off and in Island Mode."; + s.StateMachine.Message = "Inverter are on waiting for k3 to close"; s.DcDc.Enable(); s.AcDc.Enable(); s.AcDc.EnableIslandMode(); s.Relays.DisconnectIslandBusFromGrid(); - return true; - // => 24 + return false; + + // => 28 } + + private static Boolean State25(StatusRecord s) + { + s.StateMachine.Message = ""; + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableIslandMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 9 + } + + private static Boolean State26(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableIslandMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 10 + } + + private static Boolean State27(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableIslandMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 9 + } + private static Boolean State28(StatusRecord s) { s.StateMachine.Message = "Island Mode"; @@ -267,21 +527,35 @@ public static class Controller // => 13 } - - private static Boolean State24(StatusRecord s) + + private static Boolean State30(StatusRecord s) { - s.StateMachine.Message = "Inverter are on waiting for k3 to close"; - - s.DcDc.Enable(); - s.AcDc.Enable(); + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); s.AcDc.EnableIslandMode(); s.Relays.DisconnectIslandBusFromGrid(); - - return false; - // => 28 + return false; + + // => 14 } - + + private static Boolean State31(StatusRecord s) + { + s.StateMachine.Message = ""; + + s.DcDc.Disable(); + s.AcDc.Disable(); + s.AcDc.EnableIslandMode(); + s.Relays.DisconnectIslandBusFromGrid(); + + return false; + + // => 13 + } + private static Boolean State101(StatusRecord s) { s.StateMachine.Message = "Relay device is not available"; @@ -360,7 +634,7 @@ public static class Controller .ForAll(c => c.PowerStageEnable = false); } - + //this is must be deleted private static void Disable(this DcDcDevicesRecord dcDc) { // For Test purpose, The transition from island mode to grid tier and vis versa , may not need to disable Dc/Dc. diff --git a/csharp/App/SaliMax/src/SystemConfig/Config.cs b/csharp/App/SaliMax/src/SystemConfig/Config.cs index 32468ee0d..61089d13a 100644 --- a/csharp/App/SaliMax/src/SystemConfig/Config.cs +++ b/csharp/App/SaliMax/src/SystemConfig/Config.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using InnovEnergy.App.SaliMax.Devices; using InnovEnergy.Lib.Utils; using static System.Text.Json.JsonSerializer; @@ -26,11 +27,11 @@ public class Config //TODO: let IE choose from config files (Json) and connect t public required Double MaxBatteryDischargingCurrent { get; set; } public required Double MaxDcPower { get; set; } - public required Double MaxChargeBatteryVoltage { get; set; } - public required Double MinDischargeBatteryVoltage { get; set; } + public required Double MaxChargeBatteryVoltage { get; set; } + public required Double MinDischargeBatteryVoltage { get; set; } - public required DeviceConfig Devices { get; set; } - public required S3Config? S3 { get; set; } + public required DeviceConfig Devices { get; set; } + public required S3Config? S3 { get; set; } private static String? LastSavedData { get; set; } @@ -86,15 +87,20 @@ public class Config //TODO: let IE choose from config files (Json) and connect t Devices = new () { - TruConvertAcIp = new() { Host = "localhost", Port = 5001}, - TruConvertDcIp = new() { Host = "localhost", Port = 5002}, - GridMeterIp = new() { Host = "localhost", Port = 5003}, - IslandBusLoadMeterIp = new() { Host = "localhost", Port = 5004}, - AmptIp = new() { Host = "localhost", Port = 5005}, - RelaysIp = new() { Host = "localhost", Port = 5006}, - BatteryIp = new() { Host = "localhost", Port = 5007}, + RelaysIp = new() { Host = "localhost", Port = 5006, DeviceState = DeviceState.Measured}, + GridMeterIp = new() { Host = "localhost", Port = 5003, DeviceState = DeviceState.Measured}, + PvOnAcGrid = new() { Host = "false" , Port = 0 , DeviceState = DeviceState.Measured}, + LoadOnAcGrid = new() { Host = "false" , Port = 0 , DeviceState = DeviceState.Measured}, + PvOnAcIsland = new() { Host = "true" , Port = 0 , DeviceState = DeviceState.Measured}, + IslandBusLoadMeterIp = new() { Host = "localhost", Port = 5004, DeviceState = DeviceState.Measured}, + TruConvertAcIp = new() { Host = "localhost", Port = 5001, DeviceState = DeviceState.Measured}, + PvOnDc = new() { Host = "localhost", Port = 5005, DeviceState = DeviceState.Measured}, + LoadOnDc = new() { Host = "false" , Port = 0 , DeviceState = DeviceState.Measured}, + TruConvertDcIp = new() { Host = "localhost", Port = 5002, DeviceState = DeviceState.Measured}, + BatteryIp = new() { Host = "localhost", Port = 5007, DeviceState = DeviceState.Measured}, BatteryNodes = new []{ 2, 3, 4, 5, 6 } }, + S3 = new() { Bucket = "1-3e5b3069-214a-43ee-8d85-57d72000c19d", @@ -155,24 +161,30 @@ public class Config //TODO: let IE choose from config files (Json) and connect t MaxChargeBatteryVoltage = 57, MinDischargeBatteryVoltage = 0, + S3 = new() { - Bucket = "saliomameiringen", + Bucket = "1-3e5b3069-214a-43ee-8d85-57d72000c19d", Region = "sos-ch-dk-2", Provider = "exo.io", - ContentType = "text/plain; charset=utf-8", - Key = "EXO2bf0cbd97fbfa75aa36ed46f", - Secret = "Bn1CDPqOG-XpDSbYjfIJxojcHTm391vZTc8z8l_fEPs" + Key = "EXObb5a49acb1061781761895e7", + Secret = "sKhln0w8ii3ezZ1SJFF33yeDo8NWR1V4w2H0D4-350I", + ContentType = "text/plain; charset=utf-8" }, - Devices = new () + + Devices = new () { - RelaysIp = new() { Host = "10.0.1.1", Port = 502}, - TruConvertAcIp = new() { Host = "10.0.2.1", Port = 502}, - TruConvertDcIp = new() { Host = "10.0.3.1", Port = 502}, - GridMeterIp = new() { Host = "10.0.4.1", Port = 502}, - IslandBusLoadMeterIp = new() { Host = "10.0.4.2", Port = 502}, - AmptIp = new() { Host = "10.0.5.1", Port = 502}, - BatteryIp = new() { Host = "localhost", Port = 6855}, + RelaysIp = new() { Host = "10.0.1.1", Port = 502, DeviceState = DeviceState.Measured}, + GridMeterIp = new() { Host = "10.0.4.1", Port = 502, DeviceState = DeviceState.Measured}, + PvOnAcGrid = new() { Host = "false" , Port = 0 , DeviceState = DeviceState.Measured}, + LoadOnAcGrid = new() { Host = "true" , Port = 0 , DeviceState = DeviceState.Measured}, + PvOnAcIsland = new() { Host = "false" , Port = 0 , DeviceState = DeviceState.Measured}, + IslandBusLoadMeterIp = new() { Host = "10.0.4.2", Port = 502, DeviceState = DeviceState.Measured}, + TruConvertAcIp = new() { Host = "10.0.2.1", Port = 502, DeviceState = DeviceState.Measured}, + PvOnDc = new() { Host = "10.0.5.1", Port = 502, DeviceState = DeviceState.Measured}, + LoadOnDc = new() { Host = "false" , Port = 0 , DeviceState = DeviceState.Measured}, + TruConvertDcIp = new() { Host = "10.0.3.1", Port = 502, DeviceState = DeviceState.Measured}, + BatteryIp = new() { Host = "localhost", Port = 6855, DeviceState = DeviceState.Measured }, BatteryNodes = new []{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, }, }; diff --git a/csharp/App/SaliMax/src/SystemConfig/DeviceConfig.cs b/csharp/App/SaliMax/src/SystemConfig/DeviceConfig.cs index 3663fe7fe..546b92a7c 100644 --- a/csharp/App/SaliMax/src/SystemConfig/DeviceConfig.cs +++ b/csharp/App/SaliMax/src/SystemConfig/DeviceConfig.cs @@ -1,15 +1,20 @@ +using InnovEnergy.App.SaliMax.Devices; using InnovEnergy.Lib.Utils.Net; namespace InnovEnergy.App.SaliMax.SystemConfig; public class DeviceConfig { - public required Ip4Address RelaysIp { get; init; } - public required Ip4Address TruConvertAcIp { get; init; } - public required Ip4Address TruConvertDcIp { get; init; } - public required Ip4Address GridMeterIp { get; init; } - public required Ip4Address IslandBusLoadMeterIp { get; init; } - public required Ip4Address AmptIp { get; init; } - public required Ip4Address BatteryIp { get; init; } - public required Int32[] BatteryNodes { get; init; } + public required SalimaxDevice RelaysIp { get; init; } + public required SalimaxDevice GridMeterIp { get; init; } + public required SalimaxDevice PvOnAcGrid { get; init; } + public required SalimaxDevice LoadOnAcGrid { get; init; } + public required SalimaxDevice PvOnAcIsland { get; init; } + public required SalimaxDevice IslandBusLoadMeterIp { get; init; } + public required SalimaxDevice TruConvertAcIp { get; init; } + public required SalimaxDevice PvOnDc { get; init; } + public required SalimaxDevice LoadOnDc { get; init; } + public required SalimaxDevice TruConvertDcIp { get; init; } + public required SalimaxDevice BatteryIp { get; init; } + public required Int32[] BatteryNodes { get; init; } } diff --git a/csharp/App/SaliMax/src/Topology.cs b/csharp/App/SaliMax/src/Topology.cs index 9891fe573..58ad19e19 100644 --- a/csharp/App/SaliMax/src/Topology.cs +++ b/csharp/App/SaliMax/src/Topology.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; +using InnovEnergy.App.SaliMax.Devices; using InnovEnergy.App.SaliMax.Ess; -using InnovEnergy.App.SaliMax.VirtualDevices; using InnovEnergy.Lib.Devices.AMPT; using InnovEnergy.Lib.Devices.Battery48TL; using InnovEnergy.Lib.Devices.EmuMeter; @@ -65,8 +65,8 @@ public static class Topology public static TextBlock CreateTopologyTextBlock(this StatusRecord status) { var a = status.GridMeter?.Ac.Power.Active; - var b = status.PvOnAcGrid?.Power.Active; - var e = status.PvOnAcIsland?.Power.Active; + var b = status.PvOnAcGrid?.Dc.Power.Value; + var e = status.PvOnAcIsland?.Dc.Power.Value; var f = status.LoadOnAcIsland?.Ac.Power.Active; var g = status.AcDc.Dc.Power.Value; var h = g; @@ -473,11 +473,11 @@ public static class Topology : Flow.Horizontal(power); } - - public static AcPowerDevice? CalculateGridBusLoad(EmuMeterRegisters? gridMeter, AcPowerDevice? pvOnAcGrid, AcPowerDevice? gridBusToIslandBusPower) + //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? CalculateGridBusLoad(EmuMeterRegisters? gridMeter, AmptStatus? pvOnAcGrid, AcPowerDevice? gridBusToIslandBusPower) { var a = gridMeter ?.Ac.Power; - var b = pvOnAcGrid ?.Power; + var b = pvOnAcGrid is not null? pvOnAcGrid?.Dc.Power.Value: 0; var d = gridBusToIslandBusPower?.Power; if (a is null || b is null || d is null) @@ -487,12 +487,13 @@ public static class Topology return new AcPowerDevice { Power = c }; } - - public static AcPowerDevice? CalculateGridBusToIslandBusPower(AcPowerDevice? pvOnAcIsland, EmuMeterRegisters? loadOnAcIsland, AcDcDevicesRecord? acDc) + + //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) { - var e = pvOnAcIsland ?.Power; - var f = loadOnAcIsland?.Ac.Power; - var g = acDc ?.Ac.Power; + var e = pvOnAcIsland is not null? pvOnAcIsland?.Dc.Power.Value: 0; + var f = loadOnAcIsland is not null? loadOnAcIsland?.Ac.Power : 0; + var g = acDc ?.Ac.Power; // We dont check on the AcDc because this device is mandatory, if this does not exist the system will not start if (e is null || f is null || g is null) return null; @@ -504,9 +505,9 @@ public static class Topology public static DcPowerDevice? CalculateDcLoad(AcDcDevicesRecord? acDc, AmptStatus? pvOnDc, DcDcDevicesRecord? dcDc) { - var h = acDc?.Dc.Power; - var i = pvOnDc?.Dc.Power; - var k = dcDc?.Dc.Link.Power; + var h = acDc?.Dc.Power; // We dont check on the AcDc because this device is mandatory + var i = pvOnDc is not null? pvOnDc?.Dc.Power: 0; + var k = dcDc?.Dc.Link.Power; // We dont check on the DcDc because this device is mandatory if (h is null || i is null || k is null) return null; diff --git a/csharp/Lib/Protocols/Modbus/Channels/NullChannel.cs b/csharp/Lib/Protocols/Modbus/Channels/NullChannel.cs new file mode 100644 index 000000000..34436f75e --- /dev/null +++ b/csharp/Lib/Protocols/Modbus/Channels/NullChannel.cs @@ -0,0 +1,14 @@ +namespace InnovEnergy.Lib.Protocols.Modbus.Channels; + +public class NullChannel : Channel +{ + public override IReadOnlyList Read(Int32 nBytes) => throw new NullChannelException(); + + public override void Write(IReadOnlyList bytes) + { + } +} + +public class NullChannelException : Exception +{ +} \ No newline at end of file diff --git a/csharp/Lib/Protocols/Modbus/Channels/TcpChannel.cs b/csharp/Lib/Protocols/Modbus/Channels/TcpChannel.cs index 4aa3bd71b..22a20d018 100644 --- a/csharp/Lib/Protocols/Modbus/Channels/TcpChannel.cs +++ b/csharp/Lib/Protocols/Modbus/Channels/TcpChannel.cs @@ -11,8 +11,8 @@ public class TcpChannel : ConnectionChannel public TcpChannel(Ip4Address ip4Address, Boolean closeAfterSuccessfulRead = false, Boolean closeAfterSuccessfulWrite = false) : - this(ip4Address.Host, - ip4Address.Port, + this(ip4Address.Host ?? "null", + ip4Address.Port.HasValue ? (Int32)ip4Address.Port.Value : 0, closeAfterSuccessfulRead, closeAfterSuccessfulWrite) { diff --git a/csharp/Lib/Units/Units.cs b/csharp/Lib/Units/Units.cs index 4a9501ded..a885d3ba2 100644 --- a/csharp/Lib/Units/Units.cs +++ b/csharp/Lib/Units/Units.cs @@ -88,8 +88,8 @@ public static class Units } else { - if (!visited.Add(parent)) - return; + //if (!visited.Add(parent)) + // return; foreach (var p in type.GetProperties(Instance | Public)) { diff --git a/csharp/Lib/Utils/Net/Ip4Address.cs b/csharp/Lib/Utils/Net/Ip4Address.cs index db1eda3de..1352f1025 100644 --- a/csharp/Lib/Utils/Net/Ip4Address.cs +++ b/csharp/Lib/Utils/Net/Ip4Address.cs @@ -1,9 +1,11 @@ +using System.Net; + namespace InnovEnergy.Lib.Utils.Net; public class Ip4Address { - public required String Host { get; init; } - public required UInt16 Port { get; init; } + public required String? Host { get; init; } + public required UInt16? Port { get; init; } public override String ToString() => $"{Host}:{Port}"; @@ -18,6 +20,7 @@ public class Ip4Address if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; + return Equals((Ip4Address)obj); } @@ -25,4 +28,12 @@ public class Ip4Address public static Boolean operator !=(Ip4Address? left, Ip4Address? right) => !Equals(left, right); public override Int32 GetHashCode() => ToString().GetHashCode(); -} \ No newline at end of file +} + + + + + + + +