Battery48TL V2

This commit is contained in:
ig 2023-06-13 12:53:52 +02:00
parent fd92374a4f
commit 8b846c01c2
11 changed files with 334 additions and 403 deletions

View File

@ -7,8 +7,7 @@ using static System.IO.Ports.Parity;
namespace InnovEnergy.Lib.Devices.Battery48TL;
public class Battery48TlDevice: ModbusDevice<Battery48TlRegisters>
public class Battery48TlDevice: ModbusDevice<Battery48TlRecord>
{
public const Parity Parity = Odd;
public const Int32 StopBits = 1;
@ -18,7 +17,7 @@ public class Battery48TlDevice: ModbusDevice<Battery48TlRegisters>
public Battery48TlDevice(String tty, Byte slaveId, SshHost host) : this
(
channel: new RemoteSerialChannel(host, tty, BaudRate, Parity, StopBits, DataBits),
channel: new RemoteSerialChannel(host, tty, BaudRate, Parity, DataBits, StopBits),
slaveId
)
{}
@ -27,8 +26,8 @@ public class Battery48TlDevice: ModbusDevice<Battery48TlRegisters>
(
channel: host switch
{
null => new SerialPortChannel ( tty, BaudRate, Parity, StopBits, DataBits),
_ => new RemoteSerialChannel(host, tty, BaudRate, Parity, StopBits, DataBits)
null => new SerialPortChannel ( tty, BaudRate, Parity, DataBits, StopBits),
_ => new RemoteSerialChannel(host, tty, BaudRate, Parity, DataBits, StopBits)
},
slaveId
)

View File

@ -0,0 +1,31 @@
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Devices.Battery48TL;
public class Battery48TlDevices
{
private readonly IReadOnlyList<Battery48TlDevice> _Devices;
public Battery48TlDevices(IReadOnlyList<Battery48TlDevice> devices) => _Devices = devices;
public Battery48TlRecords Read()
{
try
{
var records = _Devices
.Select(d => d.Read())
.ToArray(_Devices.Count);
return new Battery48TlRecords(records);
}
catch (Exception e)
{
Console.WriteLine(e);
// TODO: log
return Battery48TlRecords.Null;
}
}
}

View File

@ -0,0 +1,195 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Battery48TL.DataTypes;
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Units.Power;
using static InnovEnergy.Lib.Devices.Battery48TL.DataTypes.LedState;
namespace InnovEnergy.Lib.Devices.Battery48TL;
using Strings = IReadOnlyList<String>;
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "ConvertToAutoProperty")]
public partial class Battery48TlRecord
{
public Dc_ Dc => new Dc_(this);
public Leds_ Leds => new Leds_(this);
public Temperatures_ Temperatures => new Temperatures_(this);
public Boolean ConnectedToDcBus => (_IoStates & 1) == 0;
public Boolean Eoc => Leds is { Green: On, Amber: Off, Blue : Off };
public Strings Warnings => ParseWarnings().OrderBy(w => w).ToList();
public Strings Alarms => ParseAlarms() .OrderBy(w => w).ToList();
public Percent Soc => _Soc;
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 Battery48TlRecord Self { get; }
internal Leds_(Battery48TlRecord self) => this.Self = self;
}
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_(Battery48TlRecord self) => Self = self;
private Battery48TlRecord Self { get; }
}
public readonly struct Cells_
{
public Temperature Center => Self._TemperaturesCellsCenter;
public Temperature Left => Self._TemperaturesCellsLeft;
public Temperature Right => Self._TemperaturesCellsRight;
internal Cells_(Battery48TlRecord self) => Self = self;
private Battery48TlRecord Self { get; }
}
public readonly struct Dc_
{
public Voltage Voltage => Self._DcVoltage;
public Current Current => Self._DcCurrent;
public ActivePower Power => Self._DcVoltage * Self._DcCurrent;
internal Dc_(Battery48TlRecord self) => Self = self;
private Battery48TlRecord Self { get; }
}
[SuppressMessage("ReSharper", "StringLiteralTypo")]
internal IEnumerable<String> ParseAlarms()
{
Boolean HasBit(Int16 bit) => (_AlarmFlags & 1uL << bit) > 0;
if (HasBit(0) ) yield return "Tam : BMS temperature too low";
if (HasBit(2) ) yield return "TaM2 : BMS 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 :";
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(22)) yield return "vsm1 : String voltage too low";
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(33)) yield return "CCBF : Internal charger hardware failure";
if (HasBit(34)) yield return "AhFL :";
if (HasBit(36)) yield return "TbCM :";
if (HasBit(37)) yield return "BRNF :";
if (HasBit(42)) yield return "HTFS : Heater Fuse Blown";
if (HasBit(43)) yield return "DATA : Parameters out of range";
if (HasBit(45)) yield return "CELL2:";
}
[SuppressMessage("ReSharper", "StringLiteralTypo")]
internal 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(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(35)) yield return "Ah_W: String SOC low";
if (HasBit(38)) yield return "MPMM: Midpoint wiring problem";
if (HasBit(39)) yield return "TCMM:";
if (HasBit(40)) yield return "TCdi: Temperature difference between strings high";
if (HasBit(41)) yield return "WMTO:";
if (HasBit(44)) yield return "bit44:";
if (HasBit(46)) yield return "CELL1:";
}
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);
}
}
}

View File

@ -0,0 +1,40 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Battery48TL.DataTypes;
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
using InnovEnergy.Lib.SrcGen.Attributes;
namespace InnovEnergy.Lib.Devices.Battery48TL;
#pragma warning disable CS0169, CS0649
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
[BigEndian]
[NestProperties("Battery48TlRecord")]
public partial class Battery48TlRecord
{
[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 _DcVoltage;
[InputRegister(1000, Scale = 0.01, Offset = -10000)] private Double _DcCurrent;
[InputRegister(1053, Scale = 0.1)] private Double _Soc;
[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;
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; }
}

View File

@ -0,0 +1,36 @@
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.Devices.Battery48TL;
public class Battery48TlRecords
{
public Battery48TlRecords(IReadOnlyList<Battery48TlRecord> records)
{
var empty = records.Count == 0;
Devices = records;
Eoc = !empty && records.All(r => r.Eoc);
Warnings = records.SelectMany(r => r.Warnings).Distinct().ToList();
Alarms = records.SelectMany(r => r.Alarms).Distinct().ToList();
Soc = empty ? 0 : records.Min(r => r.Soc.Value);
Dc = empty
? DcBus.FromVoltageCurrent(0, 0)
: DcBus.FromVoltageCurrent
(
records.Average(r => r.Dc.Voltage),
records.Sum(r => r.Dc.Current)
);
}
public DcBus Dc { get; init; }
public Boolean Eoc { get; init; }
public IReadOnlyList<String> Warnings { get; init; }
public IReadOnlyList<String> Alarms { get; init; }
public Percent Soc { get; init; }
public IReadOnlyList<Battery48TlRecord> Devices { get; init; }
public static Battery48TlRecords Null { get; } = new Battery48TlRecords(Array.Empty<Battery48TlRecord>());
}

View File

@ -1,55 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Battery48TL.DataTypes;
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
using InnovEnergy.Lib.StatusApi.DeviceTypes;
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.Devices.Battery48TL;
#pragma warning disable CS0169, CS0649
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[BigEndian] // alarm/warning flags
public record Battery48TlRegisters : IBattery
{
[InputRegister(1004)] internal UInt16 _LedStates;
[InputRegister<UInt64>(1005)] internal UInt64 _WarningFlags;
[InputRegister<UInt64>(1009)] internal UInt64 _AlarmFlags;
[InputRegister(1013)] internal UInt16 _IoStates;
[InputRegister(999, Scale = 0.01)] internal Double _Voltage ;
[InputRegister(1000, Scale = 0.01, Offset = -10000)] internal Double _Current ;
[InputRegister(1053, Scale = 0.1)] internal Double _Soc;
[InputRegister(1014, Scale = 0.1, Offset = -400)] internal Double _TemperatureBoard ;
[InputRegister(1015, Scale = 0.1, Offset = -400)] internal Double _TemperatureCellsCenter ;
[InputRegister(1016, Scale = 0.1, Offset = -400)] internal Double _TemperatureCellsLeft ;
[InputRegister(1017, Scale = 0.1, Offset = -400)] internal Double _TemperatureCellsRight ;
public DcBus Dc => DcBus.FromVoltageCurrent(_Voltage, _Current);
public Percent Soc => _Soc;
public Leds Leds => this.ParseLeds();
public Temperatures Temperature => this.ParseBatteryTemperatures();
public Boolean ConnectedToDcBus => this.ParseConnectedToDcBus();
public Boolean Heating => this.ParseHeating();
public Boolean Eoc => this.ParseEoc();
public IReadOnlyList<String> Warnings => this.ParseWarnings().ToList() ;
public IReadOnlyList<String> Alarms => this.ParseAlarms().ToList() ;
//
// public Decimal CellsVoltage { get; init; }
//
// public Decimal MaxChargingPower { get; init; }
// public Decimal MaxDischargingPower { get; init; }
}

View File

@ -16,16 +16,16 @@ public static class Constants
public const Int32 DataBits = 8;
public static TimeSpan Timeout { get; } = TimeSpan.FromMilliseconds(100);
public const Decimal VMax = 59.0m;
public const Decimal VMin = 42.0m;
public const Decimal AhPerString = 40.0m;
public const Double VMax = 59.0;
public const Double VMin = 42.0;
public const Double AhPerString = 40.0;
private const Decimal RStringMin = 0.125m;
private const Decimal RStringMax = 0.250m;
private const Decimal IMaxPerString = 20.0m;
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 Decimal RIntMin = RStringMin / NumberOfStrings;
public const Decimal RIntMax = RStringMax / NumberOfStrings;
public const Decimal IMax = NumberOfStrings * IMaxPerString;
public const Double RIntMin = RStringMin / NumberOfStrings;
public const Double RIntMax = RStringMax / NumberOfStrings;
public const Double IMax = NumberOfStrings * IMaxPerString;
}

View File

@ -1,23 +0,0 @@
using InnovEnergy.Lib.Units;
using static InnovEnergy.Lib.Devices.Battery48TL.DataTypes.LedState;
namespace InnovEnergy.Lib.Devices.Battery48TL.DataTypes;
public readonly struct Temperatures
{
public CellTemperatures Cells { get; internal init; }
public Temperature Board { get; internal init; }
public TemperatureState State { get; internal init; }
}
// public abstract record Result
// {
// private Result() { }
//
// public sealed record Ok(object result) : Result;
// public sealed record Error(string message) : Result;
// }

View File

@ -1,183 +0,0 @@
// using System.Diagnostics.CodeAnalysis;
// using InnovEnergy.Lib.Devices.Battery48TL.DataTypes;
// using InnovEnergy.Lib.Protocols.Modbus.Conversions;
// using InnovEnergy.Lib.Utils;
//
// namespace InnovEnergy.Lib.Devices.Battery48TL;
//
// public static class ModbusParser
// {
// public static Decimal ParseDecimal(this ModbusRegisters data, Int32 register, Decimal scaleFactor = 1.0m, Double offset = 0.0)
// {
// var value = data[register].ConvertTo<Int32>(); // widen to 32bit signed
//
// if (value >= 0x8000)
// value -= 0x10000; // Fiamm stores their integers signed AND with sign-offset @#%^&!
//
// return (Decimal)(value + offset) * scaleFactor;
// }
//
// internal static Decimal ParseCurrent(this ModbusRegisters data)
// {
// return data.ParseDecimal(register: 1001, scaleFactor: 0.01m, offset: -10000);
// }
//
// internal static Decimal ParseBusVoltage(this ModbusRegisters data)
// {
// return data.ParseDecimal(register: 1002, scaleFactor: 0.01m);
// }
//
// internal static Boolean ParseBool(this ModbusRegisters data, Int32 baseRegister, Int16 bit)
// {
// var x = bit / 16;
// var y = bit % 16;
//
// var value = (UInt32)data[baseRegister + x];
//
// return (value & (1 << y)) > 0;
// }
//
//
// internal static LedState ParseLed(this UInt16 ledStates, LedColor led)
// {
// return (LedState)((ledStates >> (Int32)led * 2) & 3);
// }
//
//
// private static Decimal CalcPowerLimitImposedByVoltageLimit(Decimal v, Decimal i, Decimal vLimit, Decimal rInt)
// {
// var dv = vLimit - v;
// var di = dv / rInt;
// var pLimit = vLimit * (i + di);
//
// return pLimit;
// }
//
// private static Decimal CalcPowerLimitImposedByCurrentLimit(Decimal v, Decimal i, Decimal iLimit, Decimal rInt)
// {
// var di = iLimit - i;
// var dv = di * rInt;
// var pLimit = iLimit * (v + dv);
//
// return pLimit;
// }
//
//
// private static Decimal CalcPowerLimitImposedByTempLimit(Decimal t, Decimal maxAllowedTemp, Decimal power , Decimal setpoint)
// {
// // const Int32 holdZone = 300;
// // const Int32 maxAllowedTemp = 315;
//
// var kp = 0.05m;
// var error = setpoint - power;
// var controlOutput = (kp * error) *(1 - Math.Abs((t-307.5m)/7.5m));
//
// return controlOutput;
//
// // var a = holdZone - maxAllowedTemp;
// // var b = -a * maxAllowedTemp;
// }
//
// internal static Decimal CalcMaxChargePower(this ModbusRegisters data)
// {
// var v = data.ParseDecimal(register: 1000, scaleFactor: 0.01m);
// var i = ParseCurrent(data);
//
// var pLimits = new[]
// {
// // TODO: review
// CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMax, Constants.RIntMin),
// CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMax, Constants.RIntMax),
// CalcPowerLimitImposedByCurrentLimit(v, i, Constants.IMax, Constants.RIntMin),
// CalcPowerLimitImposedByCurrentLimit(v, i, Constants.IMax, Constants.RIntMax)
// };
//
// var pLimit = pLimits.Min();
//
// return Math.Max(pLimit, 0);
// }
//
// internal static DcBus ParseDcBus(this ModbusRegisters data) => new()
// {
// Current = data.ParseCurrent(),
// Voltage = data.ParseBusVoltage(),
// };
//
// internal static Decimal CalcMaxDischargePower(this ModbusRegisters data)
// {
// var v = data.ParseDecimal(register: 1000, scaleFactor: 0.01m);
// var i = ParseCurrent(data);
//
// var pLimits = new[]
// {
// // TODO: review
// CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMin, Constants.RIntMin),
// CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMin, Constants.RIntMax),
// CalcPowerLimitImposedByCurrentLimit(v, i, -Constants.IMax, Constants.RIntMin),
// CalcPowerLimitImposedByCurrentLimit(v, i, -Constants.IMax, Constants.RIntMax),
// // CalcPowerLimitImposedByTempLimit(t,315,300)
// };
//
// var pLimit = pLimits.Max();
//
// return Math.Min(pLimit, 0);
// }
//
//
// [SuppressMessage("ReSharper", "StringLiteralTypo")]
// internal static IEnumerable<String> ParseAlarms(this ModbusRegisters data)
// {
// if (data.ParseBool(1010, 0)) yield return "Tam : BMS temperature too low";
// if (data.ParseBool(1010, 2)) yield return "TaM2 : BMS temperature too high";
// if (data.ParseBool(1010, 3)) yield return "Tbm : Battery temperature too low";
// if (data.ParseBool(1010, 5)) yield return "TbM2 : Battery temperature too high";
// if (data.ParseBool(1010, 7)) yield return "VBm2 : Bus voltage too low";
// if (data.ParseBool(1010, 9)) yield return "VBM2 : Bus voltage too high";
// if (data.ParseBool(1010, 11)) yield return "IDM2 : Discharge current too high";
// if (data.ParseBool(1010, 12)) yield return "ISOB : Electrical insulation failure";
// if (data.ParseBool(1010, 13)) yield return "MSWE : Main switch failure";
// if (data.ParseBool(1010, 14)) yield return "FUSE : Main fuse blown";
// if (data.ParseBool(1010, 15)) yield return "HTRE : Battery failed to warm up";
// if (data.ParseBool(1010, 16)) yield return "TCPE : Temperature sensor failure";
// if (data.ParseBool(1010, 17)) yield return "STRE :";
// if (data.ParseBool(1010, 18)) yield return "CME : Current sensor failure";
// if (data.ParseBool(1010, 19)) yield return "HWFL : BMS hardware failure";
// if (data.ParseBool(1010, 20)) yield return "HWEM : Hardware protection tripped";
// if (data.ParseBool(1010, 21)) yield return "ThM : Heatsink temperature too high";
// if (data.ParseBool(1010, 22)) yield return "vsm1 : String voltage too low";
// if (data.ParseBool(1010, 23)) yield return "vsm2 : Low string voltage failure";
// if (data.ParseBool(1010, 25)) yield return "vsM2 : String voltage too high";
// if (data.ParseBool(1010, 27)) yield return "iCM2 : Charge current too high";
// if (data.ParseBool(1010, 29)) yield return "iDM2 : Discharge current too high";
// if (data.ParseBool(1010, 31)) yield return "MID2 : String voltage unbalance too high";
// if (data.ParseBool(1010, 33)) yield return "CCBF : Internal charger hardware failure";
// if (data.ParseBool(1010, 34)) yield return "AhFL :";
// if (data.ParseBool(1010, 36)) yield return "TbCM :";
// if (data.ParseBool(1010, 37)) yield return "BRNF :";
// if (data.ParseBool(1010, 42)) yield return "HTFS : If Heaters Fuse Blown";
// if (data.ParseBool(1010, 43)) yield return "DATA : Parameters out of range";
// if (data.ParseBool(1010, 45)) yield return "CELL2:";
// }
//
// [SuppressMessage("ReSharper", "StringLiteralTypo")]
// internal static IEnumerable<String> ParseWarnings(this ModbusRegisters data)
// {
// if (data.ParseBool(1006, 1)) yield return "TaM1: BMS temperature high";
// if (data.ParseBool(1006, 4)) yield return "TbM1: Battery temperature high";
// if (data.ParseBool(1006, 6)) yield return "VBm1: Bus voltage low";
// if (data.ParseBool(1006, 8)) yield return "VBM1: Bus voltage high";
// if (data.ParseBool(1006, 10)) yield return "IDM1: Discharge current high";
// if (data.ParseBool(1006, 24)) yield return "vsM1: String voltage high";
// if (data.ParseBool(1006, 26)) yield return "iCM1: Charge current high";
// if (data.ParseBool(1006, 28)) yield return "iDM1: Discharge current high";
// if (data.ParseBool(1006, 30)) yield return "MID1: String voltages unbalanced";
// if (data.ParseBool(1006, 32)) yield return "BLPW: Not enough charging power on bus";
// if (data.ParseBool(1006, 35)) yield return "Ah_W: String SOC low";
// if (data.ParseBool(1006, 38)) yield return "MPMM: Midpoint wiring problem";
// if (data.ParseBool(1006, 39)) yield return "TCMM:";
// if (data.ParseBool(1006, 40)) yield return "TCdi: Temperature difference between strings high";
// if (data.ParseBool(1006, 41)) yield return "WMTO:";
// if (data.ParseBool(1006, 44)) yield return "bit44:";
// if (data.ParseBool(1006, 46)) yield return "CELL1:";
// }
// }

View File

@ -1,122 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Battery48TL.DataTypes;
using InnovEnergy.Lib.Protocols.Modbus.Conversions;
using static InnovEnergy.Lib.Devices.Battery48TL.DataTypes.LedState;
using static InnovEnergy.Lib.Devices.Battery48TL.DataTypes.TemperatureState;
namespace InnovEnergy.Lib.Devices.Battery48TL;
using R = Battery48TlRegisters;
internal static class Parser
{
internal static Boolean ParseEoc(this R r)
{
return r.Leds is
{
Green: On,
Amber: Off,
Blue : Off
};
}
internal static Leds ParseLeds(this R r)
{
LedState ParseLed(LedColor led) => (LedState)((r._LedStates >> (Int32)led) & 3);
return new()
{
Blue = ParseLed(LedColor.Blue),
Green = ParseLed(LedColor.Green),
Amber = ParseLed(LedColor.Amber),
Red = ParseLed(LedColor.Red),
};
}
internal static Temperatures ParseBatteryTemperatures(this R r) => new()
{
Board = r._TemperatureBoard,
Cells = r.ParseCells(),
State = r.ParseTemperatureState()
};
private static TemperatureState ParseTemperatureState(this R r) => r.Leds switch
{
{ Green: >= Blinking, Blue: >= Blinking } => Cold,
_ => Operation,
// TODO: overheated
};
private static CellTemperatures ParseCells(this R r) => new()
{
Left = r._TemperatureCellsLeft,
Right = r._TemperatureCellsRight,
Center = r._TemperatureCellsCenter
};
internal static Boolean ParseConnectedToDcBus(this R r) => (r._IoStates & 1) == 0; // inverted
internal static Boolean ParseHeating (this R r) => (r._IoStates & 64) != 0;
[SuppressMessage("ReSharper", "StringLiteralTypo")]
internal static IEnumerable<String> ParseAlarms(this R data)
{
Boolean HasBit(Int16 bit) => (data._AlarmFlags & 1uL << bit) > 0;
if (HasBit(0) ) yield return "Tam : BMS temperature too low";
if (HasBit(2) ) yield return "TaM2 : BMS 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 :";
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(22)) yield return "vsm1 : String voltage too low";
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(33)) yield return "CCBF : Internal charger hardware failure";
if (HasBit(34)) yield return "AhFL :";
if (HasBit(36)) yield return "TbCM :";
if (HasBit(37)) yield return "BRNF :";
if (HasBit(42)) yield return "HTFS : If Heaters Fuse Blown";
if (HasBit(43)) yield return "DATA : Parameters out of range";
if (HasBit(45)) yield return "CELL2:";
}
[SuppressMessage("ReSharper", "StringLiteralTypo")]
internal static IEnumerable<String> ParseWarnings(this R data)
{
Boolean HasBit(Int16 bit) => (data._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(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(35)) yield return "Ah_W: String SOC low";
if (HasBit(38)) yield return "MPMM: Midpoint wiring problem";
if (HasBit(39)) yield return "TCMM:";
if (HasBit(40)) yield return "TCdi: Temperature difference between strings high";
if (HasBit(41)) yield return "WMTO:";
if (HasBit(44)) yield return "bit44:";
if (HasBit(46)) yield return "CELL1:";
}
}

View File

@ -1,7 +1,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Protocols.Modbus.Channels;
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Utils;
using static InnovEnergy.Lib.Devices.Battery48TL.Battery48TlDevice;
namespace InnovEnergy.Lib.Devices.Battery48TL;
@ -9,14 +9,27 @@ public static class Program
{
public static Task Main(string[] args)
{
var d = new Battery48TlDevice("ttyUSB0", 2, "10.2.3.47");
var host = new SshHost("10.2.3.115", "ie-entwicklung");
var channel = new RemoteSerialChannel(host, "ttyUSB0", BaudRate, Parity, DataBits, StopBits);
var nodes = new Byte[] { 2 };
var devices = nodes
.Select(n => new Battery48TlDevice(channel, n))
.ToList();
var d = new Battery48TlDevices(devices);
//var options = new JsonSerializerOptions { WriteIndented = true, Converters = { new JsonStringEnumConverter() }};
var options = new JsonSerializerOptions { WriteIndented = true, Converters = { new JsonStringEnumConverter() }};
while (true)
{
var x = d.Read();
(x, options).Apply(JsonSerializer.Serialize).WriteLine();
x.ToCsv().WriteLine();
//(x, options).Apply(JsonSerializer.Serialize).WriteLine();
}
}
}