diff --git a/csharp/App/RemoteSupportConsole/RemoteSupportConsole.csproj b/csharp/App/RemoteSupportConsole/RemoteSupportConsole.csproj
index c00eed4bb..1f571c26d 100644
--- a/csharp/App/RemoteSupportConsole/RemoteSupportConsole.csproj
+++ b/csharp/App/RemoteSupportConsole/RemoteSupportConsole.csproj
@@ -6,9 +6,6 @@
-
-
-
diff --git a/csharp/App/SaliMax/src/Utils.cs b/csharp/App/SaliMax/src/Utils.cs
index 4104b5384..1cf608f84 100644
--- a/csharp/App/SaliMax/src/Utils.cs
+++ b/csharp/App/SaliMax/src/Utils.cs
@@ -6,6 +6,6 @@ public static class Utils
{
public static Decimal Round3(this Decimal d)
{
- return DecimalUtils.RoundToSignificantFigures(d, 3);
+ return DecimalUtils.RoundToSignificantDigits(d, 3);
}
}
\ No newline at end of file
diff --git a/csharp/Lib/Devices/AMPT/AmptDeviceStatus.cs b/csharp/Lib/Devices/AMPT/AmptDeviceStatus.cs
index 371395e46..8ee809b72 100644
--- a/csharp/Lib/Devices/AMPT/AmptDeviceStatus.cs
+++ b/csharp/Lib/Devices/AMPT/AmptDeviceStatus.cs
@@ -1,5 +1,5 @@
+using InnovEnergy.Lib.StatusApi;
using InnovEnergy.Lib.StatusApi.Connections;
-using InnovEnergy.Lib.StatusApi.Devices;
namespace InnovEnergy.Lib.Devices.AMPT;
@@ -11,5 +11,5 @@ public record AmptDeviceStatus
UInt32 Timestamp, // The UTC timestamp of the measurements
Decimal ProductionToday, // converted to kW in AmptCU class
IReadOnlyList Strings
-): Mppt(Dc, Strings)
+): MpptStatus(Dc, Strings)
{}
\ No newline at end of file
diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs b/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs
index 979eafaf7..6507ac32d 100644
--- a/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs
+++ b/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs
@@ -1,7 +1,5 @@
using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Connections;
-using InnovEnergy.Lib.Protocols.Modbus.Conversions;
-using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.Devices.Battery48TL;
@@ -33,18 +31,11 @@ public class Battery48TlDevice
public Battery48TLStatus? ReadStatus() //Already try catch is implemented
{
- if (Modbus is null) // TODO : remove fake
- {
- Console.WriteLine("Battery is null");
- return null;
- }
-
- // Console.WriteLine("Reading Battery Data");
-
try
{
- var registers = Modbus.ReadInputRegisters(Constants.BaseAddress, Constants.NoOfRegisters);
- return TryReadStatus(registers);
+ return Modbus
+ .ReadInputRegisters(Constants.BaseAddress, Constants.NoOfRegisters)
+ .ParseBatteryStatus();
}
catch (Exception e)
{
@@ -53,92 +44,4 @@ public class Battery48TlDevice
return null;
}
}
-
- private Battery48TLStatus? TryReadStatus(ModbusRegisters data)
- {
- var soc = data.ParseDecimal(register: 1054, scaleFactor: 0.1m);
- var eocReached = data.ParseEocReached();
-
- var warnings = new List();
-
- if (data.ParseBool(1006, 1)) warnings.Add("TaM1: BMS temperature high");
- if (data.ParseBool(1006, 4)) warnings.Add("TbM1: Battery temperature high");
- if (data.ParseBool(1006, 6)) warnings.Add("VBm1: Bus voltage low");
- if (data.ParseBool(1006, 8)) warnings.Add("VBM1: Bus voltage high");
- if (data.ParseBool(1006, 10)) warnings.Add("IDM1: Discharge current high");
- if (data.ParseBool(1006, 24)) warnings.Add("vsM1: String voltage high");
- if (data.ParseBool(1006, 26)) warnings.Add("iCM1: Charge current high");
- if (data.ParseBool(1006, 28)) warnings.Add("iDM1: Discharge current high");
- if (data.ParseBool(1006, 30)) warnings.Add("MID1: String voltages unbalanced");
- if (data.ParseBool(1006, 32)) warnings.Add("BLPW: Not enough charging power on bus");
- if (data.ParseBool(1006, 35)) warnings.Add("Ah_W: String SOC low");
- if (data.ParseBool(1006, 38)) warnings.Add("MPMM: Midpoint wiring problem");
- if (data.ParseBool(1006, 39)) warnings.Add("TCMM:");
- if (data.ParseBool(1006, 40)) warnings.Add("TCdi: Temperature difference between strings high");
- if (data.ParseBool(1006, 41)) warnings.Add("WMTO:");
- if (data.ParseBool(1006, 44)) warnings.Add("bit44:");
- if (data.ParseBool(1006, 46)) warnings.Add("CELL1:");
-
- var alarms = new List();
-
- if (data.ParseBool(1010, 0)) alarms.Add("Tam : BMS temperature too low");
- if (data.ParseBool(1010, 2)) alarms.Add("TaM2 : BMS temperature too high");
- if (data.ParseBool(1010, 3)) alarms.Add("Tbm : Battery temperature too low");
- if (data.ParseBool(1010, 5)) alarms.Add("TbM2 : Battery temperature too high");
- if (data.ParseBool(1010, 7)) alarms.Add("VBm2 : Bus voltage too low");
- if (data.ParseBool(1010, 9)) alarms.Add("VBM2 : Bus voltage too high");
- if (data.ParseBool(1010, 11)) alarms.Add("IDM2 : Discharge current too high");
- if (data.ParseBool(1010, 12)) alarms.Add("ISOB : Electrical insulation failure");
- if (data.ParseBool(1010, 13)) alarms.Add("MSWE : Main switch failure");
- if (data.ParseBool(1010, 14)) alarms.Add("FUSE : Main fuse blown");
- if (data.ParseBool(1010, 15)) alarms.Add("HTRE : Battery failed to warm up");
- if (data.ParseBool(1010, 16)) alarms.Add("TCPE : Temperature sensor failure");
- if (data.ParseBool(1010, 17)) alarms.Add("STRE :");
- if (data.ParseBool(1010, 18)) alarms.Add("CME : Current sensor failure");
- if (data.ParseBool(1010, 19)) alarms.Add("HWFL : BMS hardware failure");
- if (data.ParseBool(1010, 20)) alarms.Add("HWEM : Hardware protection tripped");
- if (data.ParseBool(1010, 21)) alarms.Add("ThM : Heatsink temperature too high");
- if (data.ParseBool(1010, 22)) alarms.Add("vsm1 : String voltage too low");
- if (data.ParseBool(1010, 23)) alarms.Add("vsm2 : Low string voltage failure");
- if (data.ParseBool(1010, 25)) alarms.Add("vsM2 : String voltage too high");
- if (data.ParseBool(1010, 27)) alarms.Add("iCM2 : Charge current too high");
- if (data.ParseBool(1010, 29)) alarms.Add("iDM2 : Discharge current too high");
- if (data.ParseBool(1010, 31)) alarms.Add("MID2 : String voltage unbalance too high");
- if (data.ParseBool(1010, 33)) alarms.Add("CCBF : Internal charger hardware failure");
- if (data.ParseBool(1010, 34)) alarms.Add("AhFL :");
- if (data.ParseBool(1010, 36)) alarms.Add("TbCM :");
- if (data.ParseBool(1010, 37)) alarms.Add("BRNF :");
- if (data.ParseBool(1010, 42)) alarms.Add("HTFS : If Heaters Fuse Blown");
- if (data.ParseBool(1010, 43)) alarms.Add("DATA : Parameters out of range");
- if (data.ParseBool(1010, 45)) alarms.Add("CELL2:");
-
-
-return new Battery48TLStatus(
- Dc: new DcConnection
- (
- Voltage : data.ReadVoltage(),
- Current : data.ReadCurrent()),
-
- Soc : !eocReached && soc >= 100m ? 99.9m : soc,
- Temperature : data.ParseDecimal(register: 1004, scaleFactor: 0.1m, offset: -400),
- BusVoltage : data.ParseDecimal(register: 1002, scaleFactor: 0.01m),
- GreenLed : data.ParseLedState(register: 1005, led: LedColor.Green),
- AmberLed : data.ParseLedState(register: 1006, led: LedColor.Amber),
- BlueLed : data.ParseLedState(register: 1005, led: LedColor.Blue),
- RedLed : data.ParseLedState(register: 1005, led: LedColor.Red),
- Warnings : warnings,
- Alarms : alarms,
- MainSwitchClosed : data.ParseBool(baseRegister: 1014, bit: 0),
- AlarmOutActive : data.ParseBool(baseRegister: 1014, bit: 1),
- InternalFanActive : data.ParseBool(baseRegister: 1014, bit: 2),
- VoltMeasurementAllowed: data.ParseBool(baseRegister: 1014, bit: 3),
- AuxRelay : data.ParseBool(baseRegister: 1014, bit: 4),
- RemoteState : data.ParseBool(baseRegister: 1014, bit: 5),
- HeaterOn : data.ParseBool(baseRegister: 1014, bit: 6),
- EocReached : eocReached,
- BatteryCold : data.ParseBatteryCold(),
- MaxChargingPower : data.CalcMaxChargePower(),
- MaxDischargingPower : data.CalcMaxDischargePower()
- );
- }
}
\ No newline at end of file
diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs b/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs
index 0871f0645..b9feb07d0 100644
--- a/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs
+++ b/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs
@@ -1,39 +1,50 @@
using System.Diagnostics.CodeAnalysis;
-using InnovEnergy.Lib.Protocols.Modbus.Conversions;
-using InnovEnergy.Lib.StatusApi.Connections;
-using InnovEnergy.Lib.StatusApi.Devices;
+using InnovEnergy.Lib.StatusApi;
+using InnovEnergy.Lib.Units;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Devices.Battery48TL;
+using T = Battery48TLStatus;
+
[SuppressMessage("ReSharper", "InconsistentNaming")]
-public record Battery48TLStatus
-(
- DcConnection Dc,
- Decimal Soc,
- Decimal Temperature,
- //Decimal Current,
- //Decimal Voltage,
- Decimal BusVoltage,
- LedState GreenLed,
- LedState AmberLed,
- LedState BlueLed,
- LedState RedLed,
- IReadOnlyList Warnings,
- IReadOnlyList Alarms,
- Boolean MainSwitchClosed,
- Boolean AlarmOutActive,
- Boolean InternalFanActive,
- Boolean VoltMeasurementAllowed,
- Boolean AuxRelay,
- Boolean RemoteState,
- Boolean HeaterOn,
- Boolean EocReached,
- Boolean BatteryCold,
- Decimal MaxChargingPower,
- Decimal MaxDischargingPower
-)
-: Battery(Dc, Soc, Temperature)
+public record Battery48TLStatus : BatteryStatus
{
+ public Voltage CellsVoltage { get; init; }
+
+ public Power MaxChargingPower { get; init; }
+ public Power MaxDischargingPower { get; init; }
+
+ public State GreenLed { get; init; }
+ public State AmberLed { get; init; }
+ public State BlueLed { get; init; }
+ public State RedLed { get; init; }
+
+ public State Warnings { get; init; }
+ public State Alarms { get; init; }
+
+ public State MainSwitchState { get; init; } // connected to bus | disconnected from bus
+ public State HeaterState { get; init; } // heating | not heating
+ public State EocState { get; init; } // EOC reached | EOC not reached
+ public State TemperatureState { get; init; } // cold | operating temperature | overheated
+
+
+ public static T operator |(T left, T right) => OpParallel(left, right);
+ private static readonly Func OpParallel = "|".CreateBinaryOpForProps();
+
+
+
+ // TODO: strings
+ // TODO
+ // public State LimitedBy { get; init; }
+
+ // TODO
+ // public Boolean AlarmOutActive { get; init; }
+ // public Boolean InternalFanActive { get; init; }
+ // public Boolean VoltMeasurementAllowed { get; init; }
+ // public Boolean AuxRelay { get; init; }
+ // public Boolean RemoteState { get; init; }
+
}
diff --git a/csharp/Lib/Devices/Battery48TL/BatteryDataParser.cs b/csharp/Lib/Devices/Battery48TL/BatteryDataParser.cs
deleted file mode 100644
index 916c8989c..000000000
--- a/csharp/Lib/Devices/Battery48TL/BatteryDataParser.cs
+++ /dev/null
@@ -1,167 +0,0 @@
-using InnovEnergy.Lib.Protocols.Modbus.Conversions;
-using InnovEnergy.Lib.Utils;
-
-namespace InnovEnergy.Lib.Devices.Battery48TL;
-
-public static class BatteryDataParser
-{
- 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 ReadCurrent(this ModbusRegisters data)
- {
- return ParseDecimal(data, register: 1001, scaleFactor: 0.01m, offset: -10000);
- }
-
- internal static Decimal ReadVoltage(this ModbusRegisters data)
- {
- return ParseDecimal(data, register: 1000, 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 ParseLedState(this ModbusRegisters data, Int32 register, LedColor led)
- {
- var lo = ParseBool(data, register, (led.ConvertTo() * 2).ConvertTo());
- var hi = ParseBool(data, register, (led.ConvertTo() * 2 + 1).ConvertTo());
-
- if (hi)
- {
- if (lo)
- {
- return LedState.BlinkingFast;
- }
- else
- {
- return LedState.BlinkingSlow;
- }
- }
- else
- {
- if (lo)
- {
- return LedState.On;
- }
- else
- {
- return LedState.Off;
- }
- }
-
- }
-
- internal static String ParseRegisters(this ModbusRegisters data, Int32 register, Int16 count)
- {
- var container = "";
-
- var start = register;
- var end = register + count;
-
- for (var i = start; i < end; i++)
- {
- var binary = Convert.ToString(data[register], 2);
- container += binary.PadLeft(16, '0');
- }
- return container;
- }
-
- internal static Boolean ParseEocReached(this ModbusRegisters data)
- {
- return ParseLedState(data, 1005, LedColor.Green) == LedState.On &&
- ParseLedState(data, 1005, LedColor.Amber) == LedState.Off &&
- ParseLedState(data, 1005, LedColor.Blue) == LedState.Off;
- }
-
- internal static Boolean ParseBatteryCold(this ModbusRegisters data)
- {
- return ParseLedState(data, 1005, LedColor.Green) >= LedState.BlinkingSlow &&
- ParseLedState(data, 1005, LedColor.Blue) >= LedState.BlinkingSlow;
- }
-
- 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 = ReadVoltage(data);
- var i = ReadCurrent(data);
-
- var pLimits = new[]
- {
- 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 Decimal CalcMaxDischargePower(this ModbusRegisters data)
- {
- var v = ReadVoltage(data);
- var i = ReadCurrent(data);
- var t = data.ParseDecimal(register: 1004, scaleFactor: 0.1m, offset: -400);
-
- var pLimits = new[]
- {
- 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);
- }
-}
\ No newline at end of file
diff --git a/csharp/Lib/Devices/Battery48TL/ModbusParser.cs b/csharp/Lib/Devices/Battery48TL/ModbusParser.cs
new file mode 100644
index 000000000..d16c3dc5d
--- /dev/null
+++ b/csharp/Lib/Devices/Battery48TL/ModbusParser.cs
@@ -0,0 +1,272 @@
+using System.Diagnostics.CodeAnalysis;
+using InnovEnergy.Lib.Protocols.Modbus.Conversions;
+using InnovEnergy.Lib.Units;
+using InnovEnergy.Lib.Units.Composite;
+using InnovEnergy.Lib.Utils;
+
+namespace InnovEnergy.Lib.Devices.Battery48TL;
+
+public static class ModbusParser
+{
+ internal static Battery48TLStatus ParseBatteryStatus(this ModbusRegisters data)
+ {
+ return new Battery48TLStatus
+ {
+ Dc = data.ParseDcBus(),
+ Alarms = data.ParseAlarms().ToList(),
+ Warnings = data.ParseWarnings().ToList(),
+ Soc = data.ParseSoc(),
+ Temperature = data.ParseTemperature(),
+ GreenLed = data.ParseGreenLed(),
+ AmberLed = data.ParseAmberLed(),
+ BlueLed = data.ParseBlueLed(),
+ RedLed = data.ParseRedLed(),
+ MainSwitchState = data.ParseMainSwitchState(),
+ HeaterState = data.ParseHeaterState(),
+ EocState = data.ParseEocState(),
+ TemperatureState = data.ParseTemperatureState(),
+ MaxChargingPower = data.CalcMaxChargePower(),
+ MaxDischargingPower = data.CalcMaxDischargePower(),
+ CellsVoltage = data.ParseCellsVoltage(),
+ };
+ }
+
+
+ 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 ParseCellsVoltage(this ModbusRegisters data)
+ {
+ return data.ParseDecimal(register: 1000, scaleFactor: 0.01m);
+ }
+
+ 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 ParseLedState(this ModbusRegisters data, Int32 register, LedColor led)
+ {
+ var lo = data.ParseBool(register, (led.ConvertTo() * 2 ).ConvertTo());
+ var hi = data.ParseBool(register, (led.ConvertTo() * 2 + 1).ConvertTo());
+
+ return (hi, lo) switch
+ {
+ (false, false) => LedState.Off,
+ (false, true) => LedState.On,
+ (true, false) => LedState.BlinkingSlow,
+ (true, true) => LedState.BlinkingFast,
+ };
+ }
+
+
+ private static Boolean ParseEocReached(this ModbusRegisters data)
+ {
+ return ParseLedState(data, 1005, LedColor.Green) == LedState.On &&
+ ParseLedState(data, 1005, LedColor.Amber) == LedState.Off &&
+ ParseLedState(data, 1005, LedColor.Blue) == LedState.Off;
+ }
+
+ internal static State ParseTemperatureState(this ModbusRegisters data)
+ {
+ return data.ParseBatteryCold() ? "cold" : "operating temperature"; // TODO: overheated,
+ }
+
+ internal static Decimal ParseTemperature(this ModbusRegisters data)
+ {
+ return data.ParseDecimal(register: 1004, scaleFactor: 0.1m, offset: -400);
+ }
+
+ internal static Decimal ParseSoc(this ModbusRegisters data)
+ {
+ return data.ParseDecimal(register: 1054, scaleFactor: 0.1m);
+ }
+
+ internal static State ParseEocState(this ModbusRegisters data)
+ {
+ return data.ParseEocReached() ? "EOC reached" : "EOC not reached";
+ }
+
+ internal static State ParseHeaterState(this ModbusRegisters data)
+ {
+ return data.ParseBool(baseRegister: 1014, bit: 6) ? "heating" : "not heating";
+ }
+
+ internal static State ParseMainSwitchState(this ModbusRegisters data)
+ {
+ return data.ParseBool(baseRegister: 1014, bit: 0) ? "connected to bus" : "disconnected from bus";
+ }
+
+ internal static Boolean ParseBatteryCold(this ModbusRegisters data)
+ {
+ return ParseLedState(data, 1005, LedColor.Green) >= LedState.BlinkingSlow &&
+ ParseLedState(data, 1005, LedColor.Blue) >= LedState.BlinkingSlow;
+ }
+
+ 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 = ParseCellsVoltage(data);
+ var i = ParseCurrent(data);
+
+ var pLimits = new[]
+ {
+ 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)
+ {
+ return new()
+ {
+ Current = data.ParseCurrent(),
+ Voltage = data.ParseBusVoltage(),
+ };
+ }
+
+ internal static Decimal CalcMaxDischargePower(this ModbusRegisters data)
+ {
+ var v = ParseCellsVoltage(data);
+ var i = ParseCurrent(data);
+ var t = data.ParseDecimal(register: 1004, scaleFactor: 0.1m, offset: -400);
+
+ var pLimits = new[]
+ {
+ 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);
+ }
+
+
+ internal static LedState ParseGreenLed(this ModbusRegisters data) => data.ParseLedState(register: 1005, led: LedColor.Green);
+ internal static LedState ParseAmberLed(this ModbusRegisters data) => data.ParseLedState(register: 1006, led: LedColor.Amber);
+ internal static LedState ParseBlueLed (this ModbusRegisters data) => data.ParseLedState(register: 1005, led: LedColor.Blue);
+ internal static LedState ParseRedLed (this ModbusRegisters data) => data.ParseLedState(register: 1005, led: LedColor.Red);
+
+
+ [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/EmuMeter/EmuMeterDevice.cs b/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs
index c219755b3..ef3ba19ec 100644
--- a/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs
+++ b/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs
@@ -1,7 +1,8 @@
+using DecimalMath;
using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Connections;
using InnovEnergy.Lib.StatusApi.Connections;
-using InnovEnergy.Lib.StatusApi.Phases;
+using InnovEnergy.Lib.Units.Composite;
using InnovEnergy.Lib.Utils;
using static DecimalMath.DecimalEx;
@@ -29,7 +30,9 @@ public class EmuMeterDevice
return null;
}
}
- private static Decimal GetPhi(Decimal cosPhi) => cosPhi.Clamp(-1m, 1m).Apply(ACos);
+
+
+ //private static Decimal GetPhi(Decimal cosPhi) => cosPhi.Clamp(-1m, 1m).Apply(ACos);
private EmuMeterStatus TryReadStatus()
{
@@ -75,45 +78,70 @@ public class EmuMeterDevice
var energyImportL3 = energyPhases[80 / 4] / 1000.0m;
var energyExportL3 = energyPhases[100 / 4] / 1000.0m;
+ // Ac: new Ac3Bus
+ // (
+ // new AcPhase(
+ // voltageL1N,
+ // currentL1,
+ // GetPhi(powerFactorL1)
+ // ),
+ //
+ // new AcPhase(
+ // voltageL2N,
+ // currentL2,
+ // GetPhi(powerFactorL2)
+ // ),
+ //
+ // new AcPhase(
+ // voltageL3N,
+ // currentL3,
+ // GetPhi(powerFactorL3)
+ // ),
+ // frequency
+ // ),
+ // activePowerL123,
+ // reactivePowerL123,
+ // apparentPowerL123,
+ // currentL123,
+ // voltageL1L2,
+ // voltageL2L3,
+ // voltageL3L1,
+ // energyImportL123,
+ // energyImportL1,
+ // energyImportL2,
+ // energyImportL3,
+ // energyExportL123,
+ // energyExportL1,
+ // energyExportL2,
+ // energyExportL3
+ // );
+
return new EmuMeterStatus
- (
- Ac: new ThreePhaseAcConnection
- (
- new AcPhase(
- voltageL1N,
- currentL1,
- GetPhi(powerFactorL1)
- ),
-
- new AcPhase(
- voltageL2N,
- currentL2,
- GetPhi(powerFactorL2)
- ),
-
- new AcPhase(
- voltageL3N,
- currentL3,
- GetPhi(powerFactorL3)
- ),
- frequency
- ),
- activePowerL123,
- reactivePowerL123,
- apparentPowerL123,
- currentL123,
- voltageL1L2,
- voltageL2L3,
- voltageL3L1,
- energyImportL123,
- energyImportL1,
- energyImportL2,
- energyImportL3,
- energyExportL123,
- energyExportL1,
- energyExportL2,
- energyExportL3
- );
+ {
+ Ac = new Ac3Bus
+ {
+ Frequency = frequency,
+ L1 = new AcPhase
+ {
+ Current = currentL1,
+ Voltage = voltageL1N,
+ Phi = ATan2(reactivePowerL1, activePowerL1) // TODO: check that this works
+ },
+ L2 = new AcPhase
+ {
+ Current = currentL2,
+ Voltage = voltageL2N,
+ Phi = ATan2(reactivePowerL2, activePowerL2)
+ },
+ L3 = new AcPhase
+ {
+ Current = currentL3,
+ Voltage = voltageL3N,
+ Phi = ATan2(reactivePowerL3, activePowerL3)
+ }
+ }
+ };
+
}
}
\ No newline at end of file
diff --git a/csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs b/csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs
index 713a4b2de..c1c9eb26e 100644
--- a/csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs
+++ b/csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs
@@ -1,26 +1,10 @@
-using InnovEnergy.Lib.StatusApi.Connections;
-using InnovEnergy.Lib.StatusApi.Devices;
+using InnovEnergy.Lib.StatusApi;
namespace InnovEnergy.Lib.Devices.EmuMeter;
-public record EmuMeterStatus
-(
- ThreePhaseAcConnection Ac,
- Decimal ActivePowerL123,
- Decimal ReactivePowerL123,
- Decimal ApparentPowerL123,
- Decimal CurrentL123,
- Decimal VoltageL1L2,
- Decimal VoltageL2L3,
- Decimal VoltageL3L1,
- Decimal EnergyImportL123,
- Decimal EnergyImportL1,
- Decimal EnergyImportL2,
- Decimal EnergyImportL3,
- Decimal EnergyExportL123,
- Decimal EnergyExportL1,
- Decimal EnergyExportL2,
- Decimal EnergyExportL3
-):GridMeter(Ac)
-{}
+public record EmuMeterStatus : PowerMeterStatus
+{
+ // TODO add serial nb, (and other?)
+}
+
diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs
index 6308553aa..66cc153a7 100644
--- a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs
+++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs
@@ -2,8 +2,7 @@ using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Connections;
-using InnovEnergy.Lib.StatusApi.Connections;
-using InnovEnergy.Lib.StatusApi.Phases;
+using InnovEnergy.Lib.Units.Composite;
using InnovEnergy.Lib.Utils;
using static DecimalMath.DecimalEx;
using static InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.AcControlRegisters;
@@ -216,7 +215,7 @@ public class TruConvertAcDevice
return new TruConvertAcStatus
(
- Ac: new ThreePhaseAcConnection
+ Ac: new Ac3Bus
(
new AcPhase(gridVoltageL1,phaseCurrentL1, ACos(powerAcL1/apparentPowerAcL1)),
new AcPhase(gridVoltageL2,phaseCurrentL2, ACos(powerAcL2/apparentPowerAcL2)),
diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcStatus.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcStatus.cs
index 8f2047ebb..4747e0579 100644
--- a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcStatus.cs
+++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcStatus.cs
@@ -1,6 +1,6 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.StatusApi.Connections;
-using InnovEnergy.Lib.StatusApi.Devices;
+using InnovEnergy.Lib.Units.Composite;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
@@ -9,7 +9,7 @@ using WarningMessages = IReadOnlyList;
public record TruConvertAcStatus
(
- ThreePhaseAcConnection Ac,
+ Ac3Bus Ac,
DcConnection Dc,
String SerialNumber,
MainState MainState,
diff --git a/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcStatus.cs b/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcStatus.cs
index 88551dee1..bf78b928b 100644
--- a/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcStatus.cs
+++ b/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcStatus.cs
@@ -1,6 +1,7 @@
-using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
-using InnovEnergy.Lib.StatusApi.Connections;
-using InnovEnergy.Lib.StatusApi.Devices;
+using InnovEnergy.Lib.StatusApi;
+using InnovEnergy.Lib.Units;
+using InnovEnergy.Lib.Units.Composite;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
@@ -8,20 +9,24 @@ using AlarmMessages = IReadOnlyList;
using WarningMessages = IReadOnlyList;
using DcCurrentLimitStates = IReadOnlyList;
-public record TruConvertDcStatus
+public record TruConvertDcStatus
(
- DcConnection Dc,
- MainState MainState,
- UInt16 NumberOfConnectedSlaves,
- UInt16 NumberOfConnectedSubSlaves,
- Decimal BatteryVoltage,
- Decimal BatteryCurrent,
- Decimal TotalDcPower,
- DcCurrentLimitStates StatusOfCurrentLimiting,
- Decimal OverloadCapacity,
- Decimal DcDcInletTemperature,
- AlarmMessages Alarms,
- WarningMessages Warnings,
- Boolean PowerOperation
-):DcDevice(Dc)
-{}
\ No newline at end of file
+ DcBus DcLeft,
+ DcBus DcRight,
+ State MainState,
+ Power TotalDcPower, // TODO: necessary?
+ State StatusOfCurrentLimiting,
+ Decimal OverloadCapacity,
+ Temperature DcDcInletTemperature,
+ State Alarms,
+ State Warnings,
+ State PowerOperation
+
+ // UInt16 NumberOfConnectedSlaves, // TODO: necessary?
+ // UInt16 NumberOfConnectedSubSlaves, // TODO: necessary?
+) :
+ DcDcConverterStatus(DcLeft, DcRight)
+{
+ public static TruConvertDcStatus operator |(TruConvertDcStatus left, TruConvertDcStatus right) => OpParallel(left, right);
+ private static readonly Func OpParallel = Operators.Op("|");
+}
\ No newline at end of file
diff --git a/csharp/Lib/StatusApi/BatteryStatus.cs b/csharp/Lib/StatusApi/BatteryStatus.cs
index fc8961fd1..f8a0124d5 100644
--- a/csharp/Lib/StatusApi/BatteryStatus.cs
+++ b/csharp/Lib/StatusApi/BatteryStatus.cs
@@ -10,8 +10,8 @@ using T = BatteryStatus;
[OpParallel]
public partial record BatteryStatus : DeviceStatus, IDcConnection
{
- public required DcPhase Dc { get; init; }
- public required Percent Soc { get; init; }
- public required Temperature Temperature { get; init; }
+ public DcBus Dc { get; init; }
+ public Percent Soc { get; init; }
+ public Temperature Temperature { get; init; }
}
\ No newline at end of file
diff --git a/csharp/Lib/StatusApi/Connections/IAc1Connection.cs b/csharp/Lib/StatusApi/Connections/IAc1Connection.cs
index d90b57938..54060cb20 100644
--- a/csharp/Lib/StatusApi/Connections/IAc1Connection.cs
+++ b/csharp/Lib/StatusApi/Connections/IAc1Connection.cs
@@ -4,5 +4,5 @@ namespace InnovEnergy.Lib.StatusApi.Connections;
public interface IAc1Connection
{
- Ac1Phase Ac { get; }
+ Ac1Bus Ac { get; }
}
\ No newline at end of file
diff --git a/csharp/Lib/StatusApi/Connections/IAc3Connection.cs b/csharp/Lib/StatusApi/Connections/IAc3Connection.cs
index b95939124..a1c0ca1b5 100644
--- a/csharp/Lib/StatusApi/Connections/IAc3Connection.cs
+++ b/csharp/Lib/StatusApi/Connections/IAc3Connection.cs
@@ -4,5 +4,5 @@ namespace InnovEnergy.Lib.StatusApi.Connections;
public interface IAc3Connection
{
- Ac3Phase Ac { get; }
+ Ac3Bus Ac { get; }
}
\ No newline at end of file
diff --git a/csharp/Lib/StatusApi/Connections/IDcConnection.cs b/csharp/Lib/StatusApi/Connections/IDcConnection.cs
index 6074a6750..04d83289f 100644
--- a/csharp/Lib/StatusApi/Connections/IDcConnection.cs
+++ b/csharp/Lib/StatusApi/Connections/IDcConnection.cs
@@ -5,5 +5,5 @@ namespace InnovEnergy.Lib.StatusApi.Connections;
public interface IDcConnection
{
- DcPhase Dc { get; }
+ DcBus Dc { get; }
}
\ No newline at end of file
diff --git a/csharp/Lib/StatusApi/Connections/IPvConnection.cs b/csharp/Lib/StatusApi/Connections/IPvConnection.cs
index a117f2d17..6dfddccea 100644
--- a/csharp/Lib/StatusApi/Connections/IPvConnection.cs
+++ b/csharp/Lib/StatusApi/Connections/IPvConnection.cs
@@ -4,5 +4,5 @@ namespace InnovEnergy.Lib.StatusApi.Connections;
public interface IPvConnection
{
- IReadOnlyList Strings { get; }
+ IReadOnlyList Strings { get; }
}
\ No newline at end of file
diff --git a/csharp/Lib/StatusApi/DcDcConverterStatus.cs b/csharp/Lib/StatusApi/DcDcConverterStatus.cs
index a7d931065..21941d5e6 100644
--- a/csharp/Lib/StatusApi/DcDcConverterStatus.cs
+++ b/csharp/Lib/StatusApi/DcDcConverterStatus.cs
@@ -6,8 +6,8 @@ namespace InnovEnergy.Lib.StatusApi;
[OpParallel]
public partial record DcDcConverterStatus : DeviceStatus
{
- public required DcPhase Left { get; init; }
- public required DcPhase Right { get; init; }
+ public DcBus Left { get; init; }
+ public DcBus Right { get; init; }
}
diff --git a/csharp/Lib/StatusApi/DeviceStatus.cs b/csharp/Lib/StatusApi/DeviceStatus.cs
index 6cdc1ef3f..ef92280ab 100644
--- a/csharp/Lib/StatusApi/DeviceStatus.cs
+++ b/csharp/Lib/StatusApi/DeviceStatus.cs
@@ -1,12 +1,64 @@
+using System.Text.Json;
using InnovEnergy.Lib.Utils;
+using static InnovEnergy.Lib.Units.Units;
namespace InnovEnergy.Lib.StatusApi;
public abstract record DeviceStatus
{
+ private static readonly JsonSerializerOptions JsonSerializerOptions;
+
+ static DeviceStatus()
+ {
+ JsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
+ JsonConverters.ForEach(JsonSerializerOptions.Converters.Add); // how stupid is that?!!
+ }
+
public String DeviceType => GetType()
.Generate(t => t.BaseType!)
.First(t => t.IsAbstract)
.Name
.Replace("Status", "");
-}
\ No newline at end of file
+
+ public String ToJson() => JsonSerializer.Serialize(this, GetType(), JsonSerializerOptions);
+}
+
+
+// public static class Program
+// {
+// public static void Main(string[] args)
+// {
+// var x = new ThreePhasePvInverterStatus
+// {
+// Ac = new()
+// {
+// Frequency = 50,
+// L1 = new()
+// {
+// Current = 10,
+// Voltage = 10,
+// Phi = 0,
+// },
+// L2 = new()
+// {
+// Current = 52,
+// Voltage = 220,
+// Phi = Angle.Pi / 2,
+// },
+// L3 = new()
+// {
+// Current = 158,
+// Voltage = 454,
+// Phi = Angle.Pi / 3,
+// },
+// },
+// Strings = new DcBus[]
+// {
+// new() { Current = 10, Voltage = 22 },
+// new() { Current = 12, Voltage = 33 },
+// }
+// };
+//
+// var s = x.ToJson();
+// }
+// }
\ No newline at end of file
diff --git a/csharp/Lib/StatusApi/MpptStatus.cs b/csharp/Lib/StatusApi/MpptStatus.cs
index 6514ad5f0..53acdf439 100644
--- a/csharp/Lib/StatusApi/MpptStatus.cs
+++ b/csharp/Lib/StatusApi/MpptStatus.cs
@@ -7,8 +7,8 @@ namespace InnovEnergy.Lib.StatusApi;
[OpParallel]
public partial record MpptStatus : IDcConnection, IPvConnection
{
- public required DcPhase Dc { get; init; }
- public required IReadOnlyList Strings { get; init; }
+ public DcBus Dc { get; init; }
+ public IReadOnlyList Strings { get; init; }
}
\ No newline at end of file
diff --git a/csharp/Lib/StatusApi/PowerMeterStatus.cs b/csharp/Lib/StatusApi/PowerMeterStatus.cs
index d02a2ea72..8140afef3 100644
--- a/csharp/Lib/StatusApi/PowerMeterStatus.cs
+++ b/csharp/Lib/StatusApi/PowerMeterStatus.cs
@@ -7,5 +7,5 @@ namespace InnovEnergy.Lib.StatusApi;
[OpParallel]
public partial record PowerMeterStatus : DeviceStatus, IAc3Connection
{
- public required Ac3Phase Ac { get; init; }
+ public Ac3Bus Ac { get; init; }
}
\ No newline at end of file
diff --git a/csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs b/csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs
index efd9e7f5c..6688d8886 100644
--- a/csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs
+++ b/csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs
@@ -10,6 +10,6 @@ public partial record SinglePhaseInverterStatus :
IAc1Connection,
IDcConnection
{
- public required Ac1Phase Ac { get; init; }
- public required DcPhase Dc { get; init; }
+ public Ac1Bus Ac { get; init; }
+ public DcBus Dc { get; init; }
}
diff --git a/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs b/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs
index 3fc2db56a..269254b6e 100644
--- a/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs
+++ b/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs
@@ -10,6 +10,6 @@ public partial record SinglePhasePvInverterStatus :
IAc1Connection,
IPvConnection
{
- public required Ac1Phase Ac { get; init; }
- public required IReadOnlyList Strings { get; init; }
+ public Ac1Bus Ac { get; init; }
+ public IReadOnlyList Strings { get; init; }
}
diff --git a/csharp/Lib/StatusApi/StatusApi.csproj b/csharp/Lib/StatusApi/StatusApi.csproj
index d14ca02c9..b68a8b119 100644
--- a/csharp/Lib/StatusApi/StatusApi.csproj
+++ b/csharp/Lib/StatusApi/StatusApi.csproj
@@ -1,5 +1,6 @@
+
diff --git a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs
index 306430190..c525a6a67 100644
--- a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs
+++ b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs
@@ -10,7 +10,7 @@ public partial record ThreePhaseInverterStatus :
IAc3Connection,
IDcConnection
{
- public required Ac3Phase Ac { get; init; }
- public required DcPhase Dc { get; init; }
+ public Ac3Bus Ac { get; init; }
+ public DcBus Dc { get; init; }
}
\ No newline at end of file
diff --git a/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs b/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs
index b5a7686da..8c122ffb3 100644
--- a/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs
+++ b/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs
@@ -10,6 +10,6 @@ public partial record ThreePhasePvInverterStatus :
IAc3Connection,
IPvConnection
{
- public required Ac3Phase Ac { get; init; }
- public required IReadOnlyList Strings { get; init; }
+ public Ac3Bus Ac { get; init; }
+ public IReadOnlyList Strings { get; init; }
}
diff --git a/csharp/Lib/Units/Angle.generated.cs b/csharp/Lib/Units/Angle.generated.cs
index f2317f977..0c1abd7e5 100644
--- a/csharp/Lib/Units/Angle.generated.cs
+++ b/csharp/Lib/Units/Angle.generated.cs
@@ -2,6 +2,9 @@
#define Sum
using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@@ -10,7 +13,7 @@ using T = Angle;
public readonly partial struct Angle
{
public Decimal Value { get; }
- public override String ToString() => Value + Unit;
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@@ -75,3 +78,19 @@ public readonly partial struct Angle
public override Int32 GetHashCode() => Value.GetHashCode();
}
+
+
+internal class AngleConverter : JsonConverter
+{
+ public override Angle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new Angle(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, Angle value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/ApparentPower.generated.cs b/csharp/Lib/Units/ApparentPower.generated.cs
index 0775151c9..ae632e889 100644
--- a/csharp/Lib/Units/ApparentPower.generated.cs
+++ b/csharp/Lib/Units/ApparentPower.generated.cs
@@ -2,6 +2,9 @@
#define Sum
using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@@ -10,7 +13,7 @@ using T = ApparentPower;
public readonly partial struct ApparentPower
{
public Decimal Value { get; }
- public override String ToString() => Value + Unit;
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@@ -75,3 +78,19 @@ public readonly partial struct ApparentPower
public override Int32 GetHashCode() => Value.GetHashCode();
}
+
+
+internal class ApparentPowerConverter : JsonConverter
+{
+ public override ApparentPower Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new ApparentPower(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, ApparentPower value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Composite/Ac1Phase.cs b/csharp/Lib/Units/Composite/Ac1Bus.cs
similarity index 67%
rename from csharp/Lib/Units/Composite/Ac1Phase.cs
rename to csharp/Lib/Units/Composite/Ac1Bus.cs
index d7cfc20e7..f2c769f24 100644
--- a/csharp/Lib/Units/Composite/Ac1Phase.cs
+++ b/csharp/Lib/Units/Composite/Ac1Bus.cs
@@ -1,19 +1,18 @@
-
using System.Diagnostics.CodeAnalysis;
namespace InnovEnergy.Lib.Units.Composite;
-public record Ac1Phase : AcPhase
+public record Ac1Bus : AcPhase
{
- public required Frequency Frequency { get; init; }
+ public Frequency Frequency { get; init; }
[SuppressMessage("ReSharper", "RedundantCast")]
- public static Ac1Phase operator |(Ac1Phase left, Ac1Phase right)
+ public static Ac1Bus operator |(Ac1Bus left, Ac1Bus right)
{
var f = left.Frequency | right.Frequency;
var p = (AcPhase)left | (AcPhase)right;
- return new Ac1Phase
+ return new Ac1Bus
{
Frequency = f,
Current = p.Current,
@@ -21,7 +20,6 @@ public record Ac1Phase : AcPhase
Phi = p.Phi
};
}
-
}
diff --git a/csharp/Lib/Units/Composite/Ac3Phase.cs b/csharp/Lib/Units/Composite/Ac3Bus.cs
similarity index 51%
rename from csharp/Lib/Units/Composite/Ac3Phase.cs
rename to csharp/Lib/Units/Composite/Ac3Bus.cs
index d73f8e9e4..e35c73cfc 100644
--- a/csharp/Lib/Units/Composite/Ac3Phase.cs
+++ b/csharp/Lib/Units/Composite/Ac3Bus.cs
@@ -3,20 +3,18 @@ using static DecimalMath.DecimalEx;
namespace InnovEnergy.Lib.Units.Composite;
-public record Ac3Phase
+public record Ac3Bus
{
- public required AcPhase L1 { get; init; }
- public required AcPhase L2 { get; init; }
- public required AcPhase L3 { get; init; }
- public required Frequency Frequency { get; init; }
+ public AcPhase L1 { get; init; }
+ public AcPhase L2 { get; init; }
+ public AcPhase L3 { get; init; }
+ public Frequency Frequency { get; init; }
public ApparentPower ApparentPower => L1.ApparentPower + L2.ApparentPower + L3.ApparentPower;
public ReactivePower ReactivePower => L1.ReactivePower + L2.ReactivePower + L3.ReactivePower;
public Power ActivePower => L1.ActivePower + L2.ActivePower + L3.ActivePower;
public Angle Phi => ATan2(ReactivePower, ActivePower);
- public static Ac3Phase operator |(Ac3Phase left, Ac3Phase right) => OpParallel(left, right);
- private static readonly Func OpParallel = "|".CreateBinaryOpForProps();
-
-
+ public static Ac3Bus operator |(Ac3Bus left, Ac3Bus right) => OpParallel(left, right);
+ private static readonly Func OpParallel = "|".CreateBinaryOpForProps();
}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Composite/AcPhase.cs b/csharp/Lib/Units/Composite/AcPhase.cs
index 426091fbc..d590fbdee 100644
--- a/csharp/Lib/Units/Composite/AcPhase.cs
+++ b/csharp/Lib/Units/Composite/AcPhase.cs
@@ -3,28 +3,28 @@ using static DecimalMath.DecimalEx;
namespace InnovEnergy.Lib.Units.Composite;
-public record AcPhase : IPhase
+public record AcPhase : IBus
{
private readonly Voltage _Voltage;
- public required Voltage Voltage
+ public Voltage Voltage
{
get => _Voltage;
- init => _Voltage = value >= 0 ? value : throw new ArgumentException("RMS value cannot be negative");
+ init => _Voltage = value >= 0m ? value : throw new ArgumentException("RMS value cannot be negative");
}
private readonly Current _Current;
- public required Current Current
+ public Current Current
{
get => _Current;
- init => _Current = value >= 0 ? value : throw new ArgumentException("RMS value cannot be negative");
+ init => _Current = value >= 0m ? value : throw new ArgumentException("RMS value cannot be negative");
}
- public required Angle Phi { get; init; }
+ public Angle Phi { get; init; }
public ApparentPower ApparentPower => Voltage.Value * Current.Value ;
- public Power ActivePower => ApparentPower.Value * PowerFactor;
+ public Power ActivePower => ApparentPower.Value * PowerFactor.Value;
public ReactivePower ReactivePower => ApparentPower.Value * Sin(Phi);
- public Decimal PowerFactor => Cos(Phi);
+ public Number PowerFactor => Cos(Phi);
public static AcPhase operator |(AcPhase left, AcPhase right)
diff --git a/csharp/Lib/Units/Composite/DcBus.cs b/csharp/Lib/Units/Composite/DcBus.cs
new file mode 100644
index 000000000..9bab0143a
--- /dev/null
+++ b/csharp/Lib/Units/Composite/DcBus.cs
@@ -0,0 +1,14 @@
+using InnovEnergy.Lib.Utils;
+
+namespace InnovEnergy.Lib.Units.Composite;
+
+public record DcBus : IBus
+{
+ public Voltage Voltage { get; init; }
+ public Current Current { get; init; }
+
+ public Power Power => Current * Voltage;
+
+ public static DcBus operator |(DcBus left, DcBus right) => OpParallel(left, right);
+ private static readonly Func OpParallel = "|".CreateBinaryOpForProps();
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Composite/DcPhase.cs b/csharp/Lib/Units/Composite/DcPhase.cs
deleted file mode 100644
index 2d0b24b68..000000000
--- a/csharp/Lib/Units/Composite/DcPhase.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using InnovEnergy.Lib.Utils;
-
-namespace InnovEnergy.Lib.Units.Composite;
-
-public record DcPhase : IPhase
-{
- public required Voltage Voltage { get; init;}
- public required Current Current { get; init;}
-
- public Power Power => Current * Voltage;
-
- public static DcPhase operator |(DcPhase left, DcPhase right) => OpParallel(left, right);
- private static readonly Func OpParallel = "|".CreateBinaryOpForProps();
-
-
-}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Composite/IPhase.cs b/csharp/Lib/Units/Composite/IBus.cs
similarity index 89%
rename from csharp/Lib/Units/Composite/IPhase.cs
rename to csharp/Lib/Units/Composite/IBus.cs
index b0ccfee66..8b9694972 100644
--- a/csharp/Lib/Units/Composite/IPhase.cs
+++ b/csharp/Lib/Units/Composite/IBus.cs
@@ -4,7 +4,7 @@ namespace InnovEnergy.Lib.Units.Composite;
[SuppressMessage("ReSharper", "MemberCanBeProtected.Global")]
-public interface IPhase
+public interface IBus
{
public Voltage Voltage { get; }
public Current Current { get; }
diff --git a/csharp/Lib/Units/Current.generated.cs b/csharp/Lib/Units/Current.generated.cs
index 93e9bdbf7..1bb733666 100644
--- a/csharp/Lib/Units/Current.generated.cs
+++ b/csharp/Lib/Units/Current.generated.cs
@@ -2,6 +2,9 @@
#define Sum
using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@@ -10,7 +13,7 @@ using T = Current;
public readonly partial struct Current
{
public Decimal Value { get; }
- public override String ToString() => Value + Unit;
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@@ -75,3 +78,19 @@ public readonly partial struct Current
public override Int32 GetHashCode() => Value.GetHashCode();
}
+
+
+internal class CurrentConverter : JsonConverter
+{
+ public override Current Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new Current(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, Current value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Frequency.generated.cs b/csharp/Lib/Units/Frequency.generated.cs
index 9618c18bc..b1e8c6e65 100644
--- a/csharp/Lib/Units/Frequency.generated.cs
+++ b/csharp/Lib/Units/Frequency.generated.cs
@@ -2,6 +2,9 @@
#define Equal
using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@@ -10,7 +13,7 @@ using T = Frequency;
public readonly partial struct Frequency
{
public Decimal Value { get; }
- public override String ToString() => Value + Unit;
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@@ -75,3 +78,19 @@ public readonly partial struct Frequency
public override Int32 GetHashCode() => Value.GetHashCode();
}
+
+
+internal class FrequencyConverter : JsonConverter
+{
+ public override Frequency Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new Frequency(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, Frequency value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Generator/Template.txt b/csharp/Lib/Units/Generator/Template.txt
index c78a3fcc6..857ecad58 100644
--- a/csharp/Lib/Units/Generator/Template.txt
+++ b/csharp/Lib/Units/Generator/Template.txt
@@ -1,7 +1,10 @@
#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source.
-#define Type
+#define AggregationType
using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@@ -10,7 +13,7 @@ using T = Template;
public readonly partial struct Template
{
public Decimal Value { get; }
- public override String ToString() => Value + Unit;
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@@ -75,3 +78,19 @@ public readonly partial struct Template
public override Int32 GetHashCode() => Value.GetHashCode();
}
+
+
+internal class TemplateConverter : JsonConverter
+{
+ public override Template Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new Template(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, Template value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Generator/generate.sh b/csharp/Lib/Units/Generator/generate.sh
index 625f32f89..74cc6a0c4 100755
--- a/csharp/Lib/Units/Generator/generate.sh
+++ b/csharp/Lib/Units/Generator/generate.sh
@@ -11,5 +11,5 @@ do
file=$(basename -- "$path")
class="${file%.*}"
echo "generating $file"
- sed "s/Template/$class/g; s/Type/$type/" "./Generator/Template.txt" > "./$class.generated.cs"
+ sed "s/Template/$class/g; s/AggregationType/$type/g" "./Generator/Template.txt" > "./$class.generated.cs"
done
\ No newline at end of file
diff --git a/csharp/Lib/Units/Json/CurrentConverter.cs b/csharp/Lib/Units/Json/CurrentConverter.cs
deleted file mode 100644
index b89ec4a90..000000000
--- a/csharp/Lib/Units/Json/CurrentConverter.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace InnovEnergy.Lib.Units.Json;
-
-public class CurrentConverter : JsonConverter
-{
- public override Current Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- return new Current(reader.GetDecimal());
- }
-
- public override void Write(Utf8JsonWriter writer, Current value, JsonSerializerOptions options)
- {
- writer.WriteNumberValue(value.Value);
- }
-}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Json/PowerConverter.cs b/csharp/Lib/Units/Json/PowerConverter.cs
deleted file mode 100644
index 766f3636c..000000000
--- a/csharp/Lib/Units/Json/PowerConverter.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace InnovEnergy.Lib.Units.Json;
-
-public class PowerConverter : JsonConverter
-{
- public override Power Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- return new Power(reader.GetDecimal());
- }
-
- public override void Write(Utf8JsonWriter writer, Power value, JsonSerializerOptions options)
- {
- writer.WriteNumberValue(value.Value);
- }
-}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Json/ResistanceConverter.cs b/csharp/Lib/Units/Json/ResistanceConverter.cs
deleted file mode 100644
index 67ec28a13..000000000
--- a/csharp/Lib/Units/Json/ResistanceConverter.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace InnovEnergy.Lib.Units.Json;
-
-public class ResistanceConverter : JsonConverter
-{
- public override Current Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- return new Current(reader.GetDecimal());
- }
-
- public override void Write(Utf8JsonWriter writer, Current value, JsonSerializerOptions options)
- {
- writer.WriteNumberValue(value.Value);
- }
-}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Json/VoltageConverter.cs b/csharp/Lib/Units/Json/VoltageConverter.cs
deleted file mode 100644
index 290c6f38b..000000000
--- a/csharp/Lib/Units/Json/VoltageConverter.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace InnovEnergy.Lib.Units.Json;
-
-public class VoltageConverter : JsonConverter
-{
- public override Voltage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- return new Voltage(reader.GetDecimal());
- }
-
- public override void Write(Utf8JsonWriter writer, Voltage value, JsonSerializerOptions options)
- {
- writer.WriteNumberValue(value.Value);
- }
-}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Number.cs b/csharp/Lib/Units/Number.cs
new file mode 100644
index 000000000..fdc9b3b42
--- /dev/null
+++ b/csharp/Lib/Units/Number.cs
@@ -0,0 +1,13 @@
+using InnovEnergy.Lib.Units.Generator;
+
+
+namespace InnovEnergy.Lib.Units;
+
+[Sum]
+public readonly partial struct Number
+{
+ public static String Unit => "";
+ public static String Symbol => "";
+
+ public Number(Decimal value) => Value = value;
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Number.generated.cs b/csharp/Lib/Units/Number.generated.cs
new file mode 100644
index 000000000..4e533f664
--- /dev/null
+++ b/csharp/Lib/Units/Number.generated.cs
@@ -0,0 +1,96 @@
+#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source.
+#define Sum
+
+using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
+
+namespace InnovEnergy.Lib.Units;
+
+using T = Number;
+
+public readonly partial struct Number
+{
+ public Decimal Value { get; }
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
+
+ // scalar multiplication
+
+ public static T operator *(Decimal scalar, T t) => new T(scalar * t.Value);
+ public static T operator *(T t, Decimal scalar) => new T(scalar * t.Value);
+ public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar);
+
+ // parallel
+
+ #if Sum
+
+ public static T operator |(T left, T right) => new T(left.Value + right.Value);
+ public static T operator -(T t) => new T(-t.Value);
+
+ #elif Mean
+
+ public static T operator |(T left, T right) => new T((left.Value + right.Value)/2m);
+
+ #elif Equal
+
+ public static T operator |(T left, T right)
+ {
+ var d = Max(Abs(left.Value), Abs(right.Value));
+
+ if (d == 0m)
+ return new T(0m);
+
+ var relativeError = Abs(left.Value - right.Value) / d;
+
+ const Decimal maxRelativeError = 0.05m;
+
+ if (relativeError > maxRelativeError)
+ throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" +
+ $"Difference > {maxRelativeError * 100}% detected\n" +
+ $"{nameof(left)} : {left}\n" +
+ $"{nameof(right)}: {right}");
+
+ return new T((left.Value + right.Value) / 2m);
+ }
+ #endif
+
+ // compare
+
+ public static Boolean operator ==(T left, T right) => left.Value == right.Value;
+ public static Boolean operator !=(T left, T right) => left.Value != right.Value;
+ public static Boolean operator > (T left, T right) => left.Value > right.Value;
+ public static Boolean operator < (T left, T right) => left.Value < right.Value;
+ public static Boolean operator >=(T left, T right) => left.Value >= right.Value;
+ public static Boolean operator <=(T left, T right) => left.Value <= right.Value;
+
+ // conversion
+
+ public static implicit operator T(Decimal d) => new T(d);
+ public static implicit operator T(Double d) => new T((Decimal)d);
+ public static implicit operator T(Int32 i) => new T(i);
+ public static implicit operator Decimal(T t) => t.Value;
+
+ // equality
+
+ public Boolean Equals(T other) => Value == other.Value;
+ public override Boolean Equals(Object? obj) => obj is T other && Equals(other);
+ public override Int32 GetHashCode() => Value.GetHashCode();
+
+}
+
+
+internal class NumberConverter : JsonConverter
+{
+ public override Number Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new Number(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, Number value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Percent.cs b/csharp/Lib/Units/Percent.cs
index a358c438f..577dec8a0 100644
--- a/csharp/Lib/Units/Percent.cs
+++ b/csharp/Lib/Units/Percent.cs
@@ -10,6 +10,7 @@ public readonly struct Percent
public Percent(Decimal value) => Value = value;
// not generated
+ // TODO: generate?
public Decimal Value { get; }
public override String ToString() => Value + Unit;
@@ -20,4 +21,23 @@ public readonly struct Percent
// parallel
public static Percent operator |(T left, T right) => new T((left.Value + right.Value) / 2m);
+
+ // compare
+ public static Boolean operator ==(T left, T right) => left.Value == right.Value;
+ public static Boolean operator !=(T left, T right) => left.Value != right.Value;
+ public static Boolean operator > (T left, T right) => left.Value > right.Value;
+ public static Boolean operator < (T left, T right) => left.Value < right.Value;
+ public static Boolean operator >=(T left, T right) => left.Value >= right.Value;
+ public static Boolean operator <=(T left, T right) => left.Value <= right.Value;
+
+ // conversion
+ public static implicit operator T(Decimal d) => new T(d);
+ public static implicit operator T(Double d) => new T((Decimal)d);
+ public static implicit operator T(Int32 i) => new T(i);
+ public static implicit operator Decimal(T t) => t.Value;
+
+ // equality
+ public Boolean Equals(T other) => Value == other.Value;
+ public override Boolean Equals(Object? obj) => obj is T other && Equals(other);
+ public override Int32 GetHashCode() => Value.GetHashCode();
}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Power.cs b/csharp/Lib/Units/Power.cs
index eaedbf7f2..00d8b01c1 100644
--- a/csharp/Lib/Units/Power.cs
+++ b/csharp/Lib/Units/Power.cs
@@ -10,7 +10,6 @@ public readonly partial struct Power
public static String Symbol => "P";
public Power(Decimal value) => Value = value;
-
// P=UI
public static Voltage operator /(Power power, Current current) => new Voltage(power.Value / current.Value);
diff --git a/csharp/Lib/Units/Power.generated.cs b/csharp/Lib/Units/Power.generated.cs
index 5ccca90ef..923275e3b 100644
--- a/csharp/Lib/Units/Power.generated.cs
+++ b/csharp/Lib/Units/Power.generated.cs
@@ -2,6 +2,9 @@
#define Sum
using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@@ -10,7 +13,7 @@ using T = Power;
public readonly partial struct Power
{
public Decimal Value { get; }
- public override String ToString() => Value + Unit;
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@@ -75,3 +78,19 @@ public readonly partial struct Power
public override Int32 GetHashCode() => Value.GetHashCode();
}
+
+
+internal class PowerConverter : JsonConverter
+{
+ public override Power Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new Power(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, Power value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/ReactivePower.generated.cs b/csharp/Lib/Units/ReactivePower.generated.cs
index f438dd865..252438ae1 100644
--- a/csharp/Lib/Units/ReactivePower.generated.cs
+++ b/csharp/Lib/Units/ReactivePower.generated.cs
@@ -2,6 +2,9 @@
#define Sum
using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@@ -10,7 +13,7 @@ using T = ReactivePower;
public readonly partial struct ReactivePower
{
public Decimal Value { get; }
- public override String ToString() => Value + Unit;
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@@ -75,3 +78,19 @@ public readonly partial struct ReactivePower
public override Int32 GetHashCode() => Value.GetHashCode();
}
+
+
+internal class ReactivePowerConverter : JsonConverter
+{
+ public override ReactivePower Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new ReactivePower(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, ReactivePower value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Resistance.generated.cs b/csharp/Lib/Units/Resistance.generated.cs
index 134384467..d81ace678 100644
--- a/csharp/Lib/Units/Resistance.generated.cs
+++ b/csharp/Lib/Units/Resistance.generated.cs
@@ -2,6 +2,9 @@
#define Sum
using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@@ -10,7 +13,7 @@ using T = Resistance;
public readonly partial struct Resistance
{
public Decimal Value { get; }
- public override String ToString() => Value + Unit;
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@@ -75,3 +78,19 @@ public readonly partial struct Resistance
public override Int32 GetHashCode() => Value.GetHashCode();
}
+
+
+internal class ResistanceConverter : JsonConverter
+{
+ public override Resistance Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new Resistance(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, Resistance value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/State.cs b/csharp/Lib/Units/State.cs
index ecabbd034..3e8e48395 100644
--- a/csharp/Lib/Units/State.cs
+++ b/csharp/Lib/Units/State.cs
@@ -1,6 +1,8 @@
+using System.Collections;
+
namespace InnovEnergy.Lib.Units;
-public readonly struct State
+public readonly struct State : IReadOnlyList
{
public IReadOnlyList Values { get; }
@@ -13,13 +15,23 @@ public readonly struct State
}
public State(params String[] values) : this((IReadOnlyList)values){}
- public State(params State[] states) : this(states.SelectMany(s => s.Values).ToList()){}
+ public State(params State[] states) : this((IReadOnlyList)states.SelectMany(s => s.Values).ToList()){}
- public static implicit operator State(String s) => new State(s);
- public static implicit operator State(Enum e) => new State(e.ToString());
- public static implicit operator State(Boolean s) => new State(s.ToString());
+ public static implicit operator State(String s) => new(s);
+ public static implicit operator State(Enum e) => new(e.ToString());
+ public static implicit operator State(Boolean s) => new(s.ToString());
+ public static implicit operator State(List s) => new((IReadOnlyList)s);
+ public static implicit operator State(String[] s) => new((IReadOnlyList)s);
+ public static implicit operator State(List es) => new(es.Select(e => e.ToString()).ToList());
+ public static implicit operator State(Enum[] es) => new(es.Select(e => e.ToString()).ToList());
- public static State operator |(State left, State right) => new State(left, right);
+ public static State operator |(State left, State right) => new(left, right);
+
+ public IEnumerator GetEnumerator() => Values.GetEnumerator();
public override String ToString() => String.Join("; ", Values);
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+ public Int32 Count => Values.Count;
+ public String this[Int32 index] => Values[index];
}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Temperature.generated.cs b/csharp/Lib/Units/Temperature.generated.cs
index cc173ee61..e0ff31eaa 100644
--- a/csharp/Lib/Units/Temperature.generated.cs
+++ b/csharp/Lib/Units/Temperature.generated.cs
@@ -2,6 +2,9 @@
#define Mean
using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@@ -10,7 +13,7 @@ using T = Temperature;
public readonly partial struct Temperature
{
public Decimal Value { get; }
- public override String ToString() => Value + Unit;
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@@ -75,3 +78,19 @@ public readonly partial struct Temperature
public override Int32 GetHashCode() => Value.GetHashCode();
}
+
+
+internal class TemperatureConverter : JsonConverter
+{
+ public override Temperature Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new Temperature(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, Temperature value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Units.cs b/csharp/Lib/Units/Units.cs
index 98bc153e8..0ee78882b 100644
--- a/csharp/Lib/Units/Units.cs
+++ b/csharp/Lib/Units/Units.cs
@@ -1,10 +1,27 @@
using System.Text.Json.Serialization;
-using InnovEnergy.Lib.Units.Json;
namespace InnovEnergy.Lib.Units;
public static class Units
{
+ static Units()
+ {
+ JsonConverters = typeof(Units)
+ .Assembly
+ .GetTypes()
+ .Where(t => t.IsAssignableTo(typeof(JsonConverter)))
+ .Select(Activator.CreateInstance)
+ .Cast()
+ .ToArray();
+ }
+
+
+ public static IReadOnlyList JsonConverters { get; }
+
+ public static Byte DisplaySignificantDigits { get; set; } = 3;
+ public static Byte JsonSignificantDigits { get; set; } = 3;
+
+
public const Decimal MaxRelativeError = 0.05m; // 5%
public static Current A (this Decimal value) => new Current(value);
@@ -16,14 +33,6 @@ public static class Units
public static Frequency Hz (this Decimal value) => new Frequency(value);
public static Angle Rad (this Decimal value) => new Angle(value);
public static Temperature Celsius(this Decimal value) => new Temperature(value);
+
- public static readonly IReadOnlyList JsonConverters = new JsonConverter[]
- {
- new CurrentConverter(),
- new VoltageConverter(),
- new PowerConverter(),
- new ResistanceConverter(),
-
- // TODO
- };
}
\ No newline at end of file
diff --git a/csharp/Lib/Units/Voltage.generated.cs b/csharp/Lib/Units/Voltage.generated.cs
index cdb63dcda..44c32da19 100644
--- a/csharp/Lib/Units/Voltage.generated.cs
+++ b/csharp/Lib/Units/Voltage.generated.cs
@@ -2,6 +2,9 @@
#define Equal
using static System.Math;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@@ -10,7 +13,7 @@ using T = Voltage;
public readonly partial struct Voltage
{
public Decimal Value { get; }
- public override String ToString() => Value + Unit;
+ public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@@ -75,3 +78,19 @@ public readonly partial struct Voltage
public override Int32 GetHashCode() => Value.GetHashCode();
}
+
+
+internal class VoltageConverter : JsonConverter
+{
+ public override Voltage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new Voltage(reader.GetDecimal());
+ }
+
+ public override void Write(Utf8JsonWriter writer, Voltage value, JsonSerializerOptions options)
+ {
+ var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
+
+ writer.WriteNumberValue(rounded);
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Utils/DecimalUtils.cs b/csharp/Lib/Utils/DecimalUtils.cs
index 709393af4..6090a2ba6 100644
--- a/csharp/Lib/Utils/DecimalUtils.cs
+++ b/csharp/Lib/Utils/DecimalUtils.cs
@@ -1,32 +1,36 @@
using DecimalMath;
+using static System.Math;
+using static DecimalMath.DecimalEx;
namespace InnovEnergy.Lib.Utils;
public static class DecimalUtils
{
- public static Double RoundToSignificantFigures(this Double num, Int32 n)
+ public static Double RoundToSignificantDigits(this Double num, Int32 n)
{
if (num == 0)
return 0;
- var d = Math.Ceiling(Math.Log10(num < 0 ? -num : num));
+ var d = Ceiling(Log10(num < 0 ? -num : num));
var power = n - (Int32)d;
var magnitude = Math.Pow(10, power);
- var shifted = Math.Round(num * magnitude);
+ var shifted = Round(num * magnitude);
+
return shifted / magnitude;
}
- public static Decimal RoundToSignificantFigures(this Decimal num, Int32 n)
+ public static Decimal RoundToSignificantDigits(this Decimal num, Int32 n)
{
if (num == 0)
return 0;
- var d = Math.Ceiling(DecimalEx.Log10(num < 0 ? -num : num));
+ var d = Ceiling(Log10(num < 0 ? -num : num));
var power = n - (Int32)d;
var magnitude = DecimalEx.Pow(10, power);
- var shifted = Math.Round(num * magnitude);
+ var shifted = Round(num * magnitude);
+
return shifted / magnitude;
}
}
\ No newline at end of file
diff --git a/csharp/Lib/Utils/EnumerableUtils.cs b/csharp/Lib/Utils/EnumerableUtils.cs
index af64b103e..dd0243ef8 100644
--- a/csharp/Lib/Utils/EnumerableUtils.cs
+++ b/csharp/Lib/Utils/EnumerableUtils.cs
@@ -106,7 +106,7 @@ public static class EnumerableUtils
public static IEnumerable NullableToEnumerable(this T? t)
{
if (t is not null)
- yield return t!;
+ yield return t;
}
public static IEnumerable<(T left, T right)> Pairwise(this IEnumerable ts)
@@ -246,7 +246,7 @@ public static class EnumerableUtils
public static IEnumerable Generate(this T seed, Func next)
{
var value = seed;
- while (true)
+ while (value is not null)
{
yield return value;
value = next(value);
diff --git a/csharp/Lib/Victron/VeDBus/VeDBus.csproj b/csharp/Lib/Victron/VeDBus/VeDBus.csproj
index fe0000124..c7d6bf0a9 100644
--- a/csharp/Lib/Victron/VeDBus/VeDBus.csproj
+++ b/csharp/Lib/Victron/VeDBus/VeDBus.csproj
@@ -2,11 +2,6 @@
-
-
- latest
-
-
diff --git a/csharp/Lib/Victron/VictronVRM/VictronVRM.csproj b/csharp/Lib/Victron/VictronVRM/VictronVRM.csproj
index f37c8f354..c5a94a419 100644
--- a/csharp/Lib/Victron/VictronVRM/VictronVRM.csproj
+++ b/csharp/Lib/Victron/VictronVRM/VictronVRM.csproj
@@ -6,11 +6,6 @@
full
-
-
- latest
-
-