From 3758165c08d0c4d38fa4920860a0410a649123a4 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 08:02:49 +0100 Subject: [PATCH 01/41] fix RootNamespace for Apps --- csharp/App/InnovEnergy.App.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/App/InnovEnergy.App.props b/csharp/App/InnovEnergy.App.props index 38d62f4dc..fe6d1e334 100644 --- a/csharp/App/InnovEnergy.App.props +++ b/csharp/App/InnovEnergy.App.props @@ -19,7 +19,7 @@ Exe - InnovEnergy.App.$(AssemblyName) + \ No newline at end of file From a32cf8389312e8e672fd1d4f04256478c315b9c9 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 08:04:53 +0100 Subject: [PATCH 02/41] add CreateBinaryOpForProps --- csharp/Lib/Utils/Operators.cs | 95 +++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 csharp/Lib/Utils/Operators.cs diff --git a/csharp/Lib/Utils/Operators.cs b/csharp/Lib/Utils/Operators.cs new file mode 100644 index 000000000..644cb2906 --- /dev/null +++ b/csharp/Lib/Utils/Operators.cs @@ -0,0 +1,95 @@ +using System.Reflection; +using static System.Reflection.BindingFlags; + +namespace InnovEnergy.Lib.Utils; + +public static class Operators +{ + public static Func CreateBinaryOpForProps(this String op) + { + var methodName = GetMethodNameForBinaryOp(op); + + var props = typeof(T) + .GetProperties(Instance | Public) + .Where(p => p.CanWrite) + .Select(p => + ( + prop: p, + op: GetOpMethod(methodName, p.PropertyType) ?? + throw new ArgumentException($"Type {p.PropertyType.Name} " + + $"of property {p.Name} " + + $"has no suitable {op} operator defined.")) + ) + .ToArray(); + + var ctr = typeof(T).GetConstructors().FirstOrDefault(c => c.GetParameters().Length == 0); + + if (ctr is null) + throw new ArgumentException($"Type {typeof(T).Name} has no suitable parameterless constructor."); + + + T Op(T left, T right) + { + // TODO: make this faster/nicer using Expression API (low prio) + + var result = ctr.Invoke(null); + + foreach (var (p, m) in props) + { + var l = p.GetValue(left); + var r = p.GetValue(right); + + var s = m.Invoke(null, new[] { l, r }); + + p.SetValue(result, s); + } + + return (T) result; + } + + return Op; + } + + private static String GetMethodNameForBinaryOp(String op) + { + // from https://stackoverflow.com/a/29495075 + + return op switch + { + "&" => "op_BitwiseAnd", + "|" => "op_BitwiseOr", + "+" => "op_Addition", + "-" => "op_Subtraction", + "/" => "op_Division", + "%" => "op_Modulus", + "*" => "op_Multiply", + "<<" => "op_LeftShift", + ">>" => "op_RightShift", + "^" => "op_ExclusiveOr", + "==" => "op_Equality", + "!=" => "op_Inequality", + ">" => "op_GreaterThan", + "<" => "op_LessThan", + ">=" => "op_GreaterThanOrEqual", + "<=" => "op_LessThanOrEqual", + _ => throw new ArgumentException("unknown operator", nameof(op)) + }; + } + + private static MethodInfo? GetOpMethod(String? methodName, Type type) + { + return type + .GetMethods(Static | Public) + .FirstOrDefault(m => m.Name == methodName + && m.ReturnType == type + && m.IsMonoidOp()); + } + + private static Boolean IsMonoidOp(this MethodInfo m) + { + var ps = m.GetParameters(); + + return ps.Length == 2 && + ps.All(p => p.ParameterType == m.ReturnType); + } +} \ No newline at end of file From 2070fce4eccb89c2ece58f10a6de07ecb5b9adaa Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 08:05:57 +0100 Subject: [PATCH 03/41] implement | (parallel) operator for all Units --- csharp/Lib/Units/Angle.generated.cs | 11 +++--- csharp/Lib/Units/ApparentPower.generated.cs | 11 +++--- csharp/Lib/Units/Composite/Ac1Phase.cs | 27 +++++++------ csharp/Lib/Units/Composite/Ac3Phase.cs | 23 +++++------ csharp/Lib/Units/Composite/AcPhase.cs | 44 +++++++++++++-------- csharp/Lib/Units/Composite/DcPhase.cs | 21 +++++----- csharp/Lib/Units/Composite/IPhase.cs | 11 ++++++ csharp/Lib/Units/Composite/Phase.cs | 7 ---- csharp/Lib/Units/Current.generated.cs | 11 +++--- csharp/Lib/Units/Frequency.generated.cs | 11 +++--- csharp/Lib/Units/Generator/Template.txt | 11 +++--- csharp/Lib/Units/Power.generated.cs | 11 +++--- csharp/Lib/Units/ReactivePower.generated.cs | 11 +++--- csharp/Lib/Units/Resistance.cs | 3 ++ csharp/Lib/Units/Resistance.generated.cs | 11 +++--- csharp/Lib/Units/State.cs | 2 +- csharp/Lib/Units/Temperature.cs | 1 - csharp/Lib/Units/Temperature.generated.cs | 11 +++--- csharp/Lib/Units/Units.cs | 2 + csharp/Lib/Units/Voltage.generated.cs | 11 +++--- 20 files changed, 131 insertions(+), 120 deletions(-) create mode 100644 csharp/Lib/Units/Composite/IPhase.cs delete mode 100644 csharp/Lib/Units/Composite/Phase.cs diff --git a/csharp/Lib/Units/Angle.generated.cs b/csharp/Lib/Units/Angle.generated.cs index ad576594a..f2317f977 100644 --- a/csharp/Lib/Units/Angle.generated.cs +++ b/csharp/Lib/Units/Angle.generated.cs @@ -18,25 +18,24 @@ public readonly partial struct Angle 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); - // addition + // parallel #if Sum - public static T operator +(T left, T right) => new T(left.Value + right.Value); - public static T operator -(T left, T right) => new T(left.Value - right.Value); + 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); + 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) + public static T operator |(T left, T right) { var d = Max(Abs(left.Value), Abs(right.Value)); - if (d != 0m) + if (d == 0m) return new T(0m); var relativeError = Abs(left.Value - right.Value) / d; diff --git a/csharp/Lib/Units/ApparentPower.generated.cs b/csharp/Lib/Units/ApparentPower.generated.cs index cfa6174ed..0775151c9 100644 --- a/csharp/Lib/Units/ApparentPower.generated.cs +++ b/csharp/Lib/Units/ApparentPower.generated.cs @@ -18,25 +18,24 @@ public readonly partial struct ApparentPower 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); - // addition + // parallel #if Sum - public static T operator +(T left, T right) => new T(left.Value + right.Value); - public static T operator -(T left, T right) => new T(left.Value - right.Value); + 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); + 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) + public static T operator |(T left, T right) { var d = Max(Abs(left.Value), Abs(right.Value)); - if (d != 0m) + if (d == 0m) return new T(0m); var relativeError = Abs(left.Value - right.Value) / d; diff --git a/csharp/Lib/Units/Composite/Ac1Phase.cs b/csharp/Lib/Units/Composite/Ac1Phase.cs index e48807866..d7cfc20e7 100644 --- a/csharp/Lib/Units/Composite/Ac1Phase.cs +++ b/csharp/Lib/Units/Composite/Ac1Phase.cs @@ -1,25 +1,28 @@ + using System.Diagnostics.CodeAnalysis; namespace InnovEnergy.Lib.Units.Composite; -public record Ac1Phase -( - Voltage Voltage, - Current Current, - Angle Phi, - Frequency Frequency -) - : AcPhase(Voltage, Current, Phi) +public record Ac1Phase : AcPhase { + public required Frequency Frequency { get; init; } [SuppressMessage("ReSharper", "RedundantCast")] - public static Ac1Phase operator +(Ac1Phase left, Ac1Phase right) + public static Ac1Phase operator |(Ac1Phase left, Ac1Phase right) { - var f = (left.Frequency + right.Frequency) / 2m; // TODO: check that l & r approximately equal - var acPhase = (AcPhase)left + (AcPhase)right; - return new Ac1Phase(acPhase.Voltage, acPhase.Current, acPhase.Phi, f); + var f = left.Frequency | right.Frequency; + var p = (AcPhase)left | (AcPhase)right; + + return new Ac1Phase + { + Frequency = f, + Current = p.Current, + Voltage = p.Voltage, + Phi = p.Phi + }; } + } diff --git a/csharp/Lib/Units/Composite/Ac3Phase.cs b/csharp/Lib/Units/Composite/Ac3Phase.cs index a5788e452..d73f8e9e4 100644 --- a/csharp/Lib/Units/Composite/Ac3Phase.cs +++ b/csharp/Lib/Units/Composite/Ac3Phase.cs @@ -1,25 +1,22 @@ +using InnovEnergy.Lib.Utils; using static DecimalMath.DecimalEx; namespace InnovEnergy.Lib.Units.Composite; -public record Ac3Phase(AcPhase L1, AcPhase L2, AcPhase L3, Frequency Frequency) +public record Ac3Phase { + 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 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 Angle Phi => ATan2(ReactivePower, ActivePower); - - - public static Ac3Phase operator +(Ac3Phase left, Ac3Phase right) - { - var f = (left.Frequency + right.Frequency) / 2m; // TODO: check that l & r approximately equal + public static Ac3Phase operator |(Ac3Phase left, Ac3Phase right) => OpParallel(left, right); + private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); - var l1 = left.L1 + right.L1; - var l2 = left.L2 + right.L2; - var l3 = left.L3 + right.L3; - - return new Ac3Phase(l1, l2, l3, f); - } } \ No newline at end of file diff --git a/csharp/Lib/Units/Composite/AcPhase.cs b/csharp/Lib/Units/Composite/AcPhase.cs index 70cd952b2..426091fbc 100644 --- a/csharp/Lib/Units/Composite/AcPhase.cs +++ b/csharp/Lib/Units/Composite/AcPhase.cs @@ -3,17 +3,23 @@ using static DecimalMath.DecimalEx; namespace InnovEnergy.Lib.Units.Composite; -public record AcPhase : Phase +public record AcPhase : IPhase { - public AcPhase(Voltage voltage, Current current, Angle phi) : base(voltage, current) + private readonly Voltage _Voltage; + public required Voltage Voltage { - if (voltage < 0) throw new ArgumentException("RMS value cannot be negative", nameof(voltage)); - if (current < 0) throw new ArgumentException("RMS value cannot be negative", nameof(current)); - - Phi = phi; + get => _Voltage; + init => _Voltage = value >= 0 ? value : throw new ArgumentException("RMS value cannot be negative"); } - public Angle Phi { get; } + private readonly Current _Current; + public required Current Current + { + get => _Current; + init => _Current = value >= 0 ? value : throw new ArgumentException("RMS value cannot be negative"); + } + + public required Angle Phi { get; init; } public ApparentPower ApparentPower => Voltage.Value * Current.Value ; public Power ActivePower => ApparentPower.Value * PowerFactor; @@ -21,34 +27,40 @@ public record AcPhase : Phase public Decimal PowerFactor => Cos(Phi); - public static AcPhase operator +(AcPhase left, AcPhase right) + public static AcPhase operator |(AcPhase left, AcPhase right) { // the Voltages of two phases are expected to be in phase and equal - var v = (left.Voltage + right.Voltage) / 2m; // TODO: check that l & r approximately equal + var v = left.Voltage | right.Voltage; // currents (RMS) can be different and out of phase // https://www.johndcook.com/blog/2020/08/17/adding-phase-shifted-sine-waves/ // IF - // left(t) = ILeft sin(ωt) + // left(t) = ILeft sin(ωt) // right(t) = IRight sin(ωt + φ). - // sum(t) = left(t) + right(t) = ISum sin(ωt + ψ). - // THEN + // sum(t) = left(t) + right(t) = ISum sin(ωt + ψ). + // THEN // ψ = arctan( IRight * sin(φ) / (ILeft + IRight cos(φ)) ). // C = IRight * sin(φ) / sin(ψ). - // in this calc left(t) has zero phase shift. + // in this calculation left(t) has zero phase shift. // we can shift both waves by -left.Phi, so // φ := right.phi - left.phi - var phi = right.Phi - left.Phi; - + var phi = right.Phi - left.Phi; var phiSum = ATan2(right.Current * Sin(phi), left.Current + right.Current * Cos(phi)); var iSum = right.Current * Sin(phi) / Sin(phiSum); - return new AcPhase(v, iSum, phiSum); + return new AcPhase + { + Voltage = v, + Current = iSum, + Phi = phiSum + }; } + + } \ No newline at end of file diff --git a/csharp/Lib/Units/Composite/DcPhase.cs b/csharp/Lib/Units/Composite/DcPhase.cs index af6d1049a..2d0b24b68 100644 --- a/csharp/Lib/Units/Composite/DcPhase.cs +++ b/csharp/Lib/Units/Composite/DcPhase.cs @@ -1,15 +1,16 @@ +using InnovEnergy.Lib.Utils; + namespace InnovEnergy.Lib.Units.Composite; -public record DcPhase(Voltage Voltage, Current Current) : Phase(Voltage, Current) +public record DcPhase : IPhase { - public Power Power => Current * Voltage; - - public static DcPhase operator +(DcPhase left, DcPhase right) - { - var v = (left.Voltage + right.Voltage) / 2m; - var i = left.Current + right.Current; - - return new DcPhase(v, i); - } + 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/IPhase.cs new file mode 100644 index 000000000..b0ccfee66 --- /dev/null +++ b/csharp/Lib/Units/Composite/IPhase.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; + +namespace InnovEnergy.Lib.Units.Composite; + +[SuppressMessage("ReSharper", "MemberCanBeProtected.Global")] + +public interface IPhase +{ + public Voltage Voltage { get; } + public Current Current { get; } +} \ No newline at end of file diff --git a/csharp/Lib/Units/Composite/Phase.cs b/csharp/Lib/Units/Composite/Phase.cs deleted file mode 100644 index 45a3ef86d..000000000 --- a/csharp/Lib/Units/Composite/Phase.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace InnovEnergy.Lib.Units.Composite; - -public abstract record Phase -( - Voltage Voltage, - Current Current -); \ No newline at end of file diff --git a/csharp/Lib/Units/Current.generated.cs b/csharp/Lib/Units/Current.generated.cs index cda7eeadf..93e9bdbf7 100644 --- a/csharp/Lib/Units/Current.generated.cs +++ b/csharp/Lib/Units/Current.generated.cs @@ -18,25 +18,24 @@ public readonly partial struct Current 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); - // addition + // parallel #if Sum - public static T operator +(T left, T right) => new T(left.Value + right.Value); - public static T operator -(T left, T right) => new T(left.Value - right.Value); + 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); + 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) + public static T operator |(T left, T right) { var d = Max(Abs(left.Value), Abs(right.Value)); - if (d != 0m) + if (d == 0m) return new T(0m); var relativeError = Abs(left.Value - right.Value) / d; diff --git a/csharp/Lib/Units/Frequency.generated.cs b/csharp/Lib/Units/Frequency.generated.cs index 015d67536..9618c18bc 100644 --- a/csharp/Lib/Units/Frequency.generated.cs +++ b/csharp/Lib/Units/Frequency.generated.cs @@ -18,25 +18,24 @@ public readonly partial struct Frequency 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); - // addition + // parallel #if Sum - public static T operator +(T left, T right) => new T(left.Value + right.Value); - public static T operator -(T left, T right) => new T(left.Value - right.Value); + 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); + 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) + public static T operator |(T left, T right) { var d = Max(Abs(left.Value), Abs(right.Value)); - if (d != 0m) + if (d == 0m) return new T(0m); var relativeError = Abs(left.Value - right.Value) / d; diff --git a/csharp/Lib/Units/Generator/Template.txt b/csharp/Lib/Units/Generator/Template.txt index c656f51df..c78a3fcc6 100644 --- a/csharp/Lib/Units/Generator/Template.txt +++ b/csharp/Lib/Units/Generator/Template.txt @@ -18,25 +18,24 @@ public readonly partial struct Template 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); - // addition + // parallel #if Sum - public static T operator +(T left, T right) => new T(left.Value + right.Value); - public static T operator -(T left, T right) => new T(left.Value - right.Value); + 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); + 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) + public static T operator |(T left, T right) { var d = Max(Abs(left.Value), Abs(right.Value)); - if (d != 0m) + if (d == 0m) return new T(0m); var relativeError = Abs(left.Value - right.Value) / d; diff --git a/csharp/Lib/Units/Power.generated.cs b/csharp/Lib/Units/Power.generated.cs index c26ad26fd..5ccca90ef 100644 --- a/csharp/Lib/Units/Power.generated.cs +++ b/csharp/Lib/Units/Power.generated.cs @@ -18,25 +18,24 @@ public readonly partial struct Power 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); - // addition + // parallel #if Sum - public static T operator +(T left, T right) => new T(left.Value + right.Value); - public static T operator -(T left, T right) => new T(left.Value - right.Value); + 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); + 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) + public static T operator |(T left, T right) { var d = Max(Abs(left.Value), Abs(right.Value)); - if (d != 0m) + if (d == 0m) return new T(0m); var relativeError = Abs(left.Value - right.Value) / d; diff --git a/csharp/Lib/Units/ReactivePower.generated.cs b/csharp/Lib/Units/ReactivePower.generated.cs index 9b8def505..f438dd865 100644 --- a/csharp/Lib/Units/ReactivePower.generated.cs +++ b/csharp/Lib/Units/ReactivePower.generated.cs @@ -18,25 +18,24 @@ public readonly partial struct ReactivePower 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); - // addition + // parallel #if Sum - public static T operator +(T left, T right) => new T(left.Value + right.Value); - public static T operator -(T left, T right) => new T(left.Value - right.Value); + 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); + 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) + public static T operator |(T left, T right) { var d = Max(Abs(left.Value), Abs(right.Value)); - if (d != 0m) + if (d == 0m) return new T(0m); var relativeError = Abs(left.Value - right.Value) / d; diff --git a/csharp/Lib/Units/Resistance.cs b/csharp/Lib/Units/Resistance.cs index ce426e229..ab0bc7bbe 100644 --- a/csharp/Lib/Units/Resistance.cs +++ b/csharp/Lib/Units/Resistance.cs @@ -2,6 +2,9 @@ using InnovEnergy.Lib.Units.Generator; namespace InnovEnergy.Lib.Units; + +// TODO: op parallel is wrong + [Sum] public readonly partial struct Resistance { diff --git a/csharp/Lib/Units/Resistance.generated.cs b/csharp/Lib/Units/Resistance.generated.cs index 5be7685b6..134384467 100644 --- a/csharp/Lib/Units/Resistance.generated.cs +++ b/csharp/Lib/Units/Resistance.generated.cs @@ -18,25 +18,24 @@ public readonly partial struct Resistance 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); - // addition + // parallel #if Sum - public static T operator +(T left, T right) => new T(left.Value + right.Value); - public static T operator -(T left, T right) => new T(left.Value - right.Value); + 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); + 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) + public static T operator |(T left, T right) { var d = Max(Abs(left.Value), Abs(right.Value)); - if (d != 0m) + if (d == 0m) return new T(0m); var relativeError = Abs(left.Value - right.Value) / d; diff --git a/csharp/Lib/Units/State.cs b/csharp/Lib/Units/State.cs index 752a5751d..af96735e0 100644 --- a/csharp/Lib/Units/State.cs +++ b/csharp/Lib/Units/State.cs @@ -14,5 +14,5 @@ public readonly struct State public static implicit operator State(Enum e) => new State(e); public static implicit operator State(String s) => new State(s); - public static State operator +(State left, State right) => new State(left, right); + public static State operator |(State left, State right) => new State(left, right); } \ No newline at end of file diff --git a/csharp/Lib/Units/Temperature.cs b/csharp/Lib/Units/Temperature.cs index dc2d7e5ad..57e2406a3 100644 --- a/csharp/Lib/Units/Temperature.cs +++ b/csharp/Lib/Units/Temperature.cs @@ -11,6 +11,5 @@ public readonly partial struct Temperature public static String Symbol => "T"; public Temperature(Decimal value) => Value = value; - } \ No newline at end of file diff --git a/csharp/Lib/Units/Temperature.generated.cs b/csharp/Lib/Units/Temperature.generated.cs index edc3fdbfa..cc173ee61 100644 --- a/csharp/Lib/Units/Temperature.generated.cs +++ b/csharp/Lib/Units/Temperature.generated.cs @@ -18,25 +18,24 @@ public readonly partial struct Temperature 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); - // addition + // parallel #if Sum - public static T operator +(T left, T right) => new T(left.Value + right.Value); - public static T operator -(T left, T right) => new T(left.Value - right.Value); + 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); + 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) + public static T operator |(T left, T right) { var d = Max(Abs(left.Value), Abs(right.Value)); - if (d != 0m) + if (d == 0m) return new T(0m); var relativeError = Abs(left.Value - right.Value) / d; diff --git a/csharp/Lib/Units/Units.cs b/csharp/Lib/Units/Units.cs index de1b246ad..98bc153e8 100644 --- a/csharp/Lib/Units/Units.cs +++ b/csharp/Lib/Units/Units.cs @@ -5,6 +5,8 @@ namespace InnovEnergy.Lib.Units; public static class Units { + public const Decimal MaxRelativeError = 0.05m; // 5% + public static Current A (this Decimal value) => new Current(value); public static Voltage V (this Decimal value) => new Voltage(value); public static Power W (this Decimal value) => new Power(value); diff --git a/csharp/Lib/Units/Voltage.generated.cs b/csharp/Lib/Units/Voltage.generated.cs index 07dc88d06..cdb63dcda 100644 --- a/csharp/Lib/Units/Voltage.generated.cs +++ b/csharp/Lib/Units/Voltage.generated.cs @@ -18,25 +18,24 @@ public readonly partial struct Voltage 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); - // addition + // parallel #if Sum - public static T operator +(T left, T right) => new T(left.Value + right.Value); - public static T operator -(T left, T right) => new T(left.Value - right.Value); + 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); + 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) + public static T operator |(T left, T right) { var d = Max(Abs(left.Value), Abs(right.Value)); - if (d != 0m) + if (d == 0m) return new T(0m); var relativeError = Abs(left.Value - right.Value) / d; From f1003c2877460cda807532b830031c6de4f462fb Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 08:07:26 +0100 Subject: [PATCH 04/41] implement | (parallel) operator in StatusApi.csproj --- csharp/InnovEnergy.sln.DotSettings | 1 + csharp/Lib/StatusApi/BatteryStatus.cs | 9 ++++++++- csharp/Lib/StatusApi/BatteryStatus.generated.cs | 16 ++++++++++++++++ .../Lib/StatusApi/Connections/IAc3Connection.cs | 2 +- csharp/Lib/StatusApi/DcDcConverterStatus.cs | 8 +++++++- .../StatusApi/DcDcConverterStatus.generated.cs | 16 ++++++++++++++++ .../StatusApi/Generator/OpParallelAttribute.cs | 5 +++++ csharp/Lib/StatusApi/Generator/Template.txt | 16 ++++++++++++++++ csharp/Lib/StatusApi/Generator/generate.sh | 13 +++++++++++++ csharp/Lib/StatusApi/MpptStatus.cs | 8 +++++++- csharp/Lib/StatusApi/MpptStatus.generated.cs | 16 ++++++++++++++++ csharp/Lib/StatusApi/PowerMeterStatus.cs | 7 ++++++- .../Lib/StatusApi/PowerMeterStatus.generated.cs | 16 ++++++++++++++++ .../Lib/StatusApi/SinglePhaseInverterStatus.cs | 10 ++++++++-- .../SinglePhaseInverterStatus.generated.cs | 16 ++++++++++++++++ .../Lib/StatusApi/SinglePhasePvInverterStatus.cs | 10 ++++++++-- .../SinglePhasePvInverterStatus.generated.cs | 16 ++++++++++++++++ csharp/Lib/StatusApi/StatusApi.csproj | 6 +++++- csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs | 10 ++++++++-- .../ThreePhaseInverterStatus.generated.cs | 16 ++++++++++++++++ .../Lib/StatusApi/ThreePhasePvInverterStatus.cs | 10 ++++++++-- .../ThreePhasePvInverterStatus.generated.cs | 16 ++++++++++++++++ csharp/Lib/StatusApi/Utils.cs | 11 ----------- 23 files changed, 229 insertions(+), 25 deletions(-) create mode 100644 csharp/Lib/StatusApi/BatteryStatus.generated.cs create mode 100644 csharp/Lib/StatusApi/DcDcConverterStatus.generated.cs create mode 100644 csharp/Lib/StatusApi/Generator/OpParallelAttribute.cs create mode 100644 csharp/Lib/StatusApi/Generator/Template.txt create mode 100755 csharp/Lib/StatusApi/Generator/generate.sh create mode 100644 csharp/Lib/StatusApi/MpptStatus.generated.cs create mode 100644 csharp/Lib/StatusApi/PowerMeterStatus.generated.cs create mode 100644 csharp/Lib/StatusApi/SinglePhaseInverterStatus.generated.cs create mode 100644 csharp/Lib/StatusApi/SinglePhasePvInverterStatus.generated.cs create mode 100644 csharp/Lib/StatusApi/ThreePhaseInverterStatus.generated.cs create mode 100644 csharp/Lib/StatusApi/ThreePhasePvInverterStatus.generated.cs delete mode 100644 csharp/Lib/StatusApi/Utils.cs diff --git a/csharp/InnovEnergy.sln.DotSettings b/csharp/InnovEnergy.sln.DotSettings index f48e450b2..0584ce254 100644 --- a/csharp/InnovEnergy.sln.DotSettings +++ b/csharp/InnovEnergy.sln.DotSettings @@ -4,6 +4,7 @@ False True + True True True True diff --git a/csharp/Lib/StatusApi/BatteryStatus.cs b/csharp/Lib/StatusApi/BatteryStatus.cs index 0b033b420..2e241e5a9 100644 --- a/csharp/Lib/StatusApi/BatteryStatus.cs +++ b/csharp/Lib/StatusApi/BatteryStatus.cs @@ -1,7 +1,14 @@ using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -public abstract record BatteryStatus(DcPhase Dc) : DeviceStatus, IDcConnection; +using T = BatteryStatus; + +[OpParallel] +public partial record BatteryStatus : DeviceStatus, IDcConnection +{ + public required DcPhase Dc { get; init; } +} \ No newline at end of file diff --git a/csharp/Lib/StatusApi/BatteryStatus.generated.cs b/csharp/Lib/StatusApi/BatteryStatus.generated.cs new file mode 100644 index 000000000..d5f549056 --- /dev/null +++ b/csharp/Lib/StatusApi/BatteryStatus.generated.cs @@ -0,0 +1,16 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +using System.CodeDom.Compiler; +using InnovEnergy.Lib.Units.Composite; +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.StatusApi; + +using T = BatteryStatus; + +[GeneratedCode("generate.sh", "1")] +public partial record BatteryStatus +{ + private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); + public static T operator |(T left, T right) => OpParallel(left, right); +} + \ No newline at end of file diff --git a/csharp/Lib/StatusApi/Connections/IAc3Connection.cs b/csharp/Lib/StatusApi/Connections/IAc3Connection.cs index 231982cf0..b95939124 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 { - Ac1Phase Ac3 { get; } + Ac3Phase Ac { get; } } \ No newline at end of file diff --git a/csharp/Lib/StatusApi/DcDcConverterStatus.cs b/csharp/Lib/StatusApi/DcDcConverterStatus.cs index cdda395d9..a7d931065 100644 --- a/csharp/Lib/StatusApi/DcDcConverterStatus.cs +++ b/csharp/Lib/StatusApi/DcDcConverterStatus.cs @@ -1,8 +1,14 @@ +using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -public abstract record DcDcConverterStatus(DcPhase Left, DcPhase Right) : DeviceStatus; +[OpParallel] +public partial record DcDcConverterStatus : DeviceStatus +{ + public required DcPhase Left { get; init; } + public required DcPhase Right { get; init; } +} \ No newline at end of file diff --git a/csharp/Lib/StatusApi/DcDcConverterStatus.generated.cs b/csharp/Lib/StatusApi/DcDcConverterStatus.generated.cs new file mode 100644 index 000000000..32a133a8a --- /dev/null +++ b/csharp/Lib/StatusApi/DcDcConverterStatus.generated.cs @@ -0,0 +1,16 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +using System.CodeDom.Compiler; +using InnovEnergy.Lib.Units.Composite; +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.StatusApi; + +using T = DcDcConverterStatus; + +[GeneratedCode("generate.sh", "1")] +public partial record DcDcConverterStatus +{ + private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); + public static T operator |(T left, T right) => OpParallel(left, right); +} + \ No newline at end of file diff --git a/csharp/Lib/StatusApi/Generator/OpParallelAttribute.cs b/csharp/Lib/StatusApi/Generator/OpParallelAttribute.cs new file mode 100644 index 000000000..ec94f9d34 --- /dev/null +++ b/csharp/Lib/StatusApi/Generator/OpParallelAttribute.cs @@ -0,0 +1,5 @@ +namespace InnovEnergy.Lib.StatusApi.Generator; + +[AttributeUsage(AttributeTargets.Class)] +internal class OpParallelAttribute : Attribute +{} \ No newline at end of file diff --git a/csharp/Lib/StatusApi/Generator/Template.txt b/csharp/Lib/StatusApi/Generator/Template.txt new file mode 100644 index 000000000..43f22557f --- /dev/null +++ b/csharp/Lib/StatusApi/Generator/Template.txt @@ -0,0 +1,16 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +using System.CodeDom.Compiler; +using InnovEnergy.Lib.Units.Composite; +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.StatusApi; + +using T = Template; + +[GeneratedCode("generate.sh", "1")] +public partial record Template +{ + private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); + public static T operator |(T left, T right) => OpParallel(left, right); +} + \ No newline at end of file diff --git a/csharp/Lib/StatusApi/Generator/generate.sh b/csharp/Lib/StatusApi/Generator/generate.sh new file mode 100755 index 000000000..1233bd1b7 --- /dev/null +++ b/csharp/Lib/StatusApi/Generator/generate.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + + +scriptDir=$( dirname -- "$0"; ) +cd "$scriptDir/.." || exit + +for path in $(grep -e '\[OpParallel\]' -l *.cs) +do + file=$(basename -- "$path") + class="${file%.*}" + echo "generating $file" + sed "s/Template/$class/g" "./Generator/Template.txt" > "./$class.generated.cs" +done \ No newline at end of file diff --git a/csharp/Lib/StatusApi/MpptStatus.cs b/csharp/Lib/StatusApi/MpptStatus.cs index bec31ddec..6514ad5f0 100644 --- a/csharp/Lib/StatusApi/MpptStatus.cs +++ b/csharp/Lib/StatusApi/MpptStatus.cs @@ -1,8 +1,14 @@ using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -public record MpptStatus(DcPhase Dc, IReadOnlyList Strings) : IDcConnection, IPvConnection; +[OpParallel] +public partial record MpptStatus : IDcConnection, IPvConnection +{ + public required DcPhase Dc { get; init; } + public required IReadOnlyList Strings { get; init; } +} \ No newline at end of file diff --git a/csharp/Lib/StatusApi/MpptStatus.generated.cs b/csharp/Lib/StatusApi/MpptStatus.generated.cs new file mode 100644 index 000000000..5e2afe796 --- /dev/null +++ b/csharp/Lib/StatusApi/MpptStatus.generated.cs @@ -0,0 +1,16 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +using System.CodeDom.Compiler; +using InnovEnergy.Lib.Units.Composite; +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.StatusApi; + +using T = MpptStatus; + +[GeneratedCode("generate.sh", "1")] +public partial record MpptStatus +{ + private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); + public static T operator |(T left, T right) => OpParallel(left, right); +} + \ No newline at end of file diff --git a/csharp/Lib/StatusApi/PowerMeterStatus.cs b/csharp/Lib/StatusApi/PowerMeterStatus.cs index 41038f4dc..d02a2ea72 100644 --- a/csharp/Lib/StatusApi/PowerMeterStatus.cs +++ b/csharp/Lib/StatusApi/PowerMeterStatus.cs @@ -1,6 +1,11 @@ using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -public abstract record PowerMeterStatus(Ac1Phase Ac3) : DeviceStatus, IAc3Connection; \ No newline at end of file +[OpParallel] +public partial record PowerMeterStatus : DeviceStatus, IAc3Connection +{ + public required Ac3Phase Ac { get; init; } +} \ No newline at end of file diff --git a/csharp/Lib/StatusApi/PowerMeterStatus.generated.cs b/csharp/Lib/StatusApi/PowerMeterStatus.generated.cs new file mode 100644 index 000000000..9e6dcaf9c --- /dev/null +++ b/csharp/Lib/StatusApi/PowerMeterStatus.generated.cs @@ -0,0 +1,16 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +using System.CodeDom.Compiler; +using InnovEnergy.Lib.Units.Composite; +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.StatusApi; + +using T = PowerMeterStatus; + +[GeneratedCode("generate.sh", "1")] +public partial record PowerMeterStatus +{ + private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); + public static T operator |(T left, T right) => OpParallel(left, right); +} + \ No newline at end of file diff --git a/csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs b/csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs index 9e1e2c8ba..efd9e7f5c 100644 --- a/csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs +++ b/csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs @@ -1,9 +1,15 @@ using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -public abstract record SinglePhaseInverterStatus(Ac1Phase Ac, DcPhase Dc) : +[OpParallel] +public partial record SinglePhaseInverterStatus : DeviceStatus, IAc1Connection, - IDcConnection; + IDcConnection +{ + public required Ac1Phase Ac { get; init; } + public required DcPhase Dc { get; init; } +} diff --git a/csharp/Lib/StatusApi/SinglePhaseInverterStatus.generated.cs b/csharp/Lib/StatusApi/SinglePhaseInverterStatus.generated.cs new file mode 100644 index 000000000..047f609fc --- /dev/null +++ b/csharp/Lib/StatusApi/SinglePhaseInverterStatus.generated.cs @@ -0,0 +1,16 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +using System.CodeDom.Compiler; +using InnovEnergy.Lib.Units.Composite; +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.StatusApi; + +using T = SinglePhaseInverterStatus; + +[GeneratedCode("generate.sh", "1")] +public partial record SinglePhaseInverterStatus +{ + private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); + public static T operator |(T left, T right) => OpParallel(left, right); +} + \ No newline at end of file diff --git a/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs b/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs index 51c113fce..3fc2db56a 100644 --- a/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs +++ b/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs @@ -1,9 +1,15 @@ using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -public abstract record SinglePhasePvInverterStatus(Ac1Phase Ac, IReadOnlyList Strings) : +[OpParallel] +public partial record SinglePhasePvInverterStatus : DeviceStatus, IAc1Connection, - IPvConnection; + IPvConnection +{ + public required Ac1Phase Ac { get; init; } + public required IReadOnlyList Strings { get; init; } +} diff --git a/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.generated.cs b/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.generated.cs new file mode 100644 index 000000000..37340f111 --- /dev/null +++ b/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.generated.cs @@ -0,0 +1,16 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +using System.CodeDom.Compiler; +using InnovEnergy.Lib.Units.Composite; +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.StatusApi; + +using T = SinglePhasePvInverterStatus; + +[GeneratedCode("generate.sh", "1")] +public partial record SinglePhasePvInverterStatus +{ + private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); + public static T operator |(T left, T right) => OpParallel(left, right); +} + \ No newline at end of file diff --git a/csharp/Lib/StatusApi/StatusApi.csproj b/csharp/Lib/StatusApi/StatusApi.csproj index 88fda982e..d14ca02c9 100644 --- a/csharp/Lib/StatusApi/StatusApi.csproj +++ b/csharp/Lib/StatusApi/StatusApi.csproj @@ -3,9 +3,13 @@ - + + + + + diff --git a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs index 8c2fc424f..306430190 100644 --- a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs +++ b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs @@ -1,10 +1,16 @@ using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -public abstract record ThreePhaseInverterStatus(Ac1Phase Ac3, DcPhase Dc) : +[OpParallel] +public partial record ThreePhaseInverterStatus : DeviceStatus, IAc3Connection, - IDcConnection; + IDcConnection +{ + public required Ac3Phase Ac { get; init; } + public required DcPhase Dc { get; init; } +} \ No newline at end of file diff --git a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.generated.cs b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.generated.cs new file mode 100644 index 000000000..989941505 --- /dev/null +++ b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.generated.cs @@ -0,0 +1,16 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +using System.CodeDom.Compiler; +using InnovEnergy.Lib.Units.Composite; +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.StatusApi; + +using T = ThreePhaseInverterStatus; + +[GeneratedCode("generate.sh", "1")] +public partial record ThreePhaseInverterStatus +{ + private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); + public static T operator |(T left, T right) => OpParallel(left, right); +} + \ No newline at end of file diff --git a/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs b/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs index c09471d4b..b5a7686da 100644 --- a/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs +++ b/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs @@ -1,9 +1,15 @@ using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -public abstract record ThreePhasePvInverterStatus(Ac1Phase Ac3, IReadOnlyList Strings) : +[OpParallel] +public partial record ThreePhasePvInverterStatus : DeviceStatus, IAc3Connection, - IPvConnection; + IPvConnection +{ + public required Ac3Phase Ac { get; init; } + public required IReadOnlyList Strings { get; init; } +} diff --git a/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.generated.cs b/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.generated.cs new file mode 100644 index 000000000..4e7170a21 --- /dev/null +++ b/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.generated.cs @@ -0,0 +1,16 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +using System.CodeDom.Compiler; +using InnovEnergy.Lib.Units.Composite; +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.StatusApi; + +using T = ThreePhasePvInverterStatus; + +[GeneratedCode("generate.sh", "1")] +public partial record ThreePhasePvInverterStatus +{ + private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); + public static T operator |(T left, T right) => OpParallel(left, right); +} + \ No newline at end of file diff --git a/csharp/Lib/StatusApi/Utils.cs b/csharp/Lib/StatusApi/Utils.cs deleted file mode 100644 index b86db8478..000000000 --- a/csharp/Lib/StatusApi/Utils.cs +++ /dev/null @@ -1,11 +0,0 @@ -using InnovEnergy.Lib.Utils; - -namespace InnovEnergy.Lib.StatusApi; - -public static class Utils -{ - public static Decimal Round3(this Decimal d) - { - return d.RoundToSignificantFigures(3); - } -} \ No newline at end of file From 9bf23f3ec822bf0246c06ef85580dbde41a3b8e8 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 08:14:08 +0100 Subject: [PATCH 05/41] add Percent % to Units --- csharp/Lib/Units/Percent.cs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 csharp/Lib/Units/Percent.cs diff --git a/csharp/Lib/Units/Percent.cs b/csharp/Lib/Units/Percent.cs new file mode 100644 index 000000000..02bf1a146 --- /dev/null +++ b/csharp/Lib/Units/Percent.cs @@ -0,0 +1,29 @@ +namespace InnovEnergy.Lib.Units; + +using T = Percent; + +public readonly struct Percent +{ + public static String Unit => "%"; + public static String Symbol => "%"; // ?? + + public Percent(Decimal value) + { + if (value < 0) + throw new ArgumentException(nameof(Frequency) + " cannot be negative", nameof(value)); + + Value = value; + } + + // not generated + + public Decimal Value { get; } + public override String ToString() => Value + Unit; + + // scalar multiplication + public static Decimal operator *(Decimal scalar, T t) => scalar * t.Value/100m; + public static Decimal operator *(T t, Decimal scalar) => scalar * t.Value/100m; + + // parallel + public static Percent operator |(T left, T right) => new T((left.Value + right.Value)/2m); +} \ No newline at end of file From f6f4326afa1dbb6cd4f20e08268a5a263bf3f81d Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 08:14:32 +0100 Subject: [PATCH 06/41] update BatteryStatus to include SOC and Temperature --- csharp/Lib/StatusApi/BatteryStatus.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/csharp/Lib/StatusApi/BatteryStatus.cs b/csharp/Lib/StatusApi/BatteryStatus.cs index 2e241e5a9..fc8961fd1 100644 --- a/csharp/Lib/StatusApi/BatteryStatus.cs +++ b/csharp/Lib/StatusApi/BatteryStatus.cs @@ -1,5 +1,6 @@ using InnovEnergy.Lib.StatusApi.Connections; using InnovEnergy.Lib.StatusApi.Generator; +using InnovEnergy.Lib.Units; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; @@ -9,6 +10,8 @@ using T = BatteryStatus; [OpParallel] public partial record BatteryStatus : DeviceStatus, IDcConnection { - public required DcPhase Dc { get; init; } + public required DcPhase Dc { get; init; } + public required Percent Soc { get; init; } + public required Temperature Temperature { get; init; } } \ No newline at end of file From 08c747f2ea3fbd118800eacee4ffd31144ff5320 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 08:25:23 +0100 Subject: [PATCH 07/41] implement ToString for State --- csharp/Lib/Units/Percent.cs | 16 +++++----------- csharp/Lib/Units/State.cs | 10 +++++++++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/csharp/Lib/Units/Percent.cs b/csharp/Lib/Units/Percent.cs index 02bf1a146..a358c438f 100644 --- a/csharp/Lib/Units/Percent.cs +++ b/csharp/Lib/Units/Percent.cs @@ -7,23 +7,17 @@ public readonly struct Percent public static String Unit => "%"; public static String Symbol => "%"; // ?? - public Percent(Decimal value) - { - if (value < 0) - throw new ArgumentException(nameof(Frequency) + " cannot be negative", nameof(value)); - - Value = value; - } - + public Percent(Decimal value) => Value = value; + // not generated public Decimal Value { get; } public override String ToString() => Value + Unit; // scalar multiplication - public static Decimal operator *(Decimal scalar, T t) => scalar * t.Value/100m; - public static Decimal operator *(T t, Decimal scalar) => scalar * t.Value/100m; + public static Decimal operator *(Decimal scalar, T t) => scalar * t.Value / 100m; + public static Decimal operator *(T t, Decimal scalar) => scalar * t.Value / 100m; // parallel - public static Percent operator |(T left, T right) => new T((left.Value + right.Value)/2m); + public static Percent operator |(T left, T right) => new T((left.Value + right.Value) / 2m); } \ No newline at end of file diff --git a/csharp/Lib/Units/State.cs b/csharp/Lib/Units/State.cs index af96735e0..bdd76d470 100644 --- a/csharp/Lib/Units/State.cs +++ b/csharp/Lib/Units/State.cs @@ -4,7 +4,13 @@ public readonly struct State { public IReadOnlyList Values { get; } - public State(IReadOnlyList values) => Values = values; + public State(IReadOnlyList values) + { + if (values.Any(v => v.Contains(";"))) + throw new ArgumentException("State values cannot contain the character ;", nameof(values)); + + Values = values; + } public State(params String[] values) : this((IReadOnlyList)values){} public State(params State[] states) : this(states.SelectMany(s => s.Values).ToList()){} @@ -15,4 +21,6 @@ public readonly struct State public static implicit operator State(String s) => new State(s); public static State operator |(State left, State right) => new State(left, right); + + public override String ToString() => String.Join("; ", Values); } \ No newline at end of file From d91a4654cda33a0151fb6b716a8c571d764d1d12 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 08:29:36 +0100 Subject: [PATCH 08/41] add implicit op for booleans on State --- csharp/Lib/Units/State.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/csharp/Lib/Units/State.cs b/csharp/Lib/Units/State.cs index bdd76d470..ecabbd034 100644 --- a/csharp/Lib/Units/State.cs +++ b/csharp/Lib/Units/State.cs @@ -14,11 +14,10 @@ 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(Enum e) : this(e.ToString()){} - public static implicit operator State(Enum e) => new State(e); - public static implicit operator State(String s) => new State(s); + 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 State operator |(State left, State right) => new State(left, right); From d2e4f93fd14150c7076b782847eb517bb8ea215a Mon Sep 17 00:00:00 2001 From: Sina Blattmann Date: Wed, 1 Mar 2023 09:41:49 +0100 Subject: [PATCH 09/41] fix replace, so it works on windows as well --- csharp/InnovEnergy.props | 2 +- csharp/Lib/Utils/Utils.csproj | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/csharp/InnovEnergy.props b/csharp/InnovEnergy.props index 5a4943931..7315812ef 100644 --- a/csharp/InnovEnergy.props +++ b/csharp/InnovEnergy.props @@ -9,7 +9,7 @@ net6.0 true false - $(Company).$(MSBuildProjectDirectory.Replace($(SolutionDir), "").Replace("src/", "").Replace("/",".")) + $(Company).$(MSBuildProjectDirectory.Replace($(SolutionDir), "").Replace("src/", "").Replace("/",".").Replace("\",".")) $(Company) Team diff --git a/csharp/Lib/Utils/Utils.csproj b/csharp/Lib/Utils/Utils.csproj index 59af027d7..3ace16dcb 100644 --- a/csharp/Lib/Utils/Utils.csproj +++ b/csharp/Lib/Utils/Utils.csproj @@ -1,10 +1,6 @@ - - - - From 4cb8e9ecfa85069a6046ccc9bd469c78a7b4d686 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 10:38:46 +0100 Subject: [PATCH 10/41] add more operators to Percent --- csharp/Lib/Units/Percent.cs | 20 ++++++++++++++++++++ csharp/Lib/Units/State.cs | 3 ++- 2 files changed, 22 insertions(+), 1 deletion(-) 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/State.cs b/csharp/Lib/Units/State.cs index ecabbd034..3060186de 100644 --- a/csharp/Lib/Units/State.cs +++ b/csharp/Lib/Units/State.cs @@ -13,11 +13,12 @@ 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(List s) => new State((IReadOnlyList)s); public static State operator |(State left, State right) => new State(left, right); From f5ff1d70a5f78097faf106d316d59a4502678608 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 10:40:25 +0100 Subject: [PATCH 11/41] remove 'require' again (sigh). It only *seems* to build, but doesnt. we need net7.0 --- csharp/Lib/StatusApi/BatteryStatus.cs | 6 +++--- csharp/Lib/StatusApi/DcDcConverterStatus.cs | 4 ++-- csharp/Lib/StatusApi/MpptStatus.cs | 4 ++-- csharp/Lib/StatusApi/PowerMeterStatus.cs | 2 +- csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs | 4 ++-- csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs | 4 ++-- csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs | 4 ++-- csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs | 4 ++-- csharp/Lib/Units/Composite/Ac1Phase.cs | 4 +--- csharp/Lib/Units/Composite/Ac3Phase.cs | 10 ++++------ csharp/Lib/Units/Composite/AcPhase.cs | 10 +++++----- csharp/Lib/Units/Composite/DcPhase.cs | 6 ++---- 12 files changed, 28 insertions(+), 34 deletions(-) diff --git a/csharp/Lib/StatusApi/BatteryStatus.cs b/csharp/Lib/StatusApi/BatteryStatus.cs index fc8961fd1..0f1fedc46 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 DcPhase 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/DcDcConverterStatus.cs b/csharp/Lib/StatusApi/DcDcConverterStatus.cs index a7d931065..de33033d2 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 DcPhase Left { get; init; } + public DcPhase Right { get; init; } } diff --git a/csharp/Lib/StatusApi/MpptStatus.cs b/csharp/Lib/StatusApi/MpptStatus.cs index 6514ad5f0..99d4df09b 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 DcPhase 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..26552861e 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 Ac3Phase 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..caaec0d94 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 Ac1Phase Ac { get; init; } + public DcPhase Dc { get; init; } } diff --git a/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs b/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs index 3fc2db56a..d6d885a78 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 Ac1Phase Ac { get; init; } + public IReadOnlyList Strings { get; init; } } diff --git a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs index 306430190..e9fe03d3c 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 Ac3Phase Ac { get; init; } + public DcPhase 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..c2fb05d30 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 Ac3Phase Ac { get; init; } + public IReadOnlyList Strings { get; init; } } diff --git a/csharp/Lib/Units/Composite/Ac1Phase.cs b/csharp/Lib/Units/Composite/Ac1Phase.cs index d7cfc20e7..40ddd54b0 100644 --- a/csharp/Lib/Units/Composite/Ac1Phase.cs +++ b/csharp/Lib/Units/Composite/Ac1Phase.cs @@ -1,11 +1,10 @@ - using System.Diagnostics.CodeAnalysis; namespace InnovEnergy.Lib.Units.Composite; public record Ac1Phase : AcPhase { - public required Frequency Frequency { get; init; } + public Frequency Frequency { get; init; } [SuppressMessage("ReSharper", "RedundantCast")] public static Ac1Phase operator |(Ac1Phase left, Ac1Phase right) @@ -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/Ac3Phase.cs index d73f8e9e4..a80f89ba0 100644 --- a/csharp/Lib/Units/Composite/Ac3Phase.cs +++ b/csharp/Lib/Units/Composite/Ac3Phase.cs @@ -5,10 +5,10 @@ namespace InnovEnergy.Lib.Units.Composite; public record Ac3Phase { - 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; @@ -17,6 +17,4 @@ public record Ac3Phase public static Ac3Phase operator |(Ac3Phase left, Ac3Phase 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..de526650d 100644 --- a/csharp/Lib/Units/Composite/AcPhase.cs +++ b/csharp/Lib/Units/Composite/AcPhase.cs @@ -6,20 +6,20 @@ namespace InnovEnergy.Lib.Units.Composite; public record AcPhase : IPhase { 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; diff --git a/csharp/Lib/Units/Composite/DcPhase.cs b/csharp/Lib/Units/Composite/DcPhase.cs index 2d0b24b68..919589b6a 100644 --- a/csharp/Lib/Units/Composite/DcPhase.cs +++ b/csharp/Lib/Units/Composite/DcPhase.cs @@ -4,13 +4,11 @@ namespace InnovEnergy.Lib.Units.Composite; public record DcPhase : IPhase { - public required Voltage Voltage { get; init;} - public required Current Current { get; init;} + public Voltage Voltage { get; init; } + public 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 From 4bf9deffac921dac6a8dab9c357869379aa4c1d1 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 10:41:13 +0100 Subject: [PATCH 12/41] lift Battery48TL to new StatusApi --- .../Devices/Battery48TL/Battery48TLDevice.cs | 103 +------ .../Battery48TL/Battery48TLStatusRecord.cs | 71 +++-- .../Devices/Battery48TL/BatteryDataParser.cs | 167 ----------- .../Lib/Devices/Battery48TL/ModbusParser.cs | 272 ++++++++++++++++++ 4 files changed, 316 insertions(+), 297 deletions(-) delete mode 100644 csharp/Lib/Devices/Battery48TL/BatteryDataParser.cs create mode 100644 csharp/Lib/Devices/Battery48TL/ModbusParser.cs 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..79bc1c7df 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 required Voltage CellsVoltage { get; init; } + + public required Power MaxChargingPower { get; init; } + public required Power MaxDischargingPower { get; init; } + + public required State GreenLed { get; init; } + public required State AmberLed { get; init; } + public required State BlueLed { get; init; } + public required State RedLed { get; init; } + + public required State Warnings { get; init; } + public required State Alarms { get; init; } + + public required State MainSwitchState { get; init; } // connected to bus | disconnected from bus + public required State HeaterState { get; init; } // heating | not heating + public required State EocState { get; init; } // EOC reached | EOC not reached + public required 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..dbc15a3e4 --- /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 DcPhase 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 From b983614cfc4ebb50dbd3a219697ba49955205e28 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 10:52:21 +0100 Subject: [PATCH 13/41] Phase => Bus --- .../Lib/Units/Composite/{Ac1Phase.cs => Ac1Bus.cs} | 6 +++--- .../Lib/Units/Composite/{Ac3Phase.cs => Ac3Bus.cs} | 6 +++--- csharp/Lib/Units/Composite/AcPhase.cs | 2 +- csharp/Lib/Units/Composite/DcBus.cs | 14 ++++++++++++++ csharp/Lib/Units/Composite/DcPhase.cs | 14 -------------- csharp/Lib/Units/Composite/{IPhase.cs => IBus.cs} | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) rename csharp/Lib/Units/Composite/{Ac1Phase.cs => Ac1Bus.cs} (77%) rename csharp/Lib/Units/Composite/{Ac3Phase.cs => Ac3Bus.cs} (74%) create mode 100644 csharp/Lib/Units/Composite/DcBus.cs delete mode 100644 csharp/Lib/Units/Composite/DcPhase.cs rename csharp/Lib/Units/Composite/{IPhase.cs => IBus.cs} (89%) diff --git a/csharp/Lib/Units/Composite/Ac1Phase.cs b/csharp/Lib/Units/Composite/Ac1Bus.cs similarity index 77% rename from csharp/Lib/Units/Composite/Ac1Phase.cs rename to csharp/Lib/Units/Composite/Ac1Bus.cs index 40ddd54b0..f2c769f24 100644 --- a/csharp/Lib/Units/Composite/Ac1Phase.cs +++ b/csharp/Lib/Units/Composite/Ac1Bus.cs @@ -2,17 +2,17 @@ using System.Diagnostics.CodeAnalysis; namespace InnovEnergy.Lib.Units.Composite; -public record Ac1Phase : AcPhase +public record Ac1Bus : AcPhase { 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, diff --git a/csharp/Lib/Units/Composite/Ac3Phase.cs b/csharp/Lib/Units/Composite/Ac3Bus.cs similarity index 74% rename from csharp/Lib/Units/Composite/Ac3Phase.cs rename to csharp/Lib/Units/Composite/Ac3Bus.cs index a80f89ba0..e35c73cfc 100644 --- a/csharp/Lib/Units/Composite/Ac3Phase.cs +++ b/csharp/Lib/Units/Composite/Ac3Bus.cs @@ -3,7 +3,7 @@ using static DecimalMath.DecimalEx; namespace InnovEnergy.Lib.Units.Composite; -public record Ac3Phase +public record Ac3Bus { public AcPhase L1 { get; init; } public AcPhase L2 { get; init; } @@ -15,6 +15,6 @@ public record Ac3Phase 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 de526650d..faa20f23d 100644 --- a/csharp/Lib/Units/Composite/AcPhase.cs +++ b/csharp/Lib/Units/Composite/AcPhase.cs @@ -3,7 +3,7 @@ using static DecimalMath.DecimalEx; namespace InnovEnergy.Lib.Units.Composite; -public record AcPhase : IPhase +public record AcPhase : IBus { private readonly Voltage _Voltage; public Voltage Voltage 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 919589b6a..000000000 --- a/csharp/Lib/Units/Composite/DcPhase.cs +++ /dev/null @@ -1,14 +0,0 @@ -using InnovEnergy.Lib.Utils; - -namespace InnovEnergy.Lib.Units.Composite; - -public record DcPhase : IPhase -{ - public Voltage Voltage { get; init; } - public 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; } From fac1a090bfb06edfc454a3fac05cbfb9d2adf7a6 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 10:52:54 +0100 Subject: [PATCH 14/41] Phase => Bus --- csharp/Lib/StatusApi/BatteryStatus.cs | 2 +- csharp/Lib/StatusApi/Connections/IAc1Connection.cs | 2 +- csharp/Lib/StatusApi/Connections/IAc3Connection.cs | 2 +- csharp/Lib/StatusApi/Connections/IDcConnection.cs | 2 +- csharp/Lib/StatusApi/Connections/IPvConnection.cs | 2 +- csharp/Lib/StatusApi/DcDcConverterStatus.cs | 4 ++-- csharp/Lib/StatusApi/MpptStatus.cs | 4 ++-- csharp/Lib/StatusApi/PowerMeterStatus.cs | 2 +- csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs | 4 ++-- csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs | 4 ++-- csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs | 4 ++-- csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs | 4 ++-- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/csharp/Lib/StatusApi/BatteryStatus.cs b/csharp/Lib/StatusApi/BatteryStatus.cs index 0f1fedc46..6c656b1c9 100644 --- a/csharp/Lib/StatusApi/BatteryStatus.cs +++ b/csharp/Lib/StatusApi/BatteryStatus.cs @@ -10,7 +10,7 @@ using T = BatteryStatus; [OpParallel] public partial record BatteryStatus : DeviceStatus, IDcConnection { - public DcPhase Dc { get; init; } + public DcBus Dc { get; init; } public Percent Soc { get; init; } public Temperature Temperature { get; init; } } 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 de33033d2..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 DcPhase Left { get; init; } - public DcPhase Right { get; init; } + public DcBus Left { get; init; } + public DcBus Right { get; init; } } diff --git a/csharp/Lib/StatusApi/MpptStatus.cs b/csharp/Lib/StatusApi/MpptStatus.cs index 99d4df09b..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 DcPhase Dc { get; init; } - public 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 26552861e..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 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 caaec0d94..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 Ac1Phase Ac { get; init; } - public 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 d6d885a78..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 Ac1Phase Ac { get; init; } - public IReadOnlyList Strings { get; init; } + public Ac1Bus Ac { get; init; } + public IReadOnlyList Strings { get; init; } } diff --git a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs index e9fe03d3c..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 Ac3Phase Ac { get; init; } - public 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 c2fb05d30..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 Ac3Phase Ac { get; init; } - public IReadOnlyList Strings { get; init; } + public Ac3Bus Ac { get; init; } + public IReadOnlyList Strings { get; init; } } From afe83e943ffd7996ed90adf084be582ae46bbd23 Mon Sep 17 00:00:00 2001 From: ig Date: Wed, 1 Mar 2023 10:53:34 +0100 Subject: [PATCH 15/41] Phase => Bus --- csharp/Lib/Devices/AMPT/AmptDeviceStatus.cs | 4 +- .../Lib/Devices/Battery48TL/ModbusParser.cs | 2 +- csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs | 4 +- csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs | 7 +-- .../Trumpf/TruConvertAc/TruConvertAcDevice.cs | 5 +-- .../Trumpf/TruConvertAc/TruConvertAcStatus.cs | 4 +- .../Trumpf/TruConvertDc/TruConvertDcStatus.cs | 43 +++++++++++-------- 7 files changed, 37 insertions(+), 32 deletions(-) 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/ModbusParser.cs b/csharp/Lib/Devices/Battery48TL/ModbusParser.cs index dbc15a3e4..d16c3dc5d 100644 --- a/csharp/Lib/Devices/Battery48TL/ModbusParser.cs +++ b/csharp/Lib/Devices/Battery48TL/ModbusParser.cs @@ -177,7 +177,7 @@ public static class ModbusParser return Math.Max(pLimit, 0); } - internal static DcPhase ParseDcBus(this ModbusRegisters data) + internal static DcBus ParseDcBus(this ModbusRegisters data) { return new() { diff --git a/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs b/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs index c219755b3..e4a766d30 100644 --- a/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs +++ b/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs @@ -1,7 +1,7 @@ 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; @@ -77,7 +77,7 @@ public class EmuMeterDevice return new EmuMeterStatus ( - Ac: new ThreePhaseAcConnection + Ac: new Ac3Bus ( new AcPhase( voltageL1N, diff --git a/csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs b/csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs index 713a4b2de..3e629c15a 100644 --- a/csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs +++ b/csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs @@ -1,11 +1,12 @@ +using InnovEnergy.Lib.StatusApi; using InnovEnergy.Lib.StatusApi.Connections; -using InnovEnergy.Lib.StatusApi.Devices; +using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.Devices.EmuMeter; public record EmuMeterStatus ( - ThreePhaseAcConnection Ac, + Ac3Bus Ac, Decimal ActivePowerL123, Decimal ReactivePowerL123, Decimal ApparentPowerL123, @@ -21,6 +22,6 @@ public record EmuMeterStatus Decimal EnergyExportL1, Decimal EnergyExportL2, Decimal EnergyExportL3 -):GridMeter(Ac) +):PowerMeterStatus(Ac) {} 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 From 6f48b976218870809b38a4f09b42d10f14cdadf9 Mon Sep 17 00:00:00 2001 From: atef Date: Wed, 1 Mar 2023 13:23:16 +0100 Subject: [PATCH 16/41] fix some minor csproj settings --- csharp/App/RemoteSupportConsole/RemoteSupportConsole.csproj | 3 --- csharp/Lib/Victron/VeDBus/VeDBus.csproj | 5 ----- csharp/Lib/Victron/VictronVRM/VictronVRM.csproj | 5 ----- 3 files changed, 13 deletions(-) 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/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 - - From be5999e0f0b521bbc6fa51de4b95ea136ba23092 Mon Sep 17 00:00:00 2001 From: atef Date: Wed, 1 Mar 2023 13:23:42 +0100 Subject: [PATCH 17/41] remove trailing 'require' --- .../Battery48TL/Battery48TLStatusRecord.cs | 26 +++++++++---------- csharp/Lib/StatusApi/BatteryStatus.cs | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs b/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs index 79bc1c7df..b9feb07d0 100644 --- a/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs +++ b/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs @@ -10,23 +10,23 @@ using T = Battery48TLStatus; [SuppressMessage("ReSharper", "InconsistentNaming")] public record Battery48TLStatus : BatteryStatus { - public required Voltage CellsVoltage { get; init; } + public Voltage CellsVoltage { get; init; } - public required Power MaxChargingPower { get; init; } - public required Power MaxDischargingPower { get; init; } + public Power MaxChargingPower { get; init; } + public Power MaxDischargingPower { get; init; } - public required State GreenLed { get; init; } - public required State AmberLed { get; init; } - public required State BlueLed { get; init; } - public required State RedLed { get; init; } + public State GreenLed { get; init; } + public State AmberLed { get; init; } + public State BlueLed { get; init; } + public State RedLed { get; init; } - public required State Warnings { get; init; } - public required State Alarms { get; init; } + public State Warnings { get; init; } + public State Alarms { get; init; } - public required State MainSwitchState { get; init; } // connected to bus | disconnected from bus - public required State HeaterState { get; init; } // heating | not heating - public required State EocState { get; init; } // EOC reached | EOC not reached - public required State TemperatureState { get; init; } // cold | operating temperature | overheated + 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); diff --git a/csharp/Lib/StatusApi/BatteryStatus.cs b/csharp/Lib/StatusApi/BatteryStatus.cs index 6c656b1c9..f8a0124d5 100644 --- a/csharp/Lib/StatusApi/BatteryStatus.cs +++ b/csharp/Lib/StatusApi/BatteryStatus.cs @@ -10,7 +10,7 @@ using T = BatteryStatus; [OpParallel] public partial record BatteryStatus : DeviceStatus, IDcConnection { - public DcBus Dc { get; init; } + public DcBus Dc { get; init; } public Percent Soc { get; init; } public Temperature Temperature { get; init; } } From 55048b3f99016ab58a974f68203a2afd6703d962 Mon Sep 17 00:00:00 2001 From: atef Date: Wed, 1 Mar 2023 13:35:33 +0100 Subject: [PATCH 18/41] lift EmuMeter to new StatusApi --- csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs | 106 +++++++++++------- csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs | 27 +---- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs b/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs index e4a766d30..ef3ba19ec 100644 --- a/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs +++ b/csharp/Lib/Devices/EmuMeter/EmuMeterDevice.cs @@ -1,3 +1,4 @@ +using DecimalMath; using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.StatusApi.Connections; @@ -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 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 - ); + { + 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 3e629c15a..c1c9eb26e 100644 --- a/csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs +++ b/csharp/Lib/Devices/EmuMeter/EmuMeterStatus.cs @@ -1,27 +1,10 @@ using InnovEnergy.Lib.StatusApi; -using InnovEnergy.Lib.StatusApi.Connections; -using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.Devices.EmuMeter; -public record EmuMeterStatus -( - Ac3Bus 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 -):PowerMeterStatus(Ac) -{} +public record EmuMeterStatus : PowerMeterStatus +{ + // TODO add serial nb, (and other?) +} + From a3ccd2a537aa99bdf38fa4ba20a6842d38978e97 Mon Sep 17 00:00:00 2001 From: atef Date: Thu, 2 Mar 2023 15:14:22 +0100 Subject: [PATCH 19/41] Add more implicit conversions for State --- csharp/Lib/Units/State.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/csharp/Lib/Units/State.cs b/csharp/Lib/Units/State.cs index 3060186de..63b1c6d7c 100644 --- a/csharp/Lib/Units/State.cs +++ b/csharp/Lib/Units/State.cs @@ -15,12 +15,15 @@ public readonly struct State public State(params String[] values) : this((IReadOnlyList)values){} 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(List s) => new State((IReadOnlyList)s); + 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()).ToArray()); + public static implicit operator State(Enum[] es) => new(es.Select(e => e.ToString()).ToArray()); - public static State operator |(State left, State right) => new State(left, right); + public static State operator |(State left, State right) => new(left, right); public override String ToString() => String.Join("; ", Values); } \ No newline at end of file From 8c3caa06d5e82214f11ad3d49de9fe6f181b5449 Mon Sep 17 00:00:00 2001 From: atef Date: Thu, 2 Mar 2023 15:22:00 +0100 Subject: [PATCH 20/41] Introduce number type --- csharp/Lib/Units/Number.cs | 13 +++++ csharp/Lib/Units/Number.generated.cs | 77 ++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 csharp/Lib/Units/Number.cs create mode 100644 csharp/Lib/Units/Number.generated.cs 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..bfe8bcf8e --- /dev/null +++ b/csharp/Lib/Units/Number.generated.cs @@ -0,0 +1,77 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Sum + +using static System.Math; + +namespace InnovEnergy.Lib.Units; + +using T = Number; + +public readonly partial struct Number +{ + public Decimal Value { get; } + public override String ToString() => Value + 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(); + +} From 19188fa4307e550a45fcaf2f54512d132dfcf3cc Mon Sep 17 00:00:00 2001 From: atef Date: Thu, 2 Mar 2023 15:26:27 +0100 Subject: [PATCH 21/41] Implement IReadOnlyList for State --- csharp/Lib/Units/State.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/csharp/Lib/Units/State.cs b/csharp/Lib/Units/State.cs index 63b1c6d7c..90161a9b9 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; } @@ -25,5 +27,11 @@ public readonly struct State 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 From 8ae91198585305c44b9ae61303ef0c9dbcb54ae6 Mon Sep 17 00:00:00 2001 From: ig Date: Thu, 2 Mar 2023 17:15:10 +0100 Subject: [PATCH 22/41] Round Units to 3 significant digits by default (ToString). Add JsonConverters to generator --- csharp/App/SaliMax/src/Utils.cs | 2 +- csharp/Lib/Units/Angle.generated.cs | 21 +++++++++++++- csharp/Lib/Units/ApparentPower.generated.cs | 21 +++++++++++++- csharp/Lib/Units/Current.generated.cs | 21 +++++++++++++- csharp/Lib/Units/Frequency.generated.cs | 21 +++++++++++++- csharp/Lib/Units/Generator/Template.txt | 23 ++++++++++++++-- csharp/Lib/Units/Generator/generate.sh | 2 +- csharp/Lib/Units/Json/CurrentConverter.cs | 17 ------------ csharp/Lib/Units/Json/PowerConverter.cs | 17 ------------ csharp/Lib/Units/Json/ResistanceConverter.cs | 17 ------------ csharp/Lib/Units/Json/VoltageConverter.cs | 17 ------------ csharp/Lib/Units/Number.generated.cs | 21 +++++++++++++- csharp/Lib/Units/Power.cs | 1 - csharp/Lib/Units/Power.generated.cs | 21 +++++++++++++- csharp/Lib/Units/ReactivePower.generated.cs | 21 +++++++++++++- csharp/Lib/Units/Resistance.generated.cs | 21 +++++++++++++- csharp/Lib/Units/State.cs | 4 +-- csharp/Lib/Units/Temperature.generated.cs | 21 +++++++++++++- csharp/Lib/Units/Units.cs | 29 +++++++++++++------- csharp/Lib/Units/Voltage.generated.cs | 21 +++++++++++++- csharp/Lib/Utils/DecimalUtils.cs | 16 +++++++---- csharp/Lib/Utils/EnumerableUtils.cs | 4 +-- 22 files changed, 256 insertions(+), 103 deletions(-) delete mode 100644 csharp/Lib/Units/Json/CurrentConverter.cs delete mode 100644 csharp/Lib/Units/Json/PowerConverter.cs delete mode 100644 csharp/Lib/Units/Json/ResistanceConverter.cs delete mode 100644 csharp/Lib/Units/Json/VoltageConverter.cs 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/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/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