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