using InnovEnergy.App.SaliMax.Ess; using InnovEnergy.App.SaliMax.SaliMaxRelays; using InnovEnergy.Lib.Devices.Battery48TL; using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.GridType; namespace InnovEnergy.App.SaliMax.System; public static class Controller { private static Int32 GetSystemState(this StatusRecord r) { var relays = r.Relays; if (relays is null) return 101; // Message = "Panic: relay device is not available!", var acDcs = r.AcDc; if (acDcs.NotAvailable()) return 102; var k4 = acDcs.AllDisabled() ? 0 : acDcs.AllGridTied() ? 1 : acDcs.AllIsland() ? 2 : 4; if (k4 == 4) return 103; //Message = "Panic: ACDCs have unequal grid types", var nInverters = r.AcDc.Devices.Count; var k1 = relays.K1GridBusIsConnectedToGrid ? 1 : 0; var k2 = relays.K2IslandBusIsConnectedToGridBus ? 1 : 0; var k3 = relays.K3InverterIsConnectedToIslandBus.Take(nInverters).Any(c => c) ? 1 : 0; // states as defined in states excel sheet return 1 + 1*k1 + 2*k2 + 4*k3 + 8*k4; } public static Boolean ControlSystemState(this StatusRecord s) { s.StateMachine.State = s.GetSystemState(); return s.StateMachine.State switch { 1 => State1(s), 2 => State2(s), 4 => State4(s), 6 => State6(s), 9 => State9(s), //10 => State10(s), 12 => State12(s), 13 => State13(s), 15 => State15(s), 16 => State16(s), 17 => State17(s), 18 => State18(s), 21 => State21(s), 101 => State101(s), 102 => State102(s), 103 => State103(s), _ => UnknownState(s) }; } private static Boolean NotAvailable(this AcDcDevicesRecord acDcs) { return acDcs.SystemControl == null || acDcs.Devices.Count == 0; } private static Boolean NotAvailable(this DcDcDevicesRecord dcDcs) { return dcDcs.SystemControl == null || dcDcs.Devices.Count == 0; } private static Boolean NotAvailable(this Battery48TlRecords batteries) { return batteries.Devices.Count <= 0; } private static Boolean State1(StatusRecord s) { s.StateMachine.Message = "Inverters are off. Switching to Island Mode."; s.DcDc.Enable(); s.AcDc.Enable(); s.AcDc.EnableIslandMode(); s.Relays.DisconnectIslandBusFromGrid(); return false; // => 17 } private static Boolean State2(StatusRecord s) { s.StateMachine.Message = "Inverters are disconnected from Island Bus. Switching to GridTie Mode. C"; s.DcDc.Disable(); s.AcDc.Disable(); s.AcDc.EnableGridTieMode(); s.Relays.ConnectIslandBusToGrid(); return false; // => 10 } private static Boolean State4(StatusRecord s) { s.StateMachine.Message = "Turning on Inverters"; s.DcDc.Enable(); s.AcDc.Enable(); s.AcDc.EnableGridTieMode(); s.Relays.ConnectIslandBusToGrid(); return false; // => 12 } private static Boolean State6(StatusRecord s) { s.StateMachine.Message = "Inverters are off. Waiting for them to disconnect from Island Bus."; s.DcDc.Disable(); s.AcDc.Disable(); s.AcDc.EnableIslandMode(); s.Relays.DisconnectIslandBusFromGrid(); return true; // => 2 } private static Boolean State9(StatusRecord s) { s.StateMachine.Message = "Inverters have disconnected from Island Bus. Turning them off."; s.DcDc.Disable(); // TODO: leave enabled? s.AcDc.Disable(); s.AcDc.EnableGridTieMode(); s.Relays.DisconnectIslandBusFromGrid(); return true; // => 1 } // // private static Boolean State10(StatusRecord s) // { // // s.SystemState.Message = "Inverters have disconnected from AcOut. Turning them off."; // // s.DcDc.Disable(); // TODO: leave enabled? // s.AcDc.Disable(); // s.AcDc.EnableGridTieMode(); // s.Relays.DisconnectIslandBusFromGrid(); // // return true; // // // => 12 // } private static Boolean State12(StatusRecord s) { s.StateMachine.Message = "Waiting for Inverters to connect to Island Bus"; s.DcDc.Enable(); s.AcDc.Enable(); s.AcDc.EnableGridTieMode(); s.Relays.ConnectIslandBusToGrid(); return true; // => 16 } private static Boolean State13(StatusRecord s) { s.StateMachine.Message = "Disconnected from AcIn (K2), awaiting inverters to disconnect from AcOut (K3)"; s.DcDc.Enable(); s.AcDc.Enable(); s.AcDc.EnableGridTieMode(); s.Relays.DisconnectIslandBusFromGrid(); return true; // => 9 } private static Boolean State15(StatusRecord s) { s.StateMachine.Message = "Grid has been lost, disconnecting AcIn from AcOut (K2)"; s.DcDc.Enable(); s.AcDc.Enable(); s.AcDc.EnableGridTieMode(); s.Relays.DisconnectIslandBusFromGrid(); return true; // => 13 } private static Boolean State16(StatusRecord s) { // return new // ( // " Inverter is in grid-tie\n Waiting for K1AcInIsConnectedToGrid to open to leave it", // AcPowerStageEnable: true, // DcPowerStageEnable: true, // GridType.GridTied400V50Hz, // HighActivePinState.Closed // ); s.StateMachine.Message = "ESS"; s.DcDc.Enable(); s.AcDc.Enable(); s.AcDc.EnableGridTieMode(); s.Relays.ConnectIslandBusToGrid(); return true; // => 15 } private static Boolean State17(StatusRecord s) { s.StateMachine.Message = "Inverters are in Island Mode. Waiting for them to connect to AcIn."; s.DcDc.Enable(); s.AcDc.Enable(); s.AcDc.EnableIslandMode(); s.Relays.DisconnectIslandBusFromGrid(); return true; // => 21 } private static Boolean State18(StatusRecord s) { // return new // ( // " Didn't succeed to go to Island mode and K1AcInIsConnectedToGrid close\n Turning off power stage of inverter\n Moving to Grid Tie", // AcPowerStageEnable: false, // DcPowerStageEnable: false, // GridType.GridTied400V50Hz, // HighActivePinState.Open // ); s.DcDc.Disable(); s.AcDc.Disable(); s.AcDc.EnableIslandMode(); s.Relays.DisconnectIslandBusFromGrid(); return true; } private static Boolean State21(StatusRecord s) { s.StateMachine.Message = "Island Mode"; s.DcDc.Enable(); s.AcDc.Enable(); s.AcDc.EnableIslandMode(); s.Relays.DisconnectIslandBusFromGrid(); return false; // => 22 } private static Boolean State22(StatusRecord s) { s.StateMachine.Message = "Grid became available (K1). Turning off inverters."; s.DcDc.Disable(); s.AcDc.Disable(); s.AcDc.EnableIslandMode(); s.Relays.DisconnectIslandBusFromGrid(); return false; // => 6 } private static Boolean State101(StatusRecord s) { s.StateMachine.Message = "Relay device is not available"; return s.EnableSafeDefaults(); } private static Boolean State102(StatusRecord s) { s.StateMachine.Message = "ACDCs not available"; return s.EnableSafeDefaults(); } private static Boolean State103(StatusRecord s) { s.StateMachine.Message = "Panic: ACDCs have unequal grid types"; return s.EnableSafeDefaults(); } private static Boolean State104(StatusRecord s) { s.StateMachine.Message = "Panic: DCDCs not available"; return s.EnableSafeDefaults(); } private static Boolean UnknownState(StatusRecord s) { // "Unknown System State" return s.EnableSafeDefaults(); } private static Boolean AllDisabled(this AcDcDevicesRecord acDcs) { return acDcs.Devices.All(d => !d.Control.PowerStageEnable); } private static Boolean AllGridTied(this AcDcDevicesRecord acDcs) { return acDcs.Devices.All(d => d.Status.ActiveGridType is GridTied380V60Hz) || acDcs.Devices.All(d => d.Status.ActiveGridType is GridTied400V50Hz) || acDcs.Devices.All(d => d.Status.ActiveGridType is GridTied480V60Hz); } private static Boolean AllIsland(this AcDcDevicesRecord acDcs) { return acDcs.Devices.All(d => d.Status.ActiveGridType is Island400V50Hz) || acDcs.Devices.All(d => d.Status.ActiveGridType is Island480V60Hz); } private static void ForAll(this IEnumerable ts, Action action) { foreach (var t in ts) action(t); } private static void Disable(this AcDcDevicesRecord acDc) { acDc.Devices .Select(d => d.Control) .ForAll(c => c.PowerStageEnable = false); } private static void Disable(this DcDcDevicesRecord dcDc) { dcDc.Devices .Select(d => d.Control) .ForAll(c => c.PowerStageEnable = false); } private static void Enable(this AcDcDevicesRecord acDc) { acDc.Devices .Select(d => d.Control) .ForAll(c => c.PowerStageEnable = true); } private static void Enable(this DcDcDevicesRecord dcDc) { dcDc.Devices .Select(d => d.Control) .ForAll(c => c.PowerStageEnable = true); } private static void EnableGridTieMode(this AcDcDevicesRecord acDc) { acDc.Devices .Select(d => d.Control) .ForAll(c => c.Ac.GridType = GridTied400V50Hz); // TODO: config grid type } private static void EnableIslandMode(this AcDcDevicesRecord acDc) { acDc.Devices .Select(d => d.Control) .ForAll(c => c.Ac.GridType = Island400V50Hz); // TODO: config grid type } private static void DisconnectIslandBusFromGrid(this RelaysRecord? relays) { if (relays is not null) relays.K2ConnectIslandBusToGridBus = false; } private static void ConnectIslandBusToGrid(this RelaysRecord? relays) { if (relays is not null) relays.K2ConnectIslandBusToGridBus = true; } private static Boolean EnableSafeDefaults(this StatusRecord s) { s.DcDc.Disable(); s.AcDc.Disable(); s.AcDc.EnableGridTieMode(); s.Relays.DisconnectIslandBusFromGrid(); return false; } private static DcDcDevicesRecord ResetAlarms(this DcDcDevicesRecord dcDcStatus) { var sc = dcDcStatus.SystemControl; if (sc is not null) sc.ResetAlarmsAndWarnings = sc.Alarms.Any(); foreach (var d in dcDcStatus.Devices) d.Control.ResetAlarmsAndWarnings = d.Status.Alarms.Any() || d.Status.Warnings.Any(); return dcDcStatus; } private static AcDcDevicesRecord ResetAlarms(this AcDcDevicesRecord acDcStatus) { var sc = acDcStatus.SystemControl; if (sc is not null) sc.ResetAlarmsAndWarnings = sc.Alarms.Any() || sc.Warnings.Any(); foreach (var d in acDcStatus.Devices) d.Control.ResetAlarmsAndWarnings = d.Status.Alarms.Any() || d.Status.Warnings.Any(); return acDcStatus; } }