Compare commits
No commits in common. "90a4257bbf63ead90a6455ce356ee6e44c2f7f3d" and "17e03309843b9c2f2124002e5ecffd12c80ab9da" have entirely different histories.
90a4257bbf
...
17e0330984
|
|
@ -9,8 +9,6 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../../Lib/Devices/BatteryDeligreen/BatteryDeligreen.csproj" />
|
<ProjectReference Include="../../Lib/Devices/BatteryDeligreen/BatteryDeligreen.csproj" />
|
||||||
<ProjectReference Include="..\..\Lib\Devices\Amax5070\Amax5070.csproj" />
|
|
||||||
<ProjectReference Include="..\..\Lib\Protocols\Modbus\Modbus.csproj" />
|
|
||||||
<ProjectReference Include="..\..\Lib\Units\Units.csproj" />
|
<ProjectReference Include="..\..\Lib\Units\Units.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
namespace InnovEnergy.App.DeligreenBatteryCommunication;
|
|
||||||
|
|
||||||
public enum DeviceState
|
|
||||||
{
|
|
||||||
Disabled,
|
|
||||||
Measured,
|
|
||||||
Computed
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,4 @@
|
||||||
using System.Net;
|
using InnovEnergy.Lib.Devices.BatteryDeligreen;
|
||||||
using InnovEnergy.Lib.Devices.BatteryDeligreen;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
|
||||||
using InnovEnergy.Lib.Utils.Net;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.DeligreenBatteryCommunication;
|
namespace InnovEnergy.App.DeligreenBatteryCommunication;
|
||||||
|
|
||||||
|
|
@ -10,7 +6,7 @@ internal static class Program
|
||||||
{
|
{
|
||||||
private static readonly TimeSpan UpdateInterval = TimeSpan.FromSeconds(2);
|
private static readonly TimeSpan UpdateInterval = TimeSpan.FromSeconds(2);
|
||||||
|
|
||||||
private static Channel _relaysChannel;
|
// private static readonly Channel? BatteriesChannel;
|
||||||
|
|
||||||
private const String Port = "/dev/ttyUSB0";
|
private const String Port = "/dev/ttyUSB0";
|
||||||
|
|
||||||
|
|
@ -23,21 +19,18 @@ internal static class Program
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task Main(String[] args)
|
public static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
var device1 = new SalimaxDevice { Host = "10.0.1.3" , Port = 502, DeviceState = DeviceState.Measured };
|
var listOfBatteries = new List<BatteryDeligreenDevice>
|
||||||
|
|
||||||
_relaysChannel = CreateChannel(device1);
|
|
||||||
|
|
||||||
var saliMaxRelaysDevice = new RelaysDeviceAmax(_relaysChannel);
|
|
||||||
|
|
||||||
/* var listOfBatteries = new List<BatteryDeligreenDevice>
|
|
||||||
{
|
{
|
||||||
new BatteryDeligreenDevice(Port, 0),
|
new BatteryDeligreenDevice(Port, 0),
|
||||||
new BatteryDeligreenDevice(Port, 1)
|
new BatteryDeligreenDevice(Port, 1),
|
||||||
|
new BatteryDeligreenDevice(Port, 2),
|
||||||
|
new BatteryDeligreenDevice(Port, 3),
|
||||||
|
new BatteryDeligreenDevice(Port, 4)
|
||||||
};
|
};
|
||||||
|
|
||||||
var batteryDevices = new BatteryDeligreenDevices(listOfBatteries);*/
|
var batteryDevices = new BatteryDeligreenDevices(listOfBatteries);
|
||||||
|
|
||||||
Console.WriteLine("Starting Battery Communication");
|
Console.WriteLine("Starting Battery Communication");
|
||||||
|
|
||||||
|
|
@ -47,65 +40,21 @@ internal static class Program
|
||||||
{
|
{
|
||||||
var startTime = DateTime.Now;
|
var startTime = DateTime.Now;
|
||||||
Console.WriteLine("***************************** Reading Battery Data *********************************************");
|
Console.WriteLine("***************************** Reading Battery Data *********************************************");
|
||||||
// Console.WriteLine($"Start Reading all Batteries: {startTime}");
|
Console.WriteLine($"Start Reading all Batteries: {startTime}");
|
||||||
//var batteriesRecord = batteryDevices.Read();
|
var batteriesRecord = batteryDevices.Read();
|
||||||
var stopTime = DateTime.Now;
|
var stopTime = DateTime.Now;
|
||||||
//Console.WriteLine($"Finish Reading all Batteries: {stopTime}");
|
Console.WriteLine($"Finish Reading all Batteries: {stopTime}");
|
||||||
var relays = saliMaxRelaysDevice.Read();
|
|
||||||
|
|
||||||
Console.WriteLine("***************************** Writing register 27 to true Amax *********************************************");
|
|
||||||
|
|
||||||
relays.K0 = true;
|
|
||||||
relays.K1 = true;
|
|
||||||
relays.R0 = true;
|
|
||||||
relays.R1 = true;
|
|
||||||
relays.R2 = true;
|
|
||||||
relays.R3 = true;
|
|
||||||
// relays.K0Input.WriteLine(" : K0input");
|
|
||||||
saliMaxRelaysDevice.Write(relays);
|
|
||||||
|
|
||||||
Console.WriteLine("***************************** Reading Amax *********************************************");
|
|
||||||
|
|
||||||
|
|
||||||
// relays.K1GridBusIsConnectedToGrid.WriteLine(" : K1");
|
|
||||||
|
|
||||||
await Task.Delay(2000);
|
|
||||||
|
|
||||||
Console.WriteLine("***************************** Writing register 27 to false Amax *********************************************");
|
|
||||||
relays.K0 = false;
|
|
||||||
relays.K1 = false;
|
|
||||||
relays.R0 = false;
|
|
||||||
relays.R1 = false;
|
|
||||||
relays.R2 = false;
|
|
||||||
relays.R3 = false;
|
|
||||||
// relays.K0Input.WriteLine(" : K0input");
|
|
||||||
|
|
||||||
saliMaxRelaysDevice.Write(relays);
|
|
||||||
|
|
||||||
Console.WriteLine("***************************** Reading Amax *********************************************");
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine("Time used for reading all batteries:" + (stopTime - startTime));
|
Console.WriteLine("Time used for reading all batteries:" + (stopTime - startTime));
|
||||||
|
|
||||||
Console.WriteLine("Average SOC " + batteriesRecord?.Soc);
|
Console.WriteLine("Average SOC " + batteriesRecord?.Soc);
|
||||||
Console.WriteLine("Cell Alarm 1 : " + batteriesRecord?.Devices[0].BatteryDeligreenAlarmRecord.CellAlarmList[0]);
|
Console.WriteLine("SOC Battery 0 : " + batteriesRecord?.Devices[0].BatteryDeligreenDataRecord.Soc);
|
||||||
Console.WriteLine("Cell Alarm 2 : " + batteriesRecord?.Devices[0].BatteryDeligreenAlarmRecord.CellAlarmList[1]);
|
Console.WriteLine("SOC Battery 1 : " + batteriesRecord?.Devices[1].BatteryDeligreenDataRecord.Soc);
|
||||||
|
Console.WriteLine("SOC Battery 2 : " + batteriesRecord?.Devices[2].BatteryDeligreenDataRecord.Soc);
|
||||||
Console.WriteLine("Cell Temperature Alarm 1 : " + batteriesRecord?.Devices[0].BatteryDeligreenAlarmRecord.CellTemperatureAlarm[0]);
|
Console.WriteLine("SOC Battery 3 : " + batteriesRecord?.Devices[3].BatteryDeligreenDataRecord.Soc);
|
||||||
Console.WriteLine("Cell Temperature Alarm 2 : " + batteriesRecord?.Devices[0].BatteryDeligreenAlarmRecord.CellTemperatureAlarm[1]);
|
Console.WriteLine("SOC Battery 4 : " + batteriesRecord?.Devices[4].BatteryDeligreenDataRecord.Soc);
|
||||||
|
Console.WriteLine("Min Soc " + batteriesRecord?.CurrentMinSoc);
|
||||||
Console.WriteLine("Battery 1 EnviTemp Alarm: " + batteriesRecord?.Devices[0].BatteryDeligreenAlarmRecord.EnviTempAlarm);
|
Console.WriteLine("count " + batteriesRecord?.Devices.Count);
|
||||||
Console.WriteLine("Battery 1 Current Alarm : " + batteriesRecord?.Devices[0].BatteryDeligreenAlarmRecord.CurrentAlarm);
|
|
||||||
|
|
||||||
Console.WriteLine("Battery 2 EnviTemp Alarm: " + batteriesRecord?.Devices[1].BatteryDeligreenAlarmRecord.EnviTempAlarm);
|
|
||||||
Console.WriteLine("Battery 2 Current Alarm : " + batteriesRecord?.Devices[1].BatteryDeligreenAlarmRecord.CurrentAlarm);
|
|
||||||
|
|
||||||
Console.WriteLine("TotalVoltage Alarm : " + batteriesRecord?.Devices[0].BatteryDeligreenAlarmRecord.TotalVoltageAlarm);
|
|
||||||
Console.WriteLine("PowerTemp Alarm : " + batteriesRecord?.Devices[0].BatteryDeligreenAlarmRecord.PowerTempAlarm);*/
|
|
||||||
|
|
||||||
|
|
||||||
// Wait for 2 seconds before the next reading
|
// Wait for 2 seconds before the next reading
|
||||||
await Task.Delay(2000); // Delay in milliseconds (2000ms = 2 seconds)
|
await Task.Delay(2000); // Delay in milliseconds (2000ms = 2 seconds)
|
||||||
|
|
@ -117,8 +66,6 @@ internal static class Program
|
||||||
await Task.Delay(2000); // Delay in milliseconds (2000ms = 2 seconds)
|
await Task.Delay(2000); // Delay in milliseconds (2000ms = 2 seconds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel CreateChannel(SalimaxDevice device) => new TcpChannel(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
using InnovEnergy.Lib.Devices.Amax5070;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.DeligreenBatteryCommunication;
|
|
||||||
|
|
||||||
public class RelaysRecordAmax
|
|
||||||
{
|
|
||||||
private readonly Amax5070Registers _regs;
|
|
||||||
|
|
||||||
private RelaysRecordAmax(Amax5070Registers regs) => _regs = regs;
|
|
||||||
|
|
||||||
//public UInt16 K0Input
|
|
||||||
//{
|
|
||||||
// get => _regs.DigitalInput;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean K0
|
|
||||||
{
|
|
||||||
get => _regs.DigitalOutput0;
|
|
||||||
set => _regs.DigitalOutput0 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean K1
|
|
||||||
{
|
|
||||||
get => _regs.DigitalOutput1;
|
|
||||||
set => _regs.DigitalOutput1 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean K2
|
|
||||||
{
|
|
||||||
get => _regs.DigitalOutput2;
|
|
||||||
set => _regs.DigitalOutput2 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean K3
|
|
||||||
{
|
|
||||||
get => _regs.DigitalOutput3;
|
|
||||||
set => _regs.DigitalOutput3 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean R0
|
|
||||||
{
|
|
||||||
get => _regs.Relay12;
|
|
||||||
set => _regs.Relay12 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean R1
|
|
||||||
{
|
|
||||||
get => _regs.Relay22;
|
|
||||||
set => _regs.Relay22 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean R2
|
|
||||||
{
|
|
||||||
get => _regs.Relay32;
|
|
||||||
set => _regs.Relay32 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean R3
|
|
||||||
{
|
|
||||||
get => _regs.Relay42;
|
|
||||||
set => _regs.Relay42 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
public Boolean K1GridBusIsConnectedToGrid => _regs.DigitalInput22;
|
|
||||||
public Boolean K2IslandBusIsConnectedToGridBus => !_regs.DigitalInput20;
|
|
||||||
public IEnumerable<Boolean> K3InverterIsConnectedToIslandBus
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
yield return K3Inverter1IsConnectedToIslandBus;
|
|
||||||
yield return K3Inverter2IsConnectedToIslandBus;
|
|
||||||
yield return K3Inverter3IsConnectedToIslandBus;
|
|
||||||
yield return K3Inverter4IsConnectedToIslandBus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Boolean K3Inverter1IsConnectedToIslandBus => !_regs.DigitalInput16;
|
|
||||||
private Boolean K3Inverter2IsConnectedToIslandBus => !_regs.DigitalInput17;
|
|
||||||
private Boolean K3Inverter3IsConnectedToIslandBus => !_regs.DigitalInput18;
|
|
||||||
private Boolean K3Inverter4IsConnectedToIslandBus => !_regs.DigitalInput19;
|
|
||||||
|
|
||||||
public Boolean FiWarning => !_regs.DigitalInput21;
|
|
||||||
public Boolean FiError => !_regs.DigitalInput23;*/
|
|
||||||
|
|
||||||
//public Boolean K2ConnectIslandBusToGridBus
|
|
||||||
//{
|
|
||||||
// get => _regs.Relay22;
|
|
||||||
// set => _regs.Relay22 = value;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
public static implicit operator Amax5070Registers(RelaysRecordAmax d) => d._regs;
|
|
||||||
public static implicit operator RelaysRecordAmax(Amax5070Registers d) => new RelaysRecordAmax(d);
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
using InnovEnergy.Lib.Utils.Net;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.DeligreenBatteryCommunication;
|
|
||||||
|
|
||||||
public class SalimaxDevice : Ip4Address
|
|
||||||
{
|
|
||||||
public required DeviceState DeviceState { get; init; }
|
|
||||||
|
|
||||||
public override String ToString() => $"{base.ToString()} ({DeviceState})";
|
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), DeviceState);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#define Amax
|
#undef Amax
|
||||||
#undef GridLimit
|
#undef GridLimit
|
||||||
|
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
|
|
||||||
|
|
@ -1,211 +0,0 @@
|
||||||
using System.Reflection.Metadata;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.SaliMaxRelays;
|
|
||||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
|
||||||
|
|
||||||
public class CombinedAdamRelaysRecord : IRelaysRecord
|
|
||||||
{
|
|
||||||
private const UInt16 SlowFreq = 3000;
|
|
||||||
private const UInt16 HighFreq = 1000;
|
|
||||||
|
|
||||||
public CombinedAdamRelaysRecord(RelaysRecordAdam6060? relaysRecordAdam6060, RelaysRecordAdam6360D? relaysRecordAdam6360D)
|
|
||||||
{
|
|
||||||
_recordAdam6060 = relaysRecordAdam6060;
|
|
||||||
_recordAdam6360D = relaysRecordAdam6360D;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static RelaysRecordAdam6060? _recordAdam6060;
|
|
||||||
private static RelaysRecordAdam6360D? _recordAdam6360D;
|
|
||||||
|
|
||||||
public static IRelaysRecord Instance { get; } = new CombinedAdamRelaysRecord(_recordAdam6060, _recordAdam6360D);
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean K1GridBusIsConnectedToGrid => _recordAdam6360D.K1GridBusIsConnectedToGrid;
|
|
||||||
|
|
||||||
public Boolean K2IslandBusIsConnectedToGridBus => _recordAdam6360D.K2IslandBusIsConnectedToGridBus;
|
|
||||||
public Boolean FiWarning => _recordAdam6360D.FiWarning;
|
|
||||||
public Boolean FiError => _recordAdam6360D.FiError;
|
|
||||||
public Boolean K2ConnectIslandBusToGridBus
|
|
||||||
{
|
|
||||||
get => _recordAdam6360D.K2ConnectIslandBusToGridBus;
|
|
||||||
set => _recordAdam6360D.K2ConnectIslandBusToGridBus = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean Inverter1WagoStatus => _recordAdam6360D.Inverter1WagoStatus;
|
|
||||||
public Boolean Inverter2WagoStatus => _recordAdam6360D.Inverter2WagoStatus;
|
|
||||||
public Boolean Inverter3WagoStatus => _recordAdam6360D.Inverter3WagoStatus;
|
|
||||||
public Boolean Inverter4WagoStatus => _recordAdam6360D.Inverter4WagoStatus;
|
|
||||||
|
|
||||||
public Boolean Dc1WagoStatus => _recordAdam6060.Dc1WagoStatus;
|
|
||||||
public Boolean Dc2WagoStatus => _recordAdam6060.Dc2WagoStatus;
|
|
||||||
public Boolean Dc3WagoStatus => _recordAdam6060.Dc3WagoStatus;
|
|
||||||
public Boolean Dc4WagoStatus => _recordAdam6060.Dc4WagoStatus;
|
|
||||||
public Boolean DcSystemControlWagoStatus => _recordAdam6060.DcSystemControlWagoStatus;
|
|
||||||
|
|
||||||
public Boolean LedGreen { get => _recordAdam6360D.LedGreen; set => _recordAdam6360D.LedGreen = value;}
|
|
||||||
public Boolean LedRed { get => _recordAdam6360D.LedRed; set => _recordAdam6360D.LedRed = value;}
|
|
||||||
public Boolean Harvester1Step => _recordAdam6360D.Harvester1Step;
|
|
||||||
public Boolean Harvester2Step => _recordAdam6360D.Harvester2Step;
|
|
||||||
public Boolean Harvester3Step => _recordAdam6360D.Harvester3Step;
|
|
||||||
public Boolean Harvester4Step => _recordAdam6360D.Harvester4Step;
|
|
||||||
|
|
||||||
public UInt16 DigitalOutput0Mode { get => _recordAdam6360D.DigitalOutput0Mode; set => _recordAdam6360D.DigitalOutput0Mode = value; }
|
|
||||||
|
|
||||||
public UInt16 DigitalOutput1Mode
|
|
||||||
{
|
|
||||||
get => _recordAdam6360D.DigitalOutput1Mode;
|
|
||||||
set => _recordAdam6360D.DigitalOutput1Mode = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UInt16 DigitalOutput2Mode
|
|
||||||
{
|
|
||||||
get => _recordAdam6360D.DigitalOutput2Mode;
|
|
||||||
set => _recordAdam6360D.DigitalOutput2Mode = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UInt16 DigitalOutput3Mode
|
|
||||||
{
|
|
||||||
get => _recordAdam6360D.DigitalOutput3Mode;
|
|
||||||
set => _recordAdam6360D.DigitalOutput3Mode = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UInt16 DigitalOutput4Mode
|
|
||||||
{
|
|
||||||
get => _recordAdam6360D.DigitalOutput4Mode;
|
|
||||||
set => _recordAdam6360D.DigitalOutput4Mode = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UInt16 DigitalOutput5Mode
|
|
||||||
{
|
|
||||||
get => _recordAdam6360D.DigitalOutput5Mode;
|
|
||||||
set => _recordAdam6360D.DigitalOutput5Mode = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean Do0StartPulse { get => _recordAdam6360D.Do0Pulse; set => _recordAdam6360D.Do0Pulse = value; }
|
|
||||||
public Boolean Do1StartPulse { get => _recordAdam6360D.Do1Pulse; set => _recordAdam6360D.Do1Pulse = value; }
|
|
||||||
public Boolean Do2StartPulse { get => _recordAdam6360D.Do2Pulse; set => _recordAdam6360D.Do2Pulse = value; }
|
|
||||||
public Boolean Do3StartPulse { get => _recordAdam6360D.Do3Pulse; set => _recordAdam6360D.Do3Pulse = value; }
|
|
||||||
public Boolean Do4StartPulse { get => _recordAdam6360D.Do4Pulse; set => _recordAdam6360D.Do4Pulse = value; }
|
|
||||||
public Boolean Do5StartPulse { get => _recordAdam6360D.Do5Pulse; set => _recordAdam6360D.Do5Pulse = value; }
|
|
||||||
|
|
||||||
|
|
||||||
public UInt16 PulseOut0LowTime { get => _recordAdam6360D.PulseOut0LowTime; set => _recordAdam6360D.PulseOut0LowTime = value; }
|
|
||||||
public UInt16 PulseOut1LowTime { get => _recordAdam6360D.PulseOut1LowTime; set => _recordAdam6360D.PulseOut1LowTime = value; }
|
|
||||||
public UInt16 PulseOut2LowTime { get => _recordAdam6360D.PulseOut2LowTime; set => _recordAdam6360D.PulseOut2LowTime = value; }
|
|
||||||
public UInt16 PulseOut3LowTime { get => _recordAdam6360D.PulseOut3LowTime; set => _recordAdam6360D.PulseOut3LowTime = value; }
|
|
||||||
public UInt16 PulseOut4LowTime { get => _recordAdam6360D.PulseOut4LowTime; set => _recordAdam6360D.PulseOut4LowTime = value; }
|
|
||||||
public UInt16 PulseOut5LowTime { get => _recordAdam6360D.PulseOut5LowTime; set => _recordAdam6360D.PulseOut5LowTime = value; }
|
|
||||||
|
|
||||||
public UInt16 PulseOut0HighTime { get => _recordAdam6360D.PulseOut0HighTime; set => _recordAdam6360D.PulseOut0HighTime = value; }
|
|
||||||
public UInt16 PulseOut1HighTime { get => _recordAdam6360D.PulseOut1HighTime; set => _recordAdam6360D.PulseOut1HighTime = value; }
|
|
||||||
public UInt16 PulseOut2HighTime { get => _recordAdam6360D.PulseOut2HighTime; set => _recordAdam6360D.PulseOut2HighTime = value; }
|
|
||||||
public UInt16 PulseOut3HighTime { get => _recordAdam6360D.PulseOut3HighTime; set => _recordAdam6360D.PulseOut3HighTime = value; }
|
|
||||||
public UInt16 PulseOut4HighTime { get => _recordAdam6360D.PulseOut4HighTime; set => _recordAdam6360D.PulseOut4HighTime = value; }
|
|
||||||
public UInt16 PulseOut5HighTime { get => _recordAdam6360D.PulseOut5HighTime; set => _recordAdam6360D.PulseOut5HighTime = value; }
|
|
||||||
|
|
||||||
/**************************** Green LED *********************************/
|
|
||||||
|
|
||||||
public void PerformSolidGreenLed()
|
|
||||||
{
|
|
||||||
DigitalOutput0Mode = 0;
|
|
||||||
DigitalOutput1Mode = 0;
|
|
||||||
LedGreen = true;
|
|
||||||
LedRed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformSlowFlashingGreenLed()
|
|
||||||
{
|
|
||||||
PulseOut0HighTime = SlowFreq;
|
|
||||||
PulseOut0LowTime = SlowFreq;
|
|
||||||
DigitalOutput0Mode = 2;
|
|
||||||
Do0StartPulse = true;
|
|
||||||
Do1StartPulse = false; // make sure the red LED is off
|
|
||||||
|
|
||||||
Console.WriteLine("Green Slow Flashing Starting");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformFastFlashingGreenLed()
|
|
||||||
{
|
|
||||||
PulseOut0HighTime = HighFreq;
|
|
||||||
PulseOut0LowTime = HighFreq;
|
|
||||||
DigitalOutput0Mode = 2;
|
|
||||||
Do0StartPulse = true;
|
|
||||||
Do1StartPulse = false;// make sure the red LED is off
|
|
||||||
|
|
||||||
Console.WriteLine("Green Slow Flashing Starting");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************** Orange LED *********************************/
|
|
||||||
|
|
||||||
public void PerformSolidOrangeLed()
|
|
||||||
{
|
|
||||||
DigitalOutput0Mode = 0;
|
|
||||||
DigitalOutput1Mode = 0;
|
|
||||||
LedGreen = true;
|
|
||||||
LedRed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformSlowFlashingOrangeLed()
|
|
||||||
{
|
|
||||||
PerformSlowFlashingGreenLed();
|
|
||||||
PerformSlowFlashingRedLed();
|
|
||||||
Do0StartPulse = true;
|
|
||||||
Do1StartPulse = true;
|
|
||||||
|
|
||||||
Console.WriteLine("Orange Slow Flashing Starting");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformFastFlashingOrangeLed()
|
|
||||||
{
|
|
||||||
PerformFastFlashingGreenLed();
|
|
||||||
PerformFastFlashingRedLed();
|
|
||||||
Do0StartPulse = true;
|
|
||||||
Do1StartPulse = true;
|
|
||||||
Console.WriteLine("Orange Fast Flashing Starting");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************** RED LED *********************************/
|
|
||||||
|
|
||||||
public void PerformSolidRedLed()
|
|
||||||
{
|
|
||||||
DigitalOutput0Mode = 0;
|
|
||||||
DigitalOutput1Mode = 0;
|
|
||||||
LedGreen = false;
|
|
||||||
LedRed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformSlowFlashingRedLed()
|
|
||||||
{
|
|
||||||
PulseOut1HighTime = SlowFreq;
|
|
||||||
PulseOut1LowTime = SlowFreq;
|
|
||||||
DigitalOutput1Mode = 2;
|
|
||||||
Do0StartPulse = false; // make sure the green LED is off
|
|
||||||
Do1StartPulse = true;
|
|
||||||
|
|
||||||
Console.WriteLine("Red Slow Flashing Starting");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformFastFlashingRedLed()
|
|
||||||
{
|
|
||||||
PulseOut1HighTime = HighFreq;
|
|
||||||
PulseOut1LowTime = HighFreq;
|
|
||||||
DigitalOutput1Mode = 2;
|
|
||||||
Do0StartPulse = false; // make sure the green LED is off
|
|
||||||
Do1StartPulse = true;
|
|
||||||
|
|
||||||
Console.WriteLine("Red Fast Flashing Starting");
|
|
||||||
}
|
|
||||||
|
|
||||||
public RelaysRecordAdam6360D? GetAdam6360DRecord()
|
|
||||||
{
|
|
||||||
return _recordAdam6360D;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RelaysRecordAdam6060? GetAdam6060Record()
|
|
||||||
{
|
|
||||||
return _recordAdam6060;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Boolean> K3InverterIsConnectedToIslandBus => _recordAdam6360D.K3InverterIsConnectedToIslandBus;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
namespace InnovEnergy.App.SaliMax.SaliMaxRelays;
|
|
||||||
|
|
||||||
|
|
||||||
public interface IRelaysRecord
|
|
||||||
{
|
|
||||||
Boolean K1GridBusIsConnectedToGrid { get; }
|
|
||||||
Boolean K2IslandBusIsConnectedToGridBus { get; }
|
|
||||||
IEnumerable<Boolean> K3InverterIsConnectedToIslandBus { get; }
|
|
||||||
Boolean FiWarning { get; }
|
|
||||||
Boolean FiError { get; }
|
|
||||||
Boolean K2ConnectIslandBusToGridBus { get; set; }
|
|
||||||
|
|
||||||
// Boolean Inverter1WagoRelay { get; set; } // to add in the future
|
|
||||||
// Boolean Inverter2WagoRelay { get; set; } // to add in the future
|
|
||||||
// Boolean Inverter3WagoRelay { get; set; } // to add in the future
|
|
||||||
// Boolean Inverter4WagoRelay { get; set; } // to add in the future
|
|
||||||
|
|
||||||
/* Boolean Inverter1WagoStatus { get; }
|
|
||||||
Boolean Inverter2WagoStatus { get; }
|
|
||||||
Boolean Inverter3WagoStatus { get; }
|
|
||||||
Boolean Inverter4WagoStatus { get; }
|
|
||||||
|
|
||||||
Boolean Dc1WagoStatus { get; } // to test
|
|
||||||
Boolean Dc2WagoStatus { get; } // to test
|
|
||||||
Boolean Dc3WagoStatus { get; } // to test
|
|
||||||
Boolean Dc4WagoStatus { get; } // to test
|
|
||||||
|
|
||||||
Boolean DcSystemControlWagoStatus { get; } // to test
|
|
||||||
|
|
||||||
Boolean LedGreen { get; set; }
|
|
||||||
Boolean LedRed { get; }
|
|
||||||
Boolean Harvester1Step { get; }
|
|
||||||
Boolean Harvester2Step { get; }
|
|
||||||
Boolean Harvester3Step { get; }
|
|
||||||
Boolean Harvester4Step { get; }
|
|
||||||
|
|
||||||
Boolean Do0StartPulse { get; set; }
|
|
||||||
Boolean Do1StartPulse { get; set; }
|
|
||||||
Boolean Do2StartPulse { get; set; }
|
|
||||||
Boolean Do3StartPulse { get; set; }
|
|
||||||
Boolean Do4StartPulse { get; set; }
|
|
||||||
Boolean Do5StartPulse { get; set; }
|
|
||||||
|
|
||||||
UInt16 DigitalOutput0Mode { get; set; }
|
|
||||||
UInt16 DigitalOutput1Mode { get; set; }
|
|
||||||
UInt16 DigitalOutput2Mode { get; set; }
|
|
||||||
UInt16 DigitalOutput3Mode { get; set; }
|
|
||||||
UInt16 DigitalOutput4Mode { get; set; }
|
|
||||||
UInt16 DigitalOutput5Mode { get; set; }
|
|
||||||
|
|
||||||
UInt16 PulseOut0LowTime { get; set; }
|
|
||||||
UInt16 PulseOut1LowTime { get; set; }
|
|
||||||
UInt16 PulseOut2LowTime { get; set; }
|
|
||||||
UInt16 PulseOut3LowTime { get; set; }
|
|
||||||
UInt16 PulseOut4LowTime { get; set; }
|
|
||||||
UInt16 PulseOut5LowTime { get; set; }
|
|
||||||
|
|
||||||
UInt16 PulseOut0HighTime { get; set; }
|
|
||||||
UInt16 PulseOut1HighTime { get; set; }
|
|
||||||
UInt16 PulseOut2HighTime { get; set; }
|
|
||||||
UInt16 PulseOut3HighTime { get; set; }
|
|
||||||
UInt16 PulseOut4HighTime { get; set; }
|
|
||||||
UInt16 PulseOut5HighTime { get; set; }
|
|
||||||
|
|
||||||
void PerformSolidGreenLed();
|
|
||||||
void PerformSlowFlashingGreenLed();
|
|
||||||
void PerformFastFlashingGreenLed();
|
|
||||||
|
|
||||||
|
|
||||||
void PerformSolidOrangeLed();
|
|
||||||
void PerformSlowFlashingOrangeLed();
|
|
||||||
void PerformFastFlashingOrangeLed();
|
|
||||||
|
|
||||||
void PerformSolidRedLed();
|
|
||||||
void PerformSlowFlashingRedLed();
|
|
||||||
void PerformFastFlashingRedLed();*/
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
using InnovEnergy.Lib.Devices.Adam6360D;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.SaliMaxRelays;
|
|
||||||
|
|
||||||
public class RelaysDeviceAdam6360
|
|
||||||
{
|
|
||||||
private Adam6360DDevice AdamDevice6360D { get; }
|
|
||||||
|
|
||||||
public RelaysDeviceAdam6360(String hostname) => AdamDevice6360D = new Adam6360DDevice(hostname, 2);
|
|
||||||
public RelaysDeviceAdam6360(Channel channel) => AdamDevice6360D = new Adam6360DDevice(channel, 2);
|
|
||||||
|
|
||||||
|
|
||||||
public RelaysRecordAdam6360D? Read()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return AdamDevice6360D.Read();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
$"Failed to read from {nameof(RelaysDeviceAdam6360)}\n{e}".LogError();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(RelaysRecordAdam6360D r)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AdamDevice6360D.Write(r);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
$"Failed to write to {nameof(RelaysDeviceAdam6360)}\n{e}".LogError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
using InnovEnergy.Lib.Devices.Adam6060;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.SaliMaxRelays;
|
|
||||||
|
|
||||||
public class RelaysDeviceAdam6060
|
|
||||||
{
|
|
||||||
private Adam6060Device AdamDevice6060 { get; }
|
|
||||||
|
|
||||||
public RelaysDeviceAdam6060(String hostname) => AdamDevice6060 = new Adam6060Device(hostname, 2);
|
|
||||||
public RelaysDeviceAdam6060(Channel channel) => AdamDevice6060 = new Adam6060Device(channel, 2);
|
|
||||||
|
|
||||||
|
|
||||||
public RelaysRecordAdam6060? Read()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return AdamDevice6060.Read();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
$"Failed to read from {nameof(RelaysDeviceAdam6060)}\n{e}".LogError();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(RelaysRecordAdam6060 r)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AdamDevice6060.Write(r);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
$"Failed to write to {nameof(RelaysDeviceAdam6060)}\n{e}".LogError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
using InnovEnergy.Lib.Devices.Amax5070;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
|
||||||
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.SaliMaxRelays;
|
|
||||||
|
|
||||||
public class RelaysDeviceAmax
|
|
||||||
{
|
|
||||||
private Amax5070Device AmaxDevice { get; }
|
|
||||||
|
|
||||||
public RelaysDeviceAmax(String hostname) => AmaxDevice = new Amax5070Device(hostname);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
using InnovEnergy.Lib.Devices.Adam6060;
|
|
||||||
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.SaliMaxRelays;
|
|
||||||
|
|
||||||
public class RelaysRecordAdam6060
|
|
||||||
{
|
|
||||||
private readonly Adam6060Registers _Regs;
|
|
||||||
|
|
||||||
private RelaysRecordAdam6060(Adam6060Registers regs) => _Regs = regs;
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean Dc1WagoStatus => _Regs.DigitalInput0; // to test
|
|
||||||
public Boolean Dc2WagoStatus => _Regs.DigitalInput1; // to test
|
|
||||||
public Boolean Dc3WagoStatus => _Regs.DigitalInput4; // to test
|
|
||||||
public Boolean Dc4WagoStatus => _Regs.DigitalInput5; // to test
|
|
||||||
|
|
||||||
public Boolean DcSystemControlWagoStatus => _Regs.DigitalInput3; // to test
|
|
||||||
|
|
||||||
|
|
||||||
public static implicit operator Adam6060Registers(RelaysRecordAdam6060 d) => d._Regs;
|
|
||||||
public static implicit operator RelaysRecordAdam6060(Adam6060Registers d) => new RelaysRecordAdam6060(d);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
using InnovEnergy.Lib.Devices.Adam6360D;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.SaliMaxRelays;
|
|
||||||
|
|
||||||
public class RelaysRecordAdam6360D
|
|
||||||
{
|
|
||||||
private readonly Adam6360DRegisters _Regs;
|
|
||||||
|
|
||||||
private RelaysRecordAdam6360D(Adam6360DRegisters regs) => _Regs = regs;
|
|
||||||
|
|
||||||
public Boolean K1GridBusIsConnectedToGrid => _Regs.DigitalInput6;
|
|
||||||
public Boolean K2IslandBusIsConnectedToGridBus => !_Regs.DigitalInput4;
|
|
||||||
|
|
||||||
public Boolean Inverter1WagoStatus => _Regs.DigitalInput8;
|
|
||||||
public Boolean Inverter2WagoStatus => _Regs.DigitalInput9;
|
|
||||||
public Boolean Inverter3WagoStatus => _Regs.DigitalInput10;
|
|
||||||
public Boolean Inverter4WagoStatus => _Regs.DigitalInput11;
|
|
||||||
|
|
||||||
public IEnumerable<Boolean> K3InverterIsConnectedToIslandBus
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
yield return K3Inverter1IsConnectedToIslandBus;
|
|
||||||
yield return K3Inverter2IsConnectedToIslandBus;
|
|
||||||
yield return K3Inverter3IsConnectedToIslandBus;
|
|
||||||
yield return K3Inverter4IsConnectedToIslandBus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Boolean K3Inverter1IsConnectedToIslandBus => !_Regs.DigitalInput0; // change it to private should be ok
|
|
||||||
private Boolean K3Inverter2IsConnectedToIslandBus => !_Regs.DigitalInput1;
|
|
||||||
private Boolean K3Inverter3IsConnectedToIslandBus => !_Regs.DigitalInput2;
|
|
||||||
private Boolean K3Inverter4IsConnectedToIslandBus => !_Regs.DigitalInput3;
|
|
||||||
|
|
||||||
public Boolean FiWarning => !_Regs.DigitalInput5;
|
|
||||||
public Boolean FiError => !_Regs.DigitalInput7;
|
|
||||||
|
|
||||||
public Boolean Harvester1Step =>_Regs.DigitalOutput2;
|
|
||||||
public Boolean Harvester2Step =>_Regs.DigitalOutput3;
|
|
||||||
public Boolean Harvester3Step =>_Regs.DigitalOutput4;
|
|
||||||
public Boolean Harvester4Step =>_Regs.DigitalOutput5;
|
|
||||||
|
|
||||||
public Boolean LedGreen { get =>_Regs.DigitalOutput0; set => _Regs.DigitalOutput0 = value;}
|
|
||||||
public Boolean LedRed { get =>_Regs.DigitalOutput1; set => _Regs.DigitalOutput1 = value;}
|
|
||||||
|
|
||||||
public Boolean Do0Pulse { get => _Regs.Do0Pulse; set => _Regs.Do0Pulse = value;}
|
|
||||||
public Boolean Do1Pulse { get => _Regs.Do1Pulse; set => _Regs.Do1Pulse = value;}
|
|
||||||
public Boolean Do2Pulse { get => _Regs.Do2Pulse; set => _Regs.Do2Pulse = value;}
|
|
||||||
public Boolean Do3Pulse { get => _Regs.Do3Pulse; set => _Regs.Do3Pulse = value;}
|
|
||||||
public Boolean Do4Pulse { get => _Regs.Do4Pulse; set => _Regs.Do4Pulse = value;}
|
|
||||||
public Boolean Do5Pulse { get => _Regs.Do5Pulse; set => _Regs.Do5Pulse = value;}
|
|
||||||
|
|
||||||
public UInt16 PulseOut0LowTime { get => _Regs.PulseOut0LowTime; set => _Regs.PulseOut0LowTime = value;} //in milleseconds
|
|
||||||
public UInt16 PulseOut1LowTime { get => _Regs.PulseOut1LowTime; set => _Regs.PulseOut1LowTime = value;}
|
|
||||||
public UInt16 PulseOut2LowTime { get => _Regs.PulseOut2LowTime; set => _Regs.PulseOut2LowTime = value;}
|
|
||||||
public UInt16 PulseOut3LowTime { get => _Regs.PulseOut3LowTime; set => _Regs.PulseOut3LowTime = value;}
|
|
||||||
public UInt16 PulseOut4LowTime { get => _Regs.PulseOut4LowTime; set => _Regs.PulseOut4LowTime = value;}
|
|
||||||
public UInt16 PulseOut5LowTime { get => _Regs.PulseOut5LowTime; set => _Regs.PulseOut5LowTime = value;}
|
|
||||||
|
|
||||||
public UInt16 PulseOut0HighTime { get => _Regs.PulseOut0HighTime; set => _Regs.PulseOut0HighTime = value;} // in milleseconds
|
|
||||||
public UInt16 PulseOut1HighTime { get => _Regs.PulseOut1HighTime; set => _Regs.PulseOut1HighTime = value;}
|
|
||||||
public UInt16 PulseOut2HighTime { get => _Regs.PulseOut2HighTime; set => _Regs.PulseOut2HighTime = value;}
|
|
||||||
public UInt16 PulseOut3HighTime { get => _Regs.PulseOut3HighTime; set => _Regs.PulseOut3HighTime = value;}
|
|
||||||
public UInt16 PulseOut4HighTime { get => _Regs.PulseOut4HighTime; set => _Regs.PulseOut4HighTime = value;}
|
|
||||||
public UInt16 PulseOut5HighTime { get => _Regs.PulseOut5HighTime; set => _Regs.PulseOut5HighTime = value;}
|
|
||||||
|
|
||||||
public UInt16 DigitalOutput0Mode { get => _Regs.DigitalOutput0Mode; set => _Regs.DigitalOutput0Mode = value;} // To test: 0, 1 or 2
|
|
||||||
public UInt16 DigitalOutput1Mode { get => _Regs.DigitalOutput1Mode; set => _Regs.DigitalOutput1Mode = value;}
|
|
||||||
public UInt16 DigitalOutput2Mode { get => _Regs.DigitalOutput2Mode; set => _Regs.DigitalOutput2Mode = value;}
|
|
||||||
public UInt16 DigitalOutput3Mode { get => _Regs.DigitalOutput3Mode; set => _Regs.DigitalOutput3Mode = value;}
|
|
||||||
public UInt16 DigitalOutput4Mode { get => _Regs.DigitalOutput4Mode; set => _Regs.DigitalOutput4Mode = value;}
|
|
||||||
public UInt16 DigitalOutput5Mode { get => _Regs.DigitalOutput5Mode; set => _Regs.DigitalOutput5Mode = value;}
|
|
||||||
|
|
||||||
public Boolean K2ConnectIslandBusToGridBus { get => _Regs.Relay0; set => _Regs.Relay0 = value;}
|
|
||||||
|
|
||||||
public static implicit operator Adam6360DRegisters(RelaysRecordAdam6360D d) => d._Regs;
|
|
||||||
public static implicit operator RelaysRecordAdam6360D(Adam6360DRegisters d) => new RelaysRecordAdam6360D(d);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,134 +0,0 @@
|
||||||
using InnovEnergy.Lib.Devices.Amax5070;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.SaliMaxRelays;
|
|
||||||
|
|
||||||
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 Boolean Inverter1WagoStatus => _Regs.DigitalInput0;
|
|
||||||
public Boolean Inverter2WagoStatus => _Regs.DigitalInput1;
|
|
||||||
public Boolean Inverter3WagoStatus => _Regs.DigitalInput2;
|
|
||||||
public Boolean Inverter4WagoStatus => _Regs.DigitalInput3;
|
|
||||||
|
|
||||||
public Boolean Dc1WagoStatus => _Regs.DigitalInput6;
|
|
||||||
public Boolean Dc2WagoStatus => _Regs.DigitalInput7;
|
|
||||||
public Boolean Dc3WagoStatus => _Regs.DigitalInput10;
|
|
||||||
public Boolean Dc4WagoStatus => _Regs.DigitalInput11;
|
|
||||||
public Boolean DcSystemControlWagoStatus => _Regs.DigitalInput9;
|
|
||||||
|
|
||||||
public Boolean LedGreen
|
|
||||||
{
|
|
||||||
get => _Regs.DigitalOutput0;
|
|
||||||
set => _Regs.DigitalOutput0 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean LedRed => _Regs.DigitalOutput1;
|
|
||||||
public Boolean Harvester1Step => _Regs.DigitalOutput2;
|
|
||||||
public Boolean Harvester2Step => _Regs.DigitalOutput3;
|
|
||||||
public Boolean Harvester3Step => _Regs.DigitalOutput4;
|
|
||||||
public Boolean Harvester4Step => _Regs.DigitalOutput5;
|
|
||||||
/* public Boolean Do0StartPulse { get; set; }
|
|
||||||
public Boolean Do1StartPulse { get; set; }
|
|
||||||
public Boolean Do2StartPulse { get; set; }
|
|
||||||
public Boolean Do3StartPulse { get; set; }
|
|
||||||
public Boolean Do4StartPulse { get; set; }
|
|
||||||
public Boolean Do5StartPulse { get; set; }
|
|
||||||
public UInt16 DigitalOutput0Mode { get; set; }
|
|
||||||
public UInt16 DigitalOutput1Mode { get; set; }
|
|
||||||
public UInt16 DigitalOutput2Mode { get; set; }
|
|
||||||
public UInt16 DigitalOutput3Mode { get; set; }
|
|
||||||
public UInt16 DigitalOutput4Mode { get; set; }
|
|
||||||
public UInt16 DigitalOutput5Mode { get; set; }
|
|
||||||
public UInt16 PulseOut0LowTime { get; set; }
|
|
||||||
public UInt16 PulseOut1LowTime { get; set; }
|
|
||||||
public UInt16 PulseOut2LowTime { get; set; }
|
|
||||||
public UInt16 PulseOut3LowTime { get; set; }
|
|
||||||
public UInt16 PulseOut4LowTime { get; set; }
|
|
||||||
public UInt16 PulseOut5LowTime { get; set; }
|
|
||||||
public UInt16 PulseOut0HighTime { get; set; }
|
|
||||||
public UInt16 PulseOut1HighTime { get; set; }
|
|
||||||
public UInt16 PulseOut2HighTime { get; set; }
|
|
||||||
public UInt16 PulseOut3HighTime { get; set; }
|
|
||||||
public UInt16 PulseOut4HighTime { get; set; }
|
|
||||||
public UInt16 PulseOut5HighTime { get; set; }*/
|
|
||||||
/*
|
|
||||||
public void PerformSolidGreenLed()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Solid Green: This is not yet implemented ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformSlowFlashingGreenLed()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Slow Flashing Green: This is not yet implemented ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformFastFlashingGreenLed()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Fast Flashing Green: This is not yet implemented ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformSolidOrangeLed()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Solid Orange: This is not yet implemented ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformSlowFlashingOrangeLed()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Slow Flashing Orange: This is not yet implemented ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformFastFlashingOrangeLed()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Fast Flashing Orange: This is not yet implemented ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformSolidRedLed()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Solid Red: This is not yet implemented ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformSlowFlashingRedLed()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Slow Flashing Red: This is not yet implemented ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PerformFastFlashingRedLed()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Fast Flashing Red: This is not yet implemented ");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
public IEnumerable<Boolean> 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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -53,6 +53,7 @@ public static class Controller
|
||||||
};
|
};
|
||||||
|
|
||||||
var essDelta = s.ComputePowerDelta(mode);
|
var essDelta = s.ComputePowerDelta(mode);
|
||||||
|
essDelta.WriteLine("Power Correction");
|
||||||
|
|
||||||
var unlimitedControl = new EssControl
|
var unlimitedControl = new EssControl
|
||||||
{
|
{
|
||||||
|
|
@ -140,6 +141,9 @@ public static class Controller
|
||||||
{
|
{
|
||||||
var chargePower = s.AcDc.Devices.Sum(d => d.Status.Nominal.Power.Value);
|
var chargePower = s.AcDc.Devices.Sum(d => d.Status.Nominal.Power.Value);
|
||||||
|
|
||||||
|
|
||||||
|
s.Config.GridSetPoint.WriteLine(" GridSetPoint");
|
||||||
|
|
||||||
return mode switch
|
return mode switch
|
||||||
{
|
{
|
||||||
EssMode.ReachMinSoc => s.ControlInverterPower(chargePower),
|
EssMode.ReachMinSoc => s.ControlInverterPower(chargePower),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#define Amax
|
#undef Amax
|
||||||
#undef GridLimit
|
#undef GridLimit
|
||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
@ -54,6 +54,7 @@ internal static class Program
|
||||||
private static readonly Channel PvOnAcGrid;
|
private static readonly Channel PvOnAcGrid;
|
||||||
private static readonly Channel PvOnAcIsland;
|
private static readonly Channel PvOnAcIsland;
|
||||||
private static readonly Channel RelaysChannel;
|
private static readonly Channel RelaysChannel;
|
||||||
|
private static readonly Channel RelaysTsChannel;
|
||||||
private static readonly Channel BatteriesChannel;
|
private static readonly Channel BatteriesChannel;
|
||||||
|
|
||||||
private static Boolean _curtailFlag = false;
|
private static Boolean _curtailFlag = false;
|
||||||
|
|
@ -85,6 +86,7 @@ internal static class Program
|
||||||
PvOnAcGrid = CreateChannel(d.PvOnAcGrid);
|
PvOnAcGrid = CreateChannel(d.PvOnAcGrid);
|
||||||
PvOnAcIsland = CreateChannel(d.PvOnAcIsland);
|
PvOnAcIsland = CreateChannel(d.PvOnAcIsland);
|
||||||
RelaysChannel = CreateChannel(d.RelaysIp);
|
RelaysChannel = CreateChannel(d.RelaysIp);
|
||||||
|
RelaysTsChannel = CreateChannel(d.TsRelaysIp);
|
||||||
BatteriesChannel = CreateChannel(d.BatteryIp);
|
BatteriesChannel = CreateChannel(d.BatteryIp);
|
||||||
|
|
||||||
BatteryNodes = config
|
BatteryNodes = config
|
||||||
|
|
@ -138,11 +140,13 @@ internal static class Program
|
||||||
var pvOnDcDevice = new AmptDevices(PvOnDc);
|
var pvOnDcDevice = new AmptDevices(PvOnDc);
|
||||||
var pvOnAcGridDevice = new AmptDevices(PvOnAcGrid);
|
var pvOnAcGridDevice = new AmptDevices(PvOnAcGrid);
|
||||||
var pvOnAcIslandDevice = new AmptDevices(PvOnAcIsland);
|
var pvOnAcIslandDevice = new AmptDevices(PvOnAcIsland);
|
||||||
|
var saliMaxTsRelaysDevice = new RelaysDeviceAdam6060(RelaysTsChannel);
|
||||||
|
|
||||||
|
|
||||||
#if Amax
|
#if Amax
|
||||||
var saliMaxRelaysDevice = new RelaysDeviceAmax(RelaysChannel);
|
var saliMaxRelaysDevice = new RelaysDeviceAmax(RelaysChannel);
|
||||||
#else
|
#else
|
||||||
var saliMaxRelaysDevice = new RelaysDevice(RelaysChannel);
|
var saliMaxRelaysDevice = new RelaysDeviceAdam6360(RelaysChannel);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -153,10 +157,12 @@ internal static class Program
|
||||||
var acDc = acDcDevices.Read();
|
var acDc = acDcDevices.Read();
|
||||||
var dcDc = dcDcDevices.Read();
|
var dcDc = dcDcDevices.Read();
|
||||||
var relays = saliMaxRelaysDevice.Read();
|
var relays = saliMaxRelaysDevice.Read();
|
||||||
|
var tsRelays = saliMaxTsRelaysDevice.Read();
|
||||||
var loadOnAcIsland = acIslandLoadMeter.Read();
|
var loadOnAcIsland = acIslandLoadMeter.Read();
|
||||||
var gridMeter = gridMeterDevice.Read();
|
var gridMeter = gridMeterDevice.Read();
|
||||||
var pvOnDc = pvOnDcDevice.Read();
|
var pvOnDc = pvOnDcDevice.Read();
|
||||||
var battery = batteryDevices.Read();
|
var battery = batteryDevices.Read();
|
||||||
|
|
||||||
var pvOnAcGrid = pvOnAcGridDevice.Read();
|
var pvOnAcGrid = pvOnAcGridDevice.Read();
|
||||||
var pvOnAcIsland = pvOnAcIslandDevice.Read();
|
var pvOnAcIsland = pvOnAcIslandDevice.Read();
|
||||||
|
|
||||||
|
|
@ -174,13 +180,18 @@ internal static class Program
|
||||||
Topology.CalculateAcDcToDcLink(pvOnDc, dcDc, acDc)
|
Topology.CalculateAcDcToDcLink(pvOnDc, dcDc, acDc)
|
||||||
: new DcPowerDevice{ Power = acDc.Dc.Power};
|
: new DcPowerDevice{ Power = acDc.Dc.Power};
|
||||||
|
|
||||||
|
#if Amax
|
||||||
|
var combinedRelays = relays;
|
||||||
|
#else
|
||||||
|
var combinedRelays = new CombinedAdamRelaysRecord(tsRelays, relays);
|
||||||
|
#endif
|
||||||
|
|
||||||
return new StatusRecord
|
return new StatusRecord
|
||||||
{
|
{
|
||||||
AcDc = acDc,
|
AcDc = acDc,
|
||||||
DcDc = dcDc,
|
DcDc = dcDc,
|
||||||
Battery = battery,
|
Battery = battery,
|
||||||
Relays = relays,
|
Relays = combinedRelays,
|
||||||
GridMeter = gridMeter,
|
GridMeter = gridMeter,
|
||||||
PvOnAcGrid = pvOnAcGrid,
|
PvOnAcGrid = pvOnAcGrid,
|
||||||
PvOnAcIsland = pvOnAcIsland,
|
PvOnAcIsland = pvOnAcIsland,
|
||||||
|
|
@ -204,9 +215,13 @@ internal static class Program
|
||||||
#if Amax
|
#if Amax
|
||||||
saliMaxRelaysDevice.Write((RelaysRecordAmax)r.Relays);
|
saliMaxRelaysDevice.Write((RelaysRecordAmax)r.Relays);
|
||||||
#else
|
#else
|
||||||
((RelaysDevice)saliMaxRelaysDevice).Write((RelaysRecord)r.Relays);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
if (r.Relays is CombinedAdamRelaysRecord adamRelays)
|
||||||
|
{
|
||||||
|
saliMaxRelaysDevice.Write(adamRelays.GetAdam6360DRecord() ?? throw new InvalidOperationException());
|
||||||
|
saliMaxTsRelaysDevice.Write(adamRelays.GetAdam6060Record() ?? throw new InvalidOperationException());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
acDcDevices.Write(r.AcDc);
|
acDcDevices.Write(r.AcDc);
|
||||||
|
|
@ -231,13 +246,41 @@ internal static class Program
|
||||||
Watchdog.NotifyAlive();
|
Watchdog.NotifyAlive();
|
||||||
|
|
||||||
var record = ReadStatus();
|
var record = ReadStatus();
|
||||||
|
/*
|
||||||
|
if (record.Relays != null)
|
||||||
|
{
|
||||||
|
record.Relays.Do0StartPulse = true;
|
||||||
|
|
||||||
|
record.Relays.PulseOut0HighTime = 20000;
|
||||||
|
record.Relays.PulseOut0LowTime = 20000;
|
||||||
|
record.Relays.DigitalOutput0Mode = 2;
|
||||||
|
|
||||||
|
record.Relays.LedGreen = false;
|
||||||
|
|
||||||
|
record.Relays.Do0StartPulse.WriteLine(" = start pulse 0");
|
||||||
|
|
||||||
|
record.Relays.PulseOut0HighTime.WriteLine(" = PulseOut0HighTime");
|
||||||
|
|
||||||
|
record.Relays.PulseOut0LowTime.WriteLine(" = PulseOut0LowTime");
|
||||||
|
|
||||||
|
record.Relays.DigitalOutput0Mode.WriteLine(" = DigitalOutput0Mode");
|
||||||
|
|
||||||
|
record.Relays.LedGreen.WriteLine(" = LedGreen");
|
||||||
|
|
||||||
|
record.Relays.LedRed.WriteLine(" = LedRed");
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
" Relays are null".WriteLine();
|
||||||
|
}*/
|
||||||
|
|
||||||
SendSalimaxStateAlarm(GetSalimaxStateAlarm(record), record); // to improve
|
SendSalimaxStateAlarm(GetSalimaxStateAlarm(record), record); // to improve
|
||||||
|
|
||||||
record.ControlConstants();
|
record.ControlConstants();
|
||||||
record.ControlSystemState();
|
record.ControlSystemState();
|
||||||
|
|
||||||
//record.ControlPvPower(record.Config.CurtailP, record.Config.PvInstalledPower);
|
record.ControlPvPower(record.Config.CurtailP, record.Config.PvInstalledPower);
|
||||||
|
|
||||||
var essControl = record.ControlEss().WriteLine();
|
var essControl = record.ControlEss().WriteLine();
|
||||||
|
|
||||||
|
|
@ -248,7 +291,7 @@ internal static class Program
|
||||||
|
|
||||||
DistributePower(record, essControl);
|
DistributePower(record, essControl);
|
||||||
|
|
||||||
//record.PerformLed();
|
record.PerformLed();
|
||||||
|
|
||||||
WriteControl(record);
|
WriteControl(record);
|
||||||
|
|
||||||
|
|
@ -486,13 +529,8 @@ internal static class Program
|
||||||
var inverters = r.AcDc.Devices;
|
var inverters = r.AcDc.Devices;
|
||||||
var dcDevices = r.DcDc.Devices;
|
var dcDevices = r.DcDc.Devices;
|
||||||
var configFile = r.Config;
|
var configFile = r.Config;
|
||||||
var devicesConfig = r.AcDc.Devices.All(d => d.Control.Ac.GridType == GridType.GridTied400V50Hz) ? configFile.GridTie : configFile.IslandMode; // TODO if any of the grid tie mode
|
|
||||||
|
|
||||||
Double maxBatteryChargingCurrentLive ; //used with deligreenBattery for limiting charging
|
|
||||||
Double maxBatteryDischargingCurrentLive; //used with deligreenBattery for limiting discharging
|
|
||||||
|
|
||||||
|
|
||||||
//var maxBatteryDischargingCurrentLive = 0.0; //never used with deligreenBattery
|
//var maxBatteryDischargingCurrentLive = 0.0; //never used with deligreenBattery
|
||||||
|
var devicesConfig = r.AcDc.Devices.All(d => d.Control.Ac.GridType == GridType.GridTied400V50Hz) ? configFile.GridTie : configFile.IslandMode; // TODO if any of the grid tie mode
|
||||||
/*
|
/*
|
||||||
// This adapting the max discharging current to the current Active Strings
|
// This adapting the max discharging current to the current Active Strings
|
||||||
if (r.Battery != null)
|
if (r.Battery != null)
|
||||||
|
|
@ -523,27 +561,6 @@ internal static class Program
|
||||||
*/
|
*/
|
||||||
// TODO The discharging current is well calculated but not communicated to live. But Written in S3
|
// TODO The discharging current is well calculated but not communicated to live. But Written in S3
|
||||||
|
|
||||||
// Deligreen upper current limitation dynCCL
|
|
||||||
if (r.Battery?.Voltage != null && (r.Battery?.Voltage ?? 0) > 61.0 )
|
|
||||||
{
|
|
||||||
maxBatteryChargingCurrentLive = r.Battery.Devices.Count * 10; // Max charging current is 10 A * Number of batteries
|
|
||||||
maxBatteryChargingCurrentLive.WriteLine("dynCCL Active: Max Battery Charging is "+ maxBatteryChargingCurrentLive);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
maxBatteryChargingCurrentLive = devicesConfig.DcDc.MaxBatteryChargingCurrent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deligreen lower current limitation dynDCL
|
|
||||||
if (r.Battery?.Soc != null && (r.Battery?.Soc ?? 100) < r.Config.MinSoc )
|
|
||||||
{
|
|
||||||
maxBatteryDischargingCurrentLive = 0; // Max charging current is 10 A * Number of batteries
|
|
||||||
maxBatteryDischargingCurrentLive.WriteLine("dynDCL Active: Max Battery disCharging is "+ maxBatteryDischargingCurrentLive);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
maxBatteryDischargingCurrentLive = devicesConfig.DcDc.MaxBatteryDischargingCurrent;
|
|
||||||
}
|
|
||||||
|
|
||||||
inverters.ForEach(d => d.Control.Dc.MaxVoltage = devicesConfig.AcDc.MaxDcLinkVoltage);
|
inverters.ForEach(d => d.Control.Dc.MaxVoltage = devicesConfig.AcDc.MaxDcLinkVoltage);
|
||||||
inverters.ForEach(d => d.Control.Dc.MinVoltage = devicesConfig.AcDc.MinDcLinkVoltage);
|
inverters.ForEach(d => d.Control.Dc.MinVoltage = devicesConfig.AcDc.MinDcLinkVoltage);
|
||||||
|
|
@ -555,8 +572,8 @@ internal static class Program
|
||||||
dcDevices.ForEach(d => d.Control.DroopControl.LowerVoltage = devicesConfig.DcDc.LowerDcLinkVoltage);
|
dcDevices.ForEach(d => d.Control.DroopControl.LowerVoltage = devicesConfig.DcDc.LowerDcLinkVoltage);
|
||||||
dcDevices.ForEach(d => d.Control.DroopControl.ReferenceVoltage = devicesConfig.DcDc.ReferenceDcLinkVoltage);
|
dcDevices.ForEach(d => d.Control.DroopControl.ReferenceVoltage = devicesConfig.DcDc.ReferenceDcLinkVoltage);
|
||||||
|
|
||||||
dcDevices.ForEach(d => d.Control.CurrentControl.MaxBatteryChargingCurrent = maxBatteryChargingCurrentLive);
|
dcDevices.ForEach(d => d.Control.CurrentControl.MaxBatteryChargingCurrent = devicesConfig.DcDc.MaxBatteryChargingCurrent);
|
||||||
dcDevices.ForEach(d => d.Control.CurrentControl.MaxBatteryDischargingCurrent = maxBatteryDischargingCurrentLive);
|
dcDevices.ForEach(d => d.Control.CurrentControl.MaxBatteryDischargingCurrent = devicesConfig.DcDc.MaxBatteryDischargingCurrent);
|
||||||
dcDevices.ForEach(d => d.Control.MaxDcPower = devicesConfig.DcDc.MaxDcPower);
|
dcDevices.ForEach(d => d.Control.MaxDcPower = devicesConfig.DcDc.MaxDcPower);
|
||||||
|
|
||||||
dcDevices.ForEach(d => d.Control.VoltageLimits.MaxBatteryVoltage = devicesConfig.DcDc.MaxChargeBatteryVoltage);
|
dcDevices.ForEach(d => d.Control.VoltageLimits.MaxBatteryVoltage = devicesConfig.DcDc.MaxChargeBatteryVoltage);
|
||||||
|
|
@ -682,7 +699,7 @@ internal static class Program
|
||||||
}
|
}
|
||||||
|
|
||||||
// To test, most probably the curtailing flag will not work
|
// To test, most probably the curtailing flag will not work
|
||||||
/*private static void PerformLed(this StatusRecord record)
|
private static void PerformLed(this StatusRecord record)
|
||||||
{
|
{
|
||||||
if (record.StateMachine.State == 23)
|
if (record.StateMachine.State == 23)
|
||||||
{
|
{
|
||||||
|
|
@ -734,7 +751,7 @@ internal static class Program
|
||||||
{
|
{
|
||||||
record.Relays?.PerformFastFlashingRedLed();
|
record.Relays?.PerformFastFlashingRedLed();
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
private static Double IncreaseInverterUpperLimit(Double upperLimit, Double stepSize)
|
private static Double IncreaseInverterUpperLimit(Double upperLimit, Double stepSize)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,211 @@
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.SodiStoreMax.SaliMaxRelays;
|
||||||
|
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||||
|
|
||||||
|
public class CombinedAdamRelaysRecord : IRelaysRecord
|
||||||
|
{
|
||||||
|
private const UInt16 SlowFreq = 3000;
|
||||||
|
private const UInt16 HighFreq = 1000;
|
||||||
|
|
||||||
|
public CombinedAdamRelaysRecord(RelaysRecordAdam6060? relaysRecordAdam6060, RelaysRecordAdam6360D? relaysRecordAdam6360D)
|
||||||
|
{
|
||||||
|
_recordAdam6060 = relaysRecordAdam6060;
|
||||||
|
_recordAdam6360D = relaysRecordAdam6360D;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RelaysRecordAdam6060? _recordAdam6060;
|
||||||
|
private static RelaysRecordAdam6360D? _recordAdam6360D;
|
||||||
|
|
||||||
|
public static IRelaysRecord Instance { get; } = new CombinedAdamRelaysRecord(_recordAdam6060, _recordAdam6360D);
|
||||||
|
|
||||||
|
|
||||||
|
public Boolean K1GridBusIsConnectedToGrid => _recordAdam6360D.K1GridBusIsConnectedToGrid;
|
||||||
|
|
||||||
|
public Boolean K2IslandBusIsConnectedToGridBus => _recordAdam6360D.K2IslandBusIsConnectedToGridBus;
|
||||||
|
public Boolean FiWarning => _recordAdam6360D.FiWarning;
|
||||||
|
public Boolean FiError => _recordAdam6360D.FiError;
|
||||||
|
public Boolean K2ConnectIslandBusToGridBus
|
||||||
|
{
|
||||||
|
get => _recordAdam6360D.K2ConnectIslandBusToGridBus;
|
||||||
|
set => _recordAdam6360D.K2ConnectIslandBusToGridBus = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean Inverter1WagoStatus => _recordAdam6360D.Inverter1WagoStatus;
|
||||||
|
public Boolean Inverter2WagoStatus => _recordAdam6360D.Inverter2WagoStatus;
|
||||||
|
public Boolean Inverter3WagoStatus => _recordAdam6360D.Inverter3WagoStatus;
|
||||||
|
public Boolean Inverter4WagoStatus => _recordAdam6360D.Inverter4WagoStatus;
|
||||||
|
|
||||||
|
public Boolean Dc1WagoStatus => _recordAdam6060.Dc1WagoStatus;
|
||||||
|
public Boolean Dc2WagoStatus => _recordAdam6060.Dc2WagoStatus;
|
||||||
|
public Boolean Dc3WagoStatus => _recordAdam6060.Dc3WagoStatus;
|
||||||
|
public Boolean Dc4WagoStatus => _recordAdam6060.Dc4WagoStatus;
|
||||||
|
public Boolean DcSystemControlWagoStatus => _recordAdam6060.DcSystemControlWagoStatus;
|
||||||
|
|
||||||
|
public Boolean LedGreen { get => _recordAdam6360D.LedGreen; set => _recordAdam6360D.LedGreen = value;}
|
||||||
|
public Boolean LedRed { get => _recordAdam6360D.LedRed; set => _recordAdam6360D.LedRed = value;}
|
||||||
|
public Boolean Harvester1Step => _recordAdam6360D.Harvester1Step;
|
||||||
|
public Boolean Harvester2Step => _recordAdam6360D.Harvester2Step;
|
||||||
|
public Boolean Harvester3Step => _recordAdam6360D.Harvester3Step;
|
||||||
|
public Boolean Harvester4Step => _recordAdam6360D.Harvester4Step;
|
||||||
|
|
||||||
|
public UInt16 DigitalOutput0Mode { get => _recordAdam6360D.DigitalOutput0Mode; set => _recordAdam6360D.DigitalOutput0Mode = value; }
|
||||||
|
|
||||||
|
public UInt16 DigitalOutput1Mode
|
||||||
|
{
|
||||||
|
get => _recordAdam6360D.DigitalOutput1Mode;
|
||||||
|
set => _recordAdam6360D.DigitalOutput1Mode = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt16 DigitalOutput2Mode
|
||||||
|
{
|
||||||
|
get => _recordAdam6360D.DigitalOutput2Mode;
|
||||||
|
set => _recordAdam6360D.DigitalOutput2Mode = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt16 DigitalOutput3Mode
|
||||||
|
{
|
||||||
|
get => _recordAdam6360D.DigitalOutput3Mode;
|
||||||
|
set => _recordAdam6360D.DigitalOutput3Mode = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt16 DigitalOutput4Mode
|
||||||
|
{
|
||||||
|
get => _recordAdam6360D.DigitalOutput4Mode;
|
||||||
|
set => _recordAdam6360D.DigitalOutput4Mode = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UInt16 DigitalOutput5Mode
|
||||||
|
{
|
||||||
|
get => _recordAdam6360D.DigitalOutput5Mode;
|
||||||
|
set => _recordAdam6360D.DigitalOutput5Mode = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean Do0StartPulse { get => _recordAdam6360D.Do0Pulse; set => _recordAdam6360D.Do0Pulse = value; }
|
||||||
|
public Boolean Do1StartPulse { get => _recordAdam6360D.Do1Pulse; set => _recordAdam6360D.Do1Pulse = value; }
|
||||||
|
public Boolean Do2StartPulse { get => _recordAdam6360D.Do2Pulse; set => _recordAdam6360D.Do2Pulse = value; }
|
||||||
|
public Boolean Do3StartPulse { get => _recordAdam6360D.Do3Pulse; set => _recordAdam6360D.Do3Pulse = value; }
|
||||||
|
public Boolean Do4StartPulse { get => _recordAdam6360D.Do4Pulse; set => _recordAdam6360D.Do4Pulse = value; }
|
||||||
|
public Boolean Do5StartPulse { get => _recordAdam6360D.Do5Pulse; set => _recordAdam6360D.Do5Pulse = value; }
|
||||||
|
|
||||||
|
|
||||||
|
public UInt16 PulseOut0LowTime { get => _recordAdam6360D.PulseOut0LowTime; set => _recordAdam6360D.PulseOut0LowTime = value; }
|
||||||
|
public UInt16 PulseOut1LowTime { get => _recordAdam6360D.PulseOut1LowTime; set => _recordAdam6360D.PulseOut1LowTime = value; }
|
||||||
|
public UInt16 PulseOut2LowTime { get => _recordAdam6360D.PulseOut2LowTime; set => _recordAdam6360D.PulseOut2LowTime = value; }
|
||||||
|
public UInt16 PulseOut3LowTime { get => _recordAdam6360D.PulseOut3LowTime; set => _recordAdam6360D.PulseOut3LowTime = value; }
|
||||||
|
public UInt16 PulseOut4LowTime { get => _recordAdam6360D.PulseOut4LowTime; set => _recordAdam6360D.PulseOut4LowTime = value; }
|
||||||
|
public UInt16 PulseOut5LowTime { get => _recordAdam6360D.PulseOut5LowTime; set => _recordAdam6360D.PulseOut5LowTime = value; }
|
||||||
|
|
||||||
|
public UInt16 PulseOut0HighTime { get => _recordAdam6360D.PulseOut0HighTime; set => _recordAdam6360D.PulseOut0HighTime = value; }
|
||||||
|
public UInt16 PulseOut1HighTime { get => _recordAdam6360D.PulseOut1HighTime; set => _recordAdam6360D.PulseOut1HighTime = value; }
|
||||||
|
public UInt16 PulseOut2HighTime { get => _recordAdam6360D.PulseOut2HighTime; set => _recordAdam6360D.PulseOut2HighTime = value; }
|
||||||
|
public UInt16 PulseOut3HighTime { get => _recordAdam6360D.PulseOut3HighTime; set => _recordAdam6360D.PulseOut3HighTime = value; }
|
||||||
|
public UInt16 PulseOut4HighTime { get => _recordAdam6360D.PulseOut4HighTime; set => _recordAdam6360D.PulseOut4HighTime = value; }
|
||||||
|
public UInt16 PulseOut5HighTime { get => _recordAdam6360D.PulseOut5HighTime; set => _recordAdam6360D.PulseOut5HighTime = value; }
|
||||||
|
|
||||||
|
/**************************** Green LED *********************************/
|
||||||
|
|
||||||
|
public void PerformSolidGreenLed()
|
||||||
|
{
|
||||||
|
DigitalOutput0Mode = 0;
|
||||||
|
DigitalOutput1Mode = 0;
|
||||||
|
LedGreen = true;
|
||||||
|
LedRed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformSlowFlashingGreenLed()
|
||||||
|
{
|
||||||
|
PulseOut0HighTime = SlowFreq;
|
||||||
|
PulseOut0LowTime = SlowFreq;
|
||||||
|
DigitalOutput0Mode = 2;
|
||||||
|
Do0StartPulse = true;
|
||||||
|
Do1StartPulse = false; // make sure the red LED is off
|
||||||
|
|
||||||
|
Console.WriteLine("Green Slow Flashing Starting");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformFastFlashingGreenLed()
|
||||||
|
{
|
||||||
|
PulseOut0HighTime = HighFreq;
|
||||||
|
PulseOut0LowTime = HighFreq;
|
||||||
|
DigitalOutput0Mode = 2;
|
||||||
|
Do0StartPulse = true;
|
||||||
|
Do1StartPulse = false;// make sure the red LED is off
|
||||||
|
|
||||||
|
Console.WriteLine("Green Slow Flashing Starting");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************** Orange LED *********************************/
|
||||||
|
|
||||||
|
public void PerformSolidOrangeLed()
|
||||||
|
{
|
||||||
|
DigitalOutput0Mode = 0;
|
||||||
|
DigitalOutput1Mode = 0;
|
||||||
|
LedGreen = true;
|
||||||
|
LedRed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformSlowFlashingOrangeLed()
|
||||||
|
{
|
||||||
|
PerformSlowFlashingGreenLed();
|
||||||
|
PerformSlowFlashingRedLed();
|
||||||
|
Do0StartPulse = true;
|
||||||
|
Do1StartPulse = true;
|
||||||
|
|
||||||
|
Console.WriteLine("Orange Slow Flashing Starting");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformFastFlashingOrangeLed()
|
||||||
|
{
|
||||||
|
PerformFastFlashingGreenLed();
|
||||||
|
PerformFastFlashingRedLed();
|
||||||
|
Do0StartPulse = true;
|
||||||
|
Do1StartPulse = true;
|
||||||
|
Console.WriteLine("Orange Fast Flashing Starting");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************** RED LED *********************************/
|
||||||
|
|
||||||
|
public void PerformSolidRedLed()
|
||||||
|
{
|
||||||
|
DigitalOutput0Mode = 0;
|
||||||
|
DigitalOutput1Mode = 0;
|
||||||
|
LedGreen = false;
|
||||||
|
LedRed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformSlowFlashingRedLed()
|
||||||
|
{
|
||||||
|
PulseOut1HighTime = SlowFreq;
|
||||||
|
PulseOut1LowTime = SlowFreq;
|
||||||
|
DigitalOutput1Mode = 2;
|
||||||
|
Do0StartPulse = false; // make sure the green LED is off
|
||||||
|
Do1StartPulse = true;
|
||||||
|
|
||||||
|
Console.WriteLine("Red Slow Flashing Starting");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformFastFlashingRedLed()
|
||||||
|
{
|
||||||
|
PulseOut1HighTime = HighFreq;
|
||||||
|
PulseOut1LowTime = HighFreq;
|
||||||
|
DigitalOutput1Mode = 2;
|
||||||
|
Do0StartPulse = false; // make sure the green LED is off
|
||||||
|
Do1StartPulse = true;
|
||||||
|
|
||||||
|
Console.WriteLine("Red Fast Flashing Starting");
|
||||||
|
}
|
||||||
|
|
||||||
|
public RelaysRecordAdam6360D? GetAdam6360DRecord()
|
||||||
|
{
|
||||||
|
return _recordAdam6360D;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RelaysRecordAdam6060? GetAdam6060Record()
|
||||||
|
{
|
||||||
|
return _recordAdam6060;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Boolean> K3InverterIsConnectedToIslandBus => _recordAdam6360D.K3InverterIsConnectedToIslandBus;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
namespace InnovEnergy.App.SodiStoreMax.SaliMaxRelays;
|
||||||
|
|
||||||
|
|
||||||
|
public interface IRelaysRecord
|
||||||
|
{
|
||||||
|
Boolean K1GridBusIsConnectedToGrid { get; }
|
||||||
|
Boolean K2IslandBusIsConnectedToGridBus { get; }
|
||||||
|
IEnumerable<Boolean> K3InverterIsConnectedToIslandBus { get; }
|
||||||
|
Boolean FiWarning { get; }
|
||||||
|
Boolean FiError { get; }
|
||||||
|
Boolean K2ConnectIslandBusToGridBus { get; set; }
|
||||||
|
|
||||||
|
// Boolean Inverter1WagoRelay { get; set; } // to add in the future
|
||||||
|
// Boolean Inverter2WagoRelay { get; set; } // to add in the future
|
||||||
|
// Boolean Inverter3WagoRelay { get; set; } // to add in the future
|
||||||
|
// Boolean Inverter4WagoRelay { get; set; } // to add in the future
|
||||||
|
|
||||||
|
Boolean Inverter1WagoStatus { get; }
|
||||||
|
Boolean Inverter2WagoStatus { get; }
|
||||||
|
Boolean Inverter3WagoStatus { get; }
|
||||||
|
Boolean Inverter4WagoStatus { get; }
|
||||||
|
|
||||||
|
Boolean Dc1WagoStatus { get; } // to test
|
||||||
|
Boolean Dc2WagoStatus { get; } // to test
|
||||||
|
Boolean Dc3WagoStatus { get; } // to test
|
||||||
|
Boolean Dc4WagoStatus { get; } // to test
|
||||||
|
|
||||||
|
Boolean DcSystemControlWagoStatus { get; } // to test
|
||||||
|
|
||||||
|
Boolean LedGreen { get; set; }
|
||||||
|
Boolean LedRed { get; }
|
||||||
|
Boolean Harvester1Step { get; }
|
||||||
|
Boolean Harvester2Step { get; }
|
||||||
|
Boolean Harvester3Step { get; }
|
||||||
|
Boolean Harvester4Step { get; }
|
||||||
|
|
||||||
|
Boolean Do0StartPulse { get; set; }
|
||||||
|
Boolean Do1StartPulse { get; set; }
|
||||||
|
Boolean Do2StartPulse { get; set; }
|
||||||
|
Boolean Do3StartPulse { get; set; }
|
||||||
|
Boolean Do4StartPulse { get; set; }
|
||||||
|
Boolean Do5StartPulse { get; set; }
|
||||||
|
|
||||||
|
UInt16 DigitalOutput0Mode { get; set; }
|
||||||
|
UInt16 DigitalOutput1Mode { get; set; }
|
||||||
|
UInt16 DigitalOutput2Mode { get; set; }
|
||||||
|
UInt16 DigitalOutput3Mode { get; set; }
|
||||||
|
UInt16 DigitalOutput4Mode { get; set; }
|
||||||
|
UInt16 DigitalOutput5Mode { get; set; }
|
||||||
|
|
||||||
|
UInt16 PulseOut0LowTime { get; set; }
|
||||||
|
UInt16 PulseOut1LowTime { get; set; }
|
||||||
|
UInt16 PulseOut2LowTime { get; set; }
|
||||||
|
UInt16 PulseOut3LowTime { get; set; }
|
||||||
|
UInt16 PulseOut4LowTime { get; set; }
|
||||||
|
UInt16 PulseOut5LowTime { get; set; }
|
||||||
|
|
||||||
|
UInt16 PulseOut0HighTime { get; set; }
|
||||||
|
UInt16 PulseOut1HighTime { get; set; }
|
||||||
|
UInt16 PulseOut2HighTime { get; set; }
|
||||||
|
UInt16 PulseOut3HighTime { get; set; }
|
||||||
|
UInt16 PulseOut4HighTime { get; set; }
|
||||||
|
UInt16 PulseOut5HighTime { get; set; }
|
||||||
|
|
||||||
|
void PerformSolidGreenLed();
|
||||||
|
void PerformSlowFlashingGreenLed();
|
||||||
|
void PerformFastFlashingGreenLed();
|
||||||
|
|
||||||
|
|
||||||
|
void PerformSolidOrangeLed();
|
||||||
|
void PerformSlowFlashingOrangeLed();
|
||||||
|
void PerformFastFlashingOrangeLed();
|
||||||
|
|
||||||
|
void PerformSolidRedLed();
|
||||||
|
void PerformSlowFlashingRedLed();
|
||||||
|
void PerformFastFlashingRedLed();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
using InnovEnergy.Lib.Devices.Adam6360D;
|
|
||||||
using InnovEnergy.Lib.Devices.Amax5070;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SodiStoreMax.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
|
|
||||||
{
|
|
||||||
return AdamDevice.Read();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
$"Failed to read from {nameof(RelaysDevice)}\n{e}".LogError();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(RelaysRecord r)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AdamDevice.Write(r);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
$"Failed to write to {nameof(RelaysDevice)}\n{e}".LogError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
using InnovEnergy.Lib.Devices.Adam6360D;
|
||||||
|
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.SodiStoreMax.SaliMaxRelays;
|
||||||
|
|
||||||
|
public class RelaysDeviceAdam6360
|
||||||
|
{
|
||||||
|
private Adam6360DDevice AdamDevice6360D { get; }
|
||||||
|
|
||||||
|
public RelaysDeviceAdam6360(String hostname) => AdamDevice6360D = new Adam6360DDevice(hostname, 2);
|
||||||
|
public RelaysDeviceAdam6360(Channel channel) => AdamDevice6360D = new Adam6360DDevice(channel, 2);
|
||||||
|
|
||||||
|
|
||||||
|
public RelaysRecordAdam6360D? Read()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return AdamDevice6360D.Read();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
$"Failed to read from {nameof(RelaysDeviceAdam6360)}\n{e}".LogError();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(RelaysRecordAdam6360D r)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AdamDevice6360D.Write(r);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
$"Failed to write to {nameof(RelaysDeviceAdam6360)}\n{e}".LogError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
using InnovEnergy.Lib.Devices.Adam6060;
|
||||||
|
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.SodiStoreMax.SaliMaxRelays;
|
||||||
|
|
||||||
|
public class RelaysDeviceAdam6060
|
||||||
|
{
|
||||||
|
private Adam6060Device AdamDevice6060 { get; }
|
||||||
|
|
||||||
|
public RelaysDeviceAdam6060(String hostname) => AdamDevice6060 = new Adam6060Device(hostname, 2);
|
||||||
|
public RelaysDeviceAdam6060(Channel channel) => AdamDevice6060 = new Adam6060Device(channel, 2);
|
||||||
|
|
||||||
|
|
||||||
|
public RelaysRecordAdam6060? Read()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return AdamDevice6060.Read();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
$"Failed to read from {nameof(RelaysDeviceAdam6060)}\n{e}".LogError();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(RelaysRecordAdam6060 r)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AdamDevice6060.Write(r);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
$"Failed to write to {nameof(RelaysDeviceAdam6060)}\n{e}".LogError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using InnovEnergy.Lib.Devices.Amax5070;
|
using InnovEnergy.Lib.Devices.Amax5070;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||||
using InnovEnergy.Lib.Utils;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.DeligreenBatteryCommunication;
|
|
||||||
|
namespace InnovEnergy.App.SodiStoreMax.SaliMaxRelays;
|
||||||
|
|
||||||
public class RelaysDeviceAmax
|
public class RelaysDeviceAmax
|
||||||
{
|
{
|
||||||
|
|
@ -12,14 +12,13 @@ public class RelaysDeviceAmax
|
||||||
|
|
||||||
public RelaysRecordAmax? Read()
|
public RelaysRecordAmax? Read()
|
||||||
{
|
{
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return AmaxDevice.Read();
|
return AmaxDevice.Read();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
$"Failed to read from {nameof(RelaysDeviceAmax)}\n{e}".WriteLine();
|
$"Failed to read from {nameof(RelaysDeviceAmax)}\n{e}".LogError();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -32,7 +31,7 @@ public class RelaysDeviceAmax
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
$"Failed to write to {nameof(RelaysDeviceAmax)}\n{e}".WriteLine();
|
$"Failed to write to {nameof(RelaysDeviceAmax)}\n{e}".LogError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
using InnovEnergy.Lib.Devices.Adam6360D;
|
|
||||||
using InnovEnergy.Lib.Devices.Amax5070;
|
|
||||||
namespace InnovEnergy.App.SodiStoreMax.SaliMaxRelays;
|
|
||||||
|
|
||||||
public interface IRelaysRecord
|
|
||||||
{
|
|
||||||
Boolean K1GridBusIsConnectedToGrid { get; }
|
|
||||||
Boolean K2IslandBusIsConnectedToGridBus { get; }
|
|
||||||
IEnumerable<Boolean> K3InverterIsConnectedToIslandBus { get; }
|
|
||||||
Boolean FiWarning { get; }
|
|
||||||
Boolean FiError { get; }
|
|
||||||
Boolean K2ConnectIslandBusToGridBus { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RelaysRecord : IRelaysRecord
|
|
||||||
{
|
|
||||||
private readonly Adam6360DRegisters _Regs;
|
|
||||||
|
|
||||||
private RelaysRecord(Adam6360DRegisters regs) => _Regs = regs;
|
|
||||||
|
|
||||||
public Boolean K1GridBusIsConnectedToGrid => _Regs.DigitalInput6;
|
|
||||||
public Boolean K2IslandBusIsConnectedToGridBus => !_Regs.DigitalInput4;
|
|
||||||
|
|
||||||
public IEnumerable<Boolean> K3InverterIsConnectedToIslandBus
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
yield return K3Inverter1IsConnectedToIslandBus;
|
|
||||||
yield return K3Inverter2IsConnectedToIslandBus;
|
|
||||||
yield return K3Inverter3IsConnectedToIslandBus;
|
|
||||||
yield return K3Inverter4IsConnectedToIslandBus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean K3Inverter1IsConnectedToIslandBus => !_Regs.DigitalInput0;
|
|
||||||
public Boolean K3Inverter2IsConnectedToIslandBus => !_Regs.DigitalInput1;
|
|
||||||
public Boolean K3Inverter3IsConnectedToIslandBus => !_Regs.DigitalInput2;
|
|
||||||
public Boolean K3Inverter4IsConnectedToIslandBus => !_Regs.DigitalInput3;
|
|
||||||
|
|
||||||
public Boolean FiWarning => !_Regs.DigitalInput5;
|
|
||||||
public Boolean FiError => !_Regs.DigitalInput7;
|
|
||||||
|
|
||||||
public Boolean K2ConnectIslandBusToGridBus { get => _Regs.Relay0; set => _Regs.Relay0 = value;}
|
|
||||||
|
|
||||||
public static implicit operator Adam6360DRegisters(RelaysRecord d) => d._Regs;
|
|
||||||
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<Boolean> 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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
using InnovEnergy.Lib.Devices.Adam6060;
|
||||||
|
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.SodiStoreMax.SaliMaxRelays;
|
||||||
|
|
||||||
|
public class RelaysRecordAdam6060
|
||||||
|
{
|
||||||
|
private readonly Adam6060Registers _Regs;
|
||||||
|
|
||||||
|
private RelaysRecordAdam6060(Adam6060Registers regs) => _Regs = regs;
|
||||||
|
|
||||||
|
|
||||||
|
public Boolean Dc1WagoStatus => _Regs.DigitalInput0; // to test
|
||||||
|
public Boolean Dc2WagoStatus => _Regs.DigitalInput1; // to test
|
||||||
|
public Boolean Dc3WagoStatus => _Regs.DigitalInput4; // to test
|
||||||
|
public Boolean Dc4WagoStatus => _Regs.DigitalInput5; // to test
|
||||||
|
|
||||||
|
public Boolean DcSystemControlWagoStatus => _Regs.DigitalInput3; // to test
|
||||||
|
|
||||||
|
|
||||||
|
public static implicit operator Adam6060Registers(RelaysRecordAdam6060 d) => d._Regs;
|
||||||
|
public static implicit operator RelaysRecordAdam6060(Adam6060Registers d) => new RelaysRecordAdam6060(d);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
using InnovEnergy.Lib.Devices.Adam6360D;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.SodiStoreMax.SaliMaxRelays;
|
||||||
|
|
||||||
|
public class RelaysRecordAdam6360D
|
||||||
|
{
|
||||||
|
private readonly Adam6360DRegisters _Regs;
|
||||||
|
|
||||||
|
private RelaysRecordAdam6360D(Adam6360DRegisters regs) => _Regs = regs;
|
||||||
|
|
||||||
|
public Boolean K1GridBusIsConnectedToGrid => _Regs.DigitalInput6;
|
||||||
|
public Boolean K2IslandBusIsConnectedToGridBus => !_Regs.DigitalInput4;
|
||||||
|
|
||||||
|
public Boolean Inverter1WagoStatus => _Regs.DigitalInput8;
|
||||||
|
public Boolean Inverter2WagoStatus => _Regs.DigitalInput9;
|
||||||
|
public Boolean Inverter3WagoStatus => _Regs.DigitalInput10;
|
||||||
|
public Boolean Inverter4WagoStatus => _Regs.DigitalInput11;
|
||||||
|
|
||||||
|
public IEnumerable<Boolean> K3InverterIsConnectedToIslandBus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return K3Inverter1IsConnectedToIslandBus;
|
||||||
|
yield return K3Inverter2IsConnectedToIslandBus;
|
||||||
|
yield return K3Inverter3IsConnectedToIslandBus;
|
||||||
|
yield return K3Inverter4IsConnectedToIslandBus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean K3Inverter1IsConnectedToIslandBus => !_Regs.DigitalInput0; // change it to private should be ok
|
||||||
|
private Boolean K3Inverter2IsConnectedToIslandBus => !_Regs.DigitalInput1;
|
||||||
|
private Boolean K3Inverter3IsConnectedToIslandBus => !_Regs.DigitalInput2;
|
||||||
|
private Boolean K3Inverter4IsConnectedToIslandBus => !_Regs.DigitalInput3;
|
||||||
|
|
||||||
|
public Boolean FiWarning => !_Regs.DigitalInput5;
|
||||||
|
public Boolean FiError => !_Regs.DigitalInput7;
|
||||||
|
|
||||||
|
public Boolean Harvester1Step =>_Regs.DigitalOutput2;
|
||||||
|
public Boolean Harvester2Step =>_Regs.DigitalOutput3;
|
||||||
|
public Boolean Harvester3Step =>_Regs.DigitalOutput4;
|
||||||
|
public Boolean Harvester4Step =>_Regs.DigitalOutput5;
|
||||||
|
|
||||||
|
public Boolean LedGreen { get =>_Regs.DigitalOutput0; set => _Regs.DigitalOutput0 = value;}
|
||||||
|
public Boolean LedRed { get =>_Regs.DigitalOutput1; set => _Regs.DigitalOutput1 = value;}
|
||||||
|
|
||||||
|
public Boolean Do0Pulse { get => _Regs.Do0Pulse; set => _Regs.Do0Pulse = value;}
|
||||||
|
public Boolean Do1Pulse { get => _Regs.Do1Pulse; set => _Regs.Do1Pulse = value;}
|
||||||
|
public Boolean Do2Pulse { get => _Regs.Do2Pulse; set => _Regs.Do2Pulse = value;}
|
||||||
|
public Boolean Do3Pulse { get => _Regs.Do3Pulse; set => _Regs.Do3Pulse = value;}
|
||||||
|
public Boolean Do4Pulse { get => _Regs.Do4Pulse; set => _Regs.Do4Pulse = value;}
|
||||||
|
public Boolean Do5Pulse { get => _Regs.Do5Pulse; set => _Regs.Do5Pulse = value;}
|
||||||
|
|
||||||
|
public UInt16 PulseOut0LowTime { get => _Regs.PulseOut0LowTime; set => _Regs.PulseOut0LowTime = value;} //in milleseconds
|
||||||
|
public UInt16 PulseOut1LowTime { get => _Regs.PulseOut1LowTime; set => _Regs.PulseOut1LowTime = value;}
|
||||||
|
public UInt16 PulseOut2LowTime { get => _Regs.PulseOut2LowTime; set => _Regs.PulseOut2LowTime = value;}
|
||||||
|
public UInt16 PulseOut3LowTime { get => _Regs.PulseOut3LowTime; set => _Regs.PulseOut3LowTime = value;}
|
||||||
|
public UInt16 PulseOut4LowTime { get => _Regs.PulseOut4LowTime; set => _Regs.PulseOut4LowTime = value;}
|
||||||
|
public UInt16 PulseOut5LowTime { get => _Regs.PulseOut5LowTime; set => _Regs.PulseOut5LowTime = value;}
|
||||||
|
|
||||||
|
public UInt16 PulseOut0HighTime { get => _Regs.PulseOut0HighTime; set => _Regs.PulseOut0HighTime = value;} // in milleseconds
|
||||||
|
public UInt16 PulseOut1HighTime { get => _Regs.PulseOut1HighTime; set => _Regs.PulseOut1HighTime = value;}
|
||||||
|
public UInt16 PulseOut2HighTime { get => _Regs.PulseOut2HighTime; set => _Regs.PulseOut2HighTime = value;}
|
||||||
|
public UInt16 PulseOut3HighTime { get => _Regs.PulseOut3HighTime; set => _Regs.PulseOut3HighTime = value;}
|
||||||
|
public UInt16 PulseOut4HighTime { get => _Regs.PulseOut4HighTime; set => _Regs.PulseOut4HighTime = value;}
|
||||||
|
public UInt16 PulseOut5HighTime { get => _Regs.PulseOut5HighTime; set => _Regs.PulseOut5HighTime = value;}
|
||||||
|
|
||||||
|
public UInt16 DigitalOutput0Mode { get => _Regs.DigitalOutput0Mode; set => _Regs.DigitalOutput0Mode = value;} // To test: 0, 1 or 2
|
||||||
|
public UInt16 DigitalOutput1Mode { get => _Regs.DigitalOutput1Mode; set => _Regs.DigitalOutput1Mode = value;}
|
||||||
|
public UInt16 DigitalOutput2Mode { get => _Regs.DigitalOutput2Mode; set => _Regs.DigitalOutput2Mode = value;}
|
||||||
|
public UInt16 DigitalOutput3Mode { get => _Regs.DigitalOutput3Mode; set => _Regs.DigitalOutput3Mode = value;}
|
||||||
|
public UInt16 DigitalOutput4Mode { get => _Regs.DigitalOutput4Mode; set => _Regs.DigitalOutput4Mode = value;}
|
||||||
|
public UInt16 DigitalOutput5Mode { get => _Regs.DigitalOutput5Mode; set => _Regs.DigitalOutput5Mode = value;}
|
||||||
|
|
||||||
|
public Boolean K2ConnectIslandBusToGridBus { get => _Regs.Relay0; set => _Regs.Relay0 = value;}
|
||||||
|
|
||||||
|
public static implicit operator Adam6360DRegisters(RelaysRecordAdam6360D d) => d._Regs;
|
||||||
|
public static implicit operator RelaysRecordAdam6360D(Adam6360DRegisters d) => new RelaysRecordAdam6360D(d);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
using InnovEnergy.Lib.Devices.Amax5070;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.SodiStoreMax.SaliMaxRelays;
|
||||||
|
|
||||||
|
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 Boolean Inverter1WagoStatus => _Regs.DigitalInput0;
|
||||||
|
public Boolean Inverter2WagoStatus => _Regs.DigitalInput1;
|
||||||
|
public Boolean Inverter3WagoStatus => _Regs.DigitalInput2;
|
||||||
|
public Boolean Inverter4WagoStatus => _Regs.DigitalInput3;
|
||||||
|
|
||||||
|
public Boolean Dc1WagoStatus => _Regs.DigitalInput6;
|
||||||
|
public Boolean Dc2WagoStatus => _Regs.DigitalInput7;
|
||||||
|
public Boolean Dc3WagoStatus => _Regs.DigitalInput10;
|
||||||
|
public Boolean Dc4WagoStatus => _Regs.DigitalInput11;
|
||||||
|
public Boolean DcSystemControlWagoStatus => _Regs.DigitalInput9;
|
||||||
|
|
||||||
|
public Boolean LedGreen
|
||||||
|
{
|
||||||
|
get => _Regs.DigitalOutput0;
|
||||||
|
set => _Regs.DigitalOutput0 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean LedRed => _Regs.DigitalOutput1;
|
||||||
|
public Boolean Harvester1Step => _Regs.DigitalOutput2;
|
||||||
|
public Boolean Harvester2Step => _Regs.DigitalOutput3;
|
||||||
|
public Boolean Harvester3Step => _Regs.DigitalOutput4;
|
||||||
|
public Boolean Harvester4Step => _Regs.DigitalOutput5;
|
||||||
|
public Boolean Do0StartPulse { get; set; }
|
||||||
|
public Boolean Do1StartPulse { get; set; }
|
||||||
|
public Boolean Do2StartPulse { get; set; }
|
||||||
|
public Boolean Do3StartPulse { get; set; }
|
||||||
|
public Boolean Do4StartPulse { get; set; }
|
||||||
|
public Boolean Do5StartPulse { get; set; }
|
||||||
|
public UInt16 DigitalOutput0Mode { get; set; }
|
||||||
|
public UInt16 DigitalOutput1Mode { get; set; }
|
||||||
|
public UInt16 DigitalOutput2Mode { get; set; }
|
||||||
|
public UInt16 DigitalOutput3Mode { get; set; }
|
||||||
|
public UInt16 DigitalOutput4Mode { get; set; }
|
||||||
|
public UInt16 DigitalOutput5Mode { get; set; }
|
||||||
|
public UInt16 PulseOut0LowTime { get; set; }
|
||||||
|
public UInt16 PulseOut1LowTime { get; set; }
|
||||||
|
public UInt16 PulseOut2LowTime { get; set; }
|
||||||
|
public UInt16 PulseOut3LowTime { get; set; }
|
||||||
|
public UInt16 PulseOut4LowTime { get; set; }
|
||||||
|
public UInt16 PulseOut5LowTime { get; set; }
|
||||||
|
public UInt16 PulseOut0HighTime { get; set; }
|
||||||
|
public UInt16 PulseOut1HighTime { get; set; }
|
||||||
|
public UInt16 PulseOut2HighTime { get; set; }
|
||||||
|
public UInt16 PulseOut3HighTime { get; set; }
|
||||||
|
public UInt16 PulseOut4HighTime { get; set; }
|
||||||
|
public UInt16 PulseOut5HighTime { get; set; }
|
||||||
|
|
||||||
|
public void PerformSolidGreenLed()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Solid Green: This is not yet implemented ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformSlowFlashingGreenLed()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Slow Flashing Green: This is not yet implemented ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformFastFlashingGreenLed()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Fast Flashing Green: This is not yet implemented ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformSolidOrangeLed()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Solid Orange: This is not yet implemented ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformSlowFlashingOrangeLed()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Slow Flashing Orange: This is not yet implemented ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformFastFlashingOrangeLed()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Fast Flashing Orange: This is not yet implemented ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformSolidRedLed()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Solid Red: This is not yet implemented ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformSlowFlashingRedLed()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Slow Flashing Red: This is not yet implemented ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PerformFastFlashingRedLed()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Fast Flashing Red: This is not yet implemented ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Boolean> K3InverterIsConnectedToIslandBus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return K3Inverter1IsConnectedToIslandBus;
|
||||||
|
yield return K3Inverter2IsConnectedToIslandBus;
|
||||||
|
yield return K3Inverter3IsConnectedToIslandBus;
|
||||||
|
yield return K3Inverter4IsConnectedToIslandBus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean K3Inverter1IsConnectedToIslandBus => !_Regs.DigitalInput16;
|
||||||
|
private Boolean K3Inverter2IsConnectedToIslandBus => !_Regs.DigitalInput17;
|
||||||
|
private Boolean K3Inverter3IsConnectedToIslandBus => !_Regs.DigitalInput18;
|
||||||
|
private 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -569,8 +569,7 @@ public static class Controller
|
||||||
private static Boolean State103(StatusRecord s)
|
private static Boolean State103(StatusRecord s)
|
||||||
{
|
{
|
||||||
s.StateMachine.Message = "Panic: ACDCs have unequal grid types or PowerStage";
|
s.StateMachine.Message = "Panic: ACDCs have unequal grid types or PowerStage";
|
||||||
s.AcDc.Enable();
|
return s.EnableSafeDefaults();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static Boolean State104(StatusRecord s)
|
// private static Boolean State104(StatusRecord s)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace InnovEnergy.Lib.Devices.Amax5070
|
||||||
[AddressOffset(-1)]
|
[AddressOffset(-1)]
|
||||||
public class Amax5070Registers
|
public class Amax5070Registers
|
||||||
{
|
{
|
||||||
[Coil(1)] public Boolean DigitalOutput0 { get; private set; }
|
[Coil(1)] public Boolean DigitalOutput0 { get; set; }
|
||||||
[Coil(2)] public Boolean DigitalOutput1 { get; private set; }
|
[Coil(2)] public Boolean DigitalOutput1 { get; private set; }
|
||||||
[Coil(3)] public Boolean DigitalOutput2 { get; private set; }
|
[Coil(3)] public Boolean DigitalOutput2 { get; private set; }
|
||||||
[Coil(4)] public Boolean DigitalOutput3 { get; private set; }
|
[Coil(4)] public Boolean DigitalOutput3 { get; private set; }
|
||||||
|
|
|
||||||
|
|
@ -27,161 +27,4 @@ public class AlarmMessage
|
||||||
LowVoltageAlarmForTotalVoltage,
|
LowVoltageAlarmForTotalVoltage,
|
||||||
UnderVoltageProtectionForTotalVoltage
|
UnderVoltageProtectionForTotalVoltage
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enum for Alarm Event 3
|
|
||||||
public enum AlarmEvent3
|
|
||||||
{
|
|
||||||
ChargeHighTemperatureAlarm,
|
|
||||||
ChargeOverTemperatureProtection,
|
|
||||||
ChargeLowTemperatureAlarm,
|
|
||||||
ChargeUnderTemperatureProtection,
|
|
||||||
DischargeHighTemperatureAlarm,
|
|
||||||
DischargeOverTemperatureProtection,
|
|
||||||
DischargeLowTemperatureAlarm,
|
|
||||||
DischargeUnderTemperatureProtection
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for Alarm Event 4
|
|
||||||
public enum AlarmEvent4
|
|
||||||
{
|
|
||||||
EnvironmentHighTemperatureAlarm,
|
|
||||||
EnvironmentOverTemperatureProtection,
|
|
||||||
EnvironmentLowTemperatureAlarm,
|
|
||||||
EnvironmentUnderTemperatureProtection,
|
|
||||||
PowerOverTemperatureProtection,
|
|
||||||
PowerHighTemperatureAlarm,
|
|
||||||
CellLowTemperatureHeating,
|
|
||||||
ReservationBit
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for Alarm Event 5
|
|
||||||
public enum AlarmEvent5
|
|
||||||
{
|
|
||||||
ChargeOverCurrentAlarm,
|
|
||||||
ChargeOverCurrentProtection,
|
|
||||||
DischargeOverCurrentAlarm,
|
|
||||||
DischargeOverCurrentProtection,
|
|
||||||
TransientOverCurrentProtection,
|
|
||||||
OutputShortCircuitProtection,
|
|
||||||
TransientOverCurrentLockout,
|
|
||||||
OutputShortCircuitLockout
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for Alarm Event 6
|
|
||||||
public enum AlarmEvent6
|
|
||||||
{
|
|
||||||
ChargeHighVoltageProtection,
|
|
||||||
IntermittentRechargeWaiting,
|
|
||||||
ResidualCapacityAlarm,
|
|
||||||
ResidualCapacityProtection,
|
|
||||||
CellLowVoltageChargingProhibition,
|
|
||||||
OutputReversePolarityProtection,
|
|
||||||
OutputConnectionFault,
|
|
||||||
InsideBit
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for On-Off State
|
|
||||||
public enum OnOffState
|
|
||||||
{
|
|
||||||
DischargeSwitchState,
|
|
||||||
ChargeSwitchState,
|
|
||||||
CurrentLimitSwitchState,
|
|
||||||
HeatingSwitchState,
|
|
||||||
ReservationBit1,
|
|
||||||
ReservationBit2,
|
|
||||||
ReservationBit3,
|
|
||||||
ReservationBit4
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for Equilibrium State 1
|
|
||||||
public enum EquilibriumState1
|
|
||||||
{
|
|
||||||
Cell01Equilibrium,
|
|
||||||
Cell02Equilibrium,
|
|
||||||
Cell03Equilibrium,
|
|
||||||
Cell04Equilibrium,
|
|
||||||
Cell05Equilibrium,
|
|
||||||
Cell06Equilibrium,
|
|
||||||
Cell07Equilibrium,
|
|
||||||
Cell08Equilibrium
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for Equilibrium State 2
|
|
||||||
public enum EquilibriumState2
|
|
||||||
{
|
|
||||||
Cell09Equilibrium,
|
|
||||||
Cell10Equilibrium,
|
|
||||||
Cell11Equilibrium,
|
|
||||||
Cell12Equilibrium,
|
|
||||||
Cell13Equilibrium,
|
|
||||||
Cell14Equilibrium,
|
|
||||||
Cell15Equilibrium,
|
|
||||||
Cell16Equilibrium
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for System State
|
|
||||||
public enum SystemState
|
|
||||||
{
|
|
||||||
Discharge,
|
|
||||||
Charge,
|
|
||||||
FloatingCharge,
|
|
||||||
ReservationBit1,
|
|
||||||
Standby,
|
|
||||||
Shutdown,
|
|
||||||
ReservationBit2,
|
|
||||||
ReservationBit3
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for Disconnection State 1
|
|
||||||
public enum DisconnectionState1
|
|
||||||
{
|
|
||||||
Cell01Disconnection,
|
|
||||||
Cell02Disconnection,
|
|
||||||
Cell03Disconnection,
|
|
||||||
Cell04Disconnection,
|
|
||||||
Cell05Disconnection,
|
|
||||||
Cell06Disconnection,
|
|
||||||
Cell07Disconnection,
|
|
||||||
Cell08Disconnection
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for Disconnection State 2
|
|
||||||
public enum DisconnectionState2
|
|
||||||
{
|
|
||||||
Cell09Disconnection,
|
|
||||||
Cell10Disconnection,
|
|
||||||
Cell11Disconnection,
|
|
||||||
Cell12Disconnection,
|
|
||||||
Cell13Disconnection,
|
|
||||||
Cell14Disconnection,
|
|
||||||
Cell15Disconnection,
|
|
||||||
Cell16Disconnection
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for Alarm Event 7
|
|
||||||
public enum AlarmEvent7
|
|
||||||
{
|
|
||||||
InsideBit1,
|
|
||||||
InsideBit2,
|
|
||||||
InsideBit3,
|
|
||||||
InsideBit4,
|
|
||||||
AutomaticChargingWaiting,
|
|
||||||
ManualChargingWaiting,
|
|
||||||
InsideBit5,
|
|
||||||
InsideBit6
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for Alarm Event 8
|
|
||||||
public enum AlarmEvent8
|
|
||||||
{
|
|
||||||
EepStorageFault,
|
|
||||||
RtcError,
|
|
||||||
VoltageCalibrationNotPerformed,
|
|
||||||
CurrentCalibrationNotPerformed,
|
|
||||||
ZeroCalibrationNotPerformed,
|
|
||||||
InsideBit1,
|
|
||||||
InsideBit2,
|
|
||||||
InsideBit3
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,26 @@
|
||||||
namespace InnovEnergy.Lib.Devices.BatteryDeligreen;
|
namespace InnovEnergy.Lib.Devices.BatteryDeligreen;
|
||||||
|
|
||||||
public class BatteryDeligreenAlarmRecord
|
public class BatteryDeligreenAlarmRecord
|
||||||
{
|
{/*
|
||||||
|
public String FwVersion { get; set; }
|
||||||
|
|
||||||
public List<String> CellAlarmList { get; set; }
|
public TemperaturesList TemperaturesList { get; set; }
|
||||||
public List<String> CellTemperatureAlarm { get; set; }
|
// public Dc_ Dc { get; set; }
|
||||||
public String EnviTempAlarm { get; set; }
|
|
||||||
public String PowerTempAlarm { get; set; }
|
|
||||||
public String CurrentAlarm { get; set; }
|
|
||||||
public String TotalVoltageAlarm { get; set; }
|
|
||||||
|
|
||||||
|
public BatteryDeligreenAlarmRecord(Voltage busVoltage, Current busCurrent ,String fwVersion, Percent soc, UInt16 numberOfCycles, Double batteryCapacity, Double ratedCapacity, Voltage totalBatteryVoltage, Percent soh, Double residualCapacity, List<Double> cellVoltage, TemperaturesList temperaturesList)
|
||||||
public BatteryDeligreenAlarmRecord( List<String> cellAlarmList, List<String> cellTemperatureAlarm, String enviTempAlarm1, String powerTempAlarm1, String currentAlarm1, String totalVoltageAlarm1)
|
|
||||||
{
|
{
|
||||||
CellAlarmList = cellAlarmList;
|
BusVoltage = busVoltage;
|
||||||
CellTemperatureAlarm = cellTemperatureAlarm;
|
BusCurrent = busCurrent;
|
||||||
EnviTempAlarm = enviTempAlarm1;
|
FwVersion = fwVersion;
|
||||||
PowerTempAlarm = powerTempAlarm1;
|
TotalBatteryVoltage = totalBatteryVoltage;
|
||||||
CurrentAlarm = currentAlarm1;
|
ResidualCapacity = residualCapacity;
|
||||||
TotalVoltageAlarm = totalVoltageAlarm1;
|
BatteryCapacity = batteryCapacity;
|
||||||
}
|
Soc = soc;
|
||||||
|
RatedCapacity = ratedCapacity;
|
||||||
|
NumberOfCycles = numberOfCycles;
|
||||||
|
Soh = soh;
|
||||||
|
CellVoltage = cellVoltage;
|
||||||
|
TemperaturesList = temperaturesList;
|
||||||
|
Power = busVoltage * busCurrent;
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
@ -4,10 +4,14 @@ using static InnovEnergy.Lib.Devices.BatteryDeligreen.Temperatures;
|
||||||
namespace InnovEnergy.Lib.Devices.BatteryDeligreen;
|
namespace InnovEnergy.Lib.Devices.BatteryDeligreen;
|
||||||
using InnovEnergy.Lib.Units;
|
using InnovEnergy.Lib.Units;
|
||||||
|
|
||||||
|
using Strings = IReadOnlyList<String>;
|
||||||
|
|
||||||
public class BatteryDeligreenDataRecord
|
public class BatteryDeligreenDataRecord
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// public Strings Warnings => ParseWarnings().OrderBy(w => w).ToList();
|
||||||
|
// public Strings Alarms => ParseAlarms() .OrderBy(w => w).ToList();
|
||||||
|
|
||||||
public String FwVersion { get; set; }
|
public String FwVersion { get; set; }
|
||||||
public Voltage BusVoltage { get; set; }
|
public Voltage BusVoltage { get; set; }
|
||||||
public Current BusCurrent { get; set; }
|
public Current BusCurrent { get; set; }
|
||||||
|
|
@ -21,6 +25,7 @@ public class BatteryDeligreenDataRecord
|
||||||
public Percent Soh { get; set; }
|
public Percent Soh { get; set; }
|
||||||
public List<Double> CellVoltage { get; set; }
|
public List<Double> CellVoltage { get; set; }
|
||||||
public TemperaturesList TemperaturesList { get; set; }
|
public TemperaturesList TemperaturesList { get; set; }
|
||||||
|
// public Dc_ Dc { get; set; }
|
||||||
|
|
||||||
public BatteryDeligreenDataRecord(Voltage busVoltage, Current busCurrent ,String fwVersion, Percent soc, UInt16 numberOfCycles, Double batteryCapacity, Double ratedCapacity, Voltage totalBatteryVoltage, Percent soh, Double residualCapacity, List<Double> cellVoltage, TemperaturesList temperaturesList)
|
public BatteryDeligreenDataRecord(Voltage busVoltage, Current busCurrent ,String fwVersion, Percent soc, UInt16 numberOfCycles, Double batteryCapacity, Double ratedCapacity, Voltage totalBatteryVoltage, Percent soh, Double residualCapacity, List<Double> cellVoltage, TemperaturesList temperaturesList)
|
||||||
{
|
{
|
||||||
|
|
@ -38,4 +43,12 @@ public class BatteryDeligreenDataRecord
|
||||||
TemperaturesList = temperaturesList;
|
TemperaturesList = temperaturesList;
|
||||||
Power = busVoltage * busCurrent;
|
Power = busVoltage * busCurrent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public struct Dc_
|
||||||
|
// {
|
||||||
|
// public Voltage Voltage => BusVoltage;
|
||||||
|
// public Current Current => BusCurrent;
|
||||||
|
// public ActivePower Power => BusVoltage * BusCurrent;
|
||||||
|
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +144,7 @@ public class BatteryDeligreenDevice
|
||||||
// Read telemetry data from the connected device
|
// Read telemetry data from the connected device
|
||||||
private async Task<BatteryDeligreenDataRecord?> ReadTelemetryData(UInt16 batteryId)
|
private async Task<BatteryDeligreenDataRecord?> ReadTelemetryData(UInt16 batteryId)
|
||||||
{
|
{
|
||||||
var frameToSend = batteryId switch
|
String frameToSend = batteryId switch
|
||||||
{
|
{
|
||||||
0 => "7E3230303034363432453030323030464433370D",
|
0 => "7E3230303034363432453030323030464433370D",
|
||||||
1 => "7E3230303134363432453030323031464433350D",
|
1 => "7E3230303134363432453030323031464433350D",
|
||||||
|
|
@ -199,7 +199,7 @@ public class BatteryDeligreenDevice
|
||||||
return Task.FromResult(responseBuffer.ToArray());
|
return Task.FromResult(responseBuffer.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<BatteryDeligreenAlarmRecord?> ReadTelecomandData(UInt16 batteryId)
|
private async Task<BatteryDeligreenAlarmRecord> ReadTelecomandData(UInt16 batteryId)
|
||||||
{
|
{
|
||||||
var frameToSend = batteryId switch
|
var frameToSend = batteryId switch
|
||||||
{
|
{
|
||||||
|
|
@ -219,14 +219,15 @@ public class BatteryDeligreenDevice
|
||||||
{
|
{
|
||||||
// Write the frame to the channel (send it to the device)
|
// Write the frame to the channel (send it to the device)
|
||||||
Write(frameToSend);
|
Write(frameToSend);
|
||||||
|
// await Task.Delay(delayFrame2);
|
||||||
// Read the response from the channel (assuming max response size)
|
// Read the response from the channel (assuming max response size)
|
||||||
var responseBytes = await ReadFullResponse(116, 64); // Assuming Read can be executed asynchronously
|
var responseBytes = await ReadFullResponse(116, 64); // Assuming Read can be executed asynchronously
|
||||||
|
|
||||||
// Convert the byte array to a hexadecimal string
|
// Convert the byte array to a hexadecimal string
|
||||||
var responseHex = BytesToHexString(responseBytes);
|
var responseHex = BytesToHexString(responseBytes);
|
||||||
|
|
||||||
return new TelecommandFrameParser().ParsingTelecommandFrame(responseHex);
|
var response = new TelecommandFrameParser().ParsingTelecommandFrame(responseHex);
|
||||||
|
|
||||||
|
return new BatteryDeligreenAlarmRecord();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -237,11 +238,11 @@ public class BatteryDeligreenDevice
|
||||||
|
|
||||||
public async Task<BatteryDeligreenRecord?> Reads()
|
public async Task<BatteryDeligreenRecord?> Reads()
|
||||||
{
|
{
|
||||||
var dataRecord = ReadTelemetryData(SlaveId).Result;
|
var dataRecord = ReadTelemetryData(SlaveId).Result;
|
||||||
var alarmRecord = ReadTelecomandData(SlaveId).Result;
|
var alarmRecord = ReadTelecomandData(SlaveId).Result;
|
||||||
await Task.Delay(5); // looks like this is need. A time delay needed between each frame to send to each battery
|
await Task.Delay(5); // looks like this is need. A time delay needed between each frame to send to each battery
|
||||||
|
|
||||||
return (dataRecord != null && alarmRecord != null ) ? new BatteryDeligreenRecord(dataRecord, alarmRecord) : null; // to check how this work if one of the record is null
|
return dataRecord != null ? new BatteryDeligreenRecord(dataRecord, alarmRecord) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String ConstructFrameToSend(UInt16 batteryId, String functionCode)
|
private static String ConstructFrameToSend(UInt16 batteryId, String functionCode)
|
||||||
|
|
@ -251,8 +252,9 @@ public class BatteryDeligreenDevice
|
||||||
var batteryIdHex = string.Concat(batteryIdAscii.Select(c => ((Int32)c).ToString("X2")));
|
var batteryIdHex = string.Concat(batteryIdAscii.Select(c => ((Int32)c).ToString("X2")));
|
||||||
Console.WriteLine("Battery ID " + batteryIdHex);
|
Console.WriteLine("Battery ID " + batteryIdHex);
|
||||||
|
|
||||||
var frameToSend = FrameStart + Version + batteryIdHex + DeviceCode + functionCode +
|
var frameToSend =
|
||||||
"453030323030464433370D"; // Example custom frame with dynamic batteryId
|
FrameStart + Version + batteryIdHex + DeviceCode + functionCode +
|
||||||
|
"453030323030464433370D"; // Example custom frame with dynamic batteryId
|
||||||
Console.WriteLine(frameToSend);
|
Console.WriteLine(frameToSend);
|
||||||
return frameToSend;
|
return frameToSend;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
import serial
|
||||||
|
|
||||||
|
def parse_start_code(frame):
|
||||||
|
soi = frame[0:2]
|
||||||
|
if soi == "~":
|
||||||
|
return "ok!"
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid start identifier! ({soi})")
|
||||||
|
|
||||||
|
def parse_version_code(frame):
|
||||||
|
ver = frame[2:6]
|
||||||
|
return f"Protocol Version V{ver[0]}.{ver[1]}"
|
||||||
|
|
||||||
|
def parse_address_code(frame):
|
||||||
|
adr = frame[6:10]
|
||||||
|
if 0 <= int(adr) <= 15:
|
||||||
|
return adr
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid address: {adr} (out of range 0-15)")
|
||||||
|
|
||||||
|
def parse_device_code(frame):
|
||||||
|
cid1 = frame[10:14]
|
||||||
|
return bms.CID1_DEVICE_CODES.get(cid1, "Unknown!")
|
||||||
|
|
||||||
|
def parse_function_code(frame):
|
||||||
|
cid2 = frame[14:18]
|
||||||
|
if cid2 in bms.CID2_COMMAND_CODES:
|
||||||
|
return f"Command -> {bms.CID2_COMMAND_CODES.get(cid2)}"
|
||||||
|
elif cid2 in bms.CID2_RETURN_CODES:
|
||||||
|
return f"Return -> {bms.CID2_RETURN_CODES.get(cid2)}"
|
||||||
|
else:
|
||||||
|
return f"Unknown CID2: {cid2}"
|
||||||
|
|
||||||
|
def parse_lchksum(length_code):
|
||||||
|
# implements chapter 3.2.2 of the Protocol Specification
|
||||||
|
lchksum = int(length_code[0], 16)
|
||||||
|
# Compute lchksum
|
||||||
|
d11d10d09d08 = int(length_code[1])
|
||||||
|
d07d06d05d04 = int(length_code[2])
|
||||||
|
d03d0ld01d00 = int(length_code[3])
|
||||||
|
sum = d11d10d09d08 + d07d06d05d04 + d03d0ld01d00
|
||||||
|
remainder = sum % 16
|
||||||
|
inverted = ~remainder & 0xF
|
||||||
|
computed_lchksum = (inverted + 1) & 0xF
|
||||||
|
if computed_lchksum == lchksum:
|
||||||
|
return "ok!"
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid LCHKSUM: {lchksum} (computed: {computed_lchksum})")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_lenid(length_code):
|
||||||
|
# implements chapter 3.2.1 of the Protocol Specification
|
||||||
|
d11d10d09d08 = int(length_code[1])
|
||||||
|
d07d06d05d04 = int(length_code[2])
|
||||||
|
d03d0ld01d00 = int(length_code[3])
|
||||||
|
lenid = d11d10d09d08 << 8 | d07d06d05d04 << 4 | d03d0ld01d00
|
||||||
|
return lenid>>1
|
||||||
|
|
||||||
|
def parse_length_code(frame):
|
||||||
|
# implements chapter 3.2 of the Protocol Specification
|
||||||
|
length_code = frame[18:26]
|
||||||
|
lchksum = parse_lchksum(length_code)
|
||||||
|
lenid = parse_lenid(length_code)
|
||||||
|
return { "LCHKSUM": lchksum, "LENID": lenid }
|
||||||
|
|
||||||
|
def parse_info(frame):
|
||||||
|
cid2 = frame[14:18]
|
||||||
|
lenid = parse_lenid(frame[18:26])
|
||||||
|
info = frame[26:26+lenid*2]
|
||||||
|
|
||||||
|
if cid2 == '00' and lenid == 49:
|
||||||
|
return parse_telecommand_return(info)
|
||||||
|
elif cid2 == '00' and lenid == 75:
|
||||||
|
return parse_telemetry_return(info)
|
||||||
|
else:
|
||||||
|
return info
|
||||||
|
|
||||||
|
def parse_telecommand_return(info_raw, info={}, index=0):
|
||||||
|
|
||||||
|
info["DATA FLAG"] = info_raw[index:index+4]
|
||||||
|
index += 4
|
||||||
|
|
||||||
|
info["COMMAND GROUP"] = info_raw[index:index+4]
|
||||||
|
index += 4
|
||||||
|
|
||||||
|
|
||||||
|
def parse_modbus_ascii_frame(frame, parsed_data = {}):
|
||||||
|
frame = bytes.fromhex(frame).decode('ascii')
|
||||||
|
parsed_data["SOI"] = parse_start_code(frame)
|
||||||
|
parsed_data["VER"] = parse_version_code(frame)
|
||||||
|
parsed_data["ADR"] = parse_address_code(frame)
|
||||||
|
parsed_data["CID1"] = parse_device_code(frame)
|
||||||
|
parsed_data["CID2"] = parse_function_code(frame)
|
||||||
|
parsed_data["LENGTH"] = parse_length_code(frame)
|
||||||
|
parsed_data["INFO"] = parse_info(frame)
|
||||||
|
parsed_data["CHKSUM"] = parse_checksum(frame)
|
||||||
|
parsed_data["EOI"] = parse_end_code(frame)
|
||||||
|
return parsed_data
|
||||||
|
|
||||||
|
def send_command():
|
||||||
|
|
||||||
|
# Define the serial port and baud rate
|
||||||
|
port = 'COM9' # Replace with your actual port
|
||||||
|
baudrate = 19200 # Replace with the correct baud rate for your BMS
|
||||||
|
|
||||||
|
# Create the serial connection
|
||||||
|
try:
|
||||||
|
with serial.Serial(port, baudrate, timeout=1) as ser:
|
||||||
|
# Convert the hex string to bytes
|
||||||
|
command = bytes.fromhex("7E3230303034363434453030323030464433350D")
|
||||||
|
|
||||||
|
# Send the command
|
||||||
|
ser.write(command)
|
||||||
|
print("Command sent successfully.")
|
||||||
|
|
||||||
|
# Wait for and read the response
|
||||||
|
response = ser.read(200) # Adjust the number of bytes to read as needed
|
||||||
|
if response:
|
||||||
|
hex_response = response.hex()
|
||||||
|
print("Response received:", hex_response)
|
||||||
|
# Process the response to check details
|
||||||
|
check_starting_byte_and_extract_details(hex_response)
|
||||||
|
else:
|
||||||
|
print("No response received.")
|
||||||
|
except serial.SerialException as e:
|
||||||
|
print(f"Error opening serial port: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An unexpected error occurred: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
send_command()
|
||||||
|
|
@ -0,0 +1,480 @@
|
||||||
|
import serial
|
||||||
|
import csv
|
||||||
|
|
||||||
|
TELECOMMAND_FILE_PATH = "Telecommand_Return_Record.csv"
|
||||||
|
|
||||||
|
# Table 3
|
||||||
|
CID1_DEVICE_CODES = {
|
||||||
|
"46": "Lithium iron phosphate battery BMS",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Table 4
|
||||||
|
CID2_COMMAND_CODES = {
|
||||||
|
"42": "Acquisition of telemetering information",
|
||||||
|
"44": "Acquisition of telecommand information",
|
||||||
|
"45": "Telecontrol command",
|
||||||
|
"47": "Acquisition of teleregulation information",
|
||||||
|
"49": "Setting of teleregulation information",
|
||||||
|
"4F": "Acquisition of the communication protocol version number",
|
||||||
|
"51": "Acquisition of device vendor information",
|
||||||
|
"4B": "Acquisition of historical data",
|
||||||
|
"4D": "Acquisition time",
|
||||||
|
"4E": "Synchronization time",
|
||||||
|
"A0": "Production calibration",
|
||||||
|
"A1": "Production setting",
|
||||||
|
"A2": "Regular recording"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Table 5
|
||||||
|
CID2_RETURN_CODES = {
|
||||||
|
"00": "Normal",
|
||||||
|
"01": "VER error",
|
||||||
|
"02": "CHKSUM error",
|
||||||
|
"03": "LCHKSUM error",
|
||||||
|
"04": "CID2 invalid",
|
||||||
|
"05": "Command format error",
|
||||||
|
"06": "Data invalid (parameter setting)",
|
||||||
|
"07": "No data (history)",
|
||||||
|
"E1": "CID1 invalid",
|
||||||
|
"E2": "Command execution failure",
|
||||||
|
"E3": "Device fault",
|
||||||
|
"E4": "Invalid permissions"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Table 12
|
||||||
|
BYTE_ALARM_CODES = {
|
||||||
|
"00": "Normal, no alarm",
|
||||||
|
"01": "Alarm that analog quantity reaches the lower limit",
|
||||||
|
"02": "Alarm that analog quantity reaches the upper limit",
|
||||||
|
"F0": "Other alarms"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Table 13
|
||||||
|
BIT_ALARM_CODES = {
|
||||||
|
"Alarm event 1": (
|
||||||
|
"Voltage sensor fault",
|
||||||
|
"Temperature sensor fault",
|
||||||
|
"Current sensor fault",
|
||||||
|
"Key switch fault",
|
||||||
|
"Cell voltage dropout fault",
|
||||||
|
"Charge switch fault",
|
||||||
|
"Discharge switch fault",
|
||||||
|
"Current limit switch fault"
|
||||||
|
),
|
||||||
|
"Alarm event 2": (
|
||||||
|
"Monomer high voltage alarm",
|
||||||
|
"Monomer overvoltage protection",
|
||||||
|
"Monomer low voltage alarm",
|
||||||
|
"Monomer under voltage protection",
|
||||||
|
"High voltage alarm for total voltage",
|
||||||
|
"Overvoltage protection for total voltage",
|
||||||
|
"Low voltage alarm for total voltage",
|
||||||
|
"Under voltage protection for total voltage"
|
||||||
|
),
|
||||||
|
"Alarm event 3": (
|
||||||
|
"Charge high temperature alarm",
|
||||||
|
"Charge over temperature protection",
|
||||||
|
"Charge low temperature alarm",
|
||||||
|
"Charge under temperature protection",
|
||||||
|
"Discharge high temperature alarm",
|
||||||
|
"Discharge over temperature protection",
|
||||||
|
"Discharge low temperature alarm",
|
||||||
|
"Discharge under temperature protection"
|
||||||
|
),
|
||||||
|
"Alarm event 4": (
|
||||||
|
"Environment high temperature alarm",
|
||||||
|
"Environment over temperature protection",
|
||||||
|
"Environment low temperature alarm",
|
||||||
|
"Environment under temperature protection",
|
||||||
|
"Power over temperature protection",
|
||||||
|
"Power high temperature alarm",
|
||||||
|
"Cell low temperature heating",
|
||||||
|
"Reservation bit"
|
||||||
|
),
|
||||||
|
"Alarm event 5": (
|
||||||
|
"Charge over current alarm",
|
||||||
|
"Charge over current protection",
|
||||||
|
"Discharge over current alarm",
|
||||||
|
"Discharge over current protection",
|
||||||
|
"Transient over current protection",
|
||||||
|
"Output short circuit protection",
|
||||||
|
"Transient over current lockout",
|
||||||
|
"Output short circuit lockout"
|
||||||
|
),
|
||||||
|
"Alarm event 6": (
|
||||||
|
"Charge high voltage protection",
|
||||||
|
"Intermittent recharge waiting",
|
||||||
|
"Residual capacity alarm",
|
||||||
|
"Residual capacity protection",
|
||||||
|
"Cell low voltage charging prohibition",
|
||||||
|
"Output reverse polarity protection",
|
||||||
|
"Output connection fault",
|
||||||
|
"Inside bit"
|
||||||
|
),
|
||||||
|
"On-off state": (
|
||||||
|
"Discharge switch state",
|
||||||
|
"Charge switch state",
|
||||||
|
"Current limit switch state",
|
||||||
|
"Heating switch state",
|
||||||
|
"Reservation bit",
|
||||||
|
"Reservation bit",
|
||||||
|
"Reservation bit",
|
||||||
|
"Reservation bit"
|
||||||
|
),
|
||||||
|
"Equilibrium state 1": (
|
||||||
|
"Cell 01 equilibrium",
|
||||||
|
"Cell 02 equilibrium",
|
||||||
|
"Cell 03 equilibrium",
|
||||||
|
"Cell 04 equilibrium",
|
||||||
|
"Cell 05 equilibrium",
|
||||||
|
"Cell 06 equilibrium",
|
||||||
|
"Cell 07 equilibrium",
|
||||||
|
"Cell 08 equilibrium"
|
||||||
|
),
|
||||||
|
"Equilibrium state 2": (
|
||||||
|
"Cell 09 equilibrium",
|
||||||
|
"Cell 10 equilibrium",
|
||||||
|
"Cell 11 equilibrium",
|
||||||
|
"Cell 12 equilibrium",
|
||||||
|
"Cell 13 equilibrium",
|
||||||
|
"Cell 14 equilibrium",
|
||||||
|
"Cell 15 equilibrium",
|
||||||
|
"Cell 16 equilibrium"
|
||||||
|
),
|
||||||
|
"System state": (
|
||||||
|
"Discharge",
|
||||||
|
"Charge",
|
||||||
|
"Floating charge",
|
||||||
|
"Reservation bit",
|
||||||
|
"Standby",
|
||||||
|
"Shutdown",
|
||||||
|
"Reservation bit",
|
||||||
|
"Reservation bit"
|
||||||
|
),
|
||||||
|
"Disconnection state 1": (
|
||||||
|
"Cell 01 disconnection",
|
||||||
|
"Cell 02 disconnection",
|
||||||
|
"Cell 03 disconnection",
|
||||||
|
"Cell 04 disconnection",
|
||||||
|
"Cell 05 disconnection",
|
||||||
|
"Cell 06 disconnection",
|
||||||
|
"Cell 07 disconnection",
|
||||||
|
"Cell 08 disconnection"
|
||||||
|
),
|
||||||
|
"Disconnection state 2": (
|
||||||
|
"Cell 09 disconnection",
|
||||||
|
"Cell 10 disconnection",
|
||||||
|
"Cell 11 disconnection",
|
||||||
|
"Cell 12 disconnection",
|
||||||
|
"Cell 13 disconnection",
|
||||||
|
"Cell 14 disconnection",
|
||||||
|
"Cell 15 disconnection",
|
||||||
|
"Cell 16 disconnection"
|
||||||
|
),
|
||||||
|
"Alarm event 7": (
|
||||||
|
"Inside bit",
|
||||||
|
"Inside bit",
|
||||||
|
"Inside bit",
|
||||||
|
"Inside bit",
|
||||||
|
"Automatic charging waiting",
|
||||||
|
"Manual charging waiting",
|
||||||
|
"Inside bit",
|
||||||
|
"Inside bit"
|
||||||
|
),
|
||||||
|
"Alarm event 3": (
|
||||||
|
"EEP storage fault",
|
||||||
|
"RTC error",
|
||||||
|
"Voltage calibration not performed",
|
||||||
|
"Current calibration not performed",
|
||||||
|
"Zero calibration not performed",
|
||||||
|
"Inside bit",
|
||||||
|
"Inside bit",
|
||||||
|
"Inside bit"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def parse_start_code(frame):
|
||||||
|
soi = frame[0:1]
|
||||||
|
if soi == "~":
|
||||||
|
return "ok!"
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid start identifier! ({soi})")
|
||||||
|
|
||||||
|
def parse_version_code(frame):
|
||||||
|
ver = frame[1:3]
|
||||||
|
return f"Protocol Version V{ver[0]}.{ver[1]}"
|
||||||
|
|
||||||
|
def parse_address_code(frame):
|
||||||
|
adr = frame[3:5]
|
||||||
|
if 0 <= int(adr) <= 15:
|
||||||
|
return adr
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid address: {adr} (out of range 0-15)")
|
||||||
|
|
||||||
|
def parse_device_code(frame):
|
||||||
|
cid1 = frame[5:7]
|
||||||
|
return CID1_DEVICE_CODES.get(cid1, "Unknown!")
|
||||||
|
|
||||||
|
def parse_function_code(frame):
|
||||||
|
cid2 = frame[7:9]
|
||||||
|
if cid2 in CID2_COMMAND_CODES:
|
||||||
|
return f"Command -> {CID2_COMMAND_CODES.get(cid2)}"
|
||||||
|
elif cid2 in CID2_RETURN_CODES:
|
||||||
|
return f"Return -> {CID2_RETURN_CODES.get(cid2)}"
|
||||||
|
else:
|
||||||
|
return f"Unknown CID2: {cid2}"
|
||||||
|
|
||||||
|
def parse_lchksum(length_code):
|
||||||
|
# implements chapter 3.2.2 of the Protocol Specification
|
||||||
|
lchksum = int(length_code[0], 16)
|
||||||
|
# Compute lchksum
|
||||||
|
d11d10d09d08 = int(length_code[1])
|
||||||
|
d07d06d05d04 = int(length_code[2])
|
||||||
|
d03d0ld01d00 = int(length_code[3])
|
||||||
|
sum = d11d10d09d08 + d07d06d05d04 + d03d0ld01d00
|
||||||
|
remainder = sum % 16
|
||||||
|
inverted = ~remainder & 0xF
|
||||||
|
computed_lchksum = (inverted + 1) & 0xF
|
||||||
|
if computed_lchksum == lchksum:
|
||||||
|
return "ok!"
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid LCHKSUM: {lchksum} (computed: {computed_lchksum})")
|
||||||
|
|
||||||
|
def parse_lenid(length_code):
|
||||||
|
# implements chapter 3.2.1 of the Protocol Specification
|
||||||
|
d11d10d09d08 = int(length_code[1])
|
||||||
|
d07d06d05d04 = int(length_code[2])
|
||||||
|
d03d0ld01d00 = int(length_code[3])
|
||||||
|
lenid = d11d10d09d08 << 8 | d07d06d05d04 << 4 | d03d0ld01d00
|
||||||
|
return lenid >> 1
|
||||||
|
|
||||||
|
def parse_length_code(frame):
|
||||||
|
# implements chapter 3.2 of the Protocol Specification
|
||||||
|
length_code = frame[9:13]
|
||||||
|
lchksum = parse_lchksum(length_code)
|
||||||
|
lenid = parse_lenid(length_code)
|
||||||
|
return { "LCHKSUM": lchksum, "LENID": lenid }
|
||||||
|
|
||||||
|
def parse_info(frame):
|
||||||
|
cid2 = frame[7:9]
|
||||||
|
lenid = parse_lenid(frame[9:13])
|
||||||
|
info = frame[13:13+lenid*2]
|
||||||
|
|
||||||
|
if cid2 == '00' and lenid == 49:
|
||||||
|
return parse_telecommand_return(info)
|
||||||
|
elif cid2 == '00' and lenid == 75:
|
||||||
|
return parse_telemetry_return(info)
|
||||||
|
else:
|
||||||
|
return info
|
||||||
|
|
||||||
|
def parse_telecommand_return(info_raw, info={}, index=0):
|
||||||
|
|
||||||
|
info["DATA FLAG"] = info_raw[index:index+2]
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
info["COMMAND GROUP"] = info_raw[index:index+2]
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
num_of_cells = int(info_raw[index:index+2], 16)
|
||||||
|
info["Number of cells"] = num_of_cells
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
for cell in range(info["Number of cells"]):
|
||||||
|
alarm = BYTE_ALARM_CODES.get(info_raw[index:index+2])
|
||||||
|
info[f"Cell {cell +1} alarm"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
num_of_temperatures = int(info_raw[index:index+2], 16)
|
||||||
|
info["Number of temperatures"] = num_of_temperatures
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
for sensor in range(4):
|
||||||
|
alarm = BYTE_ALARM_CODES.get(info_raw[index:index+2])
|
||||||
|
info[f"Cell temperature alarm {sensor}"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = BYTE_ALARM_CODES.get(info_raw[index:index+2])
|
||||||
|
info["Environment temperature alarm"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = BYTE_ALARM_CODES.get(info_raw[index:index+2])
|
||||||
|
info["Power temperature alarm 1"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = BYTE_ALARM_CODES.get(info_raw[index:index+2])
|
||||||
|
info["Charge/discharge current alarm"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = BYTE_ALARM_CODES.get(info_raw[index:index+2])
|
||||||
|
info["Total battery voltage alarm"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
num_custom = int(info_raw[index:index+2], 16)
|
||||||
|
info["Number of custom alarms"] = num_custom
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Alarm event 1"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Alarm event 2"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Alarm event 3"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Alarm event 4"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Alarm event 5"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Alarm event 6"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["On-off state"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Equilibrium state 1"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Equilibrium state 2"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["System state"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Disconnection state 1"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Disconnection state 2"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Alarm event 7"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Alarm event 8"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Reservation extention 1"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Reservation extention 2"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Reservation extention 3"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Reservation extention 4"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Reservation extention 5"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
alarm = info_raw[index:index+2]
|
||||||
|
info["Reservation extention 6"] = alarm
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
save_dict_to_csv(TELECOMMAND_FILE_PATH, info)
|
||||||
|
return f"Telecommand Return Data saved in ./{TELECOMMAND_FILE_PATH}"
|
||||||
|
|
||||||
|
|
||||||
|
def save_dict_to_csv(file_path, data):
|
||||||
|
with open(file_path, mode='a+', newline='') as csvfile:
|
||||||
|
csvfile.seek(0)
|
||||||
|
has_header = csvfile.read(1) != ""
|
||||||
|
csvfile.seek(0, 2)
|
||||||
|
writer = csv.DictWriter(csvfile, fieldnames=data.keys())
|
||||||
|
if not has_header:
|
||||||
|
writer.writeheader()
|
||||||
|
writer.writerow(data)
|
||||||
|
|
||||||
|
def parse_checksum(frame):
|
||||||
|
"""implements section 3.3 of the Protocol Specification"""
|
||||||
|
chksum = int(frame[-6:-1], 16)
|
||||||
|
data = frame[1:-5]
|
||||||
|
# Compute chksum
|
||||||
|
ascii_sum = sum(ord(char) for char in data)
|
||||||
|
remainder = ascii_sum % 65536
|
||||||
|
inverted = ~remainder & 0xFFFF
|
||||||
|
computed_chksum = (inverted + 1) & 0xFFFF
|
||||||
|
# Compare with CHKSUM in frame
|
||||||
|
if computed_chksum == chksum:
|
||||||
|
return "ok!"
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid CHKSUM: {chksum} (computed: {computed_chksum})")
|
||||||
|
|
||||||
|
def parse_end_code(frame):
|
||||||
|
eoi = frame[-1]
|
||||||
|
if eoi == "\r":
|
||||||
|
return "ok!"
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Invalid end identifier! ({eoi})")
|
||||||
|
|
||||||
|
def parse_modbus_ascii_frame(frame, parsed_data = {}):
|
||||||
|
frame = bytes.fromhex(frame).decode('ascii')
|
||||||
|
parsed_data["SOI"] = parse_start_code(frame)
|
||||||
|
parsed_data["VER"] = parse_version_code(frame)
|
||||||
|
parsed_data["ADR"] = parse_address_code(frame)
|
||||||
|
parsed_data["CID1"] = parse_device_code(frame)
|
||||||
|
parsed_data["CID2"] = parse_function_code(frame)
|
||||||
|
parsed_data["LENGTH"] = parse_length_code(frame)
|
||||||
|
parsed_data["INFO"] = parse_info(frame)
|
||||||
|
parsed_data["CHKSUM"] = parse_checksum(frame)
|
||||||
|
parsed_data["EOI"] = parse_end_code(frame)
|
||||||
|
return parsed_data
|
||||||
|
|
||||||
|
def send_command():
|
||||||
|
|
||||||
|
# Define the serial port and baud rate
|
||||||
|
port = 'COM9' # Replace with your actual port
|
||||||
|
baudrate = 19200 # Replace with the correct baud rate for your BMS
|
||||||
|
|
||||||
|
# Create the serial connection
|
||||||
|
try:
|
||||||
|
with serial.Serial(port, baudrate, timeout=1) as ser:
|
||||||
|
# Convert the hex string to bytes
|
||||||
|
command = bytes.fromhex("7E3230303034363434453030323030464433350D")
|
||||||
|
|
||||||
|
# Send the command
|
||||||
|
ser.write(command)
|
||||||
|
print("Command sent successfully.")
|
||||||
|
|
||||||
|
# Wait for and read the response
|
||||||
|
response = ser.read(200) # Adjust the number of bytes to read as needed
|
||||||
|
if response:
|
||||||
|
hex_response = response.hex()
|
||||||
|
print("Response received:", hex_response)
|
||||||
|
# Process the response to check details
|
||||||
|
parsed_result = parse_modbus_ascii_frame(hex_response)
|
||||||
|
for key, value in parsed_result.items():
|
||||||
|
print(f"{key}: {value}")
|
||||||
|
else:
|
||||||
|
print("No response received.")
|
||||||
|
except serial.SerialException as e:
|
||||||
|
print(f"Error opening serial port: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An unexpected error occurred: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
send_command()
|
||||||
|
|
@ -10,15 +10,7 @@ public class TelecommandFrameParser
|
||||||
private static Int32 _currentIndex;
|
private static Int32 _currentIndex;
|
||||||
private const Int32 FrameLength = 232;
|
private const Int32 FrameLength = 232;
|
||||||
|
|
||||||
private static readonly Dictionary<String, String> ByteAlarmCodes = new()
|
public Boolean ParsingTelecommandFrame(String response)
|
||||||
{
|
|
||||||
{ "00", "Normal, no alarm" },
|
|
||||||
{ "01", "Alarm that analog quantity reaches the lower limit" },
|
|
||||||
{ "02", "Alarm that analog quantity reaches the upper limit" },
|
|
||||||
{ "F0", "Other alarms" }
|
|
||||||
};
|
|
||||||
|
|
||||||
public BatteryDeligreenAlarmRecord? ParsingTelecommandFrame(String response)
|
|
||||||
{
|
{
|
||||||
_currentIndex = 0; // Reset currentIndex to the start
|
_currentIndex = 0; // Reset currentIndex to the start
|
||||||
|
|
||||||
|
|
@ -27,7 +19,7 @@ public class TelecommandFrameParser
|
||||||
Console.WriteLine("Response is too short to contain valid data.");
|
Console.WriteLine("Response is too short to contain valid data.");
|
||||||
Console.WriteLine(" Fixed Length" + FrameLength);
|
Console.WriteLine(" Fixed Length" + FrameLength);
|
||||||
Console.WriteLine(" response Length" + response.Length);
|
Console.WriteLine(" response Length" + response.Length);
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check starting byte
|
// Check starting byte
|
||||||
|
|
@ -39,7 +31,7 @@ public class TelecommandFrameParser
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Incorrect starting byte: {startingByte}");
|
Console.WriteLine($"Incorrect starting byte: {startingByte}");
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentIndex += 2;
|
_currentIndex += 2;
|
||||||
|
|
@ -54,65 +46,35 @@ public class TelecommandFrameParser
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to decode firmware version from bytes: {versionBytes}");
|
Console.WriteLine($"Failed to decode firmware version from bytes: {versionBytes}");
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentIndex += 4;
|
_currentIndex += 4;
|
||||||
|
|
||||||
// Extract and parse other fields
|
// Extract and parse other fields
|
||||||
ParseAndPrintHexField(response, "Device Address", 4); // this is not added to the Alarm record
|
ParseAndPrintHexField(response, "Device Address", 4);
|
||||||
ParseAndPrintHexField(response, "Device Code (CID1)", 4); // this is not added to the Alarm record
|
ParseAndPrintHexField(response, "Device Code (CID1)", 4);
|
||||||
ParseAndPrintHexField(response, "Function Code", 4); // this is not added to the Alarm record
|
ParseAndPrintHexField(response, "Function Code", 4);
|
||||||
ParseAndPrintHexField(response, "Length Code", 8); // this is not added to the Alarm record
|
ParseAndPrintHexField(response, "Length Code", 8);
|
||||||
ParseAndPrintHexField(response, "Data Flag", 4); // this is not added to the Alarm record
|
ParseAndPrintHexField(response, "Data Flag", 4);
|
||||||
ParseAndPrintHexField(response, "Command Group", 4); // this is not added to the Alarm record
|
ParseAndPrintHexField(response, "Command Group", 4);
|
||||||
ParseAndPrintHexField(response, "Number of Cells", 4); // this is not added to the Alarm record
|
ParseAndPrintHexField(response, "Number of Cells", 4);
|
||||||
|
ExtractCellAlarm(response);
|
||||||
// Parse Cell Temperature Alarm fields
|
return true;
|
||||||
var cellAlarmList = ExtractCellAlarm(response);
|
|
||||||
|
|
||||||
// Parse Number of Temperature Alarm
|
|
||||||
ParseAndPrintHexField(response, "Number of Temperature ", 4); // this is not added to the Alarm record
|
|
||||||
|
|
||||||
// Parse Cell Temperature Alarm fields
|
|
||||||
var cellTemperatureAlarm = ExtractCellTempAlarm(response);
|
|
||||||
var enviTempAlarm = ParseAndPrintField(response, "Environment Temperature Alarm" );
|
|
||||||
var powerTempAlarm = ParseAndPrintField(response, "Power Temperature Alarm" );
|
|
||||||
var currentAlarm = ParseAndPrintField(response, "Charge/Discharge Current Alarm" );
|
|
||||||
var totalVoltageAlarm = ParseAndPrintField(response, "Total Battery Voltage Alarm" );
|
|
||||||
|
|
||||||
var batteryAlarmRecord = new BatteryDeligreenAlarmRecord(cellAlarmList, cellTemperatureAlarm, enviTempAlarm, powerTempAlarm,currentAlarm, totalVoltageAlarm);
|
|
||||||
|
|
||||||
return batteryAlarmRecord;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> ExtractCellTempAlarm(String response)
|
|
||||||
{
|
|
||||||
var cellTempAlarmList = new List<String>();
|
|
||||||
|
|
||||||
var tempCellAlarm = response.Substring(_currentIndex, 4);
|
|
||||||
for (var i = 0; i < 4; i++)
|
private static void ExtractCellAlarm(String response)
|
||||||
|
{
|
||||||
|
|
||||||
|
Dictionary<string, string> byteAlarmCodes = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
try
|
{ "00", "Normal, no alarm" },
|
||||||
{
|
{ "01", "Alarm that analog quantity reaches the lower limit" },
|
||||||
var tempAscii = HexToAscii(tempCellAlarm);
|
{ "02", "Alarm that analog quantity reaches the upper limit" },
|
||||||
var alarmMessage = ByteAlarmCodes.ContainsKey(tempAscii) ? ByteAlarmCodes[tempAscii] : "Unknown alarm code";
|
{ "F0", "Other alarms" }
|
||||||
cellTempAlarmList.Add(alarmMessage);
|
};
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Failed to decode Cell Temp Alarm {i + 1} from bytes: {tempCellAlarm}");
|
|
||||||
}
|
|
||||||
_currentIndex += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cellTempAlarmList;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static List<String> ExtractCellAlarm(String response)
|
|
||||||
{
|
|
||||||
var cellAlarmList = new List<String>();
|
|
||||||
|
|
||||||
// Process Alarms for all 16 cells
|
// Process Alarms for all 16 cells
|
||||||
for (var i = 0; i < 16; i++)
|
for (var i = 0; i < 16; i++)
|
||||||
|
|
@ -121,28 +83,28 @@ public class TelecommandFrameParser
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var alarmAscii = HexToAscii(cellAlarm);
|
var alarmAscii = HexToAscii(cellAlarm);
|
||||||
var alarmMessage = ByteAlarmCodes.ContainsKey(alarmAscii) ? ByteAlarmCodes[alarmAscii] : "Unknown alarm code";
|
var cellVoltageDecimal = HexToDecimal(alarmAscii);
|
||||||
cellAlarmList.Add(alarmMessage);
|
string alarmMessage = byteAlarmCodes.ContainsKey(alarmAscii) ? byteAlarmCodes[alarmAscii] : "Unknown alarm code";
|
||||||
|
|
||||||
// Console.WriteLine($"Cell {i + 1}: Alarm Code {cellAlarm}, Status: {alarmMessage}");
|
// Console.WriteLine($"Cell {i + 1}: Alarm Code {cellAlarm}, Status: {alarmMessage}");
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to decode Cell Alarm {i + 1} from bytes: {cellAlarm}");
|
Console.WriteLine($"Failed to decode Voltage of Cell {i + 1} from bytes: {cellAlarm}");
|
||||||
}
|
}
|
||||||
_currentIndex += 4;
|
_currentIndex += 4;
|
||||||
}
|
}
|
||||||
return cellAlarmList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ParseAndPrintHexField(String response, String fieldName, Int32 length)
|
private static void ParseAndPrintHexField(String response, String fieldName, int length)
|
||||||
{
|
{
|
||||||
var hexBytes = response.Substring(_currentIndex, length);
|
var hexBytes = response.Substring(_currentIndex, length);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var asciiValue = HexToAscii(hexBytes);
|
var asciiValue = HexToAscii(hexBytes);
|
||||||
var decimalValue = int.Parse(asciiValue, NumberStyles.HexNumber);
|
var decimalValue = int.Parse(asciiValue, NumberStyles.HexNumber);
|
||||||
//Console.WriteLine($"{fieldName}: {hexBytes} (Hex), ASCII: {asciiValue}, Decimal: {decimalValue}");
|
// Console.WriteLine($"{fieldName}: {hexBytes} (Hex), ASCII: {asciiValue}, Decimal: {decimalValue}");
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
|
@ -150,24 +112,20 @@ public class TelecommandFrameParser
|
||||||
}
|
}
|
||||||
_currentIndex += length;
|
_currentIndex += length;
|
||||||
}
|
}
|
||||||
|
private static void ParseAndPrintField(String response, String fieldName, Int32 length, Func<Double, Double> conversion, String unit)
|
||||||
private static String ParseAndPrintField(String response, String fieldName)
|
|
||||||
{
|
{
|
||||||
var fieldBytes = response.Substring(_currentIndex, 4);
|
var fieldBytes = response.Substring(_currentIndex, length);
|
||||||
var alarmMessage = "Failed to read alarm";
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var tempAscii = HexToAscii(fieldBytes);
|
var fieldAscii = HexToAscii(fieldBytes);
|
||||||
alarmMessage = ByteAlarmCodes.ContainsKey(tempAscii) ? ByteAlarmCodes[tempAscii] : "Unknown alarm code";
|
var fieldDecimal = conversion(HexToDecimal(fieldAscii));
|
||||||
|
Console.WriteLine($"{fieldName}: {fieldBytes} (Hex), ASCII: {fieldAscii}, {fieldName}: {fieldDecimal:F3} {unit}");
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to decode : {fieldName}" + " Alarm");
|
Console.WriteLine($"Failed to decode {fieldName} from bytes: {fieldBytes}");
|
||||||
}
|
}
|
||||||
_currentIndex += 4;
|
_currentIndex += length;
|
||||||
|
|
||||||
return alarmMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String HexToAscii(String hex)
|
private static String HexToAscii(String hex)
|
||||||
|
|
|
||||||
|
|
@ -52,18 +52,18 @@ public class TelemetryFrameParser
|
||||||
_currentIndex += 4;
|
_currentIndex += 4;
|
||||||
|
|
||||||
// Extract and parse other fields
|
// Extract and parse other fields
|
||||||
ParseAndPrintHexField(response, "Device Address", 4); // this is not added to the Data record
|
ParseAndPrintHexField(response, "Device Address", 4);
|
||||||
ParseAndPrintHexField(response, "Device Code (CID1)", 4); // this is not added to the Data record
|
ParseAndPrintHexField(response, "Device Code (CID1)", 4);
|
||||||
ParseAndPrintHexField(response, "Function Code", 4); // this is not added to the Data record
|
ParseAndPrintHexField(response, "Function Code", 4);
|
||||||
ParseAndPrintHexField(response, "Length Code", 8); // this is not added to the Data record
|
ParseAndPrintHexField(response, "Length Code", 8);
|
||||||
ParseAndPrintHexField(response, "Data Flag", 4); // this is not added to the Data record
|
ParseAndPrintHexField(response, "Data Flag", 4);
|
||||||
ParseAndPrintHexField(response, "Command Group", 4); // this is not added to the Data record
|
ParseAndPrintHexField(response, "Command Group", 4);
|
||||||
ParseAndPrintHexField(response, "Number of Cells", 4); // this is not added to the Data record
|
ParseAndPrintHexField(response, "Number of Cells", 4);
|
||||||
|
|
||||||
var cellVoltages = ExtractCellVoltage(response);
|
var cellVoltages = ExtractCellVoltage(response);
|
||||||
|
|
||||||
// Parse other fields
|
// Parse other fields
|
||||||
ParseAndPrintHexField(response, "Number of Temperature Sensors", 4); // this is not added to the Data record
|
ParseAndPrintHexField(response, "Number of Temperature Sensors", 4);
|
||||||
var cellTemperature = new List<Double>();
|
var cellTemperature = new List<Double>();
|
||||||
|
|
||||||
// Parse cell temperatures
|
// Parse cell temperatures
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue