diff --git a/csharp/App/Backend/Controllers/Controller.cs b/csharp/App/Backend/Controller.cs similarity index 100% rename from csharp/App/Backend/Controllers/Controller.cs rename to csharp/App/Backend/Controller.cs diff --git a/csharp/App/Backend/DataTypes/Methods/Session.cs b/csharp/App/Backend/DataTypes/Methods/Session.cs index d3e599ebc..c0e6b3e33 100644 --- a/csharp/App/Backend/DataTypes/Methods/Session.cs +++ b/csharp/App/Backend/DataTypes/Methods/Session.cs @@ -156,11 +156,11 @@ public static class SessionMethods .WithParent(sessionUser) .Do(() => newUser.Password = newUser.SaltAndHashPassword(newUser.Password)) .Do(() => newUser.MustResetPassword = true) - .Apply(Db.Create) - && Mailer.Mailer.SendVerificationMessage(newUser); - + .Apply(Db.Create); + // && Mailer.Mailer.SendVerificationMessage(newUser); + //Send Email to new user to verify email and set password - + } public static Boolean Update(this Session? session, User? editedUser) diff --git a/csharp/App/Backend/DataTypes/Methods/User.cs b/csharp/App/Backend/DataTypes/Methods/User.cs index f20ae6b87..2ce43c2e9 100644 --- a/csharp/App/Backend/DataTypes/Methods/User.cs +++ b/csharp/App/Backend/DataTypes/Methods/User.cs @@ -182,9 +182,9 @@ public static class UserMethods { return other?.Type switch { - "installation" => user.HasAccessTo(Db.GetInstallationById(other.ParentId)), - "user" => user.HasAccessTo(Db.GetUserById(other.ParentId)), - "folder" => user.HasAccessTo(Db.GetFolderById(other.ParentId)), + "Installation" => user.HasAccessTo(Db.GetFolderById(other.ParentId)), + "User" => user.HasAccessTo(Db.GetUserById(other.ParentId)), + "Folder" => user.HasAccessTo(Db.GetFolderById(other.ParentId)), _ => false }; } diff --git a/csharp/App/Backend/Database/Db.cs b/csharp/App/Backend/Database/Db.cs index e9cb827ca..d9d5ae1cd 100644 --- a/csharp/App/Backend/Database/Db.cs +++ b/csharp/App/Backend/Database/Db.cs @@ -16,20 +16,21 @@ public static partial class Db private static SQLiteConnection Connection { get; } = new SQLiteConnection(DbPath); - public static TableQuery Sessions => Connection.Table(); - public static TableQuery Folders => Connection.Table(); - public static TableQuery DeletedFolders => Connection.Table(); - public static TableQuery Installations => Connection.Table(); - public static TableQuery DeletedInstallations => Connection.Table(); - public static TableQuery Users => Connection.Table(); - public static TableQuery DeletedUsers => Connection.Table(); - public static TableQuery FolderAccess => Connection.Table(); - public static TableQuery InstallationAccess => Connection.Table(); - public static TableQuery OrderNumber2Installation => Connection.Table(); - + public static TableQuery Sessions => Connection.Table(); + public static TableQuery Folders => Connection.Table(); + public static TableQuery Installations => Connection.Table(); + public static TableQuery Users => Connection.Table(); + public static TableQuery FolderAccess => Connection.Table(); + public static TableQuery InstallationAccess => Connection.Table(); + public static TableQuery OrderNumber2Installation => Connection.Table(); + + public static TableQuery DeletedInstallations => Connection.Table(); + public static TableQuery DeletedUsers => Connection.Table(); + public static TableQuery DeletedFolders => Connection.Table(); public static void Init() { + // used to force static constructor } @@ -54,6 +55,7 @@ public static partial class Db Observable.Interval(TimeSpan.FromDays(0.5)) .StartWith(0) // Do it right away (on startup) .ObserveOn(TaskPoolScheduler.Default) + .SubscribeOn(TaskPoolScheduler.Default) .SelectMany(Cleanup) .Subscribe(); } diff --git a/csharp/App/OpenVpnCertificatesServer/newToken.sh b/csharp/App/OpenVpnCertificatesServer/newToken.sh index 22f34698f..37984f65a 100755 --- a/csharp/App/OpenVpnCertificatesServer/newToken.sh +++ b/csharp/App/OpenVpnCertificatesServer/newToken.sh @@ -1,4 +1,5 @@ #!/bin/bash +## create a new VRM access token ## USAGE: ./newToken.sh -u Username -p Password -n UniqueTokenName diff --git a/csharp/App/SaliMax/SaliMax.csproj b/csharp/App/SaliMax/SaliMax.csproj index c647ee0d5..6802aca05 100644 --- a/csharp/App/SaliMax/SaliMax.csproj +++ b/csharp/App/SaliMax/SaliMax.csproj @@ -2,23 +2,23 @@ - - - - - - - - - - + + + + + + + + + + - - - - + + + + diff --git a/csharp/App/SaliMax/src/Controller/AvgBatteriesStatus.cs b/csharp/App/SaliMax/src/Controller/AvgBatteriesStatus.cs index b62316d85..745b18187 100644 --- a/csharp/App/SaliMax/src/Controller/AvgBatteriesStatus.cs +++ b/csharp/App/SaliMax/src/Controller/AvgBatteriesStatus.cs @@ -1,51 +1,53 @@ using InnovEnergy.Lib.Devices.Battery48TL; +using InnovEnergy.Lib.StatusApi; +using InnovEnergy.Lib.Units; +using InnovEnergy.Lib.Units.Composite; +using static InnovEnergy.Lib.Devices.Battery48TL.TemperatureState; namespace InnovEnergy.App.SaliMax.Controller; -public class AvgBatteriesStatus +public static class AvgBatteriesStatus { - public Decimal Soc { get; set; } - public Decimal Current { get; set; } - public Decimal Voltage { get; set; } - public Decimal Power { get; set; } - public Decimal BusVoltage { get; set; } - public Decimal BatteryTemperature { get; set; } - public IReadOnlyList Warnings { get; set; } - public IReadOnlyList Alarms { get; set; } - public Boolean HeaterOn { get; set; } - public Boolean EocReached { get; set; } - public Boolean BatteryCold { get; set; } - public Decimal MaxChargingPower { get; set; } - public Decimal MaxDischargingPower { get; set; } - - public static AvgBatteriesStatus ReadBatteriesStatus(IReadOnlyList batteriesStatus) + public static CombinedStatus? Combine(this IReadOnlyList stati) { - var soc = batteriesStatus.Any() ? batteriesStatus.Average(b => b.Soc) : 0; - var current = batteriesStatus.Select(b => b.Dc.Current).Aggregate(0m,(a, b) => a + b); - var voltage = batteriesStatus.Any() ? batteriesStatus.Average(b => b.Dc.Voltage) : 0; - var power = batteriesStatus.Select(b => b.Dc.Power).Aggregate(0m,(a, b) => a + b); - var busVoltage = batteriesStatus.Any() ? batteriesStatus.Average(b => b.BusVoltage): 0; - var batteryTemperature = batteriesStatus.Any() ? batteriesStatus.Average(b => b.Temperature): 0; - var heaterOn = batteriesStatus.Any() && batteriesStatus.Select(b => b.HeaterOn).Aggregate((a, b) => a | b); - var eocReached = batteriesStatus.All(b => b.EocReached); - var batteryCold = batteriesStatus.Any(b => b.BatteryCold); - var maxChargingPower = batteriesStatus.Select(b => b.MaxChargingPower).Aggregate(0m, (a, b) => a + b); - var maxDischargingPower = batteriesStatus.Select(b => b.MaxDischargingPower).Aggregate(0m, (a, b) => a + b); - - - return new AvgBatteriesStatus + var combined = stati.Count == 0 + ? null + : new Battery48TLStatus { - Soc = soc, - Current = current, - Voltage = voltage, - Power = power, - BusVoltage = busVoltage, - BatteryTemperature = batteryTemperature, - HeaterOn = heaterOn, - EocReached = eocReached, - BatteryCold = batteryCold, - MaxChargingPower = maxChargingPower, - MaxDischargingPower = maxDischargingPower + Soc = stati.Min(b => b.Soc), + Temperature = stati.Average(b => b.Temperature), + Dc = new DcBus + { + Voltage = stati.Average(b => b.Dc.Voltage), + Current = stati.Sum(b => b.Dc.Current), + }, + + Alarms = stati.SelectMany(b => b.Alarms).Distinct().ToList(), + Warnings = stati.SelectMany(b => b.Warnings).Distinct().ToList(), + + MaxChargingPower = stati.Sum(b => b.MaxChargingPower), + MaxDischargingPower = stati.Sum(b => b.MaxDischargingPower), + + Heating = stati.Any(b => b.Heating), + + AmberLed = LedState.Off, // not used for combined battery + BlueLed = LedState.Off, + RedLed = LedState.Off, + GreenLed = LedState.Off, + + CellsVoltage = stati.Average(b => b.CellsVoltage), + ConnectedToDc = stati.Any(b => b.ConnectedToDc), + + TemperatureState = stati.Any(b => b.TemperatureState == OperatingTemperature) // TODO: revisit when we have the overheated state + ? OperatingTemperature + : Cold, + + }; + + return new CombinedStatus + { + Combined = combined!, + Children = stati }; } } \ No newline at end of file diff --git a/csharp/App/SaliMax/src/Controller/StatusRecord.cs b/csharp/App/SaliMax/src/Controller/StatusRecord.cs index 53de658b8..9071f5976 100644 --- a/csharp/App/SaliMax/src/Controller/StatusRecord.cs +++ b/csharp/App/SaliMax/src/Controller/StatusRecord.cs @@ -5,18 +5,19 @@ using InnovEnergy.Lib.Devices.Battery48TL; using InnovEnergy.Lib.Devices.EmuMeter; using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; +using InnovEnergy.Lib.StatusApi; namespace InnovEnergy.App.SaliMax.Controller; public record StatusRecord { - public TruConvertAcStatus? InverterStatus { get; init; } - public TruConvertDcStatus? DcDcStatus { get; init; } - public Battery48TLStatus[]? BatteriesStatus { get; set; } = Array.Empty(); // TODO remove static - public AvgBatteriesStatus? AvgBatteriesStatus { get; init; } - public EmuMeterStatus? GridMeterStatus { get; init; } - public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; } - public AmptStatus? AmptStatus { get; init; } - public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; } - public SalimaxConfig SalimaxConfig { get; init; } = null!; + public TruConvertAcStatus? InverterStatus { get; init; } + public TruConvertDcStatus? DcDcStatus { get; init; } + public CombinedStatus? BatteriesStatus { get; init; } + + public EmuMeterStatus? GridMeterStatus { get; init; } + public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; } + public AmptStatus? AmptStatus { get; init; } + public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; } + public SalimaxConfig SalimaxConfig { get; init; } = null!; } \ No newline at end of file diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index 229e3f0b8..d4d080a11 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -13,6 +13,7 @@ using InnovEnergy.Lib.Devices.EmuMeter; using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; using InnovEnergy.Lib.Time.Unix; +using InnovEnergy.Lib.Utils; #pragma warning disable IL2026 @@ -41,14 +42,26 @@ internal static class Program { Console.WriteLine("Starting SaliMax"); + var batteryNodes = new Byte[] { 2, 3 }; + + var batteryTty = "/dev/ttyUSB0"; + + var relaysIp = "10.0.1.1"; + var truConvertAcIp = "10.0.2.1"; + var truConvertDcIp = "10.0.3.1"; + var gridMeterIp = "10.0.4.1"; + var internalMeter = "10.0.4.2"; + var amptIp = "10.0.5.1"; + + var s3Config = new S3Config { - Bucket = "saliomameiringen", - Region = "sos-ch-dk-2", - Provider = "exo.io", + Bucket = "saliomameiringen", + Region = "sos-ch-dk-2", + Provider = "exo.io", ContentType = "text/plain; charset=utf-8", - Key = "EXO2bf0cbd97fbfa75aa36ed46f", - Secret = "Bn1CDPqOG-XpDSbYjfIJxojcHTm391vZTc8z8l_fEPs" + Key = "EXO2bf0cbd97fbfa75aa36ed46f", + Secret = "Bn1CDPqOG-XpDSbYjfIJxojcHTm391vZTc8z8l_fEPs" }; #if DEBUG @@ -62,48 +75,42 @@ internal static class Program var firstBattery48TlDevice =Battery48TlDevice.Fake();; var salimaxConfig = new SalimaxConfig(); #else -#if BatteriesAllowed - var firstBattery48TlDevice = new Battery48TlDevice("/dev/ttyUSB0", 2); - var secondBattery48TlDevice = new Battery48TlDevice("/dev/ttyUSB0", 3); -#endif - var inverterDevice = new TruConvertAcDevice("192.168.1.2"); - var dcDcDevice = new TruConvertDcDevice("192.168.1.3"); - var gridMeterDevice = new EmuMeterDevice("192.168.1.241"); - var acInToAcOutMeterDevice = new EmuMeterDevice("192.168.1.241"); // TODO: use real device - var amptDevice = new AmptCommunicationUnit("192.168.1.249"); - var saliMaxRelaysDevice = new SaliMaxRelaysDevice("192.168.1.242"); + + var batteries = batteryNodes.Select(n => new Battery48TlDevice(batteryTty, n)).ToList(); + + + var inverterDevice = new TruConvertAcDevice(truConvertAcIp); + var dcDcDevice = new TruConvertDcDevice(truConvertDcIp); + + var gridMeterDevice = new EmuMeterDevice(gridMeterIp); + var acInToAcOutMeterDevice = new EmuMeterDevice(internalMeter); // TODO: use real device + + var amptDevice = new AmptCommunicationUnit(amptIp); + + var saliMaxRelaysDevice = new SaliMaxRelaysDevice(relaysIp); var salimaxConfig = new SalimaxConfig(); #endif // This is will be always add manually ? or do we need to read devices automatically in a range of IP @ -#if BatteriesAllowed - var battery48TlDevices = new[] { firstBattery48TlDevice, secondBattery48TlDevice }; -#endif - - var dcDcDevices = new[] { dcDcDevice }; - var inverterDevices = new[] { inverterDevice}; + StatusRecord ReadStatus() { -#if BatteriesAllowed - - var battery48TlStatusArray = battery48TlDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); -#endif - // var dcDcStatusArray = dcDcDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); + var combinedBatteryStatus = batteries + .Select(b => b.ReadStatus()) + .NotNull() + .ToList() + .Combine(); + + // var dcDcStatusArray = dcDcDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); // var inverterStatusArray = inverterDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); return new StatusRecord { InverterStatus = inverterDevice.ReadStatus(), DcDcStatus = dcDcDevice.ReadStatus(), -#if BatteriesAllowed - BatteriesStatus = battery48TlStatusArray, - AvgBatteriesStatus = AvgBatteriesStatus.ReadBatteriesStatus(battery48TlStatusArray), -#else - BatteriesStatus = null, - AvgBatteriesStatus = null, -#endif + BatteriesStatus = combinedBatteryStatus, AcInToAcOutMeterStatus = acInToAcOutMeterDevice.ReadStatus(), GridMeterStatus = gridMeterDevice.ReadStatus(), SaliMaxRelayStatus = saliMaxRelaysDevice.ReadStatus(), diff --git a/csharp/App/SaliMax/tunneltoProto.sh b/csharp/App/SaliMax/tunneltoProto.sh new file mode 100644 index 000000000..215e43c1d --- /dev/null +++ b/csharp/App/SaliMax/tunneltoProto.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +host=ie-entwicklung@10.2.3.115 + +tunnel() { + name=$1 + ip=$2 + rPort=$3 + lPort=$4 + + echo -n "localhost:$lPort $name " + ssh -nNTL "$lPort:$ip:$rPort" "$host" 2> /dev/null & + + until nc -vz 127.0.0.1 $lPort 2> /dev/null + do + echo -n . + sleep 0.3 + done + + echo "ok" +} + +echo "" + +tunnel "Trumpf Inverter (http) " 10.0.2.1 80 8001 +tunnel "Trumpf DCDC (http) " 10.0.3.1 80 8002 +tunnel "Ext Emu Meter (http) " 10.0.4.1 80 8003 +tunnel "Int Emu Meter (http) " 10.0.4.2 80 8004 +tunnel "AMPT (http) " 10.0.5.1 8080 8005 + +tunnel "Trumpf Inverter (modbus)" 10.0.2.1 502 5001 +tunnel "Trumpf DCDC (modbus) " 10.0.3.1 502 5002 +tunnel "Ext Emu Meter (modbus) " 10.0.4.1 502 5003 +tunnel "Int Emu Meter " 10.0.4.2 502 5004 +tunnel "AMPT (modbus) " 10.0.5.1 502 5005 + + + +echo +echo "press any key to close the tunnels ..." +read -r -n 1 -s +kill $(jobs -p) +echo "done" \ No newline at end of file diff --git a/csharp/InnovEnergy.props b/csharp/InnovEnergy.props index 7315812ef..b1aafb267 100644 --- a/csharp/InnovEnergy.props +++ b/csharp/InnovEnergy.props @@ -9,8 +9,12 @@ net6.0 true false - $(Company).$(MSBuildProjectDirectory.Replace($(SolutionDir), "").Replace("src/", "").Replace("/",".").Replace("\",".")) + Please.reload.the.project.Rider.is.stupid $(Company) Team - + + + $(Company).$(MSBuildProjectDirectory.Replace($(SolutionDir), "").Replace("/",".").Replace("\",".")) + + diff --git a/csharp/InnovEnergy.sln b/csharp/InnovEnergy.sln index 8d368b9cb..bababc313 100644 --- a/csharp/InnovEnergy.sln +++ b/csharp/InnovEnergy.sln @@ -60,20 +60,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Channels", "Lib/Channels/Ch EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Backend", "App/Backend/Backend.csproj", "{A56F58C2-B265-435B-A985-53B4D6F49B1A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Units", "Lib/Units/Units.csproj", "{C04FB6DA-23C6-46BB-9B21-8F4FBA32FFF7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Units", "Lib\Units\Units.csproj", "{C04FB6DA-23C6-46BB-9B21-8F4FBA32FFF7}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemControl", "Lib/Devices/Trumpf/SystemControl/SystemControl.csproj", "{B816BB44-E97E-4E02-B80A-BEDB5B923A96}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Meta", "Meta", "{AED84693-C389-44C9-B2C0-ACB560189CF2}" ProjectSection(SolutionItems) = preProject InnovEnergy.props = InnovEnergy.props - App\InnovEnergy.App.props = App\InnovEnergy.App.props - Lib\InnovEnergy.Lib.props = Lib\InnovEnergy.Lib.props + App/InnovEnergy.App.props = App/InnovEnergy.App.props + Lib/InnovEnergy.Lib.props = Lib/InnovEnergy.Lib.props InnovEnergy.sln.DotSettings = InnovEnergy.sln.DotSettings - ..\.gitignore = ..\.gitignore + ../.gitignore = ../.gitignore EndProjectSection EndProject - Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -180,6 +180,10 @@ Global {C04FB6DA-23C6-46BB-9B21-8F4FBA32FFF7}.Debug|Any CPU.Build.0 = Debug|Any CPU {C04FB6DA-23C6-46BB-9B21-8F4FBA32FFF7}.Release|Any CPU.ActiveCfg = Release|Any CPU {C04FB6DA-23C6-46BB-9B21-8F4FBA32FFF7}.Release|Any CPU.Build.0 = Release|Any CPU + {B816BB44-E97E-4E02-B80A-BEDB5B923A96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B816BB44-E97E-4E02-B80A-BEDB5B923A96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B816BB44-E97E-4E02-B80A-BEDB5B923A96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B816BB44-E97E-4E02-B80A-BEDB5B923A96}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A} @@ -211,5 +215,6 @@ Global {A56F58C2-B265-435B-A985-53B4D6F49B1A} = {145597B4-3E30-45E6-9F72-4DD43194539A} {C04FB6DA-23C6-46BB-9B21-8F4FBA32FFF7} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854} {4A67D79F-F0C9-4BBC-9601-D5948E6C05D3} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854} + {B816BB44-E97E-4E02-B80A-BEDB5B923A96} = {DDDBEFD0-5DEA-4C7C-A9F2-FDB4636CF092} EndGlobalSection EndGlobal diff --git a/csharp/InnovEnergy.sln.DotSettings b/csharp/InnovEnergy.sln.DotSettings index 8232b1720..61f3b696e 100644 --- a/csharp/InnovEnergy.sln.DotSettings +++ b/csharp/InnovEnergy.sln.DotSettings @@ -28,6 +28,8 @@ True True True + True + True True True True @@ -38,6 +40,7 @@ True True True + True True \ No newline at end of file diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs b/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs index 6507ac32d..97462b720 100644 --- a/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs +++ b/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs @@ -1,5 +1,6 @@ using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Connections; +using static InnovEnergy.Lib.Devices.Battery48TL.Constants; namespace InnovEnergy.Lib.Devices.Battery48TL; @@ -10,10 +11,10 @@ public class Battery48TlDevice public Battery48TlDevice(String device, Byte nodeId) { var serialConnection = new ModbusSerialConnection(device, - Constants.BaudRate, - Constants.Parity, - Constants.DataBits, - Constants.StopBits, + BaudRate, + Parity, + DataBits, + StopBits, Constants.Timeout); Modbus = new ModbusRtuClient(serialConnection, nodeId); @@ -34,7 +35,7 @@ public class Battery48TlDevice try { return Modbus - .ReadInputRegisters(Constants.BaseAddress, Constants.NoOfRegisters) + .ReadInputRegisters(BaseAddress, NoOfRegisters) .ParseBatteryStatus(); } catch (Exception e) diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs b/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs index b9feb07d0..c42532fc6 100644 --- a/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs +++ b/csharp/Lib/Devices/Battery48TL/Battery48TLStatusRecord.cs @@ -1,7 +1,6 @@ using System.Diagnostics.CodeAnalysis; using InnovEnergy.Lib.StatusApi; using InnovEnergy.Lib.Units; -using InnovEnergy.Lib.Utils; namespace InnovEnergy.Lib.Devices.Battery48TL; @@ -15,22 +14,17 @@ public record Battery48TLStatus : BatteryStatus public Power MaxChargingPower { get; init; } public Power MaxDischargingPower { get; init; } - public State GreenLed { get; init; } - public State AmberLed { get; init; } - public State BlueLed { get; init; } - public State RedLed { get; init; } - - public State Warnings { get; init; } - public State Alarms { get; init; } - - public State MainSwitchState { get; init; } // connected to bus | disconnected from bus - public State HeaterState { get; init; } // heating | not heating - public State EocState { get; init; } // EOC reached | EOC not reached - public State TemperatureState { get; init; } // cold | operating temperature | overheated + public LedState GreenLed { get; init; } + public LedState AmberLed { get; init; } + public LedState BlueLed { get; init; } + public LedState RedLed { get; init; } + public IReadOnlyList Warnings { get; init; } = Array.Empty(); + public IReadOnlyList Alarms { get; init; } = Array.Empty(); - public static T operator |(T left, T right) => OpParallel(left, right); - private static readonly Func OpParallel = "|".CreateBinaryOpForProps(); + public Boolean ConnectedToDc { get; init; } + public Boolean Heating { get; init; } + public TemperatureState TemperatureState { get; init; } // cold | operating temperature | overheated diff --git a/csharp/Lib/Devices/Battery48TL/Constants.cs b/csharp/Lib/Devices/Battery48TL/Constants.cs index 44234a09c..ea2e7501e 100644 --- a/csharp/Lib/Devices/Battery48TL/Constants.cs +++ b/csharp/Lib/Devices/Battery48TL/Constants.cs @@ -24,7 +24,7 @@ public static class Constants private const Decimal RStringMin = 0.125m; private const Decimal RStringMax = 0.250m; private const Decimal IMaxPerString = 20.0m; - private const UInt16 NumberOfStrings = 5; + private const UInt16 NumberOfStrings = 5; public const Decimal RIntMin = RStringMin / NumberOfStrings; public const Decimal RIntMax = RStringMax / NumberOfStrings; diff --git a/csharp/Lib/Devices/Battery48TL/ModbusParser.cs b/csharp/Lib/Devices/Battery48TL/ModbusParser.cs index d16c3dc5d..af2c3568a 100644 --- a/csharp/Lib/Devices/Battery48TL/ModbusParser.cs +++ b/csharp/Lib/Devices/Battery48TL/ModbusParser.cs @@ -1,8 +1,8 @@ using System.Diagnostics.CodeAnalysis; using InnovEnergy.Lib.Protocols.Modbus.Conversions; -using InnovEnergy.Lib.Units; using InnovEnergy.Lib.Units.Composite; using InnovEnergy.Lib.Utils; +using static InnovEnergy.Lib.Devices.Battery48TL.LedState; namespace InnovEnergy.Lib.Devices.Battery48TL; @@ -10,24 +10,44 @@ public static class ModbusParser { internal static Battery48TLStatus ParseBatteryStatus(this ModbusRegisters data) { + var greenLed = data.ParseLedState(register: 1005, led: LedColor.Green); + var amberLed = data.ParseLedState(register: 1005, led: LedColor.Amber); + var blueLed = data.ParseLedState(register: 1005, led: LedColor.Blue); + var redLed = data.ParseLedState(register: 1005, led: LedColor.Red); + + var soc = data.ParseSoc(); + + var eoc = greenLed is On + && amberLed is Off + && blueLed is Off; + + var maxSoc = eoc ? 100m : 99.9m; + + var batteryCold = greenLed >= BlinkingSlow + && blueLed >= BlinkingSlow; + + var temperatureState = batteryCold + ? TemperatureState.Cold + : TemperatureState.OperatingTemperature; // TODO: overheated + + 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(), + Soc = Math.Min(soc, maxSoc), + Temperature = data.ParseDecimal(register: 1004, scaleFactor: 0.1m, offset: -400), + GreenLed = greenLed, + AmberLed = amberLed, + BlueLed = blueLed, + RedLed = redLed, + Heating = data.ParseBool(baseRegister: 1014, bit: 6), + ConnectedToDc = data.ParseBool(baseRegister: 1014, bit: 0), + TemperatureState = temperatureState, MaxChargingPower = data.CalcMaxChargePower(), MaxDischargingPower = data.CalcMaxDischargePower(), - CellsVoltage = data.ParseCellsVoltage(), + CellsVoltage = data.ParseDecimal(register: 1000, scaleFactor: 0.01m), }; } @@ -47,11 +67,6 @@ public static class ModbusParser 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); @@ -74,57 +89,19 @@ public static class ModbusParser return (hi, lo) switch { - (false, false) => LedState.Off, - (false, true) => LedState.On, - (true, false) => LedState.BlinkingSlow, - (true, true) => LedState.BlinkingFast, + (false, false) => Off, + (false, true) => On, + (true, false) => BlinkingSlow, + (true, true) => 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; @@ -161,11 +138,12 @@ public static class ModbusParser internal static Decimal CalcMaxChargePower(this ModbusRegisters data) { - var v = ParseCellsVoltage(data); + var v = data.ParseDecimal(register: 1000, scaleFactor: 0.01m); var i = ParseCurrent(data); var pLimits = new[] { + // TODO: review CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMax, Constants.RIntMin), CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMax, Constants.RIntMax), CalcPowerLimitImposedByCurrentLimit(v, i, Constants.IMax, Constants.RIntMin), @@ -177,23 +155,20 @@ public static class ModbusParser return Math.Max(pLimit, 0); } - internal static DcBus ParseDcBus(this ModbusRegisters data) + internal static DcBus ParseDcBus(this ModbusRegisters data) => new() { - return new() - { - Current = data.ParseCurrent(), - Voltage = data.ParseBusVoltage(), - }; - } + Current = data.ParseCurrent(), + Voltage = data.ParseBusVoltage(), + }; internal static Decimal CalcMaxDischargePower(this ModbusRegisters data) { - var v = ParseCellsVoltage(data); + var v = data.ParseDecimal(register: 1000, scaleFactor: 0.01m); var i = ParseCurrent(data); - var t = data.ParseDecimal(register: 1004, scaleFactor: 0.1m, offset: -400); var pLimits = new[] { + // TODO: review CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMin, Constants.RIntMin), CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMin, Constants.RIntMax), CalcPowerLimitImposedByCurrentLimit(v, i, -Constants.IMax, Constants.RIntMin), @@ -207,12 +182,6 @@ public static class ModbusParser } - 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) { diff --git a/csharp/Lib/Devices/Battery48TL/TemperatureState.cs b/csharp/Lib/Devices/Battery48TL/TemperatureState.cs new file mode 100644 index 000000000..6bb71b4e1 --- /dev/null +++ b/csharp/Lib/Devices/Battery48TL/TemperatureState.cs @@ -0,0 +1,8 @@ +namespace InnovEnergy.Lib.Devices.Battery48TL; + +public enum TemperatureState +{ + Cold = 0, + OperatingTemperature = 1, + Overheated = 2, +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/SystemControl/AlarmMessage.cs b/csharp/Lib/Devices/Trumpf/SystemControl/AlarmMessage.cs new file mode 100644 index 000000000..d63b5dfb8 --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/SystemControl/AlarmMessage.cs @@ -0,0 +1,18 @@ +using System.Diagnostics.CodeAnalysis; + +namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl; + +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum AlarmMessage +{ + NoAlarm = 0, + BmsCommunicationTimeoutHasOccured = 40302, // BMS communication timeout has occured. + Rs485CommunicationAlarm = 40303, // RS-485 communication alarm. + SoftwareVersionsOfSystemControlAndModulesDoNotMatch1 = 40412, // Software versions of system control and module(s) do not match. + SoftwareVersionsOfSystemControlAndModulesDoNotMatch2 = 40413, // Software versions of system control and module(s) do not match. + SoftwareVersionsOfSystemControlAndModulesDoNotMatch3 = 40414, // Software versions of system control and module(s) do not match. + SoftwareVersionsOfSystemControlAndModulesDoNotMatch4 = 40415, // Software versions of system control and module(s) do not match. + SoftwareVersionsOfSystemControlAndModulesDoNotMatch5 = 40416, // Software versions of system control and module(s) do not match. + NoSlaveModuleWasFoundPleaseCheckRs485Connection = 40304, // No slave module was found, please check RS-485 connection(s). + NumberOfOrCombinationOfConnectedSlaveTypesNotSupported = 40305, // Number of or combination of connected slave types not supported. +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/SystemControl/ControlRecord.cs b/csharp/Lib/Devices/Trumpf/SystemControl/ControlRecord.cs new file mode 100644 index 000000000..b5879384e --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/SystemControl/ControlRecord.cs @@ -0,0 +1,84 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl; + +public record ControlRecord +{ + private static readonly TimeSpan DefaultCommunicationTimeOut = TimeSpan.FromSeconds(10); + + // TODO + + // public UInt32 Date { get; init;} + // public UInt32 Time { get; init;} + // public UInt32 IpAddress { get; init;} //= 0x C0A80102; + // public UInt32 Subnet { get; init;} //= 0x FFFFFF00; + // public UInt32 Gateway { get; init;} //= 0x C0A80102; + // public Boolean ResetParamToDefault { get; init;} = false ; // Coil + // public TimeSpan CommunicationTimeout { get; init;} = DefaultCommunicationTimeOut; + // public Boolean FactoryResetParameters { get; init;} = false; + // public SystemConfig ConnectedSystemConfig { get; init;} = 0; + // public UInt16 UpdateSwTrigger { get; init;} = 0; + // public UInt16 AutomaticSwUpdate { get; init;} = 0; + // public UInt16 CustomerValuesSaveReset { get; init;} = 0; + // public UInt16 SerialNumberSystemControl { get; init;} = 0; + // public UInt16 SerialNumberAcDc { get; init;} = 0; + // public UInt16 IntegrationLevel { get; init;} = 0; + // public UInt16 IlBuildnumber { get; init;} = 0; + // public Boolean PowerStageEnable { get; init;} = true; + // public SymmetricAcOperationMode SetValueConfig { get; init;} = 0; + // public Boolean ResetsAlarmAndWarning { get; init;} = false; + // public PreChargeDcLinkConfig PreChargeDcLinkConfig { get; init;} = (PreChargeDcLinkConfig)0; + // public PowerFactorConvention PowerFactorConvention { get; init;} = 0; //0 = producer + // public UInt16 SlaveAddress { get; init;} = Slave.Broadcast; + // public ErrorPolicy ErrorHandlingPolicy { get; init;} = 0; + // public AcDcGridType GridType { get; init;} = 0; + // public UInt16 SubSlaveAddress { get; init;} = 0; + // public Boolean UseModbusSlaveIdForAddressing { get; init;} = false; + // public UInt16 SubSlaveErrorPolicy { get; init;} = 0; // must be an enum + // public Decimal SignedPowerNominalValue { get; init;} = 0; // resolution 0.001 and Unit kva, + // public Decimal SignedPowerSetValueL1 { get; init;} = 0; // resolution 0.001 and Unit kva, + // public Decimal SignedPowerSetValueL2 { get; init;} = 0; // resolution 0.001 and Unit kva, + // public Decimal SignedPowerSetValueL3 { get; init;} = 0; // resolution 0.001 and Unit kva, + // public Decimal PowerSetValue { get; init;} = 0; // resolution 0.001 and Unit kva, + // public Decimal PowerSetValueL1 { get; init;} = 0; // resolution 0.001 and Unit kva, + // public Decimal PowerSetValueL2 { get; init;} = 0; // resolution 0.001 and Unit kva, + // public Decimal PowerSetValueL3 { get; init;} = 0; // resolution 0.001 and Unit kva, + // public Decimal MaximumGridCurrentRmsL1 { get; init;} = 0; // resolution : 0.01 + // public Decimal MaximumGridCurrentRmsL2 { get; init;} = 0; // resolution : 0.01 + // public Decimal MaximumGridCurrentRmsL3 { get; init;} = 0; // resolution : 0.01 + // public Decimal CosPhiSetValueL1 { get; init;} = 0; // resolution : 0.01 + // public Decimal CosPhiSetValueL2 { get; init;} = 0; // resolution : 0.01 + // public Decimal CosPhiSetValueL3 { get; init;} = 0; // resolution : 0.01 + // public Boolean PhaseL1IsCapacitive { get; init;} = true; // True = Capacitive, false = Inductive + // public Boolean PhaseL2IsCapacitive { get; init;} = true; // True = Capacitive, false = Inductive + // public Boolean PhaseL3IsCapacitive { get; init;} = true; // True = Capacitive, false = Inductive + // public Boolean PhasesAreCapacitive { get; init;} = true; // True = Capacitive, false = Inductive + // public Double SetPointCosPhi { get; init;} = 0; // resolution 0.01 + // public Double SetPointSinPhi { get; init;} = 0; // resolution 0.01 + // public Double SetPointSinPhiL1 { get; init;} = 0; // resolution 0.01 + // public Double SetPointSinPhiL2 { get; init;} = 0; // resolution 0.01 + // public Double SetPointSinPhiL3 { get; init;} = 0; // resolution 0.01 + // public Decimal FrequencyOffsetIm { get; init;} = 0; // resolution 0.01 + // public UInt16 VoltageAdjustmentFactorIm { get; init;} = 0; + // public UInt16 PreChargeDcLinkVoltage { get; init;} = 0; + // public Decimal MaxPeakCurrentVoltageControlL1 { get; init;} = 0; // resolution 0.01 + // public Decimal MaxPeakCurrentVoltageControlL2 { get; init;} = 0; // resolution 0.01 + // public Decimal MaxPeakCurrentVoltageControlL3 { get; init;} = 0; // resolution 0.01 + // public UInt16 GridFormingMode { get; init;} = 1; // 0 = not grid-forming (grid-tied) ,1 = grid-forming + // public UInt16 DcLinkRefVoltage { get; init;} = 800; + // public UInt16 DcLinkMinVoltage { get; init;} = 780; + // public UInt16 DcLinkMaxVoltage { get; init;} = 820; + // public UInt16 DcVoltageRefUs { get; init;} = 900; + // public UInt16 DcMinVoltageUs { get; init;} = 880; + // public UInt16 DcMaxVoltageUs { get; init;} = 920; + // // Need to discuss this with Ivo + // // public UInt16 FrequencySlopeIslandMode { get; init;} = 200; // resolution 0.01 + // // public UInt16 VoltageSlopeIslandMode { get; init;} = 500; // resolution 0.01 + // public UInt16 AcDcGcBypassMode { get; init;} = 0; + // public UInt16 AcDcGcPMaxThresholdPercent { get; init;} = 0; // resolution 0.01 + // public UInt16 AcDcGcStartupRampEnable { get; init;} = 0; + // public DcStageConfiguration DcConfigModule { get; init;} = 0; // this must be an enum + // public UInt16 DcDcPowerDistribution { get; init;} = 0; // 0.1 resolution + // public AcDcDistributionMode AcDcDistributionMode { get; init;} = 0; + + + +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/SystemControl/ErrorPolicy.cs b/csharp/Lib/Devices/Trumpf/SystemControl/ErrorPolicy.cs new file mode 100644 index 000000000..9a57a9f3d --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/SystemControl/ErrorPolicy.cs @@ -0,0 +1,7 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl; + +public enum ErrorPolicy : UInt16 +{ + Relaxed = 0, // 0 = relaxed (System keeps running even if some slaves are in error state.) + Strict = 1, // 1 = strict (System shuts down as soon as one component is in error state.) +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/SystemControl/StatusRecord.cs b/csharp/Lib/Devices/Trumpf/SystemControl/StatusRecord.cs new file mode 100644 index 000000000..511019b83 --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/SystemControl/StatusRecord.cs @@ -0,0 +1,43 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl; + +using AlarmMessages = IReadOnlyList; +using WarningMessages = IReadOnlyList; + + +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS8618 + + +public record StatusRecord +{ + + // TODO + + // public MainState MainState { get; init; } + // public String SerialNumber { get; init; } + // public AcDcGridType GridType { get; init; } + // public WarningMessages Warnings { get; init; } + // public AlarmMessages Alarms { get; init; } + // public Decimal NumberOfConnectedSlaves { get; init; } + // public Decimal NumberOfConnectedSubSlaves { get; init; } + // public Frequency AcDcNominalGridFrequency { get; init; } + // public Voltage AcDcNominalGridVoltage { get; init; } + // public Power AcDcActNominalPower { get; init; } + // public Decimal AcDcPowerLimitingStatusAct { get; init; } // TODO: enum + // public Voltage AcDcDcVoltageReference { get; init; } + // public Voltage AcDcDcLinkVoltageMinAct { get; init; } + // public Voltage AcDcDcLinkVoltageMaxAct { get; init; } + // public Voltage AcDcDcLinkChargedMinVoltage { get; init; } + // public Decimal AcDcStmActCustomer { get; init; } + // public Decimal AcDcOverloadIntegratorStatusL1 { get; init; } + // public Decimal AcDcOverloadIntegratorStatusL2 { get; init; } + // public Decimal AcDcOverloadIntegratorStatusL3 { get; init; } + // public Power AcSignedPowerValue { get; init; } + // public Voltage ActualDcLinkVoltageUpperHalf { get; init; } + // public Voltage ActualDcLinkVoltageLowerHalf { get; init; } + // public Voltage ActualDcLinkVoltageUpperHalfExt { get; init; } + // public Voltage ActualDcLinkVoltageLowerHalfExt { get; init; } + // public Voltage VoltageIntNtoPe { get; init; } + // public Voltage VoltageExtNtoPe { get; init; } + // public Temperature InletAirTemperature { get; init; } +} diff --git a/csharp/Lib/Devices/Trumpf/SystemControl/SubSlavesErrorPolicy.cs b/csharp/Lib/Devices/Trumpf/SystemControl/SubSlavesErrorPolicy.cs new file mode 100644 index 000000000..107b6b42b --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/SystemControl/SubSlavesErrorPolicy.cs @@ -0,0 +1,8 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl; + +public enum SubSlavesErrorPolicy : UInt16 +{ + Strict = 0, // (AC-DC module switches to error state if at least one submodules is in error state + Relaxed = 1, // (AC-DC module switches to error state if all submodules are in error state.) + Off = 2, // (If possible AC-DC module continues operation even if all submodules are in error state. +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/SystemControl/SystemControl.csproj b/csharp/Lib/Devices/Trumpf/SystemControl/SystemControl.csproj new file mode 100644 index 000000000..be34f2198 --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/SystemControl/SystemControl.csproj @@ -0,0 +1,7 @@ + + + + + + + diff --git a/csharp/Lib/Devices/Trumpf/SystemControl/SystemControlDevice.cs b/csharp/Lib/Devices/Trumpf/SystemControl/SystemControlDevice.cs new file mode 100644 index 000000000..cc3e94af0 --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/SystemControl/SystemControlDevice.cs @@ -0,0 +1,324 @@ +using System.Diagnostics.CodeAnalysis; +using InnovEnergy.Lib.Protocols.Modbus.Clients; +using InnovEnergy.Lib.Protocols.Modbus.Connections; +using InnovEnergy.Lib.Utils; +using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.SystemControlRegisters; + + +namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl; + +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class SystemControlDevice +{ + private ModbusTcpClient ModbusTcpClient { get; } + + public SystemControlDevice(String hostname, UInt16 port = ModbusTcpClient.DefaultPort, Byte slaveAddress = 0) + { + var connection = new ModbusTcpConnection(hostname, port); + ModbusTcpClient = new ModbusTcpClient(connection, slaveAddress); + } + + + public void WriteControl(ControlRecord c) + { + /* + WriteRegs(AcControlRegisters.Date, new List { c.Date.ConvertTo()}); + WriteRegs(AcControlRegisters.Time, new List { c.Time.ConvertTo()}); + WriteRegs(AcControlRegisters.IpAddress, new List { c.IpAddress.ConvertTo()}); + WriteRegs(AcControlRegisters.Subnet, new List { c.Subnet.ConvertTo()}); + WriteRegs(AcControlRegisters.Gateway, new List { c.Gateway.ConvertTo()}); + WriteCoils(AcControlRegisters.ResetParamToDefault, c.ResetParamToDefault); + WriteCoils(AcControlRegisters.FactoryResetParameters, c.FactoryResetParameters); + ModbusTcpClient.WriteRegisters(AcControlRegisters.UpdateSwTrigger, c.UpdateSwTrigger, c.AutomaticSwUpdate, c.CustomerValuesSaveReset); + */ + + + WriteRegs(CommunicationTimeout, c.CommunicationTimeout.TotalSeconds.ConvertTo()); + + WriteRegs(ConnectedSystemConfig, c.ConnectedSystemConfig); + + + WriteCoils(PowerStageConfig, c.PowerStageEnable, + c.SetValueConfig.ConvertTo(), + c.ResetsAlarmAndWarning); + WriteRegs(PreChargeDcLinkConfigR, c.PreChargeDcLinkConfig, + c.PowerFactorConvention, c.SlaveAddress, + c.ErrorHandlingPolicy, + c.GridType, c.SubSlaveAddress); + WriteCoils(ModbusSlaveId, c.UseModbusSlaveIdForAddressing); + WriteRegs(SubSlaveErrorPolicy, c.SubSlaveErrorPolicy); + + WriteRegs(SignedPowerNominalValue, -1.0m, c.SignedPowerNominalValue);/*, c.SignedPowerSetValueL1, + c.SignedPowerSetValueL2, c.SignedPowerSetValueL3, + c.PowerSetValue, c.PowerSetValueL1, + c.PowerSetValueL2, c.PowerSetValuesL3);*/ + + + WriteRegs(MaximumGridCurrentRmsL1, 0.01m, c.MaximumGridCurrentRmsL1, c.MaximumGridCurrentRmsL2, + c.MaximumGridCurrentRmsL3, c.CosPhiSetValueL1, + c.CosPhiSetValueL2, c.CosPhiSetValueL3); + + WriteCoils(PhaseL1IsCapacitive, c.PhaseL1IsCapacitive, + c.PhaseL2IsCapacitive, + c.PhaseL3IsCapacitive, + c.PhasesAreCapacitive); + + /* WriteRegs(SetPointCosPhi, 0.01m, c.SetPointCosPhi.ConvertTo(), + c.SetPointSinPhi.ConvertTo(), + c.SetPointSinPhiL1.ConvertTo(), + c.SetPointSinPhiL2.ConvertTo(), + c.SetPointSinPhiL3.ConvertTo(), + c.FrequencyOffsetIm);*/ + + WriteRegs(VoltageAdjustmentFactorIm, c.VoltageAdjustmentFactorIm); + WriteRegs(PreChargeDcLinkVoltage, c.PreChargeDcLinkVoltage); + WriteRegs(MaxPeakCurrentVoltageControlL1, 0.01m, c.MaxPeakCurrentVoltageControlL1, + c.MaxPeakCurrentVoltageControlL2, + c.MaxPeakCurrentVoltageControlL3); + WriteRegs(GridFormingMode, c.GridFormingMode, c.DcLinkRefVoltage, + c.DcLinkMinVoltage, c.DcLinkMaxVoltage, + c.DcVoltageRefUs, c.DcMinVoltageUs, c.DcMaxVoltageUs); + WriteRegs(AcDcGcBypassMode, c.AcDcGcBypassMode); + WriteRegs(AcDcGcPMaxThresholdPercent, 0.01m, c.AcDcGcPMaxThresholdPercent); + WriteRegs(AcDcGcStartupRampEnable, c.AcDcGcStartupRampEnable); + WriteRegs(DcConfigModule, c.DcConfigModule); + WriteRegs(DcDcPowerDistribution, 0.1m, c.DcDcPowerDistribution); + WriteRegs(SystemControlRegisters.AcDcDistributionMode, c.AcDcDistributionMode); + } + + private void WriteRegs (UInt16 a, Decimal res = 1.0m, params Decimal[] regs) => ModbusTcpClient.WriteRegisters(a, regs.ToUInt16(res)); + private void WriteRegs (UInt16 a, params IConvertible[] regs) => ModbusTcpClient.WriteRegisters(a, regs.Select(v => v.ConvertTo()).ToArray()); + private void WriteRegs (UInt16 a, params UInt16[] regs) => ModbusTcpClient.WriteRegisters(a, regs); + private void WriteCoils(UInt16 a, params Boolean[] coils) => ModbusTcpClient.WriteMultipleCoils(a, coils); + + private static Decimal GetPhi(Decimal cosPhi) => cosPhi.Clamp(-1m, 1m).Apply(ACos); + + public StatusRecord? ReadStatus() + { + try + { + return TryReadStatus(); + } + catch (Exception e) + { + ModbusTcpClient.CloseConnection(); + Console.WriteLine("Failed to read inverter status"); + e.Message.WriteLine(); + + return null; + } + } + + private StatusRecord TryReadStatus() + { + // Console.WriteLine("Reading Ac Device"); + + var acSerialNumber = ModbusTcpClient.ReadInputRegisters(2009, 2); + var acActualMain = ModbusTcpClient.ReadInputRegisters(5001, 3); + var acActualAcDc = ModbusTcpClient.ReadInputRegisters(5021, 9); + var acActualAcDc2 = ModbusTcpClient.ReadInputRegisters(5031, 1); + var acActualAcDc3 = ModbusTcpClient.ReadInputRegisters(5131, 6); + var acActualMeasurement = ModbusTcpClient.ReadInputRegisters(5141, 3); + var acActualMeasurement1 = ModbusTcpClient.ReadInputRegisters(5151, 3); + var acActualMeasurement2 = ModbusTcpClient.ReadInputRegisters(5161, 3); + var acActualMeasurement3 = ModbusTcpClient.ReadInputRegisters(5171, 3); + var acActualMeasurement4 = ModbusTcpClient.ReadInputRegisters(5187, 2); + var acActualMeasurement5 = ModbusTcpClient.ReadInputRegisters(5189, 2); + var acActualMeasurement6 = ModbusTcpClient.ReadInputRegisters(5191, 2); + var acActualMeasurement7 = ModbusTcpClient.ReadInputRegisters(5201, 1); + var acActualMeasurement8 = ModbusTcpClient.ReadInputRegisters(5211, 4); + var acActualMeasurement9 = ModbusTcpClient.ReadInputRegisters(5221, 2); + var acActualTemp = ModbusTcpClient.ReadInputRegisters(5501, 1); + var acWarningValues = ModbusTcpClient.ReadInputRegisters(2402, 22); + var acAlarmValues = ModbusTcpClient.ReadInputRegisters(2809, 22); + var acSetValues = ModbusTcpClient.ReadInputRegisters(4196, 1); + + var warnings = Enumerable + .Range(2404, 20) + .Select(n => acWarningValues.GetUInt16((UInt16)n).ConvertTo()) + .ToArray(); + + var alarms = Enumerable + .Range(2811, 20) + .Select(n => acAlarmValues.GetUInt16((UInt16)n).ConvertTo()) + .Where(m => m != AlarmMessage.NoAlarm) + .ToArray(); + + + var dcPower = acActualMeasurement.GetInt16(5141) * 1m + acActualMeasurement.GetInt16(5142) * 1m + acActualMeasurement.GetInt16(5143) * 1m; + var dcVoltage = acActualMeasurement8.GetUInt16(5214) + acActualMeasurement8.GetUInt16(5213); + var dcCurrent = dcVoltage != 0m + ? dcPower / dcVoltage + : 0m; + + + // //acActualMeasurement + // PowerAcL1 = acActualMeasurement.GetInt16(5141) * 1m, // in Watt + // PowerAcL2 = acActualMeasurement.GetInt16(5142) * 1m, // in Watt + // PowerAcL3 = acActualMeasurement.GetInt16(5143) * 1m, // in Watt + // + //acActualMeasurement1 + // PhaseCurrentL1 = acActualMeasurement1.GetUInt16(5151) * 0.01m, + // PhaseCurrentL2 = acActualMeasurement1.GetUInt16(5152) * 0.01m, + // PhaseCurrentL3 = acActualMeasurement1.GetUInt16(5153) * 0.01m, + + //acActualMeasurement2 + // GridVoltageL1 = acActualMeasurement2.GetUInt16(5161) * 0.1m, + // GridVoltageL2 = acActualMeasurement2.GetUInt16(5162) * 0.1m, + // GridVoltageL3 = acActualMeasurement2.GetUInt16(5163) * 0.1m, + + //acActualMeasurement3 + // CosPhiL1 = acActualMeasurement3.GetInt16(5171) * 0.01m, + // CosPhiL2 = acActualMeasurement3.GetInt16(5172) * 0.01m, + // CosPhiL3 = acActualMeasurement3.GetInt16(5173) * 0.01m, + + // //acActualMeasurement4 + // SumPowerL1 = acActualMeasurement4.GetUInt32(5187) * 1m, // in Watt + // //acActualMeasurement5 + // SumPowerL2 = acActualMeasurement5.GetUInt32(5189) * 1m, // in Watt + // //acActualMeasurement6 + // SumPowerL3 = acActualMeasurement6.GetUInt32(5191) * 1m, // in Watt + // //acActualMeasurement9 + // GridFrequency = acActualMeasurement7.GetInt16(5201) * 0.01m, + + //acActualMeasurement11 + // VoltageIntNtoPE = acActualMeasurement9.GetInt16(5221) * 0.1m, + // VoltageExtNtoPE = acActualMeasurement9.GetInt16(5222) * 0.1m, + + // + // ApparentPowerAcL1 = acActualAcDc3.GetUInt16(5131) * 1m, // in VA + // ApparentPowerAcL2 = acActualAcDc3.GetUInt16(5132) * 1m, // in VA + // ApparentPowerAcL3 = acActualAcDc3.GetUInt16(5133) * 1m, // in VA + + var apparentPowerAcL1 = acActualAcDc3.GetUInt16(5131) * 1m; + var apparentPowerAcL2 = acActualAcDc3.GetUInt16(5132) * 1m; + var apparentPowerAcL3 = acActualAcDc3.GetUInt16(5133) * 1m; + + var powerAcL1 = acActualMeasurement.GetInt16(5141) * 1m; // in Watt + var powerAcL2 = acActualMeasurement.GetInt16(5142) * 1m; // in Watt + var powerAcL3 = acActualMeasurement.GetInt16(5143) * 1m; // in Watt + + var phaseCurrentL1 = acActualMeasurement1.GetUInt16(5151) * 0.01m; + var phaseCurrentL2 = acActualMeasurement1.GetUInt16(5152) * 0.01m; + var phaseCurrentL3 = acActualMeasurement1.GetUInt16(5153) * 0.01m; + + var gridVoltageL1 = acActualMeasurement2.GetUInt16(5161) * 0.1m; + var gridVoltageL2 = acActualMeasurement2.GetUInt16(5162) * 0.1m; + var gridVoltageL3 = acActualMeasurement2.GetUInt16(5163) * 0.1m; + + var gridFrequency = acActualMeasurement7.GetInt16(5201) * 0.01m; + + return new StatusRecord + { + Ac = new Ac3Bus + { + Frequency = gridFrequency, + + L1 = new AcPhase + { + Voltage = gridVoltageL1, + Current = phaseCurrentL1, + Phi = ACos(powerAcL1 / apparentPowerAcL1), // TODO: 2pi + }, + L2 = new AcPhase + { + Voltage = gridVoltageL2, + Current = phaseCurrentL2, + Phi = ACos(powerAcL2 / apparentPowerAcL2), // TODO: 2pi + }, + L3 = new AcPhase + { + Voltage = gridVoltageL3, + Current = phaseCurrentL3, + Phi = ACos(powerAcL3 / apparentPowerAcL3), // TODO: 2pi + } + }, + Dc = new DcBus + { + Current = dcCurrent, + Voltage = dcVoltage, + }, + + MainState = acActualMain.GetInt16(5001).ConvertTo(), + Alarms = alarms, + Warnings = warnings, + GridType = acActualAcDc.GetUInt16(5024).ConvertTo(), + SerialNumber = acSerialNumber.GetInt32(2009).ToString(), // TODO: why tostring ? + NumberOfConnectedSlaves = acActualMain.GetUInt16(5002), + NumberOfConnectedSubSlaves = acActualMain.GetUInt16(5003), + AcDcNominalGridFrequency = acActualAcDc.GetUInt16(5021) * 0.1m, + AcDcNominalGridVoltage = acActualAcDc.GetUInt16(5022), + AcDcActNominalPower = acActualAcDc.GetUInt16(5023), + AcDcPowerLimitingStatusAct = acActualAcDc.GetUInt16(5025), + AcDcDcVoltageReference = acActualAcDc.GetUInt16(5026), // DC link reference + AcDcDcLinkVoltageMinAct = acActualAcDc.GetUInt16(5027), // DC link min voltage + AcDcDcLinkVoltageMaxAct = acActualAcDc.GetUInt16(5028), // DC link max voltage + AcDcDcLinkChargedMinVoltage = acActualAcDc.GetUInt16(5029) * 0.01m, + AcDcStmActCustomer = acActualAcDc2.GetUInt16(5031), //need to check + AcDcOverloadIntegratorStatusL1 = acActualAcDc3.GetUInt16(5134) * 0.1m, + AcDcOverloadIntegratorStatusL2 = acActualAcDc3.GetUInt16(5135) * 0.1m, + AcDcOverloadIntegratorStatusL3 = acActualAcDc3.GetUInt16(5136) * 0.1m, + AcSignedPowerValue = acSetValues.GetInt16(4196) * -1.0m, // this is also used for control + ActualDcLinkVoltageUpperHalf = acActualMeasurement8.GetUInt16(5211), + ActualDcLinkVoltageLowerHalf = acActualMeasurement8.GetUInt16(5212), + ActualDcLinkVoltageUpperHalfExt = acActualMeasurement8.GetUInt16(5213), + ActualDcLinkVoltageLowerHalfExt = acActualMeasurement8.GetUInt16(5214), + VoltageIntNtoPe = acActualMeasurement9.GetInt16(5221) * 0.1m, + VoltageExtNtoPe = acActualMeasurement9.GetInt16(5222) * 0.1m, + InletAirTemperature = acActualTemp.GetInt16(5501) * 0.1m, + + }; + + + + // ( + // Ac: new Ac3Bus + // ( + // new AcPhase(gridVoltageL1,phaseCurrentL1, ACos(powerAcL1/apparentPowerAcL1)), + // new AcPhase(gridVoltageL2,phaseCurrentL2, ACos(powerAcL2/apparentPowerAcL2)), + // new AcPhase(gridVoltageL3,phaseCurrentL3, ACos(powerAcL3/apparentPowerAcL3)), + // gridFrequency // Gird Frequency + // ), + // Dc: new DcConnection(dcVoltage, dcCurrent), + // + // SerialNumber : acSerialNumber.GetInt32(2009).ToString(), + // + // // acActualMainValues + // MainState : acActualMain.GetInt16(5001).ConvertTo(), + // NumberOfConnectedSlaves : acActualMain.GetUInt16(5002), + // NumberOfConnectedSubSlaves : acActualMain.GetUInt16(5003), + // + // //acActualAcDc + // AcDcNominalGridFrequency : acActualAcDc.GetUInt16(5021) * 0.1m, + // AcDcNominalGridVoltage : acActualAcDc.GetUInt16(5022), + // AcDcActNominalPower : acActualAcDc.GetUInt16(5023), + // AcDcActiveGridType : acActualAcDc.GetUInt16(5024).ConvertTo(), + // AcDcPowerLimitingStatusAct : acActualAcDc.GetUInt16(5025), + // AcDcDcVoltageReference : acActualAcDc.GetUInt16(5026), // DC link reference + // AcDcDcLinkVoltageMinAct : acActualAcDc.GetUInt16(5027), // DC link min voltage + // AcDcDcLinkVoltageMaxAct : acActualAcDc.GetUInt16(5028), // DC link max voltage + // AcDcDcLinkChargedMinVoltage : acActualAcDc.GetUInt16(5029) * 0.01m, + // + // //ac Actual AcDc 2 + // AcDcStmActCustomer : acActualAcDc2.GetUInt16(5031), //need to check + // AcDcOverloadIntegratorStatusL1 : acActualAcDc3.GetUInt16(5134) * 0.1m, + // AcDcOverloadIntegratorStatusL2 : acActualAcDc3.GetUInt16(5135) * 0.1m, + // AcDcOverloadIntegratorStatusL3 : acActualAcDc3.GetUInt16(5136) * 0.1m, + // AcSignedPowerValue : acSetValues.GetInt16(4196) * -1.0m, // this is also used for control + // + // //acActualMeasurement10 + // ActualDcLinkVoltageUpperHalf : acActualMeasurement8.GetUInt16(5211), + // ActualDcLinkVoltageLowerHalf : acActualMeasurement8.GetUInt16(5212), + // ActualDcLinkVoltageUpperHalfExt : acActualMeasurement8.GetUInt16(5213), + // ActualDcLinkVoltageLowerHalfExt : acActualMeasurement8.GetUInt16(5214), + // + // VoltageIntNtoPe : acActualMeasurement9.GetInt16(5221) * 0.1m, + // VoltageExtNtoPe : acActualMeasurement9.GetInt16(5222) * 0.1m, + // //acActualTemp + // InletAirTemperature : acActualTemp.GetInt16(5501) * 0.1m, + // + // Warnings : warnings, + // Alarms : alarms + // ); + } +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/SystemControl/SystemControlRegisters.cs b/csharp/Lib/Devices/Trumpf/SystemControl/SystemControlRegisters.cs new file mode 100644 index 000000000..6ab3817f2 --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/SystemControl/SystemControlRegisters.cs @@ -0,0 +1,83 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.SystemControl; + +public static class SystemControlRegisters +{ + + // TODO + + // public const UInt16 Date = 1001; + // public const UInt16 Time = 1003; + // public const UInt16 IpAddress = 1005; + // public const UInt16 Subnet = 1007; + // public const UInt16 Gateway = 1009; + // public const UInt16 ResetParamToDefault = 1011; + // public const UInt16 CommunicationTimeout = 1017; + // public const UInt16 RestartFlag = 1018; + // public const UInt16 ConnectedSystemConfig = 1019; + // public const UInt16 UpdateSwTrigger = 1027; + // public const UInt16 AutomaticSwUpdate = 1028; + // public const UInt16 CustomerValuesSaveReset = 1029; + // public const UInt16 SerialNumberSystemControl = 2001; + // public const UInt16 SerialNumberAcDc = 2009; + // public const UInt16 IntegrationLevel = 2051; + // public const UInt16 IlBuildnumber = 2052; + // public const UInt16 PowerStageConfig = 4001; + // public const UInt16 SetValueConfig = 4002; + // public const UInt16 ResetsAlarmAndWarning = 4003; + // public const UInt16 PreChargeDcLinkConfigR = 4006; + // public const UInt16 ReferenceFrameConvention = 4007; + // public const UInt16 SlaveAddress = 4008; + // public const UInt16 ErrorHandlingPolicy = 4009; + // public const UInt16 GridType = 4010; + // public const UInt16 SubSlaveAddress = 4011; + // public const UInt16 ModbusSlaveId = 4012; + // public const UInt16 SubSlaveErrorPolicy = 4013; + // public const UInt16 SignedPowerNominalValue = 4196; + // public const UInt16 SignedPowerSetValueL1 = 4197; + // public const UInt16 SignedPowerSetValueL2 = 4198; + // public const UInt16 SignedPowerSetValueL3 = 4199; + // public const UInt16 PowerSetValue = 4200; + // public const UInt16 PowerSetValueL1 = 4201; + // public const UInt16 PowerSetValueL2 = 4202; + // public const UInt16 PowerSetValueL3 = 4203; + // public const UInt16 MaximumGridCurrentRmsL1 = 4204; + // public const UInt16 MaximumGridCurrentRmsL2 = 4205; + // public const UInt16 MaximumGridCurrentRmsL3 = 4206; + // public const UInt16 CosPhiSetValueL1 = 4207; + // public const UInt16 CosPhiSetValueL2 = 4208; + // public const UInt16 CosPhiSetValueL3 = 4209; + // public const UInt16 PhaseL1IsCapacitive = 4214; // True = Capacitive, false = Inductive + // public const UInt16 PhaseL2IsCapacitive = 4215; // True = Capacitive, false = Inductive + // public const UInt16 PhaseL3IsCapacitive = 4216; // True = Capacitive, false = Inductive + // public const UInt16 PhasesAreCapacitive = 4217; // True = Capacitive, false = Inductive + // public const UInt16 SetPointCosPhi = 4218; + // public const UInt16 SetPointSinPhi = 4219; + // public const UInt16 SetPointSinPhiL1 = 4220; + // public const UInt16 SetPointSinPhiL2 = 4221; + // public const UInt16 SetPointSinPhiL3 = 4222; + // public const UInt16 FrequencyOffsetIm = 4223; //Im: Island mode + // public const UInt16 VoltageAdjustmentFactorIm = 4224; //Im: Island mode + // public const UInt16 PreChargeDcLinkVoltage = 4226; + // public const UInt16 MaxPeakCurrentVoltageControlL1 = 4227; + // public const UInt16 MaxPeakCurrentVoltageControlL2 = 4228; + // public const UInt16 MaxPeakCurrentVoltageControlL3 = 4229; + // public const UInt16 GridFormingMode = 4230; + // public const UInt16 DcLinkReferenceVoltage = 4231; + // public const UInt16 DcLinkMinVoltage = 4232; + // public const UInt16 DcLinkMaxVoltage = 4233; + // public const UInt16 AcDcDcVoltageRefUs = 4234; + // public const UInt16 AcDcMinDcLinkVoltageUs = 4235; + // public const UInt16 AcDcMaxDcLinkVoltageUs = 4236; + // // public const UInt16 FrequencySlopeIslandMode = 4237, // Function fN = f(active grid-power) of droop control + // // public const UInt16 VoltageSlopeIslandMode = 4238, // VN = f(reactive grid power) of droop control in island operation. + // public const UInt16 AcDcGcBypassMode = 4281; + // public const UInt16 AcDcGcPMaxThresholdPercent = 4282; // res + // public const UInt16 AcDcGcStartupRampEnable = 4283; + // public const UInt16 DcConfigModule = 4301; // 0 = DC module is off, battery voltage can be measured + // // 1 = DC module is active (DC link voltage control) + // // 2 = DC module is active(current source mode orin DC droop mode) + // public const UInt16 DcDcPowerDistribution = 4304; + // public const UInt16 AcDcDistributionMode = 4307; +} + + diff --git a/csharp/Lib/Devices/Trumpf/TruConvert/MainState.cs b/csharp/Lib/Devices/Trumpf/TruConvert/MainState.cs index 48d457b64..a4cfa89e5 100644 --- a/csharp/Lib/Devices/Trumpf/TruConvert/MainState.cs +++ b/csharp/Lib/Devices/Trumpf/TruConvert/MainState.cs @@ -2,9 +2,9 @@ namespace InnovEnergy.Lib.Devices.Trumpf.TruConvert; public enum MainState : UInt16 { - PowerUp = 0, - Alarm = 1, - Idle = 2, - Operation = 3, + PowerUp = 0, + Alarm = 1, + Idle = 2, + Operation = 3, Maintenance = 4, } diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/AcEnums.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/AcEnums.cs deleted file mode 100644 index 7337409bc..000000000 --- a/csharp/Lib/Devices/Trumpf/TruConvertAc/AcEnums.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; - -public enum AcDcGridType : UInt16 -{ - GridTied400V50Hz = 0, // grid-tied, 400V, 50Hz - GridTied480V60Hz = 1, // grid-tied, 480V, 60Hz - Island400V50Hz = 2, // island mode, 400V, 50Hz - Island480V60Hz = 3, // island mode, 480V, 60Hz - GridTied380V60Hz = 4, // grid-tied, 380V, 60Hz -} - -public enum PreChargeDcLinkConfig : UInt16 -{ - External = 0, // device waits for external precharge of DC link - Internal = 1, // device precharges external DC link to necessary start-up voltage - - InternalWithDc = - 2, // behaviour similar to 1 with additional support of DC submodules (necessary for island operation) - - InternalWithWait = - 3 // device precharges external DC link to necessary start-up voltage and waits until PrechargeDcLinkConfig gets set back to 1 or 2 -} - -public enum AcErrorPolicy : UInt16 -{ - Relaxed = 0, // 0 = relaxed (System keeps running even if some slaves are in error state.) - Strict = 1, // 1 = strict (System shuts down as soon as one component is in error state.) -} - -public enum SymmetricAcOperationMode : UInt16 -{ - //Configuration AC set values for phases L1 - L3 - Asymmetric = 0, - Symmetric = 1, -} - -public enum PowerFactorConvention : UInt16 -{ - Producer = 0, // 0 = producer reference frame - Consumer = 1, // 1 = consumer reference frame -} - -public enum SubSlavesErrorPolicy : UInt16 -{ - Strict = 0, // (AC-DC module switches to error state if at least one submodules is in error state - Relaxed = 1, // (AC-DC module switches to error state if all submodules are in error state.) - Off = 2, // (If possible AC-DC module continues operation even if all submodules are in error state. -} - -public enum DcStageConfiguration : UInt16 -{ - Off = 0, // DC module is off, power electronic circuit is deactivated, battery voltage can be measured. - Active = 1, // DC module is active and the power distribution according to parameters 4303 is active. - ActiveIndependent = 2, // DC module is active and operates independent from the AC module. The battery current set point from register 4500 is getting applied. -} - -public enum AcDcDistributionMode : UInt16 -{ - Power = 0, // power distribution - Current = 1, // current distribution - Auto = 2, // auto -} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/Doc/TRUMPF_Manual_TruConvert_AC3025.pdf b/csharp/Lib/Devices/Trumpf/TruConvertAc/Doc/TRUMPF_Manual_TruConvert_AC3025.pdf new file mode 100644 index 000000000..88a523546 Binary files /dev/null and b/csharp/Lib/Devices/Trumpf/TruConvertAc/Doc/TRUMPF_Manual_TruConvert_AC3025.pdf differ diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/AcDcDistributionMode.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/AcDcDistributionMode.cs new file mode 100644 index 000000000..80f6f625c --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/AcDcDistributionMode.cs @@ -0,0 +1,8 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; + +public enum AcDcDistributionMode : UInt16 +{ + Power = 0, // power distribution + Current = 1, // current distribution + Auto = 2, // auto +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/AcDcGridType.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/AcDcGridType.cs new file mode 100644 index 000000000..cbb766adf --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/AcDcGridType.cs @@ -0,0 +1,10 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; + +public enum AcDcGridType : UInt16 +{ + GridTied400V50Hz = 0, // grid-tied, 400V, 50Hz + GridTied480V60Hz = 1, // grid-tied, 480V, 60Hz + Island400V50Hz = 2, // island mode, 400V, 50Hz + Island480V60Hz = 3, // island mode, 480V, 60Hz + GridTied380V60Hz = 4, // grid-tied, 380V, 60Hz +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/AcErrorPolicy.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/AcErrorPolicy.cs new file mode 100644 index 000000000..8dd96d128 --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/AcErrorPolicy.cs @@ -0,0 +1,7 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; + +public enum AcErrorPolicy : UInt16 +{ + Relaxed = 0, // 0 = relaxed (System keeps running even if some slaves are in error state.) + Strict = 1, // 1 = strict (System shuts down as soon as one component is in error state.) +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/DcStageConfiguration.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/DcStageConfiguration.cs new file mode 100644 index 000000000..32ee16596 --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/DcStageConfiguration.cs @@ -0,0 +1,8 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; + +public enum DcStageConfiguration : UInt16 +{ + Off = 0, // DC module is off, power electronic circuit is deactivated, battery voltage can be measured. + Active = 1, // DC module is active and the power distribution according to parameters 4303 is active. + ActiveIndependent = 2, // DC module is active and operates independent from the AC module. The battery current set point from register 4500 is getting applied. +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/PowerFactorConvention.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/PowerFactorConvention.cs new file mode 100644 index 000000000..cfdaec558 --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/PowerFactorConvention.cs @@ -0,0 +1,7 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; + +public enum PowerFactorConvention : UInt16 +{ + Producer = 0, // 0 = producer reference frame + Consumer = 1, // 1 = consumer reference frame +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/PreChargeDcLinkConfig.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/PreChargeDcLinkConfig.cs new file mode 100644 index 000000000..206c656fd --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/PreChargeDcLinkConfig.cs @@ -0,0 +1,9 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; + +public enum PreChargeDcLinkConfig : UInt16 +{ + External = 0, // device waits for external precharge of DC link + Internal = 1, // device precharges external DC link to necessary start-up voltage + InternalWithDc = 2, // behaviour similar to 1 with additional support of DC submodules (necessary for island operation) + InternalWithWait = 3 // device precharges external DC link to necessary start-up voltage and waits until PrechargeDcLinkConfig gets set back to 1 or 2 +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/SubSlavesErrorPolicy.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/SubSlavesErrorPolicy.cs new file mode 100644 index 000000000..190072c0c --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/SubSlavesErrorPolicy.cs @@ -0,0 +1,8 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; + +public enum SubSlavesErrorPolicy : UInt16 +{ + Strict = 0, // (AC-DC module switches to error state if at least one submodules is in error state + Relaxed = 1, // (AC-DC module switches to error state if all submodules are in error state.) + Off = 2, // (If possible AC-DC module continues operation even if all submodules are in error state. +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/SymmetricAcOperationMode.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/SymmetricAcOperationMode.cs new file mode 100644 index 000000000..df9d01eca --- /dev/null +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/Enums/SymmetricAcOperationMode.cs @@ -0,0 +1,8 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; + +public enum SymmetricAcOperationMode : UInt16 +{ + //Configuration AC set values for phases L1 - L3 + Asymmetric = 0, + Symmetric = 1, +} \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj index 3a70b12a0..36322cc01 100644 --- a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj @@ -1,8 +1,6 @@ - - diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcControl.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcControl.cs index 74fb87c3a..9844f5f5b 100644 --- a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcControl.cs +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcControl.cs @@ -1,4 +1,5 @@ using InnovEnergy.Lib.Devices.Trumpf.TruConvert; +using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs index 66cc153a7..f964f0441 100644 --- a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using InnovEnergy.Lib.Devices.Trumpf.TruConvert; +using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Units.Composite; @@ -139,22 +140,22 @@ public class TruConvertAcDevice var acSetValues = ModbusTcpClient.ReadInputRegisters(4196, 1); var warnings = Enumerable - .Range(2404, 20) - .Select(n => acWarningValues.GetUInt16((UInt16)n).ConvertTo()) - .ToArray(); + .Range(2404, 20) + .Select(n => acWarningValues.GetUInt16((UInt16)n).ConvertTo()) + .ToArray(); var alarms = Enumerable - .Range(2811, 20) - .Select(n => acAlarmValues.GetUInt16((UInt16)n).ConvertTo()) - .Where(m => m != AlarmMessage.NoAlarm) - .ToArray(); + .Range(2811, 20) + .Select(n => acAlarmValues.GetUInt16((UInt16)n).ConvertTo()) + .Where(m => m != AlarmMessage.NoAlarm) + .ToArray(); var dcPower = acActualMeasurement.GetInt16(5141) * 1m + acActualMeasurement.GetInt16(5142) * 1m + acActualMeasurement.GetInt16(5143) * 1m; var dcVoltage = acActualMeasurement8.GetUInt16(5214) + acActualMeasurement8.GetUInt16(5213); var dcCurrent = dcVoltage != 0m - ? dcPower / dcVoltage - : 0m; + ? dcPower / dcVoltage + : 0m; // //acActualMeasurement @@ -212,56 +213,118 @@ public class TruConvertAcDevice var gridVoltageL3 = acActualMeasurement2.GetUInt16(5163) * 0.1m; var gridFrequency = acActualMeasurement7.GetInt16(5201) * 0.01m; - + return new TruConvertAcStatus - ( - Ac: new Ac3Bus - ( - new AcPhase(gridVoltageL1,phaseCurrentL1, ACos(powerAcL1/apparentPowerAcL1)), - new AcPhase(gridVoltageL2,phaseCurrentL2, ACos(powerAcL2/apparentPowerAcL2)), - new AcPhase(gridVoltageL3,phaseCurrentL3, ACos(powerAcL3/apparentPowerAcL3)), - gridFrequency // Gird Frequency - ), - Dc: new DcConnection(dcVoltage, dcCurrent), + { + Ac = new Ac3Bus + { + Frequency = gridFrequency, - SerialNumber : acSerialNumber.GetInt32(2009).ToString(), + L1 = new AcPhase + { + Voltage = gridVoltageL1, + Current = phaseCurrentL1, + Phi = ACos(powerAcL1 / apparentPowerAcL1), // TODO: 2pi + }, + L2 = new AcPhase + { + Voltage = gridVoltageL2, + Current = phaseCurrentL2, + Phi = ACos(powerAcL2 / apparentPowerAcL2), // TODO: 2pi + }, + L3 = new AcPhase + { + Voltage = gridVoltageL3, + Current = phaseCurrentL3, + Phi = ACos(powerAcL3 / apparentPowerAcL3), // TODO: 2pi + } + }, + Dc = new DcBus + { + Current = dcCurrent, + Voltage = dcVoltage, + }, - // acActualMainValues - MainState : acActualMain.GetInt16(5001).ConvertTo(), - NumberOfConnectedSlaves : acActualMain.GetUInt16(5002), - NumberOfConnectedSubSlaves : acActualMain.GetUInt16(5003), + MainState = acActualMain.GetInt16(5001).ConvertTo(), + Alarms = alarms, + Warnings = warnings, + GridType = acActualAcDc.GetUInt16(5024).ConvertTo(), + SerialNumber = acSerialNumber.GetInt32(2009).ToString(), // TODO: why tostring ? + NumberOfConnectedSlaves = acActualMain.GetUInt16(5002), + NumberOfConnectedSubSlaves = acActualMain.GetUInt16(5003), + AcDcNominalGridFrequency = acActualAcDc.GetUInt16(5021) * 0.1m, + AcDcNominalGridVoltage = acActualAcDc.GetUInt16(5022), + AcDcActNominalPower = acActualAcDc.GetUInt16(5023), + AcDcPowerLimitingStatusAct = acActualAcDc.GetUInt16(5025), + AcDcDcVoltageReference = acActualAcDc.GetUInt16(5026), // DC link reference + AcDcDcLinkVoltageMinAct = acActualAcDc.GetUInt16(5027), // DC link min voltage + AcDcDcLinkVoltageMaxAct = acActualAcDc.GetUInt16(5028), // DC link max voltage + AcDcDcLinkChargedMinVoltage = acActualAcDc.GetUInt16(5029) * 0.01m, + AcDcStmActCustomer = acActualAcDc2.GetUInt16(5031), //need to check + AcDcOverloadIntegratorStatusL1 = acActualAcDc3.GetUInt16(5134) * 0.1m, + AcDcOverloadIntegratorStatusL2 = acActualAcDc3.GetUInt16(5135) * 0.1m, + AcDcOverloadIntegratorStatusL3 = acActualAcDc3.GetUInt16(5136) * 0.1m, + AcSignedPowerValue = acSetValues.GetInt16(4196) * -1.0m, // this is also used for control + ActualDcLinkVoltageUpperHalf = acActualMeasurement8.GetUInt16(5211), + ActualDcLinkVoltageLowerHalf = acActualMeasurement8.GetUInt16(5212), + ActualDcLinkVoltageUpperHalfExt = acActualMeasurement8.GetUInt16(5213), + ActualDcLinkVoltageLowerHalfExt = acActualMeasurement8.GetUInt16(5214), + VoltageIntNtoPe = acActualMeasurement9.GetInt16(5221) * 0.1m, + VoltageExtNtoPe = acActualMeasurement9.GetInt16(5222) * 0.1m, + InletAirTemperature = acActualTemp.GetInt16(5501) * 0.1m, - //acActualAcDc - AcDcNominalGridFrequency : acActualAcDc.GetUInt16(5021) * 0.1m, - AcDcNominalGridVoltage : acActualAcDc.GetUInt16(5022), - AcDcActNominalPower : acActualAcDc.GetUInt16(5023), - AcDcActiveGridType : acActualAcDc.GetUInt16(5024).ConvertTo(), - AcDcPowerLimitingStatusAct : acActualAcDc.GetUInt16(5025), - AcDcDcVoltageReference : acActualAcDc.GetUInt16(5026), // DC link reference - AcDcDcLinkVoltageMinAct : acActualAcDc.GetUInt16(5027), // DC link min voltage - AcDcDcLinkVoltageMaxAct : acActualAcDc.GetUInt16(5028), // DC link max voltage - AcDcDcLinkChargedMinVoltage : acActualAcDc.GetUInt16(5029) * 0.01m, - - //ac Actual AcDc 2 - AcDcStmActCustomer : acActualAcDc2.GetUInt16(5031), //need to check - AcDcOverloadIntegratorStatusL1 : acActualAcDc3.GetUInt16(5134) * 0.1m, - AcDcOverloadIntegratorStatusL2 : acActualAcDc3.GetUInt16(5135) * 0.1m, - AcDcOverloadIntegratorStatusL3 : acActualAcDc3.GetUInt16(5136) * 0.1m, - AcSignedPowerValue : acSetValues.GetInt16(4196) * -1.0m, // this is also used for control - - //acActualMeasurement10 - ActualDcLinkVoltageUpperHalf : acActualMeasurement8.GetUInt16(5211), - ActualDcLinkVoltageLowerHalf : acActualMeasurement8.GetUInt16(5212), - ActualDcLinkVoltageUpperHalfExt : acActualMeasurement8.GetUInt16(5213), - ActualDcLinkVoltageLowerHalfExt : acActualMeasurement8.GetUInt16(5214), + }; - VoltageIntNtoPe : acActualMeasurement9.GetInt16(5221) * 0.1m, - VoltageExtNtoPe : acActualMeasurement9.GetInt16(5222) * 0.1m, - //acActualTemp - InletAirTemperature : acActualTemp.GetInt16(5501) * 0.1m, - - Warnings : warnings, - Alarms : alarms - ); + + + // ( + // Ac: new Ac3Bus + // ( + // new AcPhase(gridVoltageL1,phaseCurrentL1, ACos(powerAcL1/apparentPowerAcL1)), + // new AcPhase(gridVoltageL2,phaseCurrentL2, ACos(powerAcL2/apparentPowerAcL2)), + // new AcPhase(gridVoltageL3,phaseCurrentL3, ACos(powerAcL3/apparentPowerAcL3)), + // gridFrequency // Gird Frequency + // ), + // Dc: new DcConnection(dcVoltage, dcCurrent), + // + // SerialNumber : acSerialNumber.GetInt32(2009).ToString(), + // + // // acActualMainValues + // MainState : acActualMain.GetInt16(5001).ConvertTo(), + // NumberOfConnectedSlaves : acActualMain.GetUInt16(5002), + // NumberOfConnectedSubSlaves : acActualMain.GetUInt16(5003), + // + // //acActualAcDc + // AcDcNominalGridFrequency : acActualAcDc.GetUInt16(5021) * 0.1m, + // AcDcNominalGridVoltage : acActualAcDc.GetUInt16(5022), + // AcDcActNominalPower : acActualAcDc.GetUInt16(5023), + // AcDcActiveGridType : acActualAcDc.GetUInt16(5024).ConvertTo(), + // AcDcPowerLimitingStatusAct : acActualAcDc.GetUInt16(5025), + // AcDcDcVoltageReference : acActualAcDc.GetUInt16(5026), // DC link reference + // AcDcDcLinkVoltageMinAct : acActualAcDc.GetUInt16(5027), // DC link min voltage + // AcDcDcLinkVoltageMaxAct : acActualAcDc.GetUInt16(5028), // DC link max voltage + // AcDcDcLinkChargedMinVoltage : acActualAcDc.GetUInt16(5029) * 0.01m, + // + // //ac Actual AcDc 2 + // AcDcStmActCustomer : acActualAcDc2.GetUInt16(5031), //need to check + // AcDcOverloadIntegratorStatusL1 : acActualAcDc3.GetUInt16(5134) * 0.1m, + // AcDcOverloadIntegratorStatusL2 : acActualAcDc3.GetUInt16(5135) * 0.1m, + // AcDcOverloadIntegratorStatusL3 : acActualAcDc3.GetUInt16(5136) * 0.1m, + // AcSignedPowerValue : acSetValues.GetInt16(4196) * -1.0m, // this is also used for control + // + // //acActualMeasurement10 + // ActualDcLinkVoltageUpperHalf : acActualMeasurement8.GetUInt16(5211), + // ActualDcLinkVoltageLowerHalf : acActualMeasurement8.GetUInt16(5212), + // ActualDcLinkVoltageUpperHalfExt : acActualMeasurement8.GetUInt16(5213), + // ActualDcLinkVoltageLowerHalfExt : acActualMeasurement8.GetUInt16(5214), + // + // VoltageIntNtoPe : acActualMeasurement9.GetInt16(5221) * 0.1m, + // VoltageExtNtoPe : acActualMeasurement9.GetInt16(5222) * 0.1m, + // //acActualTemp + // InletAirTemperature : acActualTemp.GetInt16(5501) * 0.1m, + // + // Warnings : warnings, + // Alarms : alarms + // ); } } \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcStatus.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcStatus.cs index 4747e0579..b605d9ecc 100644 --- a/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcStatus.cs +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/TruConvertAcStatus.cs @@ -1,43 +1,45 @@ using InnovEnergy.Lib.Devices.Trumpf.TruConvert; -using InnovEnergy.Lib.StatusApi.Connections; -using InnovEnergy.Lib.Units.Composite; +using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums; +using InnovEnergy.Lib.StatusApi; +using InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; using AlarmMessages = IReadOnlyList; using WarningMessages = IReadOnlyList; -public record TruConvertAcStatus -( - Ac3Bus Ac, - DcConnection Dc, - String SerialNumber, - MainState MainState, - UInt16 NumberOfConnectedSlaves, - UInt16 NumberOfConnectedSubSlaves, - Decimal AcDcNominalGridFrequency, - Decimal AcDcNominalGridVoltage, - Decimal AcDcActNominalPower, - AcDcGridType AcDcActiveGridType, - Decimal AcDcPowerLimitingStatusAct, - Decimal AcDcDcVoltageReference, - Decimal AcDcDcLinkVoltageMinAct, - Decimal AcDcDcLinkVoltageMaxAct, - Decimal AcDcDcLinkChargedMinVoltage, - Decimal AcDcStmActCustomer, - Decimal AcDcOverloadIntegratorStatusL1, - Decimal AcDcOverloadIntegratorStatusL2, - Decimal AcDcOverloadIntegratorStatusL3, - Decimal AcSignedPowerValue, - Decimal ActualDcLinkVoltageUpperHalf, - Decimal ActualDcLinkVoltageLowerHalf, - Decimal ActualDcLinkVoltageUpperHalfExt, - Decimal ActualDcLinkVoltageLowerHalfExt, - Decimal VoltageIntNtoPe, - Decimal VoltageExtNtoPe, - Decimal InletAirTemperature, - WarningMessages Warnings, - AlarmMessages Alarms -) : ThreePhaseInverter(Ac, Dc) + +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS8618 + + +public record TruConvertAcStatus : ThreePhaseInverterStatus { -} \ No newline at end of file + public MainState MainState { get; init; } + public String SerialNumber { get; init; } + public AcDcGridType GridType { get; init; } + public WarningMessages Warnings { get; init; } + public AlarmMessages Alarms { get; init; } + public Decimal NumberOfConnectedSlaves { get; init; } + public Decimal NumberOfConnectedSubSlaves { get; init; } + public Frequency AcDcNominalGridFrequency { get; init; } + public Voltage AcDcNominalGridVoltage { get; init; } + public Power AcDcActNominalPower { get; init; } + public Decimal AcDcPowerLimitingStatusAct { get; init; } // TODO: enum + public Voltage AcDcDcVoltageReference { get; init; } + public Voltage AcDcDcLinkVoltageMinAct { get; init; } + public Voltage AcDcDcLinkVoltageMaxAct { get; init; } + public Voltage AcDcDcLinkChargedMinVoltage { get; init; } + public Decimal AcDcStmActCustomer { get; init; } + public Decimal AcDcOverloadIntegratorStatusL1 { get; init; } + public Decimal AcDcOverloadIntegratorStatusL2 { get; init; } + public Decimal AcDcOverloadIntegratorStatusL3 { get; init; } + public Power AcSignedPowerValue { get; init; } + public Voltage ActualDcLinkVoltageUpperHalf { get; init; } + public Voltage ActualDcLinkVoltageLowerHalf { get; init; } + public Voltage ActualDcLinkVoltageUpperHalfExt { get; init; } + public Voltage ActualDcLinkVoltageLowerHalfExt { get; init; } + public Voltage VoltageIntNtoPe { get; init; } + public Voltage VoltageExtNtoPe { get; init; } + public Temperature InletAirTemperature { get; init; } +} diff --git a/csharp/Lib/Devices/Trumpf/TruConvertAc/WarningMessage.cs b/csharp/Lib/Devices/Trumpf/TruConvertAc/WarningMessage.cs index 2fb74b947..4ceffc228 100644 --- a/csharp/Lib/Devices/Trumpf/TruConvertAc/WarningMessage.cs +++ b/csharp/Lib/Devices/Trumpf/TruConvertAc/WarningMessage.cs @@ -8,17 +8,17 @@ namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; public enum WarningMessage { - ERR_WARN_FAN =10500, //AC-DC module warning - ERR_WARN_I_OFFSET =10503, //AC-DC module warning - ERR_WARN_VG_OFFSET =10504, //AC-DC module warning - ERR_WARN_VC_OFFSET =10505, //AC-DC module warning - ERR_WARN_DC_OFFSET =10506, //AC-DC module warning - ERR_WARN_NTC_PROTECT =10507, //DC-link circuit need more time for cool down - ERR_WARN_AIR_TEMP =10508, //Overtemperature inlet air: power is derated - SurgeDetected =10509, //Temporary overvoltage in grid measurement detected (surge) - ERR_WARN_TEMP_DERATING =11021, //Temperature derating active - ERR_WARN_OVERLOAD =11022, //Overload handling is active - ERR_WARN_RUNTIME_EEPROM =11023, //AC-DC module warning - ERR_WARN_OVERCURRENT =11024 //Overcurrent handling is active + ERR_WARN_FAN = 10500, //AC-DC module warning + ERR_WARN_I_OFFSET = 10503, //AC-DC module warning + ERR_WARN_VG_OFFSET = 10504, //AC-DC module warning + ERR_WARN_VC_OFFSET = 10505, //AC-DC module warning + ERR_WARN_DC_OFFSET = 10506, //AC-DC module warning + ERR_WARN_NTC_PROTECT = 10507, //DC-link circuit need more time for cool down + ERR_WARN_AIR_TEMP = 10508, //Overtemperature inlet air: power is derated + SurgeDetected = 10509, //Temporary overvoltage in grid measurement detected (surge) + ERR_WARN_TEMP_DERATING = 11021, //Temperature derating active + ERR_WARN_OVERLOAD = 11022, //Overload handling is active + ERR_WARN_RUNTIME_EEPROM = 11023, //AC-DC module warning + ERR_WARN_OVERCURRENT = 11024 //Overcurrent handling is active } diff --git a/csharp/Lib/Devices/Trumpf/TruConvertDc/DcEnums.cs b/csharp/Lib/Devices/Trumpf/TruConvertDc/DcCurrentLimitState.cs similarity index 100% rename from csharp/Lib/Devices/Trumpf/TruConvertDc/DcEnums.cs rename to csharp/Lib/Devices/Trumpf/TruConvertDc/DcCurrentLimitState.cs diff --git a/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcDevice.cs b/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcDevice.cs index 89cd675ce..b7d0bc201 100644 --- a/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcDevice.cs +++ b/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcDevice.cs @@ -2,7 +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.Units.Composite; using InnovEnergy.Lib.Utils; using static InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.DcControlRegisters; @@ -138,27 +138,31 @@ public class TruConvertDcDevice var dcCurrent = dcLinkVoltage != 0m ? dcPower / dcLinkVoltage : 0m; return new TruConvertDcStatus - ( + { + Left = new DcBus() + { + Current = dcCurrent, + Voltage = dcLinkVoltage + }, + + Right = new DcBus() + { + Current = dcBatteryValue2.GetInt16(5111), + Voltage =dcBatteryValue.GetUInt16(5101) * 0.1m, + }, - Dc: new DcConnection - ( - dcLinkVoltage, - dcCurrent - ), - - MainState : (MainState)dcPrValMain.GetInt16(5001), - NumberOfConnectedSlaves : dcPrValMain.GetUInt16(5002), - NumberOfConnectedSubSlaves : dcPrValMain.GetUInt16(5003), - BatteryVoltage : dcBatteryValue.GetUInt16(5101) * 0.1m, - BatteryCurrent : dcBatteryValue2.GetInt16(5111), - TotalDcPower : dcBatteryValue3.GetInt32(5114) * 1m, // Resolution is 0.001 (kW) in Tru convert DC doc, but we want it in W - StatusOfCurrentLimiting : dcCurrentLimitState, - OverloadCapacity : dcPrValDcDc2.GetUInt16(5127) * 0.1m, - DcDcInletTemperature : dcTempValue.GetInt16(5511), - Warnings : warnings, - Alarms : alarms, - PowerOperation : dcSetValues.GetBoolean(4001) - ); + MainState = (MainState)dcPrValMain.GetInt16(5001), + NumberOfConnectedSlaves = dcPrValMain.GetUInt16(5002), + NumberOfConnectedSubSlaves = dcPrValMain.GetUInt16(5003), + TotalDcPower = dcBatteryValue3.GetInt32(5114) * 1m, // Resolution is 0.001 (kW) in Tru convert DC doc, but we want it in W + StatusOfCurrentLimiting = dcCurrentLimitState, + OverloadCapacity = dcPrValDcDc2.GetUInt16(5127) * 0.1m, + DcDcInletTemperature = dcTempValue.GetInt16(5511), + Warnings = warnings, + Alarms = alarms, + PowerOperation = dcSetValues.GetBoolean(4001), + + }; } } \ No newline at end of file diff --git a/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcStatus.cs b/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcStatus.cs index bf78b928b..1937849fa 100644 --- a/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcStatus.cs +++ b/csharp/Lib/Devices/Trumpf/TruConvertDc/TruConvertDcStatus.cs @@ -1,3 +1,4 @@ +using InnovEnergy.Lib.Devices.Trumpf.TruConvert; using InnovEnergy.Lib.StatusApi; using InnovEnergy.Lib.Units; using InnovEnergy.Lib.Units.Composite; @@ -9,24 +10,20 @@ using AlarmMessages = IReadOnlyList; using WarningMessages = IReadOnlyList; using DcCurrentLimitStates = IReadOnlyList; -public record TruConvertDcStatus -( - 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 record TruConvertDcStatus : DcDcConverterStatus { - public static TruConvertDcStatus operator |(TruConvertDcStatus left, TruConvertDcStatus right) => OpParallel(left, right); - private static readonly Func OpParallel = Operators.Op("|"); -} \ No newline at end of file + public MainState MainState { get; init; } + public Power TotalDcPower { get; init; } // TODO: necessary? + public DcCurrentLimitStates StatusOfCurrentLimiting { get; init; } + public Decimal OverloadCapacity { get; init; } + public Temperature DcDcInletTemperature { get; init; } + public AlarmMessages Alarms { get; init; } = Array.Empty(); + public WarningMessages Warnings { get; init; } = Array.Empty(); + public Boolean PowerOperation { get; init; } + public Decimal NumberOfConnectedSlaves { get; init; } // TODO: necessary? + public Decimal NumberOfConnectedSubSlaves { get; init; } // TODO: necessary? +} +// { +// public static TruConvertDcStatus operator |(TruConvertDcStatus left, TruConvertDcStatus right) => OpParallel(left, right); +// private static readonly Func OpParallel = Operators.Op("|"); +// } \ No newline at end of file diff --git a/csharp/Lib/Protocols/Modbus/Clients/ModbusClient.cs b/csharp/Lib/Protocols/Modbus/Clients/ModbusClient.cs index c992d0874..0a4ca6948 100644 --- a/csharp/Lib/Protocols/Modbus/Clients/ModbusClient.cs +++ b/csharp/Lib/Protocols/Modbus/Clients/ModbusClient.cs @@ -1,8 +1,6 @@ using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Protocols.Modbus.Conversions; using InnovEnergy.Lib.Protocols.Modbus.Protocol; -using static InnovEnergy.Lib.Protocols.Modbus.Protocol.MultiRegisterEndianness; -using static InnovEnergy.Lib.Protocols.Modbus.Protocol.RegisterIndexing; namespace InnovEnergy.Lib.Protocols.Modbus.Clients; @@ -15,9 +13,7 @@ public abstract class ModbusClient { protected ModbusConnection Connection { get; } protected Byte SlaveId { get; } - protected RegisterIndexing RegisterIndexing { get; } - protected MultiRegisterEndianness Endianness { get; } - + // TODO: add additional functions: coils... @@ -45,19 +41,14 @@ public abstract class ModbusClient } protected ModbusClient(ModbusConnection connection, - Byte slaveId, - RegisterIndexing registerIndexing = OneBased, - MultiRegisterEndianness endianness = LittleEndian) + Byte slaveId) { Connection = connection; SlaveId = slaveId; - RegisterIndexing = registerIndexing; - Endianness = endianness; } public void CloseConnection() => Connection.Close(); - protected UInt16 LogicToWire(UInt16 address) => RegisterIndexing.LogicToSerialized(address); - protected UInt16 SerializedToLogic(UInt16 address) => RegisterIndexing.SerializedToLogic(address); + } diff --git a/csharp/Lib/Protocols/Modbus/Clients/ModbusRtuClient.cs b/csharp/Lib/Protocols/Modbus/Clients/ModbusRtuClient.cs index c49456ab0..24171c847 100644 --- a/csharp/Lib/Protocols/Modbus/Clients/ModbusRtuClient.cs +++ b/csharp/Lib/Protocols/Modbus/Clients/ModbusRtuClient.cs @@ -30,9 +30,7 @@ public class ModbusRtuClient : ModbusClient public override ModbusRegisters ReadInputRegisters(UInt16 readAddress, UInt16 nValues) { - var wireReadAddress = LogicToWire(readAddress); - - var cmd = new ReadInputRegistersCommandFrame(SlaveId, wireReadAddress, nValues); + var cmd = new ReadInputRegistersCommandFrame(SlaveId, readAddress, nValues); var crc = CalcCrc(cmd); // TX @@ -56,9 +54,7 @@ public class ModbusRtuClient : ModbusClient public override ModbusRegisters ReadHoldingRegisters(UInt16 readAddress, UInt16 nValues) { - var wireReadAddress = LogicToWire(readAddress); - - var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, wireReadAddress, nValues); + var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, readAddress, nValues); var crc = CalcCrc(cmd.Data); // TX @@ -86,9 +82,7 @@ public class ModbusRtuClient : ModbusClient public override UInt16 WriteRegisters(UInt16 writeAddress, UInt16s values) { - var wireWriteAddress = LogicToWire(writeAddress); - - var cmd = new WriteRegistersCommandFrame(SlaveId, wireWriteAddress, values); + var cmd = new WriteRegistersCommandFrame(SlaveId, writeAddress, values); var crc = CalcCrc(cmd); var nToRead = cmd.ExpectedResponseSize + CrcSize; @@ -111,13 +105,10 @@ public class ModbusRtuClient : ModbusClient public override ModbusRegisters ReadWriteRegisters(UInt16 readAddress, UInt16 nbToRead, UInt16 writeAddress, UInt16s registersToWrite) { - var wireReadAddress = LogicToWire(readAddress); - var wireWriteAddress = LogicToWire(writeAddress); - var cmd = new ReadWriteRegistersCommandFrame(SlaveId, - wireReadAddress, + readAddress, nbToRead, - wireWriteAddress, + writeAddress, registersToWrite); var crc = CalcCrc(cmd); diff --git a/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs b/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs index 2952d4243..795cb9189 100644 --- a/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs +++ b/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs @@ -1,11 +1,10 @@ using System.Diagnostics; using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Protocols.Modbus.Conversions; -using InnovEnergy.Lib.Protocols.Modbus.Protocol; using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Commands; using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Replies; using InnovEnergy.Lib.Protocols.Modbus.Tcp; -using static InnovEnergy.Lib.Protocols.Modbus.Protocol.MultiRegisterEndianness; + namespace InnovEnergy.Lib.Protocols.Modbus.Clients; @@ -21,21 +20,16 @@ public class ModbusTcpClient : ModbusClient private UInt16 NextId() => unchecked(++_Id); - public ModbusTcpClient(ModbusConnection connection, - Byte slaveId, - RegisterIndexing registerIndexing = RegisterIndexing.OneBased, - MultiRegisterEndianness endianness = LittleEndian) : base(connection, slaveId, registerIndexing, endianness) + public ModbusTcpClient(ModbusConnection connection, Byte slaveId) : base(connection, slaveId) { } public override IReadOnlyList ReadDiscreteInputs(UInt16 readAddress, UInt16 nValues) { - var wireReadAddress = LogicToWire(readAddress); - var id = NextId(); // TODO: check response id - var cmd = new ReadDiscreteInputsCommandFrame(SlaveId, wireReadAddress, nValues); + var cmd = new ReadDiscreteInputsCommandFrame(SlaveId, readAddress, nValues); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -52,10 +46,9 @@ public class ModbusTcpClient : ModbusClient public override ModbusRegisters ReadInputRegisters(UInt16 readAddress, UInt16 nValues) { - var wireReadAddress = LogicToWire(readAddress); var id = NextId(); // TODO: check response id - var cmd = new ReadInputRegistersCommandFrame(SlaveId, wireReadAddress, nValues); + var cmd = new ReadInputRegistersCommandFrame(SlaveId, readAddress, nValues); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -77,10 +70,8 @@ public class ModbusTcpClient : ModbusClient public override ModbusRegisters ReadHoldingRegisters(UInt16 readAddress, UInt16 nValues) { - var wireReadAddress = LogicToWire(readAddress); - var id = NextId(); // TODO: check response id - var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, wireReadAddress, nValues); + var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, readAddress, nValues); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -99,10 +90,8 @@ public class ModbusTcpClient : ModbusClient public override UInt16 WriteMultipleCoils(UInt16 writeAddress, Coils coils) { - var wireWriteAddress = LogicToWire(writeAddress); - - var id = NextId(); // TODO: check response id - var cmd = new WriteCoilsCommandFrame(SlaveId, wireWriteAddress, coils); + var id = NextId(); // TODO: check response id + var cmd = new WriteCoilsCommandFrame(SlaveId, writeAddress, coils); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -120,10 +109,8 @@ public class ModbusTcpClient : ModbusClient public override UInt16 WriteRegisters(UInt16 writeAddress, UInt16s values) { - var wireWriteAddress = LogicToWire(writeAddress); - var id = NextId(); // TODO: check response id - var cmd = new WriteRegistersCommandFrame(SlaveId, wireWriteAddress, values); + var cmd = new WriteRegistersCommandFrame(SlaveId, writeAddress, values); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -142,15 +129,14 @@ public class ModbusTcpClient : ModbusClient public override ModbusRegisters ReadWriteRegisters(UInt16 readAddress, UInt16 nbToRead, UInt16 writeAddress, UInt16s registersToWrite) { - var wireReadAddress = LogicToWire(readAddress); - var wireWriteAddress = LogicToWire(writeAddress); + var id = NextId(); // TODO: check response id var cmd = new ReadWriteRegistersCommandFrame(SlaveId, - wireReadAddress, + readAddress, nbToRead, - wireWriteAddress, + writeAddress, registersToWrite); var hdr = new MbapHeader(id, cmd.Data.Count); diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs index 6db8492b9..6ff463460 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs @@ -1,6 +1,5 @@ using System.Collections; using InnovEnergy.Lib.Utils; -using static InnovEnergy.Lib.Protocols.Modbus.Protocol.MultiRegisterEndianness; namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors; @@ -10,22 +9,11 @@ public struct MbRegisters : IReadOnlyList { private MbWords Words { get; } private UInt16 StartRegister { get; } - private MultiRegisterEndianness Endianness { get; } - public MbRegisters(MbWords words, - UInt16 startRegister, - MultiRegisterEndianness endianness, - RegisterIndexing registerIndexing) + public MbRegisters(MbWords words, UInt16 startRegister) { - Words = words; - Endianness = endianness; - - var start = startRegister - (Int16) registerIndexing; // TODO: check - - if (start < 0) - throw new ArgumentOutOfRangeException(nameof(startRegister)); - - StartRegister = (UInt16)start; + Words = words; + StartRegister = startRegister; } public IEnumerator GetEnumerator() => Words.GetEnumerator(); @@ -74,9 +62,6 @@ public struct MbRegisters : IReadOnlyList var hi = (UInt32) GetUInt16(i); var lo = (UInt32) GetUInt16(++i); - if (Endianness == LittleEndian) - (lo, hi) = (hi, lo); - return hi << 16 | lo; } diff --git a/csharp/Lib/StatusApi/BatteryStatus.cs b/csharp/Lib/StatusApi/BatteryStatus.cs index f8a0124d5..be2c8f0d5 100644 --- a/csharp/Lib/StatusApi/BatteryStatus.cs +++ b/csharp/Lib/StatusApi/BatteryStatus.cs @@ -1,17 +1,15 @@ using InnovEnergy.Lib.StatusApi.Connections; -using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -using T = BatteryStatus; -[OpParallel] -public partial record BatteryStatus : DeviceStatus, IDcConnection +#pragma warning disable CS8618 + +public record BatteryStatus : IDcConnection { public DcBus Dc { get; init; } public Percent Soc { get; init; } public Temperature Temperature { get; init; } -} - \ No newline at end of file +} \ No newline at end of file diff --git a/csharp/Lib/StatusApi/BatteryStatus.generated.cs b/csharp/Lib/StatusApi/BatteryStatus.generated.cs deleted file mode 100644 index d5f549056..000000000 --- a/csharp/Lib/StatusApi/BatteryStatus.generated.cs +++ /dev/null @@ -1,16 +0,0 @@ -#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/CombinedStatus.cs b/csharp/Lib/StatusApi/CombinedStatus.cs new file mode 100644 index 000000000..132f0c573 --- /dev/null +++ b/csharp/Lib/StatusApi/CombinedStatus.cs @@ -0,0 +1,12 @@ +namespace InnovEnergy.Lib.StatusApi; + +#pragma warning disable CS8618 + +public record CombinedStatus +{ + public T Combined { get; init; } + public IReadOnlyList Children { get; init; } + + public Boolean Available => Children.Any(); + +} \ No newline at end of file diff --git a/csharp/Lib/StatusApi/DcDcConverterStatus.cs b/csharp/Lib/StatusApi/DcDcConverterStatus.cs index 21941d5e6..9a7e1c2d1 100644 --- a/csharp/Lib/StatusApi/DcDcConverterStatus.cs +++ b/csharp/Lib/StatusApi/DcDcConverterStatus.cs @@ -1,10 +1,10 @@ -using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -[OpParallel] -public partial record DcDcConverterStatus : DeviceStatus +#pragma warning disable CS8618 + +public record DcDcConverterStatus { public DcBus Left { get; init; } public DcBus Right { get; init; } diff --git a/csharp/Lib/StatusApi/DcDcConverterStatus.generated.cs b/csharp/Lib/StatusApi/DcDcConverterStatus.generated.cs deleted file mode 100644 index 32a133a8a..000000000 --- a/csharp/Lib/StatusApi/DcDcConverterStatus.generated.cs +++ /dev/null @@ -1,16 +0,0 @@ -#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/DeviceStatus.cs b/csharp/Lib/StatusApi/DeviceStatus.cs deleted file mode 100644 index 380007d85..000000000 --- a/csharp/Lib/StatusApi/DeviceStatus.cs +++ /dev/null @@ -1,52 +0,0 @@ -using InnovEnergy.Lib.Utils; - -namespace InnovEnergy.Lib.StatusApi; - -public abstract record DeviceStatus -{ - public String DeviceType => GetType() - .Unfold(t => t.BaseType) - .First(t => t.IsAbstract) - .Name - .Replace("Status", ""); -} - - -// public static class Program -// { -// public static void Main(string[] args) -// { -// var x = new ThreePhasePvInverterStatus -// { -// Ac = new() -// { -// Frequency = 50, -// L1 = new() -// { -// Current = 10, -// Voltage = 10, -// Phi = 0, -// }, -// L2 = new() -// { -// Current = 52, -// Voltage = 220, -// Phi = Angle.Pi / 2, -// }, -// L3 = new() -// { -// Current = 158, -// Voltage = 454, -// Phi = Angle.Pi / 3, -// }, -// }, -// Strings = new DcBus[] -// { -// new() { Current = 10, Voltage = 22 }, -// new() { Current = 12, Voltage = 33 }, -// } -// }; -// -// var s = x.ToJson(); -// } -// } \ No newline at end of file diff --git a/csharp/Lib/StatusApi/Generator/OpParallelAttribute.cs b/csharp/Lib/StatusApi/Generator/OpParallelAttribute.cs deleted file mode 100644 index ec94f9d34..000000000 --- a/csharp/Lib/StatusApi/Generator/OpParallelAttribute.cs +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 43f22557f..000000000 --- a/csharp/Lib/StatusApi/Generator/Template.txt +++ /dev/null @@ -1,16 +0,0 @@ -#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 deleted file mode 100755 index 1233bd1b7..000000000 --- a/csharp/Lib/StatusApi/Generator/generate.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/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 53acdf439..c8b52cb98 100644 --- a/csharp/Lib/StatusApi/MpptStatus.cs +++ b/csharp/Lib/StatusApi/MpptStatus.cs @@ -1,11 +1,11 @@ using InnovEnergy.Lib.StatusApi.Connections; -using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -[OpParallel] -public partial record MpptStatus : IDcConnection, IPvConnection +#pragma warning disable CS8618 + +public record MpptStatus : IDcConnection, IPvConnection { public DcBus Dc { get; init; } public IReadOnlyList Strings { get; init; } diff --git a/csharp/Lib/StatusApi/MpptStatus.generated.cs b/csharp/Lib/StatusApi/MpptStatus.generated.cs deleted file mode 100644 index 5e2afe796..000000000 --- a/csharp/Lib/StatusApi/MpptStatus.generated.cs +++ /dev/null @@ -1,16 +0,0 @@ -#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 8140afef3..5c10f1ded 100644 --- a/csharp/Lib/StatusApi/PowerMeterStatus.cs +++ b/csharp/Lib/StatusApi/PowerMeterStatus.cs @@ -1,11 +1,11 @@ using InnovEnergy.Lib.StatusApi.Connections; -using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -[OpParallel] -public partial record PowerMeterStatus : DeviceStatus, IAc3Connection +#pragma warning disable CS8618 + +public record PowerMeterStatus : IAc3Connection { public Ac3Bus 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 deleted file mode 100644 index 9e6dcaf9c..000000000 --- a/csharp/Lib/StatusApi/PowerMeterStatus.generated.cs +++ /dev/null @@ -1,16 +0,0 @@ -#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 6688d8886..247831ffc 100644 --- a/csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs +++ b/csharp/Lib/StatusApi/SinglePhaseInverterStatus.cs @@ -1,14 +1,12 @@ using InnovEnergy.Lib.StatusApi.Connections; -using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -[OpParallel] -public partial record SinglePhaseInverterStatus : - DeviceStatus, - IAc1Connection, - IDcConnection + +#pragma warning disable CS8618 + +public record SinglePhaseInverterStatus : IAc1Connection, IDcConnection { public Ac1Bus Ac { get; init; } public DcBus Dc { get; init; } diff --git a/csharp/Lib/StatusApi/SinglePhaseInverterStatus.generated.cs b/csharp/Lib/StatusApi/SinglePhaseInverterStatus.generated.cs deleted file mode 100644 index 047f609fc..000000000 --- a/csharp/Lib/StatusApi/SinglePhaseInverterStatus.generated.cs +++ /dev/null @@ -1,16 +0,0 @@ -#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 269254b6e..6a47bb521 100644 --- a/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs +++ b/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.cs @@ -1,14 +1,11 @@ using InnovEnergy.Lib.StatusApi.Connections; -using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -[OpParallel] -public partial record SinglePhasePvInverterStatus : - DeviceStatus, - IAc1Connection, - IPvConnection +#pragma warning disable CS8618 + +public record SinglePhasePvInverterStatus : IAc1Connection, IPvConnection { public Ac1Bus Ac { get; init; } public IReadOnlyList Strings { get; init; } diff --git a/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.generated.cs b/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.generated.cs deleted file mode 100644 index 37340f111..000000000 --- a/csharp/Lib/StatusApi/SinglePhasePvInverterStatus.generated.cs +++ /dev/null @@ -1,16 +0,0 @@ -#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 b68a8b119..a1e52bb50 100644 --- a/csharp/Lib/StatusApi/StatusApi.csproj +++ b/csharp/Lib/StatusApi/StatusApi.csproj @@ -1,15 +1,10 @@ - - - - - diff --git a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs index c525a6a67..b33618c97 100644 --- a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs +++ b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.cs @@ -1,14 +1,11 @@ using InnovEnergy.Lib.StatusApi.Connections; -using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -[OpParallel] -public partial record ThreePhaseInverterStatus : - DeviceStatus, - IAc3Connection, - IDcConnection +#pragma warning disable CS8618 + +public record ThreePhaseInverterStatus : IAc3Connection, IDcConnection { public Ac3Bus Ac { get; init; } public DcBus Dc { get; init; } diff --git a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.generated.cs b/csharp/Lib/StatusApi/ThreePhaseInverterStatus.generated.cs deleted file mode 100644 index 989941505..000000000 --- a/csharp/Lib/StatusApi/ThreePhaseInverterStatus.generated.cs +++ /dev/null @@ -1,16 +0,0 @@ -#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 8c122ffb3..94c31980d 100644 --- a/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs +++ b/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.cs @@ -1,14 +1,11 @@ using InnovEnergy.Lib.StatusApi.Connections; -using InnovEnergy.Lib.StatusApi.Generator; using InnovEnergy.Lib.Units.Composite; namespace InnovEnergy.Lib.StatusApi; -[OpParallel] -public partial record ThreePhasePvInverterStatus : - DeviceStatus, - IAc3Connection, - IPvConnection +#pragma warning disable CS8618 + +public record ThreePhasePvInverterStatus : IAc3Connection, IPvConnection { public Ac3Bus Ac { get; init; } public IReadOnlyList Strings { get; init; } diff --git a/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.generated.cs b/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.generated.cs deleted file mode 100644 index 4e7170a21..000000000 --- a/csharp/Lib/StatusApi/ThreePhasePvInverterStatus.generated.cs +++ /dev/null @@ -1,16 +0,0 @@ -#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/Units/Composite/Ac3Bus.cs b/csharp/Lib/Units/Composite/Ac3Bus.cs index e35c73cfc..bdd505a07 100644 --- a/csharp/Lib/Units/Composite/Ac3Bus.cs +++ b/csharp/Lib/Units/Composite/Ac3Bus.cs @@ -1,20 +1,19 @@ -using InnovEnergy.Lib.Utils; using static DecimalMath.DecimalEx; namespace InnovEnergy.Lib.Units.Composite; + +#pragma warning disable CS8618 + public record Ac3Bus { - public AcPhase L1 { get; init; } - public AcPhase L2 { get; init; } - public AcPhase L3 { get; init; } - public Frequency Frequency { get; init; } + public AcPhase L1 { get; init; } + public AcPhase L2 { get; init; } + public AcPhase L3 { get; init; } + public Frequency Frequency { get; init; } public ApparentPower ApparentPower => L1.ApparentPower + L2.ApparentPower + L3.ApparentPower; public ReactivePower ReactivePower => L1.ReactivePower + L2.ReactivePower + L3.ReactivePower; public Power ActivePower => L1.ActivePower + L2.ActivePower + L3.ActivePower; public Angle Phi => ATan2(ReactivePower, ActivePower); - - public static 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 8186e01f9..d57b68aa8 100644 --- a/csharp/Lib/Units/Composite/AcPhase.cs +++ b/csharp/Lib/Units/Composite/AcPhase.cs @@ -19,7 +19,7 @@ public record AcPhase : IBus init => _Current = value >= 0m ? value : throw new ArgumentException("RMS value cannot be negative"); } - public 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/DcBus.cs b/csharp/Lib/Units/Composite/DcBus.cs index 9bab0143a..8fbdd9802 100644 --- a/csharp/Lib/Units/Composite/DcBus.cs +++ b/csharp/Lib/Units/Composite/DcBus.cs @@ -1,5 +1,3 @@ -using InnovEnergy.Lib.Utils; - namespace InnovEnergy.Lib.Units.Composite; public record DcBus : IBus @@ -8,7 +6,4 @@ public record DcBus : IBus 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/Percent.generated.cs b/csharp/Lib/Units/Percent.generated.cs new file mode 100644 index 000000000..e67b97384 --- /dev/null +++ b/csharp/Lib/Units/Percent.generated.cs @@ -0,0 +1,71 @@ +#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Generate + +using static System.Math; +using System.Text.Json; +using System.Text.Json.Serialization; +using InnovEnergy.Lib.Utils; +using System.CodeDom.Compiler; + +namespace InnovEnergy.Lib.Units; + +using T = Percent; + +[GeneratedCode("generate.sh", "1")] +[JsonConverter(typeof(PercentConverter))] +public readonly partial struct Percent +{ + public Decimal Value { get; } + public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit; + + // scalar multiplication + + public static T operator *(Decimal scalar, T t) => new T(scalar * t.Value); + public static T operator *(T t, Decimal scalar) => new T(scalar * t.Value); + public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); + + // addition + + 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); + + // compare + + public static Boolean operator ==(T left, T right) => left.Value == right.Value; + public static Boolean operator !=(T left, T right) => left.Value != right.Value; + public static Boolean operator > (T left, T right) => left.Value > right.Value; + public static Boolean operator < (T left, T right) => left.Value < right.Value; + public static Boolean operator >=(T left, T right) => left.Value >= right.Value; + public static Boolean operator <=(T left, T right) => left.Value <= right.Value; + + // conversion + + public static implicit operator T(Decimal d) => new T(d); + public static implicit operator T(Double d) => new T((Decimal)d); + public static implicit operator T(Int32 i) => new T(i); + public static implicit operator Decimal(T t) => t.Value; + + // equality + + public Boolean Equals(T other) => Value == other.Value; + public override Boolean Equals(Object? obj) => obj is T other && Equals(other); + public override Int32 GetHashCode() => Value.GetHashCode(); + +} + + +internal class PercentConverter : JsonConverter +{ + public override Percent Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new Percent(reader.GetDecimal()); + } + + public override void Write(Utf8JsonWriter writer, Percent value, JsonSerializerOptions options) + { + var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits); + + writer.WriteNumberValue(rounded); + } +} \ No newline at end of file diff --git a/csharp/Lib/Units/Units.cs b/csharp/Lib/Units/Units.cs index 3694c0783..d9ee297c5 100644 --- a/csharp/Lib/Units/Units.cs +++ b/csharp/Lib/Units/Units.cs @@ -1,23 +1,7 @@ -using System.Text.Json.Serialization; - namespace InnovEnergy.Lib.Units; public static class Units { - static Units() - { - JsonConverters = typeof(Units) - .Assembly - .GetTypes() - .Where(t => t.IsAssignableTo(typeof(JsonConverter))) - .Select(Activator.CreateInstance) - .Cast() - .ToArray(); - } - - - public static IReadOnlyList JsonConverters { get; } - public static Byte DisplaySignificantDigits { get; set; } = 3; public static Byte JsonSignificantDigits { get; set; } = 3; @@ -31,4 +15,89 @@ public static class Units public static Angle Rad (this Decimal value) => value; public static Temperature Celsius(this Decimal value) => value; public static Energy KWh (this Decimal value) => value; +} + +public static class Prefixes +{ + private static readonly IReadOnlyList Big = new[] + { + "", + "k", + "M", + "G", + "T", + "P", + "E", + "Y", + }; + + private static readonly IReadOnlyList Small = new[] + { + "", + "m", + "ยต", + "n", + "p", + "f", + "a", + "z", + "y", + }; + + public static String TestGetPrefix(Double v, String unit) + { + if (v == 0) + return ""; + + var log10 = Math.Log10(v / 10); + var l = (Int32)Math.Floor(log10 / 3); + var lookUp = l > 0 ? Big : Small; + var i = Math.Abs(l); + + return $"{v / Math.Pow(10.0, l * 3.0)} {lookUp[i]}{unit}"; + } + + + public static String TestGetPrefix(Decimal v, String unit) + { + if (v == 0m) + return ""; + + var d = (Double)v; + var log10 = Math.Log10(d / 10); + var l = (Int32)Math.Floor(log10 / 3); + var lookUp = l > 0 ? Big : Small; + var i = Math.Abs(l); + + return $"{d / Math.Pow(10.0, l * 3.0)} {lookUp[i]}{unit}"; + } + + public static String TestGetPrefix2(Decimal v, String unit) + { + if (v == 0m) + return ""; + + var a = Math.Abs(v); + var s = Math.Sign(v); + + var i = 0; + + while (a >= 10000m) + { + a /= 1000; + i++; + } + while (a < 10m) + { + a *= 1000; + i--; + } + + var lookUp = i >= 0 ? Big : Small; + + var r = Decimal.Floor(a * 10m) / 10m; + + return $"{r*s} {lookUp[Math.Abs(i)]}{unit}"; + } + } \ No newline at end of file diff --git a/csharp/Lib/Utils/Reflection/DataMember.cs b/csharp/Lib/Utils/Reflection/DataMember.cs new file mode 100644 index 000000000..5d2ed7eff --- /dev/null +++ b/csharp/Lib/Utils/Reflection/DataMember.cs @@ -0,0 +1,26 @@ +namespace InnovEnergy.Lib.Utils.Reflection; + +public abstract class DataMember : Member +{ + public abstract Object? Get(); + public abstract void Set(Object value); + + public abstract Boolean IsWriteable { get; } + public abstract Boolean IsReadable { get; } +} + +public static class DataMembers +{ + public static IEnumerable OfInstance(T instance) where T : notnull + { + return instance.GetDataMembers(); + } + + public static IEnumerable GetDataMembers(this T instance) where T : notnull + { + var fields = instance.GetFields(); + var props = instance.GetProperties(); + + return fields.Concat(props); + } +} \ No newline at end of file diff --git a/csharp/Lib/Utils/Reflection/Field.cs b/csharp/Lib/Utils/Reflection/Field.cs new file mode 100644 index 000000000..d4112f4c6 --- /dev/null +++ b/csharp/Lib/Utils/Reflection/Field.cs @@ -0,0 +1,49 @@ +using System.Reflection; +using static System.Reflection.BindingFlags; + +namespace InnovEnergy.Lib.Utils.Reflection; + +public class Field : DataMember +{ + private readonly Object? _Instance; + private readonly FieldInfo _FieldInfo; + + public override String Name => _FieldInfo.Name; + public override Type Type => _FieldInfo.FieldType; + + public override Boolean IsPublic => _FieldInfo.IsPublic; + public override Boolean IsPrivate => _FieldInfo.IsPrivate; + public override Boolean IsStatic => _FieldInfo.IsStatic; + + public override Boolean IsWriteable => true; + public override Boolean IsReadable => true; + + public override IEnumerable Attributes => _FieldInfo + .GetCustomAttributes(inherit: false) + .OfType(); + + internal Field(Object? instance, FieldInfo fieldInfo) + { + _Instance = instance; + _FieldInfo = fieldInfo; + } + + public override Object? Get() => _FieldInfo.GetValue(_Instance) ; + public override void Set(Object value) => _FieldInfo.SetValue(_Instance, value); +} + +public static class Fields +{ + public static IEnumerable GetFields(this T instance) where T : notnull + { + return instance + .GetType() + .GetFields(Instance | Static | Public | NonPublic) + .Select(fi => new Field(fi.IsStatic ? null : instance, fi)); + } + + public static IEnumerable OfInstance(T instance) where T : notnull + { + return instance.GetFields(); + } +} \ No newline at end of file diff --git a/csharp/Lib/Utils/Reflection/Member.cs b/csharp/Lib/Utils/Reflection/Member.cs new file mode 100644 index 000000000..24bcdf7a6 --- /dev/null +++ b/csharp/Lib/Utils/Reflection/Member.cs @@ -0,0 +1,33 @@ +namespace InnovEnergy.Lib.Utils.Reflection; + +public abstract class Member +{ + public abstract String Name { get; } + public abstract Type Type { get; } + + public abstract Boolean IsPublic { get; } + public abstract Boolean IsPrivate { get; } + public abstract Boolean IsStatic { get; } + + public abstract IEnumerable Attributes { get; } +} + + +public static class Members +{ + public static IEnumerable OfInstance(T instance) where T : notnull + { + return instance.GetMembers(); + } + + public static IEnumerable GetMembers(this T instance) where T : notnull + { + var fields = instance.GetFields(); + var props = instance.GetProperties(); + var methods = instance.GetMethods(); + + return fields + .Concat(props) + .Concat(methods); + } +} \ No newline at end of file diff --git a/csharp/Lib/Utils/Reflection/Method.cs b/csharp/Lib/Utils/Reflection/Method.cs new file mode 100644 index 000000000..a572ea97f --- /dev/null +++ b/csharp/Lib/Utils/Reflection/Method.cs @@ -0,0 +1,52 @@ +using System.Reflection; +using static System.Reflection.BindingFlags; + +namespace InnovEnergy.Lib.Utils.Reflection; + +public class Method : Member +{ + private readonly MethodInfo _MethodInfo; + private readonly Object? _Instance; + + public override Boolean IsPublic => _MethodInfo.IsPublic; + public override Boolean IsPrivate => _MethodInfo.IsPrivate; + public override Boolean IsStatic => _MethodInfo.IsStatic; + + public override String Name => _MethodInfo.Name; + public override Type Type => _MethodInfo.ReturnType; + + public override IEnumerable Attributes => _MethodInfo.GetCustomAttributes(); + + public IEnumerable Parameters => _MethodInfo + .GetParameters() + .Select(i => new Parameter(i)); + + internal Method(Object? instance, MethodInfo fieldInfo) + { + _MethodInfo = fieldInfo; + _Instance = instance; + } + + public Object? Invoke(params Object[] parameters) + { + return _MethodInfo.Invoke(_Instance, parameters); + } + + +} + + +public static class Methods +{ + public static IEnumerable GetMethods(this T instance) where T : notnull + { + return typeof(T) + .GetMethods(Instance | Static | Public | NonPublic) + .Select(mi => new Method(mi.IsStatic ? null : instance, mi)); + } + + public static IEnumerable OfInstance(T instance) where T : notnull + { + return instance.GetMethods(); + } +} \ No newline at end of file diff --git a/csharp/Lib/Utils/Reflection/Parameter.cs b/csharp/Lib/Utils/Reflection/Parameter.cs new file mode 100644 index 000000000..e48761bf6 --- /dev/null +++ b/csharp/Lib/Utils/Reflection/Parameter.cs @@ -0,0 +1,14 @@ +using System.Reflection; + +namespace InnovEnergy.Lib.Utils.Reflection +{ + public class Parameter + { + private readonly ParameterInfo _ParameterInfo; + + internal Parameter(ParameterInfo parameterInfo) => _ParameterInfo = parameterInfo; + + public Type Type => _ParameterInfo.ParameterType; + public String Name => _ParameterInfo.Name ?? ""; + } +} \ No newline at end of file diff --git a/csharp/Lib/Utils/Reflection/Property.cs b/csharp/Lib/Utils/Reflection/Property.cs new file mode 100644 index 000000000..e89716a46 --- /dev/null +++ b/csharp/Lib/Utils/Reflection/Property.cs @@ -0,0 +1,87 @@ +using System.Reflection; +using static System.Reflection.BindingFlags; + +namespace InnovEnergy.Lib.Utils.Reflection +{ + public class Property : DataMember + { + private readonly Object? _Instance; + private readonly PropertyInfo _PropertyInfo; + + internal Property(Object? instance, PropertyInfo propertyInfo) + { + _Instance = instance; + _PropertyInfo = propertyInfo; + } + + public override Boolean IsWriteable => _PropertyInfo.CanWrite; + public override Boolean IsReadable => _PropertyInfo.CanRead; + public override String Name => _PropertyInfo.Name; + public override Type Type => _PropertyInfo.PropertyType; + + public override Boolean IsPublic => _PropertyInfo.IsPublic(); + public override Boolean IsPrivate => _PropertyInfo.IsPrivate(); + public override Boolean IsStatic => _PropertyInfo.IsStatic(); + + public override IEnumerable Attributes => GetAttributes(); + + public override Object? Get() => _PropertyInfo.GetValue(_Instance); + public override void Set(Object value) => _PropertyInfo.SetValue(_Instance, value); + + public IEnumerable GetAttributes () where T : Attribute => _PropertyInfo + .GetCustomAttributes(inherit: false) + .OfType(); + + public Boolean HasAttribute () where T : Attribute => GetAttributes().Any(); + } + + + public static class Properties + { + public static IEnumerable GetProperties(this T instance) where T : notnull + { + return instance + .GetType() + .GetProperties(Instance | Static | Public | NonPublic) + .Where(p => p.GetIndexParameters().Length == 0) // no indexers please + .Select(pi => new Property(pi.IsStatic() ? null : instance, pi)); + } + + public static IEnumerable OfInstance(T instance) where T : notnull + { + return instance.GetProperties(); + } + } + + + internal static class PropertyInfoExtensions + { + public static Boolean IsStatic(this PropertyInfo i) + { + var getter = i.GetMethod; + var setter = i.SetMethod; + + return (getter is not null && getter.IsStatic) + || (setter is not null && setter.IsStatic); + } + + public static Boolean IsPublic(this PropertyInfo i) + { + var getter = i.GetMethod; + var setter = i.SetMethod; + + return (getter is not null && getter.IsPublic) + || (setter is not null && setter.IsPublic); + } + + public static Boolean IsPrivate(this PropertyInfo i) + { + var getter = i.GetMethod; + var setter = i.SetMethod; + + return (getter is not null && getter.IsPrivate) + || (setter is not null && setter.IsPrivate); + } + } + +} \ No newline at end of file diff --git a/csharp/Lib/WebServer/WebServer.cs b/csharp/Lib/WebServer/WebServer.cs index 8021142c5..2b055a1f3 100644 --- a/csharp/Lib/WebServer/WebServer.cs +++ b/csharp/Lib/WebServer/WebServer.cs @@ -23,8 +23,8 @@ public static class WebServer listener.Start(); var handlers404 = handlers - .Concat(Default.HttpResponse) - .ToArray(); + .Concat(Default.HttpResponse) + .ToArray(); while (true) { @@ -34,9 +34,9 @@ public static class WebServer var request = context.ConvertRequest(); var response = handlers404 - .Select(f => f(request)) - .SkipWhile(r => r == null) - .First()!; + .Select(f => f(request)) + .SkipWhile(r => r == null) + .First()!; context.SendResponse(response); } diff --git a/csharp/lib/Devices/Trumpf/TruConvertDc/DcControlRegisters.cs b/csharp/lib/Devices/Trumpf/TruConvertDc/DcControlRegisters.cs new file mode 100644 index 000000000..90b0552b6 --- /dev/null +++ b/csharp/lib/Devices/Trumpf/TruConvertDc/DcControlRegisters.cs @@ -0,0 +1,48 @@ +namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; + +public static class DcControlRegisters +{ + public const UInt16 Date = 1001; + public const UInt16 Time = 1003; + public const UInt16 IpAddress = 1005; + public const UInt16 Subnet = 1007; + public const UInt16 Gateway = 1009; + public const UInt16 ResetParamToDefault = 1011; + public const UInt16 TimeoutCommunication = 1017; + public const UInt16 RestartFlag = 1018; + public const UInt16 ConnectedSystemConfig = 1019; + public const UInt16 UpdateSwTrigger = 1027; + public const UInt16 AutomaticSwUpdate = 1028; + public const UInt16 CustomerValuesSaveReset = 1029; + public const UInt16 SerialNumberSystemControl = 2001; + public const UInt16 SerialNumberDcDc = 2003; + public const UInt16 MaterialNumberDcDc = 2005; + public const UInt16 PowerStageOperation = 4001; + public const UInt16 ResetsAlarmAndWarning = 4003; + public const UInt16 SlaveAddress = 4008; + public const UInt16 SlaveAlarmPolicy = 4009; + public const UInt16 SubSlaveAddress = 4011; + public const UInt16 ModbusSlaveId = 4012; + public const UInt16 MaximumBatteryVoltage = 4101; + public const UInt16 MinimumBatteryVoltage = 4102; + public const UInt16 MaximumBatteryVoltageR = 4103; // same as the two previous ones just Different resolution// not sure + public const UInt16 MinimumBatteryVoltageR = 4104; // same as the two previous ones just Different resolution// not sure + public const UInt16 MaximumBatteryChargingCurrent = 4107; + public const UInt16 MaximumBatteryDischargingCurrent = 4110; + public const UInt16 MaximumVoltageOfVcc = 4113; + public const UInt16 MaximumCurrentOfVcc = 4116; + public const UInt16 StartCurrentOfVcc = 4119; + public const UInt16 MaximalPowerAtDc = 4122; + public const UInt16 MaximumVoltageAlarmThreshold = 4125; + public const UInt16 MinimumVoltageAlarmThreshold = 4128; + + //DcDc operation only + public const UInt16 BatteryCurrentSet = 4501; + public const UInt16 DynamicCurrentPerMillisecond = 4502; + + public const UInt16 DcLinkControlMode = 4505; + public const UInt16 ReferenceVoltage = 4506; + public const UInt16 UpperVoltageWindow = 4507; + public const UInt16 LowerVoltageWindow = 4508; + public const UInt16 VoltageDeadBand = 4509; +} \ No newline at end of file diff --git a/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcControl.cs b/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcControl.cs new file mode 100644 index 000000000..82a4e4dcc --- /dev/null +++ b/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcControl.cs @@ -0,0 +1,44 @@ +using InnovEnergy.Lib.Devices.Trumpf.TruConvert; + +namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; + +public record TruConvertDcControl +{ + public UInt32 Date { get; init;} + public UInt32 Time { get; init;} + public UInt32 IpAddress { get; init;} //= 0x C0A80102; + public UInt32 Subnet { get; init;} //= 0x FFFFFF00; + public UInt32 Gateway { get; init;} //= 0x C0A80102; + public Boolean ResetParamToDefault { get; init;} = false ; // Coil + public TimeSpan TimeoutForCommunication { get; init;} = DefaultCommunicationTimeOut; + public Boolean RestartFlag { get; init;} = false ; // Coil + public SystemConfig ConnectedSystemConfig { get; init;} = SystemConfig.NoConfig ; + public UInt16 UpdateSwTrigger { get; init;} = 0 ; + public UInt16 AutomaticSwUpdate { get; init;} = 0 ; + public UInt16 CustomerValuesSaveReset { get; init;} = 0 ; + public UInt32 SerialNumberSystemControl { get; init;} + public UInt32 SerialNumberDcDc { get; init;} + public UInt32 MaterialNumberDcDc { get; init;} + public Boolean PowerStageEnable { get; init;} = true; //Coil + public Boolean ResetsAlarmAndWarning { get; init;} = false; //Coil + public UInt16 SlaveAddress { get; init;} = Slave.Broadcast; + public UInt16 SlaveAlarmPolicy { get; init;} = 0; // this is must be a an enum + public UInt16 SubSlaveAddress { get; init;} = 0; + public Boolean ModbusSlaveId { get; init;} = false; // Coil + public Decimal MaximumBatteryVoltage { get; init;} = 0; // resolution 0.01 + public Decimal MinimumBatteryVoltage { get; init;} = 0; // resolution 0.01 + public Decimal MaximumBatteryChargingCurrent { get; init;} = 0; // resolution 0.1 + public Decimal MaximumBatteryDischargingCurrent { get; init;} = 0; // resolution 0.1 + public Decimal MaximalPowerAtDc { get; init;} = 0; + public Decimal MaximumVoltageAlarmThreshold { get; init;} = 55; // resolution 0.1 + public Decimal MinimumVoltageAlarmThreshold { get; init;} = 0; // resolution 0.1 + public Decimal BatteryCurrentSet { get; init;} = 0; // resolution 1.0 + public Decimal DynamicCurrentPerMillisecond { get; init;} = 0; // resolution : 0.01 + public Decimal DcLinkControlMode { get; init;} = 0; // Parameter aktiviert/deaktiviert "DC link voltage droop mode" + public Decimal ReferenceVoltage { get; init;} = 800; // resolution : 0.1 + public Decimal UpperVoltageWindow { get; init;} = 40; // resolution : 0.1 + public Decimal LowerVoltageWindow { get; init;} = 40; // resolution : 0.1 + public Decimal VoltageDeadBand { get; init;} = 0; // resolution : 0.1 + + private static readonly TimeSpan DefaultCommunicationTimeOut = TimeSpan.FromMinutes(10); +}