diff --git a/csharp/App/SaliMax/SaliMax.csproj b/csharp/App/SaliMax/SaliMax.csproj index 0afc37933..e07e78437 100644 --- a/csharp/App/SaliMax/SaliMax.csproj +++ b/csharp/App/SaliMax/SaliMax.csproj @@ -21,6 +21,7 @@ + diff --git a/csharp/App/SaliMax/src/Ess/StatusRecord.cs b/csharp/App/SaliMax/src/Ess/StatusRecord.cs index 89c0b94a2..2af17e202 100644 --- a/csharp/App/SaliMax/src/Ess/StatusRecord.cs +++ b/csharp/App/SaliMax/src/Ess/StatusRecord.cs @@ -23,7 +23,7 @@ public record StatusRecord 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 IRelaysRecord? Relays { get; init; } public required AmptStatus? PvOnDc { get; init; } public required Config Config { get; set; } public required SystemLog Log { get; init; } // TODO: init only diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index f75d0d528..a0bfdb996 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -1,4 +1,4 @@ -#undef Amax +#define Amax #undef GridLimit using System.Reactive.Linq; @@ -126,7 +126,13 @@ internal static class Program var pvOnDcDevice = new AmptDevices(PvOnDc); var pvOnAcGridDevice = new AmptDevices(PvOnAcGrid); var pvOnAcIslandDevice = new AmptDevices(PvOnAcIsland); + +#if Amax + var saliMaxRelaysDevice = new RelaysDeviceAmax(RelaysChannel); +#else var saliMaxRelaysDevice = new RelaysDevice(RelaysChannel); +#endif + StatusRecord ReadStatus() { @@ -183,8 +189,11 @@ internal static class Program void WriteControl(StatusRecord r) { if (r.Relays is not null) - saliMaxRelaysDevice.Write(r.Relays); - +#if Amax + saliMaxRelaysDevice.Write((RelaysRecordAmax)r.Relays); +#else + ((RelaysDevice)saliMaxRelaysDevice).Write((RelaysRecord)r.Relays); +#endif acDcDevices.Write(r.AcDc); dcDcDevices.Write(r.DcDc); } diff --git a/csharp/App/SaliMax/src/SaliMaxRelays/RelaysDevice.cs b/csharp/App/SaliMax/src/SaliMaxRelays/RelaysDevice.cs index 5413d0690..1136a7c92 100644 --- a/csharp/App/SaliMax/src/SaliMaxRelays/RelaysDevice.cs +++ b/csharp/App/SaliMax/src/SaliMaxRelays/RelaysDevice.cs @@ -1,4 +1,5 @@ using InnovEnergy.Lib.Devices.Adam6360D; +using InnovEnergy.Lib.Devices.Amax5070; using InnovEnergy.Lib.Protocols.Modbus.Channels; namespace InnovEnergy.App.SaliMax.SaliMaxRelays; @@ -6,10 +7,11 @@ namespace InnovEnergy.App.SaliMax.SaliMaxRelays; public class RelaysDevice { private Adam6360DDevice AdamDevice { get; } - + public RelaysDevice(String hostname) => AdamDevice = new Adam6360DDevice(hostname, 2); public RelaysDevice(Channel channel) => AdamDevice = new Adam6360DDevice(channel, 2); + public RelaysRecord? Read() { try @@ -37,3 +39,34 @@ public class RelaysDevice } +public class RelaysDeviceAmax +{ + private Amax5070Device AmaxDevice { get; } + + public RelaysDeviceAmax(Channel channel) => AmaxDevice = new Amax5070Device(channel); + + public RelaysRecordAmax? Read() + { + try + { + return AmaxDevice.Read(); + } + catch (Exception e) + { + $"Failed to read from {nameof(RelaysDeviceAmax)}\n{e}".LogError(); + return null; + } + } + + public void Write(RelaysRecordAmax r) + { + try + { + AmaxDevice.Write(r); + } + catch (Exception e) + { + $"Failed to write to {nameof(RelaysDeviceAmax)}\n{e}".LogError(); + } + } +} \ No newline at end of file diff --git a/csharp/App/SaliMax/src/SaliMaxRelays/RelaysRecord.cs b/csharp/App/SaliMax/src/SaliMaxRelays/RelaysRecord.cs index 0fae59c45..fbc558c35 100644 --- a/csharp/App/SaliMax/src/SaliMaxRelays/RelaysRecord.cs +++ b/csharp/App/SaliMax/src/SaliMaxRelays/RelaysRecord.cs @@ -1,8 +1,19 @@ using InnovEnergy.Lib.Devices.Adam6360D; +using InnovEnergy.Lib.Devices.Amax5070; namespace InnovEnergy.App.SaliMax.SaliMaxRelays; -public class RelaysRecord +public interface IRelaysRecord +{ + Boolean K1GridBusIsConnectedToGrid { get; } + Boolean K2IslandBusIsConnectedToGridBus { get; } + IEnumerable K3InverterIsConnectedToIslandBus { get; } + Boolean FiWarning { get; } + Boolean FiError { get; } + Boolean K2ConnectIslandBusToGridBus { get; set; } +} + +public class RelaysRecord : IRelaysRecord { private readonly Adam6360DRegisters _Regs; @@ -36,3 +47,39 @@ public class RelaysRecord public static implicit operator RelaysRecord(Adam6360DRegisters d) => new RelaysRecord(d); } + + +public class RelaysRecordAmax : IRelaysRecord +{ + private readonly Amax5070Registers _Regs; + + private RelaysRecordAmax(Amax5070Registers regs) => _Regs = regs; + + public Boolean K1GridBusIsConnectedToGrid => _Regs.DigitalInput22; + public Boolean K2IslandBusIsConnectedToGridBus => !_Regs.DigitalInput20; + + public IEnumerable K3InverterIsConnectedToIslandBus + { + get + { + yield return K3Inverter1IsConnectedToIslandBus; + yield return K3Inverter2IsConnectedToIslandBus; + yield return K3Inverter3IsConnectedToIslandBus; + yield return K3Inverter4IsConnectedToIslandBus; + } + } + + public Boolean K3Inverter1IsConnectedToIslandBus => !_Regs.DigitalInput16; + public Boolean K3Inverter2IsConnectedToIslandBus => !_Regs.DigitalInput17; + public Boolean K3Inverter3IsConnectedToIslandBus => !_Regs.DigitalInput18; + public Boolean K3Inverter4IsConnectedToIslandBus => !_Regs.DigitalInput19; + + public Boolean FiWarning => !_Regs.DigitalInput21; + public Boolean FiError => !_Regs.DigitalInput23; + + public Boolean K2ConnectIslandBusToGridBus { get => _Regs.Relay23; set => _Regs.Relay23 = value;} + + public static implicit operator Amax5070Registers(RelaysRecordAmax d) => d._Regs; + public static implicit operator RelaysRecordAmax(Amax5070Registers d) => new RelaysRecordAmax(d); + +} diff --git a/csharp/App/SaliMax/src/System/Controller.cs b/csharp/App/SaliMax/src/System/Controller.cs index db0599143..33d982d9a 100644 --- a/csharp/App/SaliMax/src/System/Controller.cs +++ b/csharp/App/SaliMax/src/System/Controller.cs @@ -704,13 +704,13 @@ public static class Controller //s.Config.LowerDcLinkVoltageFromDc = 20; } - private static void DisconnectIslandBusFromGrid(this RelaysRecord? relays) + private static void DisconnectIslandBusFromGrid(this IRelaysRecord? relays) { if (relays is not null) relays.K2ConnectIslandBusToGridBus = false; } - private static void ConnectIslandBusToGrid(this RelaysRecord? relays) + private static void ConnectIslandBusToGrid(this IRelaysRecord? relays) { if (relays is not null) relays.K2ConnectIslandBusToGridBus = true; diff --git a/csharp/Lib/Devices/Amax5070/Amax5070.csproj b/csharp/Lib/Devices/Amax5070/Amax5070.csproj new file mode 100644 index 000000000..9053a38c4 --- /dev/null +++ b/csharp/Lib/Devices/Amax5070/Amax5070.csproj @@ -0,0 +1,18 @@ + + + + + + InnovEnergy.Lib.Devices.Amax5070 + + + + + + + + + + + + diff --git a/csharp/Lib/Devices/Amax5070/Amax5070Device.cs b/csharp/Lib/Devices/Amax5070/Amax5070Device.cs new file mode 100644 index 000000000..31926d383 --- /dev/null +++ b/csharp/Lib/Devices/Amax5070/Amax5070Device.cs @@ -0,0 +1,18 @@ +using InnovEnergy.Lib.Protocols.Modbus.Channels; +using InnovEnergy.Lib.Protocols.Modbus.Clients; +using InnovEnergy.Lib.Protocols.Modbus.Slaves; + +namespace InnovEnergy.Lib.Devices.Amax5070; + +public class Amax5070Device : ModbusDevice +{ + // Amax5070 have slave ID = 0 + public Amax5070Device(String hostname, Byte slaveId = 0, UInt16 port = 502) : + this(new TcpChannel(hostname, port), slaveId) + { + } + + public Amax5070Device(Channel channel, Byte slaveId = 0) : base(new ModbusTcpClient(channel, slaveId)) + { + } +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Amax5070/Amax5070Registers.cs b/csharp/Lib/Devices/Amax5070/Amax5070Registers.cs new file mode 100644 index 000000000..27f64af97 --- /dev/null +++ b/csharp/Lib/Devices/Amax5070/Amax5070Registers.cs @@ -0,0 +1,77 @@ +using System.Diagnostics.CodeAnalysis; +using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes; + +namespace InnovEnergy.Lib.Devices.Amax5070 +{ + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")] + [SuppressMessage("ReSharper", "UnusedMember.Global")] + [AddressOffset(-1)] + public class Amax5070Registers + { + [Coil(1)] public Boolean DigitalOutput0 { get; private set; } + [Coil(2)] public Boolean DigitalOutput1 { get; private set; } + [Coil(3)] public Boolean DigitalOutput2 { get; private set; } + [Coil(4)] public Boolean DigitalOutput3 { get; private set; } + [Coil(5)] public Boolean DigitalOutput4 { get; private set; } + [Coil(6)] public Boolean DigitalOutput5 { get; private set; } + [Coil(7)] public Boolean DigitalOutput6 { get; private set; } + [Coil(8)] public Boolean DigitalOutput7 { get; private set; } + [Coil(9)] public Boolean DigitalOutput8 { get; private set; } + [Coil(10)] public Boolean DigitalOutput9 { get; private set; } + [Coil(11)] public Boolean DigitalOutput10 { get; private set; } + [Coil(12)] public Boolean DigitalOutput11 { get; private set; } + [Coil(13)] public Boolean DigitalOutput12 { get; private set; } + [Coil(14)] public Boolean DigitalOutput13 { get; private set; } + [Coil(15)] public Boolean DigitalOutput14 { get; private set; } + [Coil(16)] public Boolean DigitalOutput15 { get; private set; } + + [Coil(17)] public Boolean Relay10 { get; set; } // Relay5060 1 + [Coil(18)] public Boolean Relay11 { get; set; } // Relay5060 1 + [Coil(19)] public Boolean Relay12 { get; set; } // Relay5060 1 + [Coil(20)] public Boolean Relay13 { get; set; } // Relay5060 1 + + [Coil(25)] public Boolean Relay20 { get; set; } // Relay5060 2 + [Coil(26)] public Boolean Relay21 { get; set; } // Relay5060 2 + [Coil(27)] public Boolean Relay22 { get; set; } // Relay5060 2 + [Coil(28)] public Boolean Relay23 { get; set; } // Relay5060 2 + + [Coil(33)] public Boolean Relay30 { get; set; } // Relay5060 3 + [Coil(34)] public Boolean Relay31 { get; set; } // Relay5060 3 + [Coil(35)] public Boolean Relay32 { get; set; } // Relay5060 3 + [Coil(36)] public Boolean Relay33 { get; set; } // Relay5060 3 + + [Coil(41)] public Boolean Relay40 { get; set; } // Relay5060 4 + [Coil(42)] public Boolean Relay41 { get; set; } // Relay5060 4 + [Coil(43)] public Boolean Relay42 { get; set; } // Relay5060 4 + [Coil(44)] public Boolean Relay43 { get; set; } // Relay5060 4 + + [DiscreteInput(49)] public Boolean DigitalInput0 { get; private set; } + [DiscreteInput(50)] public Boolean DigitalInput1 { get; private set; } + [DiscreteInput(51)] public Boolean DigitalInput2 { get; private set; } + [DiscreteInput(52)] public Boolean DigitalInput3 { get; private set; } + [DiscreteInput(53)] public Boolean DigitalInput4 { get; private set; } + [DiscreteInput(54)] public Boolean DigitalInput5 { get; private set; } + [DiscreteInput(55)] public Boolean DigitalInput6 { get; private set; } + [DiscreteInput(56)] public Boolean DigitalInput7 { get; private set; } + [DiscreteInput(57)] public Boolean DigitalInput8 { get; private set; } + [DiscreteInput(58)] public Boolean DigitalInput9 { get; private set; } + [DiscreteInput(59)] public Boolean DigitalInput10 { get; private set; } + [DiscreteInput(60)] public Boolean DigitalInput11 { get; private set; } + [DiscreteInput(61)] public Boolean DigitalInput12 { get; private set; } + [DiscreteInput(62)] public Boolean DigitalInput13 { get; private set; } + [DiscreteInput(63)] public Boolean DigitalInput14 { get; private set; } + [DiscreteInput(64)] public Boolean DigitalInput15 { get; private set; } + + [DiscreteInput(65)] public Boolean DigitalInput16 { get; private set; } // Relay5060 1 + [DiscreteInput(66)] public Boolean DigitalInput17 { get; private set; } // Relay5060 1 + + [DiscreteInput(73)] public Boolean DigitalInput18 { get; private set; } // Relay5060 2 + [DiscreteInput(74)] public Boolean DigitalInput19 { get; private set; } // Relay5060 2 + + [DiscreteInput(81)] public Boolean DigitalInput20 { get; private set; } // Relay5060 3 + [DiscreteInput(82)] public Boolean DigitalInput21 { get; private set; } // Relay5060 3 + + [DiscreteInput(89)] public Boolean DigitalInput22 { get; private set; } // Relay5060 4 + [DiscreteInput(90)] public Boolean DigitalInput23 { get; private set; } // Relay5060 4 + } +} \ No newline at end of file