diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs b/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs index 8d25e2d8d..b22f5d2e5 100644 --- a/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs +++ b/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs @@ -7,8 +7,7 @@ using static System.IO.Ports.Parity; namespace InnovEnergy.Lib.Devices.Battery48TL; - -public class Battery48TlDevice: ModbusDevice +public class Battery48TlDevice: ModbusDevice { public const Parity Parity = Odd; public const Int32 StopBits = 1; @@ -18,7 +17,7 @@ public class Battery48TlDevice: ModbusDevice 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 ( 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 ) diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TlDevices.cs b/csharp/Lib/Devices/Battery48TL/Battery48TlDevices.cs new file mode 100644 index 000000000..44108e6fa --- /dev/null +++ b/csharp/Lib/Devices/Battery48TL/Battery48TlDevices.cs @@ -0,0 +1,31 @@ +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.Devices.Battery48TL; + +public class Battery48TlDevices +{ + private readonly IReadOnlyList _Devices; + + public Battery48TlDevices(IReadOnlyList 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; + } + + + } +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TlRecord.Api.cs b/csharp/Lib/Devices/Battery48TL/Battery48TlRecord.Api.cs new file mode 100644 index 000000000..9a3f57fad --- /dev/null +++ b/csharp/Lib/Devices/Battery48TL/Battery48TlRecord.Api.cs @@ -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; + +[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 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 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); + } + } +} + diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TlRecord.Modbus.cs b/csharp/Lib/Devices/Battery48TL/Battery48TlRecord.Modbus.cs new file mode 100644 index 000000000..e2b92832f --- /dev/null +++ b/csharp/Lib/Devices/Battery48TL/Battery48TlRecord.Modbus.cs @@ -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(1005)] private UInt64 _WarningFlags; + [InputRegister(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; } +} + + diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TlRecords.cs b/csharp/Lib/Devices/Battery48TL/Battery48TlRecords.cs new file mode 100644 index 000000000..516ffc46f --- /dev/null +++ b/csharp/Lib/Devices/Battery48TL/Battery48TlRecords.cs @@ -0,0 +1,36 @@ +using InnovEnergy.Lib.Units; +using InnovEnergy.Lib.Units.Composite; + +namespace InnovEnergy.Lib.Devices.Battery48TL; + +public class Battery48TlRecords +{ + public Battery48TlRecords(IReadOnlyList 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 Warnings { get; init; } + public IReadOnlyList Alarms { get; init; } + public Percent Soc { get; init; } + + public IReadOnlyList Devices { get; init; } + + public static Battery48TlRecords Null { get; } = new Battery48TlRecords(Array.Empty()); +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TlRegisters.cs b/csharp/Lib/Devices/Battery48TL/Battery48TlRegisters.cs deleted file mode 100644 index f1113fa51..000000000 --- a/csharp/Lib/Devices/Battery48TL/Battery48TlRegisters.cs +++ /dev/null @@ -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(1005)] internal UInt64 _WarningFlags; - [InputRegister(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 Warnings => this.ParseWarnings().ToList() ; - public IReadOnlyList Alarms => this.ParseAlarms().ToList() ; - - // - - // public Decimal CellsVoltage { get; init; } - // - // public Decimal MaxChargingPower { get; init; } - // public Decimal MaxDischargingPower { get; init; } -} \ No newline at end of file diff --git a/csharp/Lib/Devices/Battery48TL/DataTypes/Constants.cs b/csharp/Lib/Devices/Battery48TL/DataTypes/Constants.cs index 26d378118..cd115f88d 100644 --- a/csharp/Lib/Devices/Battery48TL/DataTypes/Constants.cs +++ b/csharp/Lib/Devices/Battery48TL/DataTypes/Constants.cs @@ -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; } \ No newline at end of file diff --git a/csharp/Lib/Devices/Battery48TL/DataTypes/Temperatures.cs b/csharp/Lib/Devices/Battery48TL/DataTypes/Temperatures.cs deleted file mode 100644 index d71fdef17..000000000 --- a/csharp/Lib/Devices/Battery48TL/DataTypes/Temperatures.cs +++ /dev/null @@ -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; - // } diff --git a/csharp/Lib/Devices/Battery48TL/ModbusParser.cs b/csharp/Lib/Devices/Battery48TL/ModbusParser.cs deleted file mode 100644 index 3ffc5bbb2..000000000 --- a/csharp/Lib/Devices/Battery48TL/ModbusParser.cs +++ /dev/null @@ -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(); // 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 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 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:"; -// } -// } \ No newline at end of file diff --git a/csharp/Lib/Devices/Battery48TL/Parser.cs b/csharp/Lib/Devices/Battery48TL/Parser.cs deleted file mode 100644 index 016073203..000000000 --- a/csharp/Lib/Devices/Battery48TL/Parser.cs +++ /dev/null @@ -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 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 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:"; - } - -} \ No newline at end of file diff --git a/csharp/Lib/Devices/Battery48TL/Program.cs b/csharp/Lib/Devices/Battery48TL/Program.cs index 66727319a..c82568a96 100644 --- a/csharp/Lib/Devices/Battery48TL/Program.cs +++ b/csharp/Lib/Devices/Battery48TL/Program.cs @@ -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(); } } + } \ No newline at end of file