Compare commits
No commits in common. "dc2fc33607d0f805ac2c348918cf93020080f3fb" and "57131ec668aaceb5b85cc441e581c2b3c2ea26ea" have entirely different histories.
dc2fc33607
...
57131ec668
|
@ -2,7 +2,7 @@ namespace InnovEnergy.App.SaliMax.SystemConfig;
|
||||||
|
|
||||||
public class AcDcConfig
|
public class AcDcConfig
|
||||||
{
|
{
|
||||||
public required Double MaxDcLinkVoltage { get; set; }
|
public required Double MaxDcLinkVoltage { get; init; }
|
||||||
public required Double MinDcLinkVoltage { get; set; }
|
public required Double MinDcLinkVoltage { get; init; }
|
||||||
public required Double ReferenceDcLinkVoltage { get; init; }
|
public required Double ReferenceDcLinkVoltage { get; init; }
|
||||||
}
|
}
|
|
@ -16,7 +16,6 @@ public class Config //TODO: let IE choose from config files (Json) and connect t
|
||||||
private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };
|
private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };
|
||||||
|
|
||||||
public required Double MinSoc { get; set; }
|
public required Double MinSoc { get; set; }
|
||||||
public required Int16 CurtailP { get; set; }
|
|
||||||
public required CalibrationChargeType ForceCalibrationChargeState { get; set; }
|
public required CalibrationChargeType ForceCalibrationChargeState { get; set; }
|
||||||
public required DateTime DayAndTimeForRepetitiveCalibration { get; set; }
|
public required DateTime DayAndTimeForRepetitiveCalibration { get; set; }
|
||||||
public required DateTime DayAndTimeForAdditionalCalibration { get; set; }
|
public required DateTime DayAndTimeForAdditionalCalibration { get; set; }
|
||||||
|
@ -123,7 +122,6 @@ public class Config //TODO: let IE choose from config files (Json) and connect t
|
||||||
public static Config Default => new()
|
public static Config Default => new()
|
||||||
{
|
{
|
||||||
MinSoc = 20,
|
MinSoc = 20,
|
||||||
CurtailP = 100,
|
|
||||||
ForceCalibrationChargeState = CalibrationChargeType.RepetitivelyEvery,
|
ForceCalibrationChargeState = CalibrationChargeType.RepetitivelyEvery,
|
||||||
DayAndTimeForRepetitiveCalibration = DefaultDatetime,
|
DayAndTimeForRepetitiveCalibration = DefaultDatetime,
|
||||||
DayAndTimeForAdditionalCalibration = DefaultDatetime,
|
DayAndTimeForAdditionalCalibration = DefaultDatetime,
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace InnovEnergy.App.SaliMax.SystemConfig;
|
||||||
|
|
||||||
public class DcDcConfig
|
public class DcDcConfig
|
||||||
{
|
{
|
||||||
public required Double LowerDcLinkVoltage { get; set; }
|
public required Double LowerDcLinkVoltage { get; init; }
|
||||||
public required Double ReferenceDcLinkVoltage { get; init; }
|
public required Double ReferenceDcLinkVoltage { get; init; }
|
||||||
public required Double UpperDcLinkVoltage { get; set; }
|
public required Double UpperDcLinkVoltage { get; init; }
|
||||||
}
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
namespace InnovEnergy.App.SaliMax.SystemConfig;
|
|
||||||
|
|
||||||
public class AcDcConfig
|
|
||||||
{
|
|
||||||
public required Double MaxDcLinkVoltage { get; init; }
|
|
||||||
public required Double MinDcLinkVoltage { get; init; }
|
|
||||||
public required Double ReferenceDcLinkVoltage { get; init; }
|
|
||||||
}
|
|
|
@ -93,8 +93,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SofarInverter", "Lib\Device
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchneiderMeterDriver", "App\SchneiderMeterDriver\SchneiderMeterDriver.csproj", "{2E7E7657-3A53-4B62-8927-FE9A082B81DE}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchneiderMeterDriver", "App\SchneiderMeterDriver\SchneiderMeterDriver.csproj", "{2E7E7657-3A53-4B62-8927-FE9A082B81DE}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Battery250UP", "Lib\Devices\Battery250UP\Battery250UP.csproj", "{F2967439-A590-4D5E-9208-1B973C83AA1C}"
|
|
||||||
EndProject
|
|
||||||
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -246,10 +244,6 @@ Global
|
||||||
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Release|Any CPU.Build.0 = Release|Any CPU
|
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{F2967439-A590-4D5E-9208-1B973C83AA1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{F2967439-A590-4D5E-9208-1B973C83AA1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{F2967439-A590-4D5E-9208-1B973C83AA1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2967439-A590-4D5E-9208-1B973C83AA1C}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
{CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||||
|
@ -292,6 +286,5 @@ Global
|
||||||
{6B98449D-BF75-415A-8893-E49518F9307D} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
{6B98449D-BF75-415A-8893-E49518F9307D} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||||
{2C7F3D89-402B-43CB-988E-8D2D853BEF44} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
|
{2C7F3D89-402B-43CB-988E-8D2D853BEF44} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
|
||||||
{2E7E7657-3A53-4B62-8927-FE9A082B81DE} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
{2E7E7657-3A53-4B62-8927-FE9A082B81DE} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||||
{F2967439-A590-4D5E-9208-1B973C83AA1C} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<Import Project="../../InnovEnergy.Lib.props" />
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<RootNamespace>InnovEnergy.Lib.Devices.Battery250UP</RootNamespace>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="../../Protocols/Modbus/Modbus.csproj" />
|
|
||||||
<ProjectReference Include="../../StatusApi/StatusApi.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
|
|
@ -1,35 +0,0 @@
|
||||||
using InnovEnergy.Lib.Utils;
|
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up;
|
|
||||||
|
|
||||||
public class Battery250UpDevices
|
|
||||||
{
|
|
||||||
private readonly IReadOnlyList<Battery250UpDevice> _Devices;
|
|
||||||
|
|
||||||
public Battery250UpDevices(IReadOnlyList<Battery250UpDevice> devices) => _Devices = devices;
|
|
||||||
|
|
||||||
public Battery250UpRecords? Read()
|
|
||||||
{
|
|
||||||
var records = _Devices
|
|
||||||
.Select(TryRead)
|
|
||||||
.NotNull()
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return Battery250UpRecords.FromBatteries(records);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Battery250UpRecord? TryRead(Battery250UpDevice d)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return d.Read();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Failed to read Battery node {d.SlaveId}\n{e.Message}");
|
|
||||||
// TODO: log
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,259 +0,0 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Text;
|
|
||||||
using InnovEnergy.Lib.Devices.Battery250Up.DataTypes;
|
|
||||||
using InnovEnergy.Lib.Units;
|
|
||||||
using InnovEnergy.Lib.Units.Power;
|
|
||||||
using static InnovEnergy.Lib.Devices.Battery250Up.DataTypes.LedState;
|
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up;
|
|
||||||
|
|
||||||
using Strings = IReadOnlyList<String>;
|
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
|
||||||
[SuppressMessage("ReSharper", "ConvertToAutoProperty")]
|
|
||||||
public partial class Battery250UpRecord
|
|
||||||
{
|
|
||||||
public Dc_ Dc => new Dc_(this);
|
|
||||||
public Leds_ Leds => new Leds_(this);
|
|
||||||
public Temperatures_ Temperatures => new Temperatures_(this);
|
|
||||||
public StringActive_ BatteryStrings => new StringActive_(this);
|
|
||||||
public IoStatus_ IoStatus => new IoStatus_(this);
|
|
||||||
|
|
||||||
public Boolean Eoc => ParseEocReached();//Leds is { Green: On, Amber: Off, Blue : Off }; // ParseEocReached(); //
|
|
||||||
|
|
||||||
public UInt16 IoStates => _IoStates;
|
|
||||||
public UInt16 LimpBitMap => _LimpBitMap;
|
|
||||||
|
|
||||||
public String BatteryState => ParseBatteryState();
|
|
||||||
|
|
||||||
public String SerialNumber => $"{_SerialNum1:X4}{_SerialNum2:X4}{_SerialNum3:X4}{_SerialNum4:X4}".TrimEnd('0');
|
|
||||||
|
|
||||||
public String FwVersion => _FwVersion.ToString("X4");
|
|
||||||
|
|
||||||
public Strings Warnings => ParseWarnings().OrderBy(w => w).ToList();
|
|
||||||
public Strings Alarms => ParseAlarms() .OrderBy(w => w).ToList();
|
|
||||||
|
|
||||||
public Percent Soc => _Soc;
|
|
||||||
public Double SOCAh => _SOCAh;
|
|
||||||
|
|
||||||
public Current BusCurrent => _BusCurrent;
|
|
||||||
|
|
||||||
public Current CellsCurrent => _CellsCurrent;
|
|
||||||
|
|
||||||
public Current HeatingCurrent => _BusCurrent - _CellsCurrent;
|
|
||||||
public DcPower HeatingPower => HeatingCurrent * Dc.Voltage;
|
|
||||||
|
|
||||||
// Time since TOC is a counter from the last moment when the battery reached EOC
|
|
||||||
// When The battery is full charged (reached EOC) the Time Since TOC is set to 0
|
|
||||||
public TimeSpan TimeSinceTOC => TimeSpan.FromMinutes(_TimeSinceToc);
|
|
||||||
|
|
||||||
public Boolean CalibrationChargeRequested => TimeSinceTOC > TimeSpan.FromDays(7); // From AF0A (Fw Version) Each 14 days , But Max and Peter asked for 7 days.
|
|
||||||
|
|
||||||
public readonly struct Leds_
|
|
||||||
{
|
|
||||||
public LedState Blue => Self.ParseLed(LedColor.Blue);
|
|
||||||
public LedState Red => Self.ParseLed(LedColor.Red);
|
|
||||||
public LedState Green => Self.ParseLed(LedColor.Green);
|
|
||||||
public LedState Amber => Self.ParseLed(LedColor.Amber);
|
|
||||||
|
|
||||||
private Battery250UpRecord Self { get; }
|
|
||||||
internal Leds_(Battery250UpRecord self) => this.Self = self;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct StringActive_
|
|
||||||
{
|
|
||||||
public Boolean String1Active => (Self._LimpBitMap & 1) == 0;
|
|
||||||
public Boolean String2Active => (Self._LimpBitMap & 2) == 0;
|
|
||||||
public Boolean String3Active => (Self._LimpBitMap & 4) == 0;
|
|
||||||
public Boolean String4Active => (Self._LimpBitMap & 8) == 0;
|
|
||||||
public Boolean String5Active => (Self._LimpBitMap & 16) == 0;
|
|
||||||
|
|
||||||
internal StringActive_(Battery250UpRecord self) => Self = self;
|
|
||||||
private Battery250UpRecord Self { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct IoStatus_
|
|
||||||
{
|
|
||||||
public Boolean ConnectedToDcBus => ((Self._IoStates >> 0) & 1) == 0;
|
|
||||||
public Boolean AlarmOutActive => ((Self._IoStates >> 1) & 1) == 0;
|
|
||||||
public Boolean InternalFanActive => ((Self._IoStates >> 2) & 1) == 1;
|
|
||||||
public Boolean VoltMeasurementAllowed => ((Self._IoStates >> 3) & 1) == 1;
|
|
||||||
public Boolean AuxRelayBus => ((Self._IoStates >> 4) & 1) == 0;
|
|
||||||
public Boolean RemoteStateActive => ((Self._IoStates >> 5) & 1) == 1;
|
|
||||||
public Boolean RiscActive => ((Self._IoStates >> 6) & 1) == 1;
|
|
||||||
|
|
||||||
internal IoStatus_(Battery250UpRecord self) => Self = self;
|
|
||||||
private Battery250UpRecord Self { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct Temperatures_
|
|
||||||
{
|
|
||||||
public Boolean Heating => (Self._IoStates & 64) != 0;
|
|
||||||
public Temperature Board => Self._TemperaturesBoard;
|
|
||||||
public Cells_ Cells => new Cells_(Self);
|
|
||||||
|
|
||||||
public TemperatureState State => Self.Leds switch
|
|
||||||
{
|
|
||||||
{ Green: >= Blinking, Blue: >= Blinking } => TemperatureState.Cold,
|
|
||||||
_ => TemperatureState.Operation,
|
|
||||||
// TODO: overheated
|
|
||||||
};
|
|
||||||
|
|
||||||
internal Temperatures_(Battery250UpRecord self) => Self = self;
|
|
||||||
private Battery250UpRecord Self { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct Cells_
|
|
||||||
{
|
|
||||||
public Temperature Center => Self._TemperaturesCellsCenter;
|
|
||||||
public Temperature Left => Self._TemperaturesCellsLeft;
|
|
||||||
public Temperature Right => Self._TemperaturesCellsRight;
|
|
||||||
public Temperature Average => Self._TemperaturesCellsAverage;
|
|
||||||
|
|
||||||
internal Cells_(Battery250UpRecord self) => Self = self;
|
|
||||||
private Battery250UpRecord Self { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct Dc_
|
|
||||||
{
|
|
||||||
public Voltage Voltage => Self._CellsVoltage;
|
|
||||||
public Current Current => Self._CellsCurrent;
|
|
||||||
public ActivePower Power => Self._CellsVoltage * Self._CellsCurrent;
|
|
||||||
|
|
||||||
internal Dc_(Battery250UpRecord self) => Self = self;
|
|
||||||
private Battery250UpRecord Self { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private String ParseBatteryState()
|
|
||||||
{
|
|
||||||
var s1 = Encoding.ASCII.GetString(BitConverter.GetBytes(_BatteryState1).Reverse().ToArray()); // endian swap
|
|
||||||
var s2 = Encoding.ASCII.GetString(BitConverter.GetBytes(_BatteryState2).Reverse().ToArray()); // endian swap
|
|
||||||
|
|
||||||
return s1 + s2;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Boolean ParseEocReached()
|
|
||||||
{
|
|
||||||
return "EOC_" == ParseBatteryState();
|
|
||||||
}
|
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
|
||||||
private IEnumerable<String> ParseAlarms()
|
|
||||||
{
|
|
||||||
Boolean HasBit(Int16 bit) => (_AlarmFlags & 1uL << bit) > 0;
|
|
||||||
|
|
||||||
if (HasBit(0)) yield return "Tam : Ambient Temperature too low";
|
|
||||||
if (HasBit(2)) yield return "TaM2 : Ambient Temperature too high";
|
|
||||||
if (HasBit(3) ) yield return "Tbm : Battery temperature too low";
|
|
||||||
if (HasBit(5) ) yield return "TbM2 : Battery temperature too high";
|
|
||||||
if (HasBit(7) ) yield return "VBm2 : Bus voltage too low";
|
|
||||||
if (HasBit(9) ) yield return "VBM2 : Bus voltage too high";
|
|
||||||
if (HasBit(11)) yield return "IDM2 : Discharge current too high";
|
|
||||||
if (HasBit(12)) yield return "ISOB : Electrical insulation failure";
|
|
||||||
if (HasBit(13)) yield return "MSWE : Main switch failure";
|
|
||||||
if (HasBit(14)) yield return "FUSE : Main fuse blown";
|
|
||||||
if (HasBit(15)) yield return "HTRE : Battery failed to warm up";
|
|
||||||
if (HasBit(16)) yield return "TCPE : Temperature sensor failure";
|
|
||||||
if (HasBit(17)) yield return "STRE : Voltage measurement circuit fails";
|
|
||||||
if (HasBit(18)) yield return "CME : Current sensor failure";
|
|
||||||
if (HasBit(19)) yield return "HWFL : BMS hardware failure";
|
|
||||||
if (HasBit(20)) yield return "HWEM : Hardware protection tripped";
|
|
||||||
if (HasBit(21)) yield return "ThM : Heatsink temperature too high";
|
|
||||||
if (HasBit(23)) yield return "vsm2 : Low string voltage failure";
|
|
||||||
if (HasBit(25)) yield return "vsM2 : String voltage too high";
|
|
||||||
if (HasBit(27)) yield return "iCM2 : Charge current too high";
|
|
||||||
if (HasBit(29)) yield return "iDM2 : Discharge current too high";
|
|
||||||
if (HasBit(31)) yield return "MID2 : String voltage unbalance too high";
|
|
||||||
if (HasBit(42)) yield return "HTFS : Heater Fuse Blown";
|
|
||||||
if (HasBit(43)) yield return "DATA : Parameters out of range";
|
|
||||||
if (HasBit(45)) yield return "LMPA : Unbalance string voltages";
|
|
||||||
if (HasBit(46)) yield return "HEBT : Loss of heartbeat";
|
|
||||||
if (HasBit(48)) yield return "CURM : Battery charge requested after EDCH";
|
|
||||||
}
|
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
|
||||||
private IEnumerable<String> ParseWarnings()
|
|
||||||
{
|
|
||||||
Boolean HasBit(Int16 bit) => (_WarningFlags & 1uL << bit) > 0;
|
|
||||||
|
|
||||||
if (HasBit(1) ) yield return "TaM1: BMS temperature high";
|
|
||||||
if (HasBit(4) ) yield return "TbM1: Battery temperature high";
|
|
||||||
if (HasBit(6) ) yield return "VBm1: Bus voltage low";
|
|
||||||
if (HasBit(8) ) yield return "VBM1: Bus voltage high";
|
|
||||||
if (HasBit(10)) yield return "IDM1: Discharge current high";
|
|
||||||
if (HasBit(22)) yield return "vsm1: String voltage too low";
|
|
||||||
if (HasBit(24)) yield return "vsM1: String voltage high";
|
|
||||||
if (HasBit(26)) yield return "iCM1: Charge current high";
|
|
||||||
if (HasBit(28)) yield return "iDM1: Discharge current high";
|
|
||||||
if (HasBit(30)) yield return "MID1: String voltages unbalanced";
|
|
||||||
if (HasBit(32)) yield return "BLPW: Not enough charging power on bus";
|
|
||||||
if (HasBit(33)) yield return "CCBF : Internal charger hardware failure";
|
|
||||||
if (HasBit(35)) yield return "Ah_W: String SOC low";
|
|
||||||
if (HasBit(38)) yield return "MPMM: Midpoint wiring problem";
|
|
||||||
if (HasBit(40)) yield return "TCdi: Temperature difference between strings high";
|
|
||||||
if (HasBit(44)) yield return "LMPW : String voltages unbalance warning";
|
|
||||||
if (HasBit(47)) yield return "TOCW : Top of Charge requested";
|
|
||||||
if (HasBit(49)) yield return "BUSL : Bus lower than string";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Double CalcPowerLimitImposedByVoltageLimit(Double vLimit, Double rInt)
|
|
||||||
{
|
|
||||||
var v = Dc.Voltage;
|
|
||||||
var i = Dc.Current;
|
|
||||||
|
|
||||||
var dv = vLimit - v;
|
|
||||||
var di = dv / rInt;
|
|
||||||
|
|
||||||
return vLimit * (i + di);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Double CalcPowerLimitImposedByCurrentLimit(Double iLimit, Double rInt)
|
|
||||||
{
|
|
||||||
var v = Dc.Voltage;
|
|
||||||
var i = Dc.Current;
|
|
||||||
|
|
||||||
var di = iLimit - i;
|
|
||||||
var dv = di * rInt;
|
|
||||||
|
|
||||||
return iLimit * (v + dv);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DcPower MaxChargePower
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var pLimits = new[]
|
|
||||||
{
|
|
||||||
CalcPowerLimitImposedByVoltageLimit(Constants.VMax, Constants.RIntMin),
|
|
||||||
CalcPowerLimitImposedByVoltageLimit(Constants.VMax, Constants.RIntMax),
|
|
||||||
CalcPowerLimitImposedByCurrentLimit(Constants.IMax, Constants.RIntMin),
|
|
||||||
CalcPowerLimitImposedByCurrentLimit(Constants.IMax, Constants.RIntMax)
|
|
||||||
};
|
|
||||||
|
|
||||||
var pLimit = pLimits.Min();
|
|
||||||
|
|
||||||
return Math.Max(pLimit, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DcPower MaxDischargePower
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var pLimits = new[]
|
|
||||||
{
|
|
||||||
CalcPowerLimitImposedByVoltageLimit(Constants.VMin, Constants.RIntMin),
|
|
||||||
CalcPowerLimitImposedByVoltageLimit(Constants.VMin, Constants.RIntMax),
|
|
||||||
CalcPowerLimitImposedByCurrentLimit(-Constants.IMax, Constants.RIntMin),
|
|
||||||
CalcPowerLimitImposedByCurrentLimit(-Constants.IMax, Constants.RIntMax),
|
|
||||||
};
|
|
||||||
|
|
||||||
var pLimit = pLimits.Max();
|
|
||||||
|
|
||||||
return Math.Min(pLimit, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using InnovEnergy.Lib.Devices.Battery250Up.DataTypes;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
|
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up;
|
|
||||||
#pragma warning disable CS0169, CS0649
|
|
||||||
|
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
|
||||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
|
||||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
|
|
||||||
[BigEndian]
|
|
||||||
public partial class Battery250UpRecord
|
|
||||||
{
|
|
||||||
[InputRegister(1004)] private UInt16 _LedStates;
|
|
||||||
[InputRegister<UInt64>(1005)] private UInt64 _WarningFlags;
|
|
||||||
[InputRegister<UInt64>(1009)] private UInt64 _AlarmFlags;
|
|
||||||
[InputRegister(1013)] private UInt16 _IoStates;
|
|
||||||
|
|
||||||
[InputRegister(999, Scale = 0.01)] private Double _CellsVoltage;
|
|
||||||
[InputRegister(1001, Scale = 0.01)] private Double _BusVoltage;
|
|
||||||
[InputRegister(1000, Scale = 0.01, Offset = -10000)] private Double _CellsCurrent;
|
|
||||||
[InputRegister(1002, Scale = 0.1, Offset = -10000)] private Double _SOCAh;
|
|
||||||
|
|
||||||
|
|
||||||
[InputRegister(1062, Scale = 0.01, Offset = -10000)] private Double _BusCurrent;
|
|
||||||
|
|
||||||
[InputRegister(1053, Scale = 0.1)] private Double _Soc;
|
|
||||||
[InputRegister(1052)] private UInt16 _TimeSinceToc;
|
|
||||||
|
|
||||||
[InputRegister(1014, Scale = 0.1, Offset = -400)] private Double _TemperaturesBoard;
|
|
||||||
[InputRegister(1015, Scale = 0.1, Offset = -400)] private Double _TemperaturesCellsCenter;
|
|
||||||
[InputRegister(1016, Scale = 0.1, Offset = -400)] private Double _TemperaturesCellsLeft;
|
|
||||||
[InputRegister(1017, Scale = 0.1, Offset = -400)] private Double _TemperaturesCellsRight;
|
|
||||||
[InputRegister(1003, Scale = 0.1, Offset = -400)] private Double _TemperaturesCellsAverage;
|
|
||||||
|
|
||||||
[InputRegister(1054)] private UInt16 _FwVersion;
|
|
||||||
[InputRegister(1055)] private UInt16 _SerialNum1;
|
|
||||||
[InputRegister(1056)] private UInt16 _SerialNum2;
|
|
||||||
[InputRegister(1057)] private UInt16 _SerialNum3;
|
|
||||||
[InputRegister(1058)] private UInt16 _SerialNum4;
|
|
||||||
[InputRegister(1059)] private UInt16 _LimpBitMap;
|
|
||||||
[InputRegister(1060)] private UInt16 _BatteryState1;
|
|
||||||
[InputRegister(1061)] private UInt16 _BatteryState2;
|
|
||||||
|
|
||||||
//[InputRegister(1063)] private UInt16 _TotalBatteryCycle;
|
|
||||||
|
|
||||||
|
|
||||||
private LedState ParseLed(LedColor led) => (LedState)((_LedStates >> (Int32)led) & 3);
|
|
||||||
|
|
||||||
// public Decimal CellsVoltage { get; init; }
|
|
||||||
//
|
|
||||||
// public Decimal MaxChargingPower { get; init; }
|
|
||||||
// public Decimal MaxDischargingPower { get; init; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
using InnovEnergy.Lib.Units;
|
|
||||||
using InnovEnergy.Lib.Units.Composite;
|
|
||||||
using InnovEnergy.Lib.Units.Power;
|
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up;
|
|
||||||
|
|
||||||
public class Battery250UpRecords
|
|
||||||
{
|
|
||||||
public required DcBus Dc { get; init; }
|
|
||||||
public required Boolean Eoc { get; init; }
|
|
||||||
public required IReadOnlyList<String> Warnings { get; init; }
|
|
||||||
public required IReadOnlyList<String> Alarms { get; init; }
|
|
||||||
public required Percent Soc { get; init; }
|
|
||||||
public required Double SocAh { get; init; }
|
|
||||||
public required Percent CurrentMinSoc { get; init; }
|
|
||||||
public required Temperature Temperature { get; init; }
|
|
||||||
public required DcPower HeatingPower { get; init; }
|
|
||||||
public required TimeSpan TimeSinceToc { get; init; }
|
|
||||||
public required Boolean CalibrationChargeRequested { get; init; }
|
|
||||||
|
|
||||||
public required IReadOnlyList<Battery250UpRecord> Devices { get; init; }
|
|
||||||
|
|
||||||
public static Battery250UpRecords? FromBatteries(IReadOnlyList<Battery250UpRecord>? records)
|
|
||||||
{
|
|
||||||
if (records is null || records.Count == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return new Battery250UpRecords
|
|
||||||
{
|
|
||||||
Devices = records,
|
|
||||||
Eoc = records.All(r => r.Eoc),
|
|
||||||
Warnings = records.SelectMany(r => r.Warnings).Distinct().ToList(),
|
|
||||||
Alarms = records.SelectMany(r => r.Alarms).Distinct().ToList(),
|
|
||||||
Soc = records.Average(r => r.Soc.Value),
|
|
||||||
SocAh = records.Average(r => r.SOCAh),
|
|
||||||
CurrentMinSoc = records.Min(r => r.Soc.Value),
|
|
||||||
Temperature = records.Average(b => b.Temperatures.Cells.Average.Value),
|
|
||||||
HeatingPower = records.Sum(b => b.HeatingPower),
|
|
||||||
TimeSinceToc = records.Max(r => r.TimeSinceTOC),
|
|
||||||
CalibrationChargeRequested = records.Any(r => r.CalibrationChargeRequested), // we changed this to Any instead of All, it's mean we wait only one battery to reach the 7 days
|
|
||||||
|
|
||||||
Dc = new()
|
|
||||||
{
|
|
||||||
Voltage = records.Average(r => r.Dc.Voltage),
|
|
||||||
Current = records.Sum(r => r.Dc.Current),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
using System.IO.Ports;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Slaves;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
|
||||||
using static System.IO.Ports.Parity;
|
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up;
|
|
||||||
|
|
||||||
public class Battery250UpDevice : ModbusDevice<Battery250UpRecord>
|
|
||||||
{
|
|
||||||
public const Parity Parity = Odd;
|
|
||||||
public const Int32 StopBits = 1;
|
|
||||||
public const Int32 BaudRate = 115200;
|
|
||||||
public const Int32 DataBits = 8;
|
|
||||||
|
|
||||||
public Byte SlaveId { get; }
|
|
||||||
|
|
||||||
public Battery250UpDevice(String tty, Byte slaveId, SshHost host) : this
|
|
||||||
(
|
|
||||||
channel: new RemoteSerialChannel(host, tty, BaudRate, Parity, DataBits, StopBits),
|
|
||||||
slaveId
|
|
||||||
)
|
|
||||||
{}
|
|
||||||
|
|
||||||
public Battery250UpDevice(String tty, Byte slaveId, String? host = null) : this
|
|
||||||
(
|
|
||||||
channel: host switch
|
|
||||||
{
|
|
||||||
null => new SerialPortChannel ( tty, BaudRate, Parity, DataBits, StopBits),
|
|
||||||
_ => new RemoteSerialChannel(host, tty, BaudRate, Parity, DataBits, StopBits)
|
|
||||||
},
|
|
||||||
slaveId
|
|
||||||
)
|
|
||||||
{}
|
|
||||||
|
|
||||||
public Battery250UpDevice(Channel channel, Byte slaveId) : this
|
|
||||||
(
|
|
||||||
client: new ModbusRtuClient(channel, slaveId)
|
|
||||||
)
|
|
||||||
{}
|
|
||||||
|
|
||||||
public Battery250UpDevice(ModbusClient client): base(client)
|
|
||||||
{
|
|
||||||
SlaveId = client.SlaveId;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
using InnovEnergy.Lib.Units;
|
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up.DataTypes;
|
|
||||||
|
|
||||||
public readonly struct CellTemperatures
|
|
||||||
{
|
|
||||||
public Temperature Center { get; internal init; }
|
|
||||||
public Temperature Left { get; internal init; }
|
|
||||||
public Temperature Right { get; internal init; }
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.IO.Ports;
|
|
||||||
using static System.IO.Ports.Parity;
|
|
||||||
|
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up.DataTypes;
|
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
|
||||||
public static class Constants
|
|
||||||
{
|
|
||||||
public const Int32 BaseAddress = 1000;
|
|
||||||
public const Int32 NoOfRegisters = 56;
|
|
||||||
|
|
||||||
public const Parity Parity = Odd;
|
|
||||||
public const Int32 StopBits = 1;
|
|
||||||
public const Int32 BaudRate = 115200;
|
|
||||||
public const Int32 DataBits = 8;
|
|
||||||
public static TimeSpan Timeout { get; } = TimeSpan.FromMilliseconds(100);
|
|
||||||
|
|
||||||
public const Double VMax = 59.0;
|
|
||||||
public const Double VMin = 42.0;
|
|
||||||
public const Double AhPerString = 40.0;
|
|
||||||
|
|
||||||
private const Double RStringMin = 0.125;
|
|
||||||
private const Double RStringMax = 0.250;
|
|
||||||
private const Double IMaxPerString = 20.0;
|
|
||||||
private const UInt16 NumberOfStrings = 5;
|
|
||||||
|
|
||||||
public const Double RIntMin = RStringMin / NumberOfStrings;
|
|
||||||
public const Double RIntMax = RStringMax / NumberOfStrings;
|
|
||||||
public const Double IMax = NumberOfStrings * IMaxPerString;
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up.DataTypes;
|
|
||||||
|
|
||||||
public enum LedColor
|
|
||||||
{
|
|
||||||
Green = 0, // don't change: numbers are important
|
|
||||||
Amber = 2,
|
|
||||||
Blue = 4,
|
|
||||||
Red = 6,
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up.DataTypes;
|
|
||||||
|
|
||||||
public enum LedState
|
|
||||||
{
|
|
||||||
Off = 0,
|
|
||||||
On = 1,
|
|
||||||
Blinking = 2,
|
|
||||||
BlinkingFast = 3
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up.DataTypes;
|
|
||||||
|
|
||||||
public readonly struct Leds
|
|
||||||
{
|
|
||||||
public LedState Blue { get; internal init; }
|
|
||||||
public LedState Green { get; internal init; }
|
|
||||||
public LedState Amber { get; internal init; }
|
|
||||||
public LedState Red { get; internal init; }
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace InnovEnergy.Lib.Devices.Battery250Up.DataTypes;
|
|
||||||
|
|
||||||
public enum TemperatureState
|
|
||||||
{
|
|
||||||
Cold = 0,
|
|
||||||
Operation = 1,
|
|
||||||
Overheated = 2,
|
|
||||||
}
|
|
Binary file not shown.
|
@ -0,0 +1,80 @@
|
||||||
|
// namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
|
||||||
|
//
|
||||||
|
// public static class AcControlRegisters
|
||||||
|
// {
|
||||||
|
// public const UInt16 Date = 1001;
|
||||||
|
// public const UInt16 Time = 1003;
|
||||||
|
// public const UInt16 IpAddress = 1005;
|
||||||
|
// public const UInt16 Subnet = 1007;
|
||||||
|
// public const UInt16 Gateway = 1009;
|
||||||
|
// public const UInt16 ResetParamToDefault = 1011;
|
||||||
|
// public const UInt16 CommunicationTimeout = 1017;
|
||||||
|
// public const UInt16 RestartFlag = 1018;
|
||||||
|
// public const UInt16 ConnectedSystemConfig = 1019;
|
||||||
|
// public const UInt16 UpdateSwTrigger = 1027;
|
||||||
|
// public const UInt16 AutomaticSwUpdate = 1028;
|
||||||
|
// public const UInt16 CustomerValuesSaveReset = 1029;
|
||||||
|
// public const UInt16 SerialNumberSystemControl = 2001;
|
||||||
|
// public const UInt16 SerialNumberAcDc = 2009;
|
||||||
|
// public const UInt16 IntegrationLevel = 2051;
|
||||||
|
// public const UInt16 IlBuildnumber = 2052;
|
||||||
|
// public const UInt16 PowerStageConfig = 4001;
|
||||||
|
// public const UInt16 SetValueConfig = 4002;
|
||||||
|
// public const UInt16 ResetsAlarmAndWarning = 4003;
|
||||||
|
// public const UInt16 PreChargeDcLinkConfigR = 4006;
|
||||||
|
// public const UInt16 ReferenceFrameConvention = 4007;
|
||||||
|
// public const UInt16 SlaveAddress = 4008;
|
||||||
|
// public const UInt16 ErrorHandlingPolicy = 4009;
|
||||||
|
// public const UInt16 GridType = 4010;
|
||||||
|
// public const UInt16 SubSlaveAddress = 4011;
|
||||||
|
// public const UInt16 ModbusSlaveId = 4012;
|
||||||
|
// public const UInt16 SubSlaveErrorPolicy = 4013;
|
||||||
|
// public const UInt16 SignedPowerNominalValue = 4196;
|
||||||
|
// public const UInt16 SignedPowerSetValueL1 = 4197;
|
||||||
|
// public const UInt16 SignedPowerSetValueL2 = 4198;
|
||||||
|
// public const UInt16 SignedPowerSetValueL3 = 4199;
|
||||||
|
// public const UInt16 Powe0rSetValue = 4200;
|
||||||
|
// public const UInt16 PowerSetValueL1 = 4201;
|
||||||
|
// public const UInt16 PowerSetValueL2 = 4202;
|
||||||
|
// public const UInt16 PowerSetValueL3 = 4203;
|
||||||
|
// public const UInt16 MaximumGridCurrentRmsL1 = 4204;
|
||||||
|
// public const UInt16 MaximumGridCurrentRmsL2 = 4205;
|
||||||
|
// public const UInt16 MaximumGridCurrentRmsL3 = 4206;
|
||||||
|
// public const UInt16 CosPhiSetValueL1 = 4207;
|
||||||
|
// public const UInt16 CosPhiSetValueL2 = 4208;
|
||||||
|
// public const UInt16 CosPhiSetValueL3 = 4209;
|
||||||
|
// public const UInt16 PhaseL1IsCapacitive = 4214; // True = Capacitive, false = Inductive
|
||||||
|
// public const UInt16 PhaseL2IsCapacitive = 4215; // True = Capacitive, false = Inductive
|
||||||
|
// public const UInt16 PhaseL3IsCapacitive = 4216; // True = Capacitive, false = Inductive
|
||||||
|
// public const UInt16 PhasesAreCapacitive = 4217; // True = Capacitive, false = Inductive
|
||||||
|
// public const UInt16 SetPointCosPhi = 4218;
|
||||||
|
// public const UInt16 SetPointSinPhi = 4219;
|
||||||
|
// public const UInt16 SetPointSinPhiL1 = 4220;
|
||||||
|
// public const UInt16 SetPointSinPhiL2 = 4221;
|
||||||
|
// public const UInt16 SetPointSinPhiL3 = 4222;
|
||||||
|
// public const UInt16 FrequencyOffsetIm = 4223; //Im: Island mode
|
||||||
|
// public const UInt16 VoltageAdjustmentFactorIm = 4224; //Im: Island mode
|
||||||
|
// public const UInt16 PreChargeDcLinkVoltage = 4226;
|
||||||
|
// public const UInt16 MaxPeakCurrentVoltageControlL1 = 4227;
|
||||||
|
// public const UInt16 MaxPeakCurrentVoltageControlL2 = 4228;
|
||||||
|
// public const UInt16 MaxPeakCurrentVoltageControlL3 = 4229;
|
||||||
|
// public const UInt16 GridFormingMode = 4230;
|
||||||
|
// public const UInt16 DcLinkReferenceVoltage = 4231;
|
||||||
|
// public const UInt16 DcLinkMinVoltage = 4232;
|
||||||
|
// public const UInt16 DcLinkMaxVoltage = 4233;
|
||||||
|
// public const UInt16 AcDcDcVoltageRefUs = 4234;
|
||||||
|
// public const UInt16 AcDcMinDcLinkVoltageUs = 4235;
|
||||||
|
// public const UInt16 AcDcMaxDcLinkVoltageUs = 4236;
|
||||||
|
// // public const UInt16 FrequencySlopeIslandMode = 4237, // Function fN = f(active grid-power) of droop control
|
||||||
|
// // public const UInt16 VoltageSlopeIslandMode = 4238, // VN = f(reactive grid power) of droop control in island operation.
|
||||||
|
// public const UInt16 AcDcGcBypassMode = 4281;
|
||||||
|
// public const UInt16 AcDcGcPMaxThresholdPercent = 4282; // res
|
||||||
|
// public const UInt16 AcDcGcStartupRampEnable = 4283;
|
||||||
|
// public const UInt16 DcConfigModule = 4301; // 0 = DC module is off, battery voltage can be measured
|
||||||
|
// // 1 = DC module is active (DC link voltage control)
|
||||||
|
// // 2 = DC module is active(current source mode orin DC droop mode)
|
||||||
|
// public const UInt16 DcDcPowerDistribution = 4304;
|
||||||
|
// public const UInt16 AcDcDistributionMode = 4307;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
Loading…
Reference in New Issue