From 175f11fccf3282a60f074be5080bd7cf48ec318e Mon Sep 17 00:00:00 2001 From: atef Date: Thu, 23 Feb 2023 13:45:09 +0100 Subject: [PATCH] Update Status to inherit from Status Api --- csharp/InnovEnergy.sln | 48 ++- .../app/EmuMeterDriver/EmuMeterDriver.csproj | 6 +- csharp/app/SaliMax/SaliMax.csproj | 6 +- .../app/SaliMax/run (BeagleBone Meiringen).sh | 28 +- csharp/app/SaliMax/src/Controller/Control.cs | 10 +- .../app/SaliMax/src/Controller/Controller.cs | 146 ++++--- csharp/app/SaliMax/src/Controller/State.cs | 12 + .../app/SaliMax/src/Controller/StateConfig.cs | 2 +- .../SaliMax/src/Controller/StatusRecord.cs | 20 +- csharp/app/SaliMax/src/Log/Ampt.cs | 15 +- csharp/app/SaliMax/src/Log/Battery48Tl.cs | 4 +- csharp/app/SaliMax/src/Log/EmuMeter.cs | 14 +- csharp/app/SaliMax/src/Log/Salimax.cs | 11 +- csharp/app/SaliMax/src/Log/TruConvertAc.cs | 29 +- csharp/app/SaliMax/src/Log/TruConvertDc.cs | 15 +- csharp/app/SaliMax/src/Program.cs | 358 +++++++++++------- .../src/SaliMaxRelays/SaliMaxRelaysStatus.cs | 3 - csharp/app/SaliMax/src/SystemConfig/Config.cs | 2 +- .../app/SaliMax/src/SystemConfig/Defaults.cs | 16 +- .../lib/Devices/AMPT/AmptCommunicationUnit.cs | 74 ++-- csharp/lib/Devices/AMPT/AmptDeviceStatus.cs | 23 +- csharp/lib/Devices/AMPT/AmptStatus.cs | 40 +- .../Devices/Battery48TL/Battery48TL.csproj | 1 + .../Devices/Battery48TL/Battery48TLDevice.cs | 95 ++++- .../Battery48TL/Battery48TLStatusRecord.cs | 137 ++----- .../Devices/Battery48TL/BatteryDataParser.cs | 20 +- csharp/lib/Devices/Battery48TL/Constants.cs | 5 +- csharp/lib/Devices/EmuMeter/EmuMeter.csproj | 1 + .../Trumpf/TruConvertAc/TruConvertAc.csproj | 1 + .../TruConvertAc/TruConvertAcControl.cs | 8 +- .../Trumpf/TruConvertAc/TruConvertAcDevice.cs | 255 ++++++++----- .../Trumpf/TruConvertAc/TruConvertAcStatus.cs | 83 ++-- .../Trumpf/TruConvertDc/TruConvertDc.csproj | 1 + .../TruConvertDc/TruConvertDcControl.cs | 7 +- .../Trumpf/TruConvertDc/TruConvertDcDevice.cs | 61 ++- .../Trumpf/TruConvertDc/TruConvertDcStatus.cs | 38 +- .../lib/StatusApi/Connections/DcConnection.cs | 3 +- .../Connections/SinglePhaseAcConnection.cs | 14 +- csharp/lib/StatusApi/Phases/AcPhase.cs | 7 +- csharp/lib/StatusApi/Utils.cs | 11 + csharp/lib/Utils/Utils.csproj | 2 +- 41 files changed, 917 insertions(+), 715 deletions(-) create mode 100644 csharp/lib/StatusApi/Utils.cs diff --git a/csharp/InnovEnergy.sln b/csharp/InnovEnergy.sln index 71a6f912e..d1ca70212 100644 --- a/csharp/InnovEnergy.sln +++ b/csharp/InnovEnergy.sln @@ -26,7 +26,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VenusLogger", "app/VenusLog EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meiringen", "app/Meiringen/Meiringen.csproj", "{4C816420-FD19-47BF-87FE-599210CA8384}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmuMeterDriver", "app\EmuMeterDriver\EmuMeterDriver.csproj", "{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmuMeterDriver", "app/EmuMeterDriver/EmuMeterDriver.csproj", "{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BmsTunnel", "app/BmsTunnel/BmsTunnel.csproj", "{40B45363-BE34-420B-8F87-775EE6EE3513}" EndProject @@ -34,21 +34,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "app", "app", "{145597B4-3E3 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "S3", "lib\S3\S3.csproj", "{C3639841-13F4-4F24-99C6-7D965593BF89}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "S3", "lib/S3/S3.csproj", "{C3639841-13F4-4F24-99C6-7D965593BF89}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deprecated", "deprecated", "{D846B46B-46FF-4EF7-9B9D-DDBEF9533C56}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deprecated", "deprecated", "{46DE03C4-52D1-47AA-8E60-8BB15361D723}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsController", "app\CsController\CsController.csproj", "{72DBBE42-A09F-43C0-9613-331039857056}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsController", "app/CsController/CsController.csproj", "{72DBBE42-A09F-43C0-9613-331039857056}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestBatteryDbus", "app\TestBatteryDbus\TestBatteryDbus.csproj", "{CB226D69-DD28-4AAF-8BBE-2488E37A0B8D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SaliMax", "app/SaliMax/SaliMax.csproj", "{25073794-D859-4824-9984-194C7E928496}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SaliMax", "app\SaliMax\SaliMax.csproj", "{25073794-D859-4824-9984-194C7E928496}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GuiFeeder", "app/GuiFeeder/GuiFeeder.csproj", "{5B953EC4-51F3-4A0A-ADF5-BAA3D1570CB2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GuiFeeder", "app\GuiFeeder\GuiFeeder.csproj", "{5B953EC4-51F3-4A0A-ADF5-BAA3D1570CB2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusApi", "lib\StatusApi\StatusApi.csproj", "{9D17E78C-8A70-43DB-A619-DC12D20D023D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusApi", "lib/StatusApi/StatusApi.csproj", "{9D17E78C-8A70-43DB-A619-DC12D20D023D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Devices", "Devices", "{4931A385-24DC-4E78-BFF4-356F8D6D5183}" EndProject @@ -58,38 +56,36 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Victron", "Victron", "{BD8C EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Trumpf", "Trumpf", "{DDDBEFD0-5DEA-4C7C-A9F2-FDB4636CF092}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TruConvert", "lib\Devices\Trumpf\TruConvert\TruConvert.csproj", "{EF46CF7B-823E-4CB7-966F-EDDC144C7954}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TruConvert", "lib/Devices/Trumpf/TruConvert/TruConvert.csproj", "{EF46CF7B-823E-4CB7-966F-EDDC144C7954}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TruConvertAc", "lib\Devices\Trumpf\TruConvertAc\TruConvertAc.csproj", "{1F4B445E-459E-44CD-813E-6D725EBB81E8}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TruConvertAc", "lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj", "{1F4B445E-459E-44CD-813E-6D725EBB81E8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TruConvertDc", "lib\Devices\Trumpf\TruConvertDc\TruConvertDc.csproj", "{F6F29829-C31A-4994-A698-E441BEA631C6}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TruConvertDc", "lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj", "{F6F29829-C31A-4994-A698-E441BEA631C6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DBus", "lib\Protocols\DBus\DBus.csproj", "{8C3C620A-087D-4DD6-B493-A47FC643F8DC}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DBus", "lib/Protocols/DBus/DBus.csproj", "{8C3C620A-087D-4DD6-B493-A47FC643F8DC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modbus", "lib\Protocols\Modbus\Modbus.csproj", "{E4AE6A33-0DEB-48EB-9D57-C0C7C63FC267}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modbus", "lib/Protocols/Modbus/Modbus.csproj", "{E4AE6A33-0DEB-48EB-9D57-C0C7C63FC267}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VeDBus", "lib\Victron\VeDBus\VeDBus.csproj", "{50B26E29-1B99-4D07-BCA5-359CD550BBAA}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VeDBus", "lib/Victron/VeDBus/VeDBus.csproj", "{50B26E29-1B99-4D07-BCA5-359CD550BBAA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VictronVRM", "lib\Victron\VictronVRM\VictronVRM.csproj", "{FE05DF69-B5C7-4C2E-8FB9-7776441A7622}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VictronVRM", "lib/Victron/VictronVRM/VictronVRM.csproj", "{FE05DF69-B5C7-4C2E-8FB9-7776441A7622}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ampt", "lib\Devices\AMPT\Ampt.csproj", "{77AF3A64-2878-4150-BCD0-F16530783165}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ampt", "lib/Devices/AMPT/Ampt.csproj", "{77AF3A64-2878-4150-BCD0-F16530783165}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Battery48TL", "lib\Devices\Battery48TL\Battery48TL.csproj", "{1C3F443A-B339-4B08-80E6-8A84817FFEC9}" - ProjectSection(ProjectDependencies) = postProject - {89A3E29C-4E57-47FE-A800-12AC68418264} = {89A3E29C-4E57-47FE-A800-12AC68418264} - EndProjectSection +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Battery48TL", "lib/Devices/Battery48TL/Battery48TL.csproj", "{1C3F443A-B339-4B08-80E6-8A84817FFEC9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmuMeter", "lib\Devices\EmuMeter\EmuMeter.csproj", "{152A4168-F612-493C-BBEA-8EB26E6E2D34}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmuMeter", "lib/Devices/EmuMeter/EmuMeter.csproj", "{152A4168-F612-493C-BBEA-8EB26E6E2D34}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "lib\Utils\Utils.csproj", "{89A3E29C-4E57-47FE-A800-12AC68418264}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "lib/Utils/Utils.csproj", "{89A3E29C-4E57-47FE-A800-12AC68418264}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Adam6060", "lib\Devices\Adam6060\Adam6060.csproj", "{4AFDB799-E6A4-4DCA-8B6D-8C0F98398461}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Adam6060", "lib/Devices/Adam6060/Adam6060.csproj", "{4AFDB799-E6A4-4DCA-8B6D-8C0F98398461}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Channels", "lib\Channels\Channels.csproj", "{AF7E8DCA-8D48-498E-AB3D-208061B244DC}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Channels", "lib/Channels/Channels.csproj", "{AF7E8DCA-8D48-498E-AB3D-208061B244DC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Backend", "app\Backend\Backend.csproj", "{A56F58C2-B265-435B-A985-53B4D6F49B1A}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Backend", "app/Backend/Backend.csproj", "{A56F58C2-B265-435B-A985-53B4D6F49B1A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FossilTui", "app/FossilTui/FossilTui.csproj", "{C40264BB-C834-4C48-9B3F-6BEF8F37C0ED}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FossilTui", "app\FossilTui\FossilTui.csproj", "{C40264BB-C834-4C48-9B3F-6BEF8F37C0ED}" EndProject Global diff --git a/csharp/app/EmuMeterDriver/EmuMeterDriver.csproj b/csharp/app/EmuMeterDriver/EmuMeterDriver.csproj index da25cbeda..9132521ae 100644 --- a/csharp/app/EmuMeterDriver/EmuMeterDriver.csproj +++ b/csharp/app/EmuMeterDriver/EmuMeterDriver.csproj @@ -6,19 +6,15 @@ - - - - - + diff --git a/csharp/app/SaliMax/SaliMax.csproj b/csharp/app/SaliMax/SaliMax.csproj index b4ff39371..52f0b084f 100644 --- a/csharp/app/SaliMax/SaliMax.csproj +++ b/csharp/app/SaliMax/SaliMax.csproj @@ -15,12 +15,16 @@ - + + + + + \ No newline at end of file diff --git a/csharp/app/SaliMax/run (BeagleBone Meiringen).sh b/csharp/app/SaliMax/run (BeagleBone Meiringen).sh index 962d2c1e7..e98675532 100755 --- a/csharp/app/SaliMax/run (BeagleBone Meiringen).sh +++ b/csharp/app/SaliMax/run (BeagleBone Meiringen).sh @@ -3,7 +3,6 @@ dotnet_version='net6.0' - set -e echo -e "\n============================ Build ============================\n" @@ -11,21 +10,28 @@ echo -e "\n============================ Build ============================\n" dotnet publish \ ./SaliMax.csproj \ -c Release \ - -r linux-arm + -r linux-x64 echo -e "\n============================ Deploy ============================\n" rsync -v \ - ./bin/Release/$dotnet_version/linux-arm/publish/* \ - debian@10.2.1.87:~/salimax + ./bin/Release/$dotnet_version/linux-x64/publish/* \ + ie-entwicklung@10.2.3.49:~/salimax + + + # debian@10.2.1.87:~/salimax -echo -e "\n============================ Run ============================\n" +echo -e "\n============================ Restart Salimax sevice ============================\n" ssh -tt \ - -o StrictHostKeyChecking=no \ - -o UserKnownHostsFile=/dev/null \ - -o ConnectTimeout=2 \ - debian@10.2.1.87 \ - '~/salimax/SaliMax' \ - 2>/dev/null + ie-entwicklung@10.2.3.49 \ + sudo systemctl restart salimax.service + + +echo -e "\n============================ Print service output ============================\n" + +ssh -tt \ + ie-entwicklung@10.2.3.49 \ + journalctl -f -u salimax.service + diff --git a/csharp/app/SaliMax/src/Controller/Control.cs b/csharp/app/SaliMax/src/Controller/Control.cs index b730fdfec..144e2b166 100644 --- a/csharp/app/SaliMax/src/Controller/Control.cs +++ b/csharp/app/SaliMax/src/Controller/Control.cs @@ -13,14 +13,14 @@ public static class Control public static Decimal ControlInverterPower(this StatusRecord status, Decimal targetInverterPower) { var s = status.InverterStatus!; - var totalInverterAcPower = s.PowerAcL1 + s.PowerAcL2 + s.PowerAcL3; + var totalInverterAcPower = s.Ac.ActivePower; return ControlPower(totalInverterAcPower, targetInverterPower,status.SalimaxConfig!.PConstant); } - public static Decimal ControlBatteryPower(this StatusRecord status, Decimal targetBatteryPower) + public static Decimal ControlBatteryPower(this StatusRecord status, Decimal targetBatteryPower, UInt16 i = 0) //this will use the avg batteries { - return ControlPower(status.BatteryStatus!.Power, targetBatteryPower, status.SalimaxConfig!.PConstant); + return ControlPower(status.BatteriesStatus![i].Dc.Power, targetBatteryPower, status.SalimaxConfig!.PConstant); } public static Decimal ControlLowBatterySoc(this StatusRecord status) @@ -31,14 +31,14 @@ public static class Control public static Decimal LowerLimit(params Decimal[] deltas) => deltas.Max(); public static Decimal UpperLimit(params Decimal[] deltas) => deltas.Min(); - private static Decimal HoldMinSocCurve(StatusRecord s) + private static Decimal HoldMinSocCurve(StatusRecord s, UInt16 i = 0) { // TODO: explain LowSOC curve var a = -2 * s.SalimaxConfig!.SelfDischargePower / s.SalimaxConfig.HoldSocZone; var b = -a * (s.SalimaxConfig.MinSoc + s.SalimaxConfig.HoldSocZone); - return s.BatteryStatus!.Soc * a + b; + return s.BatteriesStatus![i].Soc * a + b; //this will use the avg batteries } private static Decimal ControlPower(Decimal measurement, Decimal target, Decimal p) diff --git a/csharp/app/SaliMax/src/Controller/Controller.cs b/csharp/app/SaliMax/src/Controller/Controller.cs index 3165a9f86..e578c5b2d 100644 --- a/csharp/app/SaliMax/src/Controller/Controller.cs +++ b/csharp/app/SaliMax/src/Controller/Controller.cs @@ -18,7 +18,7 @@ public static class Controller private static readonly TimeSpan CommunicationTimeout = TimeSpan.FromSeconds(10); - private static readonly Int16 MaxmimumAllowedBatteryTemp = 315; + public static readonly Int16 MaxmimumAllowedBatteryTemp = 315; private static UInt16 _numberOfInverters; @@ -71,7 +71,7 @@ public static class Controller InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz } => 9, { - SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed, + SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open, InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz } => 10, { @@ -79,11 +79,11 @@ public static class Controller InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz } => 11, { - SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed, + SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open, InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz } => 12, { - SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open, + SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed, InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz } => 13, { @@ -91,7 +91,7 @@ public static class Controller InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz } => 14, { - SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open, + SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed, InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz } => 15, { @@ -140,7 +140,10 @@ public static class Controller public static ControlRecord SaliMaxControl(StatusRecord statusRecord) { - var resetInverterAlarm = CheckInverterAlarms(statusRecord); + var currentSaliMaxState = GetSaliMaxState(statusRecord); + + UInt16 acSlaveId = 1; + var resetInverterAlarm = CheckInverterAlarms(statusRecord, currentSaliMaxState).WriteLine(" reset Alarm"); var resetDcAlarm = CheckDcDcAlarms(statusRecord); var lastEocTime = GetLastEocTime(statusRecord); @@ -151,33 +154,49 @@ public static class Controller var noGridMeter = statusRecord.GridMeterStatus == null; var saliMaxConfig = statusRecord.SalimaxConfig with { LastEoc = lastEocTime }; - - var currentSaliMaxState = GetSaliMaxState(statusRecord); + ExplainState(currentSaliMaxState); - + const RelayState k2Relay = Closed; - var acPowerStageEnable = StateConfig.AcPowerStageEnableStates.Contains(currentSaliMaxState) || currentSaliMaxState == 8; + var acPowerStageEnable = StateConfig.AcPowerStageEnableStates.Contains(currentSaliMaxState); //this is logical incorrect, find better way + + var dcPowerStageEnable = statusRecord.BatteriesStatus is not null; // TODO this is to check, Can be the batteries Status be null? - var dcPowerStageEnable = statusRecord.BatteryStatus is not null; // this is to check + var salimaxRelay = statusRecord.SaliMaxRelayStatus! with { K2 = k2Relay }; // to check // this is must be control - var salimaxRelay = statusRecord.SaliMaxRelayStatus! with { K2 = k2Relay }; // to check - - - if (statusRecord.BatteryStatus == null) + if (resetInverterAlarm) { + acPowerStageEnable = !resetInverterAlarm ; + acSlaveId = 0; + } + + if (resetDcAlarm) + { + dcPowerStageEnable = !resetDcAlarm ; + } + + acSlaveId.WriteLine(" AcSlave @"); + + if (statusRecord.BatteriesStatus == null) + { + Console.WriteLine(" No batteries"); return new ControlRecord { AcControlRecord = Defaults.TruConvertAcControl with { SignedPowerNominalValue = 0, PowerStageEnable = acPowerStageEnable, + CommunicationTimeout = CommunicationTimeout, + SlaveAddress = acSlaveId, ResetsAlarmAndWarning = resetInverterAlarm }, DcControlRecord = Defaults.TruConvertDcControl with { - PowerStageEnable = dcPowerStageEnable, - ResetsAlarmAndWarning = resetDcAlarm + PowerStageEnable = dcPowerStageEnable, + ResetsAlarmAndWarning = resetDcAlarm, + TimeoutForCommunication = CommunicationTimeout + }, SalimaxConfig = saliMaxConfig, // must create a control of each SalimaxRelays = salimaxRelay, // must create a control of each @@ -201,6 +220,38 @@ public static class Controller throw new NotImplementedException(); } + var newPowerSetPoint = CalculateNewPowerSetPoint(statusRecord); + + ////////////////////////// Control Record ////////////////////////// + + var acControlRecord = Defaults.TruConvertAcControl with + { + PowerStageEnable = acPowerStageEnable, + CommunicationTimeout = CommunicationTimeout, + SignedPowerNominalValue = newPowerSetPoint, + SlaveAddress = acSlaveId, + ResetsAlarmAndWarning = resetInverterAlarm + }; + + var dcControlRecord = Defaults.TruConvertDcControl with + { + PowerStageEnable = dcPowerStageEnable, + ResetsAlarmAndWarning = resetDcAlarm, + TimeoutForCommunication = CommunicationTimeout + }; + + + return new ControlRecord + { + AcControlRecord = acControlRecord, + DcControlRecord = dcControlRecord, + SalimaxConfig = saliMaxConfig, + SalimaxRelays = salimaxRelay + }; + } + + private static Decimal CalculateNewPowerSetPoint(StatusRecord statusRecord) + { var currentPowerSetPoint = statusRecord.InverterStatus!.AcSignedPowerValue; var limitReason = "no limit"; @@ -212,7 +263,7 @@ public static class Controller goal = "Calibration Charge"; delta = statusRecord.ControlInverterPower(statusRecord.SalimaxConfig.MaxInverterPower); } - else if (statusRecord.BatteryStatus!.Soc < statusRecord.SalimaxConfig.MinSoc) + else if (statusRecord.AvgBatteriesStatus!.Soc < statusRecord.SalimaxConfig.MinSoc) // TODO { goal = $"reach min SOC (Min soc: {statusRecord.SalimaxConfig.MinSoc})"; delta = statusRecord.ControlInverterPower(statusRecord.SalimaxConfig @@ -234,7 +285,7 @@ public static class Controller delta = inverterAc2DcLimitPower; } - var batteryChargingLimitPower = statusRecord.ControlBatteryPower(statusRecord.BatteryStatus!.MaxChargingPower); + var batteryChargingLimitPower = statusRecord.ControlBatteryPower(statusRecord.BatteriesStatus[0]!.MaxChargingPower); if (delta > batteryChargingLimitPower) { @@ -253,12 +304,12 @@ public static class Controller } var batteryDischargingLimitPower = - statusRecord.ControlBatteryPower(statusRecord.BatteryStatus!.MaxDischargingPower); + statusRecord.ControlBatteryPower(statusRecord.BatteriesStatus[0]!.MaxDischargingPower); // TODO change to avg battery if (delta < batteryDischargingLimitPower) { limitReason = - $"limited by max battery discharging power: {statusRecord.BatteryStatus!.MaxDischargingPower}"; + $"limited by max battery discharging power: {statusRecord.BatteriesStatus[0]!.MaxDischargingPower}";// TODO change to avg battery delta = batteryDischargingLimitPower; } @@ -271,13 +322,13 @@ public static class Controller delta = keepMinSocLimitDelta; } - /* if (statusRecord.BatteryStatus.BatteryTemperature >= 300) must not reduce the delta - { - var softLandingFactor = (MaxmimumAllowedBatteryTemp - statusRecord.BatteryStatus.BatteryTemperature) / 15; //starting softlanding from 300 degree - limitReason = - $"limiting discharging power in order to stay keep the battery temp below 315°: {statusRecord.BatteryStatus.BatteryTemperature}°" + " Softlanding factor: " + softLandingFactor; - delta *= softLandingFactor; - }*/ + // if (statusRecord.BatteriesStatus[0]!.Temperature >= 300) //must not reduce the delta + // { + // var softLandingFactor = (MaxmimumAllowedBatteryTemp - statusRecord.BatteriesStatus[0]!.Temperature) / 15; //starting softlanding from 300 degree + // limitReason = + // $"limiting discharging power in order to stay keep the battery temp below 315°: {statusRecord.BatteriesStatus[0]!.Temperature}°" + " Softlanding factor: " + softLandingFactor; + // delta *= softLandingFactor; + // } var newPowerSetPoint = DistributePower(currentPowerSetPoint + delta, statusRecord.SalimaxConfig.MaxInverterPower); @@ -289,32 +340,7 @@ public static class Controller limitReason.WriteLine(" Limit reason"); delta.WriteLine(" Delta"); // "============".WriteLine(); - - ////////////////////////// Control Record ////////////////////////// - - var acControlRecord = Defaults.TruConvertAcControl with - { - PowerStageEnable = acPowerStageEnable, - CommunicationTimeout = CommunicationTimeout, - SignedPowerNominalValue = newPowerSetPoint, - ResetsAlarmAndWarning = resetInverterAlarm - }; - - var dcControlRecord = Defaults.TruConvertDcControl with - { - PowerStageEnable = dcPowerStageEnable, - ResetsAlarmAndWarning = resetDcAlarm, - TimeoutForCommunication = CommunicationTimeout - }; - - - return new ControlRecord - { - AcControlRecord = acControlRecord, - DcControlRecord = dcControlRecord, - SalimaxConfig = saliMaxConfig, - SalimaxRelays = salimaxRelay - }; + return newPowerSetPoint; } private static State TargetState(State currentState) @@ -423,7 +449,7 @@ public static class Controller private static UnixTime GetLastEocTime(StatusRecord statusRecord) { - if (statusRecord.BatteryStatus?.Soc >= 100) + if (statusRecord.BatteriesStatus[0]!.Soc >= 100 && statusRecord.BatteriesStatus[1]!.Soc >= 100 ) { Console.WriteLine("battery has reached EOC"); File.AppendAllTextAsync(Config.LogSalimaxLog, String.Join(Environment.NewLine, UnixTime.Now + "battery has reached EOC")); @@ -442,6 +468,7 @@ public static class Controller private static Boolean CheckDcDcAlarms(StatusRecord s) { + s.DcDcStatus?.Alarms.Count.WriteLine(" Dc Alarm count"); if ( s.DcDcStatus?.Alarms.Count > 0 && s.DcDcStatus?.PowerOperation == false) { @@ -452,14 +479,15 @@ public static class Controller return false; } - private static Boolean CheckInverterAlarms(StatusRecord s) + private static Boolean CheckInverterAlarms(StatusRecord s, UInt16 state) { - if ( s.InverterStatus?.Alarms.Count > 0 && - s.InverterStatus?.PowerOperation == false) + s.InverterStatus?.Alarms.Count.WriteLine(" Ac Alarm count"); + if ( s.InverterStatus?.Alarms.Count > 0 ) { - File.AppendAllTextAsync(Config.LogSalimaxLog, UnixTime.Now + " " + s.InverterStatus.Alarms); + File.AppendAllTextAsync(Config.LogSalimaxLog, UnixTime.Now + " " + s.InverterStatus.Alarms[0]); // Todo write every alarm in he alarm list return true; } + return false; } diff --git a/csharp/app/SaliMax/src/Controller/State.cs b/csharp/app/SaliMax/src/Controller/State.cs index 357d5410c..a8ad8d11b 100644 --- a/csharp/app/SaliMax/src/Controller/State.cs +++ b/csharp/app/SaliMax/src/Controller/State.cs @@ -5,14 +5,26 @@ public enum State : Int16 { State1 = 1, State2 = 2, + State3 = 3, State4 = 4, + State5 = 5, State6 = 6, + State7 = 7, + State8 = 8, State9 = 9, + State10 = 10, + State11 = 11, State12 = 12, State13 = 13, + State14 = 14, State15 = 15, State16 = 16, State17 = 17, + State18 = 18, + State19 = 19, + State20 = 20, State21 = 21, State22 = 22, + State23 = 23, + State24 = 24 } \ No newline at end of file diff --git a/csharp/app/SaliMax/src/Controller/StateConfig.cs b/csharp/app/SaliMax/src/Controller/StateConfig.cs index c2ae6065d..be40aafc0 100644 --- a/csharp/app/SaliMax/src/Controller/StateConfig.cs +++ b/csharp/app/SaliMax/src/Controller/StateConfig.cs @@ -3,5 +3,5 @@ namespace InnovEnergy.SaliMax.Controller; public static class StateConfig { - public static readonly IReadOnlyList AcPowerStageEnableStates = new[] { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; + public static readonly IReadOnlyList AcPowerStageEnableStates = new[] {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; } \ 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 7842aa845..0969b841b 100644 --- a/csharp/app/SaliMax/src/Controller/StatusRecord.cs +++ b/csharp/app/SaliMax/src/Controller/StatusRecord.cs @@ -10,13 +10,13 @@ namespace InnovEnergy.SaliMax.Controller; public record StatusRecord { - public TruConvertAcStatus? InverterStatus { get; init; } - public TruConvertDcStatus? DcDcStatus { get; init; } - public Battery48TLStatus? BatteryStatus { 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 + 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!; +} \ No newline at end of file diff --git a/csharp/app/SaliMax/src/Log/Ampt.cs b/csharp/app/SaliMax/src/Log/Ampt.cs index d250a01bd..1a63b9eab 100644 --- a/csharp/app/SaliMax/src/Log/Ampt.cs +++ b/csharp/app/SaliMax/src/Log/Ampt.cs @@ -10,16 +10,17 @@ public static class Ampt { if (s is null) return null; + + // TODO return one AMPT device to sum all the other return DeviceType .PvOnDc .CreateDevice("AMPT") - .AddProp("Current 1", s.Current1) - .AddProp("Current 2", s.Current2) - .AddProp("Voltage 1", s.Voltage1) - .AddProp("Voltage 2", s.Voltage2) - .AddProp("Power 1", s.Current1 * s.Voltage1) - .AddProp("Power 2", s.Current2 * s.Voltage2); - // .AddDcConnection(s.AvgCurrent.Round3(), s.AvgVolatge.Round3()); + .AddProp("Current 1", s.Devices[0].Dc.Current) + .AddProp("Current 2", s.Devices[1].Dc.Current) + .AddProp("Voltage 1", s.Devices[0].Dc.Voltage) + .AddProp("Voltage 2", s.Devices[1].Dc.Voltage) + .AddProp("Power 1", s.Devices[0].Dc.Current * s.Devices[0].Dc.Voltage) + .AddProp("Power 2", s.Devices[1].Dc.Current * s.Devices[1].Dc.Voltage); } } \ No newline at end of file diff --git a/csharp/app/SaliMax/src/Log/Battery48Tl.cs b/csharp/app/SaliMax/src/Log/Battery48Tl.cs index 612ea6e28..db755c78d 100644 --- a/csharp/app/SaliMax/src/Log/Battery48Tl.cs +++ b/csharp/app/SaliMax/src/Log/Battery48Tl.cs @@ -14,13 +14,13 @@ public static class Battery48Tl return DeviceType .Battery .CreateDevice("48TL Battery") - .AddDc48Connection(s.Current.Round3(),s.Voltage.Round3()) + .AddDc48Connection(s.Dc.Current.Round3(),s.Dc.Voltage.Round3()) .AddAlarms(s.Alarms) .AddWarnings(s.Warnings) .AddProp("Soc", s.Soc.Round3()) .AddProp("HeaterOn", s.HeaterOn) .AddProp("EocReached", s.EocReached) .AddProp("BatteryCold", s.BatteryCold) - .AddProp("Temperature", s.BatteryTemperature); + .AddProp("Temperature", s.Temperature); } } \ No newline at end of file diff --git a/csharp/app/SaliMax/src/Log/EmuMeter.cs b/csharp/app/SaliMax/src/Log/EmuMeter.cs index a6b7062cf..8b61199cf 100644 --- a/csharp/app/SaliMax/src/Log/EmuMeter.cs +++ b/csharp/app/SaliMax/src/Log/EmuMeter.cs @@ -17,16 +17,16 @@ public static class EmuMeter // - var l1 = CreateAcPhase(s.CurrentL1, s.VoltageL1N, ACos(s.PowerFactorL1)); - var l2 = CreateAcPhase(s.CurrentL2, s.VoltageL2N, ACos(s.PowerFactorL2)); - var l3 = CreateAcPhase(s.CurrentL3, s.VoltageL3N, ACos(s.PowerFactorL3)); + var l1 = CreateAcPhase(s.Ac.L1.Current, s.Ac.L1.Voltage, ACos(s.Ac.L1.PowerFactor)); + var l2 = CreateAcPhase(s.Ac.L2.Current, s.Ac.L2.Voltage, ACos(s.Ac.L2.PowerFactor)); + var l3 = CreateAcPhase(s.Ac.L3.Current, s.Ac.L3.Voltage, ACos(s.Ac.L3.PowerFactor)); var ac = new JsonObject { ["L1"] = l1, ["L2"] = l2, ["L3"] = l3, - ["Frequency"] = s.Frequency + ["Frequency"] = s.Ac.Frequency }; var status = new JsonObject @@ -39,8 +39,8 @@ public static class EmuMeter private static IEnumerable GetAcPhases(this EmuMeterStatus s) { - yield return CreateAcPhase(s.CurrentL1.Round3(),s.VoltageL1N.Round3(),s.PowerFactorL1.Apply(ACos).Round3()); - yield return CreateAcPhase(s.CurrentL2.Round3(),s.VoltageL2N.Round3(),s.PowerFactorL2.Apply(ACos).Round3()); - yield return CreateAcPhase(s.CurrentL3.Round3(),s.VoltageL3N.Round3(),s.PowerFactorL3.Apply(ACos).Round3()); + yield return CreateAcPhase(s.Ac.L1.Current.Round3(),s.Ac.L1.Voltage.Round3(),s.Ac.L1.PowerFactor.Apply(ACos).Round3()); + yield return CreateAcPhase(s.Ac.L2.Current.Round3(),s.Ac.L2.Voltage.Round3(),s.Ac.L2.PowerFactor.Apply(ACos).Round3()); + yield return CreateAcPhase(s.Ac.L3.Current.Round3(),s.Ac.L3.Voltage.Round3(),s.Ac.L3.PowerFactor.Apply(ACos).Round3()); } } \ No newline at end of file diff --git a/csharp/app/SaliMax/src/Log/Salimax.cs b/csharp/app/SaliMax/src/Log/Salimax.cs index 00ff996d8..76bd25648 100644 --- a/csharp/app/SaliMax/src/Log/Salimax.cs +++ b/csharp/app/SaliMax/src/Log/Salimax.cs @@ -24,15 +24,16 @@ public static class Salimax private static IEnumerable GetDevices(StatusRecord s) { - yield return s.InverterStatus.Log("1234"); + yield return s.InverterStatus.Log(); yield return s.DcDcStatus.Log("3214"); - yield return s.GridMeterStatus.Log(DeviceType.Grid); - yield return s.AcInToAcOutMeterStatus.Log(DeviceType.AcInToAcOut); + yield return s.GridMeterStatus.Log(DeviceType.Grid , "123"); + yield return s.AcInToAcOutMeterStatus.Log(DeviceType.AcInToAcOut, "123"); yield return s.AmptStatus.Log(); - yield return s.BatteryStatus.Log(); + yield return s.BatteriesStatus![0].Log(); + yield return s.BatteriesStatus[1].Log(); } - public static JsonArray CreateTopology() + private static JsonArray CreateTopology() { var acInBusJson = JsonUtil.CreateBus ( diff --git a/csharp/app/SaliMax/src/Log/TruConvertAc.cs b/csharp/app/SaliMax/src/Log/TruConvertAc.cs index 9a0446a66..eeb56ea4c 100644 --- a/csharp/app/SaliMax/src/Log/TruConvertAc.cs +++ b/csharp/app/SaliMax/src/Log/TruConvertAc.cs @@ -9,13 +9,12 @@ namespace InnovEnergy.SaliMax.Log; public static class TruConvertAc { - // TODO: remove serialNb arg, embed TruConvertDcStatus - public static JsonObject? Log(this TruConvertAcStatus? s, String serialNb) + public static JsonObject? Log(this TruConvertAcStatus? s) { if (s is null) return null; - - var dcPower = s.PowerAcL1 + s.PowerAcL2 + s.PowerAcL3; + + var dcPower = s.Ac.ActivePower; var dcVoltage = s.ActualDcLinkVoltageLowerHalfExt + s.ActualDcLinkVoltageUpperHalfExt; var dcCurrent = dcVoltage != 0m ? dcPower / dcVoltage @@ -25,16 +24,16 @@ public static class TruConvertAc // TODO: acos quadrant // TODO: total AC power - var l1 = CreateAcPhase(s.PhaseCurrentL1, s.GridVoltageL1, ACos(s.CosPhiL1)); - var l2 = CreateAcPhase(s.PhaseCurrentL2, s.GridVoltageL2, ACos(s.CosPhiL2)); - var l3 = CreateAcPhase(s.PhaseCurrentL3, s.GridVoltageL3, ACos(s.CosPhiL3)); + var l1 = CreateAcPhase(s.Ac.L1.Current.Round3(), s.Ac.L1.Voltage.Round3(), s.Ac.L1.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3()); + var l2 = CreateAcPhase(s.Ac.L2.Current.Round3(), s.Ac.L2.Voltage.Round3(), s.Ac.L1.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3()); + var l3 = CreateAcPhase(s.Ac.L3.Current.Round3(), s.Ac.L3.Voltage.Round3(), s.Ac.L1.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3()); var ac = new JsonObject { ["L1"] = l1, ["L2"] = l2, ["L3"] = l3, - ["Frequency"] = s.GridFrequency + ["Frequency"] = s.Ac.Frequency }; var dc = CreateDcPhase(dcCurrent, dcVoltage); @@ -47,20 +46,20 @@ public static class TruConvertAc ["Alarms"] = s.Alarms.ToJsonArray() , }; - return new JsonObject { [$"TruConvertAc {serialNb}"] = status }; + return new JsonObject { [$"TruConvertAc {s.SerialNumber}"] = status }; } private static IEnumerable GetAcPhases(this TruConvertAcStatus s) { // Math.Acos return "NaN" if the cos phi < -1 or > 1 // Decimal.Acos throw an exception - yield return JsonUtil.CreateAcPhase(s.PhaseCurrentL1.Round3(), s.GridVoltageL1.Round3(), - s.CosPhiL1.Clamp(-1m, 1m).Apply(ACos).Round3()); + yield return JsonUtil.CreateAcPhase(s.Ac.L1.Current.Round3(), s.Ac.L1.Voltage.Round3(), + s.Ac.L1.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3()); - yield return JsonUtil.CreateAcPhase(s.PhaseCurrentL2.Round3(), s.GridVoltageL2.Round3(), - s.CosPhiL2.Clamp(-1m, 1m).Apply(ACos).Round3()); + yield return JsonUtil.CreateAcPhase(s.Ac.L2.Current.Round3(), s.Ac.L2.Voltage.Round3(), + s.Ac.L2.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3()); - yield return JsonUtil.CreateAcPhase(s.PhaseCurrentL3.Round3(), s.GridVoltageL3.Round3(), - s.CosPhiL3.Clamp(-1m, 1m).Apply(ACos).Round3()); + yield return JsonUtil.CreateAcPhase(s.Ac.L3.Current.Round3(), s.Ac.L3.Voltage.Round3(), + s.Ac.L3.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3()); } } \ No newline at end of file diff --git a/csharp/app/SaliMax/src/Log/TruConvertDc.cs b/csharp/app/SaliMax/src/Log/TruConvertDc.cs index 68536c609..09e39d1f2 100644 --- a/csharp/app/SaliMax/src/Log/TruConvertDc.cs +++ b/csharp/app/SaliMax/src/Log/TruConvertDc.cs @@ -14,30 +14,19 @@ public static class TruConvertDc if (s is null) return null; - var dcCurrent = s.DcLinkVoltage != 0m - ? s.DcPower / s.DcLinkVoltage - : 0m; + var dcCurrent = s.Dc.Current; return new JO { { $"TruConvertDc {serialNb}", new JO { - { "Dc" , CreateDcPhase(dcCurrent, s.DcLinkVoltage) }, + { "Dc" , CreateDcPhase(dcCurrent, s.Dc.Voltage) }, { "Dc48" , CreateDcPhase(s.BatteryCurrent, s.BatteryVoltage) }, { "Warnings", s.Warnings.ToJsonArray() }, { "Alarms" , s.Alarms.ToJsonArray() }, } } }; - - // return DeviceType - // .DcDc - // .CreateDevice("TruConvertDc") - // //.AddDcConnection(Decimal.Round(current, 3), s.DcLinkVoltage) - // .AddDc48Connection(Decimal.Round(s.BatteryCurrent, 3), Decimal.Round(s.BatteryVoltage, 3)) - // .AddWarnings(s.Warnings) - // .AddAlarms(s.Alarms) - // .AddProp("DC Power", s.DcPower); } } \ No newline at end of file diff --git a/csharp/app/SaliMax/src/Program.cs b/csharp/app/SaliMax/src/Program.cs index aba4509a4..1bbbc8883 100644 --- a/csharp/app/SaliMax/src/Program.cs +++ b/csharp/app/SaliMax/src/Program.cs @@ -1,3 +1,6 @@ +#undef BatteriesAllowed + + using System.Diagnostics; using System.Text.Json; using System.Text.Json.Nodes; @@ -14,15 +17,18 @@ using InnovEnergy.SaliMax.Log; using InnovEnergy.SaliMax.SaliMaxRelays; using InnovEnergy.SaliMax.SystemConfig; using InnovEnergy.Time.Unix; - +using Utils = InnovEnergy.Lib.StatusApi.Utils; + + #pragma warning disable IL2026 + namespace InnovEnergy.SaliMax; internal static class Program { private const UInt32 UpdateIntervalSeconds = 2; - + public static async Task Main(String[] args) { try @@ -31,7 +37,8 @@ internal static class Program } catch (Exception e) { - await File.AppendAllTextAsync(Config.LogSalimaxLog, String.Join(Environment.NewLine, UnixTime.Now + " \n" + e)); + await File.AppendAllTextAsync(Config.LogSalimaxLog, + String.Join(Environment.NewLine, UnixTime.Now + " \n" + e)); throw; } } @@ -51,33 +58,58 @@ internal static class Program }; #if DEBUG - var inverterDevice = new TruConvertAcDevice("127.0.0.1", 5001); - var dcDcDevice = new TruConvertDcDevice("127.0.0.1", 5002); - var gridMeterDevice = new EmuMeterDevice("127.0.0.1", 5003); - var saliMaxRelaysDevice = new SaliMaxRelaysDevice("127.0.0.1", 5004); - var amptDevice = new AmptCommunicationUnit("127.0.0.1", 5005); + var inverterDevice = new TruConvertAcDevice("127.0.0.1", 5001); + var dcDcDevice = new TruConvertDcDevice("127.0.0.1", 5002); + var gridMeterDevice = new EmuMeterDevice("127.0.0.1", 5003); + var saliMaxRelaysDevice = new SaliMaxRelaysDevice("127.0.0.1", 5004); + var amptDevice = new AmptCommunicationUnit("127.0.0.1", 5005); var acInToAcOutMeterDevice = new EmuMeterDevice("127.0.0.1", 5003); // TODO: use real device - var battery48TlDevice = Battery48TlDevice.Fake(); - var salimaxConfig = new SalimaxConfig(); -#else - var battery48TlDevice = new Battery48TlDevice("/dev/ttyUSB0", 3); - 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 secondBattery48TlDevice = Battery48TlDevice.Fake(); + 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 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 inverterStatusArray = inverterDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); + return new StatusRecord { InverterStatus = inverterDevice.ReadStatus(), DcDcStatus = dcDcDevice.ReadStatus(), - BatteryStatus = battery48TlDevice.ReadStatus(), +#if BatteriesAllowed + + BatteriesStatus = battery48TlStatusArray, + AvgBatteriesStatus = AvgBatteriesStatus.ReadBatteriesStatus(battery48TlStatusArray), +#else + BatteriesStatus = null, + AvgBatteriesStatus = null, +#endif AcInToAcOutMeterStatus = acInToAcOutMeterDevice.ReadStatus(), GridMeterStatus = gridMeterDevice.ReadStatus(), SaliMaxRelayStatus = saliMaxRelaysDevice.ReadStatus(), @@ -86,11 +118,12 @@ internal static class Program }; } - - var startTime = UnixTime.Now; + + var startTime = UnixTime.Now; const Int32 delayTime = 10; - - ReleaseWriteTopology(startTime); + + + await UploadTopology(s3Config, Salimax.TopologyToLog(startTime), startTime); DebugWriteTopology(startTime); Console.WriteLine("press ctrl-C to stop"); @@ -104,19 +137,20 @@ internal static class Program await Task.Delay(delayTime); t = UnixTime.Now; } + var status = ReadStatus(); - //var jsonLog = status.ToLog(t); +#if BatteriesAllowed - //await UploadTimeSeries(s3Config, jsonLog, t); + var jsonLog = status.ToLog(t); + await UploadTimeSeries(s3Config, jsonLog, t); var controlRecord = Controller.Controller.SaliMaxControl(status); Controller.Controller.WriteControlRecord(controlRecord, inverterDevice, dcDcDevice, saliMaxRelaysDevice); - // JsonSerializer.Serialize(jsonLog, JsonOptions).WriteLine(ConsoleColor.DarkBlue); - - //ReleaseWriteLog(jsonLog, t); + //JsonSerializer.Serialize(jsonLog, JsonOptions).WriteLine(ConsoleColor.DarkBlue); +#endif PrintTopology(status); - - while (UnixTime.Now == t) + + while (UnixTime.Now == t) await Task.Delay(delayTime); } // ReSharper disable once FunctionNeverReturns @@ -127,152 +161,191 @@ internal static class Program { const String chargingSeparator = ">>>>>>>>>>"; const String dischargingSeparator = "<<<<<<<<<"; - const Int32 height = 25; + const Int32 height = 25; - - var boxSize = chargingSeparator.Length / 2; - - var pwr = s.InverterStatus!.PowerAcL1 + s.InverterStatus.PowerAcL2 + s.InverterStatus.PowerAcL3; - var pvPower = (s.AmptStatus!.Voltage1 * s.AmptStatus.Current1 + s.AmptStatus!.Voltage2 * s.AmptStatus.Current2).Round0(); - var loadPower = (s.GridMeterStatus!.ActivePowerL123 + pwr).Round3(); // it's a + because the pwr is inverted + var pwr = s.InverterStatus!.Ac.ActivePower; + var pvPower = (s.AmptStatus!.Devices[0].Dc.Voltage * s.AmptStatus.Devices[0].Dc.Current + s.AmptStatus!.Devices[1].Dc.Voltage * s.AmptStatus.Devices[1].Dc.Current).Round0(); // TODO using one Ampt + var loadPower = Utils.Round3((s.GridMeterStatus!.ActivePowerL123 + pwr)); // it's a + because the pwr is inverted - var gridSeparator = s.GridMeterStatus!.ActivePowerL123 > 0 ? chargingSeparator : dischargingSeparator; + var gridSeparator = s.GridMeterStatus!.ActivePowerL123 > 0 ? chargingSeparator : dischargingSeparator; var inverterSeparator = -pwr > 0 ? chargingSeparator : dischargingSeparator; - var dcSeparator = -s.DcDcStatus!.DcPower > 0 ? chargingSeparator : dischargingSeparator; - var batterySeparator = s.BatteryStatus!.Power > 0 ? chargingSeparator : dischargingSeparator; - - - ////////////////// Grid ////////////////////// - var boxGrid = AsciiArt.CreateBox + var dcSeparator = -s.DcDcStatus!.Dc.Power > 0 ? chargingSeparator : dischargingSeparator; +#if BatteriesAllowed + var battery1Separator = s.BatteriesStatus[0]!.Power > 0 ? chargingSeparator : dischargingSeparator; + var battery2Separator = s.BatteriesStatus[1]!.Power > 0 ? chargingSeparator : dischargingSeparator; +#endif + + ////////////////// Grid ////////////////////// + var boxGrid = AsciiArt.CreateBox ( "Grid", - s.GridMeterStatus.VoltageL1N.V(), - s.GridMeterStatus.VoltageL2N.V(), - s.GridMeterStatus.VoltageL3N.V() + s.GridMeterStatus.Ac.L1.Voltage.V(), + s.GridMeterStatus.Ac.L2.Voltage.V(), + s.GridMeterStatus.Ac.L3.Voltage.V() ).AlignCenterVertical(height); - - //var gridBox = CreateRect(0, boxGrid).AlignBottom(height); - var gridAcBusArrow = AsciiArt.CreateHorizontalArrow(s.GridMeterStatus!.ActivePowerL123.Round0(), gridSeparator).AlignCenterVertical(height); - - + + var gridAcBusArrow = AsciiArt.CreateHorizontalArrow(s.GridMeterStatus!.ActivePowerL123.Round0(), gridSeparator) + .AlignCenterVertical(height); + + ////////////////// Ac Bus ////////////////////// - var boxAcBus = AsciiArt.CreateBox + var boxAcBus = AsciiArt.CreateBox ( - "AC Bus", - s.InverterStatus.GridVoltageL1.V(), - s.InverterStatus.GridVoltageL2.V(), - s.InverterStatus.GridVoltageL3.V() + "AC Bus", + s.InverterStatus.Ac.L1.Voltage.V(), + s.InverterStatus.Ac.L2.Voltage.V(), + s.InverterStatus.Ac.L3.Voltage.V() ); - + var boxLoad = AsciiArt.CreateBox ( "", "LOAD", "" ); - - var loadRect = CreateRect(loadPower, boxAcBus, boxLoad).AlignBottom(height); - - var acBusInvertArrow = AsciiArt.CreateHorizontalArrow(-pwr.Round0(), inverterSeparator).AlignCenterVertical(height); - + + var loadRect = CreateRect(boxAcBus, boxLoad, loadPower).AlignBottom(height); + + var acBusInvertArrow = AsciiArt.CreateHorizontalArrow(-pwr.Round0(), inverterSeparator) + .AlignCenterVertical(height); + //////////////////// Inverter ///////////////////////// var inverterBox = AsciiArt.CreateBox - ( - "", - "Inverter", - "" - ).AlignCenterVertical(height); - - var inverterArrow = AsciiArt.CreateHorizontalArrow(-pwr.Round0(), inverterSeparator).AlignCenterVertical(height); - - - //////////////////// DC Bus ///////////////////////// - var dcBusBox = AsciiArt.CreateBox - ( - "DC Bus", - (s.InverterStatus.ActualDcLinkVoltageLowerHalfExt + s.InverterStatus.ActualDcLinkVoltageUpperHalfExt).V(), - "" - ); - - var pvBox = AsciiArt.CreateBox - ( - "", - "MPPT", - "" - ); + ( + "", + "Inverter", + "" + ).AlignCenterVertical(height); - var pvRect = CreateRect(pvPower, pvBox, dcBusBox).AlignTop(height); - - var dcBusArrow = AsciiArt.CreateHorizontalArrow(-s.DcDcStatus!.DcPower.Round0(), dcSeparator).AlignCenterVertical(height); + var inverterArrow = AsciiArt.CreateHorizontalArrow(-pwr.Round0(), inverterSeparator) + .AlignCenterVertical(height); + + + //////////////////// DC Bus ///////////////////////// + var dcBusBox = AsciiArt.CreateBox + ( + "DC Bus", + (s.InverterStatus.ActualDcLinkVoltageLowerHalfExt + s.InverterStatus.ActualDcLinkVoltageUpperHalfExt).V(), + "" + ); + + var pvBox = AsciiArt.CreateBox + ( + "MPPT", + ((s.AmptStatus!.Devices[0].Dc.Voltage + s.AmptStatus!.Devices[1].Dc.Voltage) / 2).Round0().V(), + "" + ); + + var pvRect = CreateRect(pvBox, dcBusBox, pvPower).AlignTop(height); + + var dcBusArrow = AsciiArt.CreateHorizontalArrow(-s.DcDcStatus!.Dc.Power, dcSeparator) + .AlignCenterVertical(height); //////////////////// Dc/Dc ///////////////////////// var dcBox = AsciiArt.CreateBox - ( - "", - "Dc/Dc", - "" - ).AlignCenterVertical(height); - - var dcArrow = AsciiArt.CreateHorizontalArrow(s.BatteryStatus!.Power.Round0(), batterySeparator).AlignCenterVertical(height); - - //////////////////// Battery ///////////////////////// - var batteryBox = AsciiArt.CreateBox - ( - "Battery", - s.BatteryStatus!.Voltage.V(), - "" - ).AlignCenterVertical(height); - - var batteryDegree = AsciiArt.CreateTransitionPadLeft(s.BatteryStatus!.Soc.Percent(), s.BatteryStatus!.BatteryTemperature.Celsius()).AlignCenterVertical(height); - - // var loadLength = boxSize * 6; - // var mpptLength = boxSize * 14; - // - // var mpptBox = AsciiArt.CreateVerticalPad(pvPower.W(),(Int16)mpptLength, true, "MPPT") + "\n"; - // var loadBox = AsciiArt.CreateVerticalPad(loadPower.W(), (Int16)loadLength, false, "Load"); + ( + "Dc/Dc", + s.DcDcStatus.BatteryVoltage.V(), + "" + ).AlignCenterVertical(height); +#if BatteriesAllowed + var dcArrow1 = AsciiArt.CreateHorizontalArrow(s.BatteriesStatus[0]!.Power.Round0(), battery1Separator); + var dcArrow2 = AsciiArt.CreateHorizontalArrow(s.BatteriesStatus[1]!.Power.Round0(), battery2Separator); +#else + var dcArrow1 =""; + var dcArrow2 = ""; + var dcArrowRect = CreateRect(dcArrow1, dcArrow2).AlignCenterVertical(height); +#endif - var topology = boxGrid.SideBySideWith(gridAcBusArrow,"") - .SideBySideWith(loadRect,"") - .SideBySideWith(acBusInvertArrow,"") - .SideBySideWith(inverterBox,"") - .SideBySideWith(inverterArrow,"") - .SideBySideWith(pvRect,"") - .SideBySideWith(dcBusArrow,"") - .SideBySideWith(dcBox,"") - .SideBySideWith(dcArrow,"") - .SideBySideWith(batteryBox,"") - .SideBySideWith(batteryDegree, "") + "\n"; - - // var topology = mpptBox + boxSide11 + loadBox; +#if BatteriesAllowed + //////////////////// Batteries ///////////////////////// + var battery1Box = AsciiArt.CreateBox + ( + "Battery 1", + s.BatteriesStatus[0].Voltage.V(), + s.BatteriesStatus[0].Soc.Percent(), + s.BatteriesStatus[0].Temperature.Celsius() + ); + + var battery2Box = AsciiArt.CreateBox + ( + "Battery 2", + s.BatteriesStatus[1].Voltage.V(), + s.BatteriesStatus[1].Soc.Percent(), + s.BatteriesStatus[1].Temperature.Celsius() + ); + + var batteryRect = CreateRect(battery1Box, battery2Box).AlignCenterVertical(height); + + var avgBatteryBox = AsciiArt.CreateBox + ( + "Batteries", + s.AvgBatteriesStatus!.Voltage.V(), + s.AvgBatteriesStatus.Soc.Percent(), + s.AvgBatteriesStatus.Temperature.Celsius() + ).AlignCenterVertical(height); + + + var topology = boxGrid.SideBySideWith(gridAcBusArrow, "") + .SideBySideWith(loadRect, "") + .SideBySideWith(acBusInvertArrow, "") + .SideBySideWith(inverterBox, "") + .SideBySideWith(inverterArrow, "") + .SideBySideWith(pvRect, "") + .SideBySideWith(dcBusArrow, "") + .SideBySideWith(dcBox, "") + .SideBySideWith(dcArrowRect, "") + .SideBySideWith(batteryRect, "") + .SideBySideWith(avgBatteryBox, "")+ "\n"; +#else + var topology = boxGrid.SideBySideWith(gridAcBusArrow, "") + .SideBySideWith(loadRect, "") + .SideBySideWith(acBusInvertArrow, "") + .SideBySideWith(inverterBox, "") + .SideBySideWith(inverterArrow, "") + .SideBySideWith(pvRect, "") + .SideBySideWith(dcBusArrow, "") + .SideBySideWith(dcBox, "")+ "\n"; +#endif Console.WriteLine(topology); - // Console.WriteLine(loadRect); - // Console.WriteLine(pvRect); } - private static String CreateRect(Decimal loadPower, String boxAcBus, String boxLoad = "") + private static String CreateRect(String boxTop, String boxBottom, Decimal power) { - var loadAcBusArrow = AsciiArt.CreateVerticalArrow(loadPower); - var boxes = new[] { boxAcBus, loadAcBusArrow, boxLoad }; + var powerArrow = AsciiArt.CreateVerticalArrow(power); + var boxes = new[] { boxTop, powerArrow, boxBottom }; var maxWidth = boxes.Max(l => l.Width()); var rect = boxes.Select(l => l.AlignCenterHorizontal(maxWidth)).JoinLines(); return rect; } + private static String CreateRect(String boxTop, String boxBottom) + { + var boxes = new[] { boxTop, boxBottom }; + var maxWidth = boxes.Max(l => l.Width()); + + var rect = boxes.Select(l => l.AlignCenterHorizontal(maxWidth)).JoinLines(); + return rect; + } + + // to delete not used anymore [Conditional("RELEASE")] private static void ReleaseWriteLog(JsonObject jsonLog, UnixTime timestamp) { - WriteToFile(jsonLog, "/home/debian/DataSaliMax/" + timestamp); + // WriteToFile(jsonLog, "/home/debian/DataSaliMax/" + timestamp); // this is was for beaglebone TODO } - [Conditional("RELEASE")] - private static void ReleaseWriteTopology(UnixTime timestamp) + // [Conditional("RELEASE")] + private static JsonObject ReleaseWriteTopology(UnixTime timestamp) { var topologyJson = Salimax.TopologyToLog(timestamp); - WriteToFile(topologyJson, "/home/debian/DataSaliMax/topology" + timestamp); + + // WriteToFile(topologyJson, "/home/debian/DataSaliMax/topology" + timestamp); // this is was for beaglebone + return topologyJson; } [Conditional("DEBUG")] @@ -318,4 +391,19 @@ internal static class Program Console.WriteLine(error); } } + + private static async Task UploadTopology(S3Config config, JsonObject json, UnixTime unixTime) + { + var payload = JsonSerializer.Serialize(json, JsonOptions); + var s3Path = "topology" + unixTime.Ticks + ".json"; + var request = config.CreatePutRequest(s3Path); + var response = await request.PutAsync(new StringContent(payload)); + + if (response.StatusCode != 200) + { + Console.WriteLine("ERROR: PUT"); + var error = response.GetStringAsync(); + Console.WriteLine(error); + } + } } \ No newline at end of file diff --git a/csharp/app/SaliMax/src/SaliMaxRelays/SaliMaxRelaysStatus.cs b/csharp/app/SaliMax/src/SaliMaxRelays/SaliMaxRelaysStatus.cs index 26b72c005..64c08b992 100644 --- a/csharp/app/SaliMax/src/SaliMaxRelays/SaliMaxRelaysStatus.cs +++ b/csharp/app/SaliMax/src/SaliMaxRelays/SaliMaxRelaysStatus.cs @@ -2,9 +2,6 @@ namespace InnovEnergy.SaliMax.SaliMaxRelays; public record SaliMaxRelayStatus { - internal const UInt16 DigitalInputsStartRegister = 1; - internal const UInt16 NbDigitalInputs = 6; - public RelayState K1 { get; init; } = RelayState.Closed; // Address on Adam(0X) 00002 public RelayState K2 { get; init; } = RelayState.Closed; // Address on Adam(0X) 00003 public RelayState K3 { get; init; } = RelayState.Closed; // Address on Adam(0X) 00004 diff --git a/csharp/app/SaliMax/src/SystemConfig/Config.cs b/csharp/app/SaliMax/src/SystemConfig/Config.cs index aaa8b3a86..c11f7d6f7 100644 --- a/csharp/app/SaliMax/src/SystemConfig/Config.cs +++ b/csharp/app/SaliMax/src/SystemConfig/Config.cs @@ -2,5 +2,5 @@ namespace InnovEnergy.SaliMax.SystemConfig; public static class Config { - public const String LogSalimaxLog = "/home/debian/Salimax.log"; + public const String LogSalimaxLog = "/home/ie-entwicklung/Salimax.log"; // todo remove ie-entwicklung } \ No newline at end of file diff --git a/csharp/app/SaliMax/src/SystemConfig/Defaults.cs b/csharp/app/SaliMax/src/SystemConfig/Defaults.cs index c45e9ae49..6b11b6ad1 100644 --- a/csharp/app/SaliMax/src/SystemConfig/Defaults.cs +++ b/csharp/app/SaliMax/src/SystemConfig/Defaults.cs @@ -13,7 +13,7 @@ public static class Defaults Subnet = default, //= 0x FFFFFF00; Gateway = default, //= 0x C0A80102; ResetParamToDefault = false, // Coil - CommunicationTimeout = default, + CommunicationTimeout = TimeSpan.FromSeconds(10), FactoryResetParameters = false, ConnectedSystemConfig = Lib.Devices.Trumpf.TruConvert.SystemConfig.AcDcAndDcDc, UpdateSwTrigger = 0, @@ -25,7 +25,7 @@ public static class Defaults // IlBuildnumber = 0, PowerStageEnable = true, SetValueConfig = SymmetricAcOperationMode.Symmetric, // Asymmetric = 0, // this is can not be seen in UI - ResetsAlarmAndWarning = false, + ResetsAlarmAndWarning = true, PreChargeDcLinkConfig = PreChargeDcLinkConfig.Internal, // 1 = internal PowerFactorConvention = PowerFactorConvention.Producer, // 0 = producer SlaveAddress = 1, @@ -66,9 +66,9 @@ public static class Defaults GridFormingMode = 0, // 0 = not grid-forming (grid-tied) ,1 = grid-forming TODO enum //remove DC stuff from AC - DcLinkRefVoltage = 850, - DcLinkMinVoltage = 830, - DcLinkMaxVoltage = 870, + DcLinkRefVoltage = 800, + DcLinkMinVoltage = 780, + DcLinkMaxVoltage = 820, DcVoltageRefUs = 900, DcMinVoltageUs = 880, DcMaxVoltageUs = 920, @@ -88,7 +88,7 @@ public static class Defaults Subnet = default, Gateway = default, ResetParamToDefault = false , - TimeoutForCommunication = default , + TimeoutForCommunication = TimeSpan.FromSeconds(10) , RestartFlag = false , ConnectedSystemConfig = Lib.Devices.Trumpf.TruConvert.SystemConfig.DcDcOnly, UpdateSwTrigger = 0, @@ -98,7 +98,7 @@ public static class Defaults SerialNumberDcDc = 0, MaterialNumberDcDc = 0, PowerStageEnable = true, - ResetsAlarmAndWarning = false, + ResetsAlarmAndWarning = false, SlaveAddress = 1, SubSlaveAddress = 0, ModbusSlaveId = false, @@ -112,7 +112,7 @@ public static class Defaults BatteryCurrentSet = 0, DynamicCurrentPerMillisecond = 2, DcLinkControlMode = 1, - ReferenceVoltage = 850, + ReferenceVoltage = 800, UpperVoltageWindow = 40, LowerVoltageWindow = 40, VoltageDeadBand = 0, diff --git a/csharp/lib/Devices/AMPT/AmptCommunicationUnit.cs b/csharp/lib/Devices/AMPT/AmptCommunicationUnit.cs index 5bc17c343..239502762 100644 --- a/csharp/lib/Devices/AMPT/AmptCommunicationUnit.cs +++ b/csharp/lib/Devices/AMPT/AmptCommunicationUnit.cs @@ -1,6 +1,7 @@ using DecimalMath; using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Connections; +using InnovEnergy.Lib.StatusApi.Connections; namespace InnovEnergy.Lib.Devices.Ampt; @@ -48,25 +49,22 @@ public class AmptCommunicationUnit .ToList(); var amptSt = new AmptStatus - { - Sid = r.GetUInt32(1), - IdSunSpec = r.GetUInt16(3), - Manufacturer = r.GetString(5, 16), - Model = r.GetString(21, 16), - Version = r.GetString(45, 8), - SerialNumber = r.GetString(53, 16), - DeviceAddress = r.GetInt16(69), - IdVendor = r.GetUInt16(71), - Devices = devices, - Current1 = r.GetInt16(90) * currentFactor, - Current2 = r.GetInt16(106) * currentFactor, - Voltage1 = r.GetUInt32(91) * voltageFactor, - Voltage2 = r.GetUInt32(107) * voltageFactor, - - //AvgVolatge = ReadDevicesVoltage(nbrOfDevices), - //AvgCurrent = ReadDevicesCurrent(nbrOfDevices) + ( + Sid : r.GetUInt32(1), + IdSunSpec : r.GetUInt16(3), + Manufacturer : r.GetString(5, 16), + Model : r.GetString(21, 16), + Version : r.GetString(45, 8), + SerialNumber : r.GetString(53, 16), + DeviceAddress : r.GetInt16(69), + IdVendor : r.GetUInt16(71), + Devices : devices + // devices.d Current1 = r.GetInt16(90) * currentFactor, + // Current2 = r.GetInt16(106) * currentFactor, + // Voltage1 = r.GetUInt32(91) * voltageFactor, + // Voltage2 = r.GetUInt32(107) * voltageFactor - }; + ); return amptSt; @@ -104,26 +102,30 @@ public class AmptCommunicationUnit var b = (UInt16)(FirstDeviceOffset + deviceNumber * RegistersPerDevice); // base address return new AmptDeviceStatus - { - DeviceId = r.GetInt16 (b) , - Timestamp = r.GetUInt32((UInt16)(b + 3)), - Current = r.GetUInt16((UInt16)(b + 5)) * currentFactor, - Voltage = r.GetUInt32((UInt16)(b + 6)) * voltageFactor, - ProductionToday = r.GetUInt32((UInt16)(b + 12))* energyFactor, - Strings = new AmptStringStatus[] + ( + Dc : new DcConnection + ( + Voltage:r.GetUInt32((UInt16)(b + 6)) * voltageFactor, + Current:r.GetUInt16((UInt16)(b + 5)) * currentFactor + ), + DeviceId : r.GetInt16 (b) , + Timestamp : r.GetUInt32((UInt16)(b + 3)), + ProductionToday : r.GetUInt32((UInt16)(b + 12))* energyFactor, + + Strings : new [] { - new() - { - Voltage = r.GetUInt32((UInt16)(b + 8)) * voltageFactor, - Current = r.GetUInt16((UInt16)(b + 14)) * currentFactor, - }, - new() - { - Voltage = r.GetUInt32((UInt16)(b + 9)) * voltageFactor, - Current = r.GetUInt16((UInt16)(b + 15)) * currentFactor, - } + new DcConnection + ( + Voltage : r.GetUInt32((UInt16)(b + 8)) * voltageFactor, + Current : r.GetUInt16((UInt16)(b + 14)) * currentFactor + ), + new DcConnection + ( + Voltage : r.GetUInt32((UInt16)(b + 9)) * voltageFactor, + Current : r.GetUInt16((UInt16)(b + 15)) * currentFactor + ) } - }; + ); } } } \ No newline at end of file diff --git a/csharp/lib/Devices/AMPT/AmptDeviceStatus.cs b/csharp/lib/Devices/AMPT/AmptDeviceStatus.cs index faf77054a..00d9e352f 100644 --- a/csharp/lib/Devices/AMPT/AmptDeviceStatus.cs +++ b/csharp/lib/Devices/AMPT/AmptDeviceStatus.cs @@ -1,14 +1,15 @@ +using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Devices; + namespace InnovEnergy.Lib.Devices.Ampt; public record AmptDeviceStatus -{ - internal const UInt16 NbrOfStrings = 2; - public Int16 DeviceId { get; init; } // The string number - public UInt32 Timestamp { get; init; } // The UTC timestamp of the measurements - - public Decimal Current { get; init; } // String output current in mA - public Decimal Voltage { get; init; } // String output voltage in mV - - public Decimal ProductionToday { get; init; } // converted to kW in AmptCU class - public IReadOnlyList Strings { get; init; } = null!; -} \ No newline at end of file +( + DcConnection Dc, + // UInt16 NbrOfStrings, + Int16 DeviceId, // The string number + UInt32 Timestamp, // The UTC timestamp of the measurements + Decimal ProductionToday, // converted to kW in AmptCU class + IReadOnlyList Strings +): Mppt(Dc, Strings) +{} \ No newline at end of file diff --git a/csharp/lib/Devices/AMPT/AmptStatus.cs b/csharp/lib/Devices/AMPT/AmptStatus.cs index 792a7c5b2..48ce01d2f 100644 --- a/csharp/lib/Devices/AMPT/AmptStatus.cs +++ b/csharp/lib/Devices/AMPT/AmptStatus.cs @@ -1,25 +1,27 @@ +using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Devices; + namespace InnovEnergy.Lib.Devices.Ampt; public record AmptStatus +( + UInt32 Sid, // A well-known value 0x53756e53, uniquely identifies this as a SunSpec Modbus Map + UInt16 IdSunSpec, // A well-known value 1, uniquely identifies this as a SunSpec Common Model + // UInt16 L, // Well-known # of 16-bit registers to follow : 66 + String? Manufacturer, // A well-known value registered with SunSpec for compliance: "Ampt" + String? Model, // Manufacturer specific value "Communication Unit" + String? Version, // Software Version + String? SerialNumber, // Manufacturer specific value + Int16 DeviceAddress, // Modbus Device ID + UInt16 IdVendor, // Ampt SunSpec Vendor Code 64050 + // Decimal Current1, + // Decimal Current2, + // Decimal Voltage1, + // Decimal Voltage2, + IReadOnlyList Devices + //internal const UInt16 StartRegister = 1; + //internal const UInt16 TotalNbOfRegister = 116; +) { - internal const UInt16 StartRegister = 1; - internal const UInt16 TotalNbOfRegister = 116; - - public UInt32 Sid { get; init; } // A well-known value 0x53756e53, uniquely identifies this as a SunSpec Modbus Map - public UInt16 IdSunSpec { get; init; } // A well-known value 1, uniquely identifies this as a SunSpec Common Model - //public UInt16 L { get; init; } // Well-known # of 16-bit registers to follow : 66 - public String? Manufacturer { get; init; } // A well-known value registered with SunSpec for compliance: "Ampt" - public String? Model { get; init; } // Manufacturer specific value "Communication Unit" - public String? Version { get; init; } // Software Version - public String? SerialNumber { get; init; } // Manufacturer specific value - public Int16 DeviceAddress { get; init; } // Modbus Device ID - public UInt16 IdVendor { get; init; } // Ampt SunSpec Vendor Code 64050 - public Decimal AvgVolatge { get; init; } - public Decimal AvgCurrent { get; init; } - public Decimal Current1 { get; init; } - public Decimal Current2 { get; init; } - public Decimal Voltage1 { get; init; } - public Decimal Voltage2 { get; init; } - public IReadOnlyList Devices { get; init; } = null!; } \ No newline at end of file diff --git a/csharp/lib/Devices/Battery48TL/Battery48TL.csproj b/csharp/lib/Devices/Battery48TL/Battery48TL.csproj index 17cea97fb..51feacfe1 100644 --- a/csharp/lib/Devices/Battery48TL/Battery48TL.csproj +++ b/csharp/lib/Devices/Battery48TL/Battery48TL.csproj @@ -9,6 +9,7 @@ + diff --git a/csharp/lib/Devices/Battery48TL/Battery48TLDevice.cs b/csharp/lib/Devices/Battery48TL/Battery48TLDevice.cs index 15bf1a882..979eafaf7 100644 --- a/csharp/lib/Devices/Battery48TL/Battery48TLDevice.cs +++ b/csharp/lib/Devices/Battery48TL/Battery48TLDevice.cs @@ -1,5 +1,7 @@ using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Connections; +using InnovEnergy.Lib.Protocols.Modbus.Conversions; +using InnovEnergy.Lib.StatusApi.Connections; namespace InnovEnergy.Lib.Devices.Battery48TL; @@ -33,6 +35,7 @@ public class Battery48TlDevice { if (Modbus is null) // TODO : remove fake { + Console.WriteLine("Battery is null"); return null; } @@ -41,13 +44,101 @@ public class Battery48TlDevice try { var registers = Modbus.ReadInputRegisters(Constants.BaseAddress, Constants.NoOfRegisters); - return new Battery48TLStatus(registers); + return TryReadStatus(registers); } catch (Exception e) { - Console.WriteLine(e.Message); + Console.WriteLine(e.Message + " Battery "); Modbus.CloseConnection(); return null; } } + + private Battery48TLStatus? TryReadStatus(ModbusRegisters data) + { + var soc = data.ParseDecimal(register: 1054, scaleFactor: 0.1m); + var eocReached = data.ParseEocReached(); + + var warnings = new List(); + + if (data.ParseBool(1006, 1)) warnings.Add("TaM1: BMS temperature high"); + if (data.ParseBool(1006, 4)) warnings.Add("TbM1: Battery temperature high"); + if (data.ParseBool(1006, 6)) warnings.Add("VBm1: Bus voltage low"); + if (data.ParseBool(1006, 8)) warnings.Add("VBM1: Bus voltage high"); + if (data.ParseBool(1006, 10)) warnings.Add("IDM1: Discharge current high"); + if (data.ParseBool(1006, 24)) warnings.Add("vsM1: String voltage high"); + if (data.ParseBool(1006, 26)) warnings.Add("iCM1: Charge current high"); + if (data.ParseBool(1006, 28)) warnings.Add("iDM1: Discharge current high"); + if (data.ParseBool(1006, 30)) warnings.Add("MID1: String voltages unbalanced"); + if (data.ParseBool(1006, 32)) warnings.Add("BLPW: Not enough charging power on bus"); + if (data.ParseBool(1006, 35)) warnings.Add("Ah_W: String SOC low"); + if (data.ParseBool(1006, 38)) warnings.Add("MPMM: Midpoint wiring problem"); + if (data.ParseBool(1006, 39)) warnings.Add("TCMM:"); + if (data.ParseBool(1006, 40)) warnings.Add("TCdi: Temperature difference between strings high"); + if (data.ParseBool(1006, 41)) warnings.Add("WMTO:"); + if (data.ParseBool(1006, 44)) warnings.Add("bit44:"); + if (data.ParseBool(1006, 46)) warnings.Add("CELL1:"); + + var alarms = new List(); + + if (data.ParseBool(1010, 0)) alarms.Add("Tam : BMS temperature too low"); + if (data.ParseBool(1010, 2)) alarms.Add("TaM2 : BMS temperature too high"); + if (data.ParseBool(1010, 3)) alarms.Add("Tbm : Battery temperature too low"); + if (data.ParseBool(1010, 5)) alarms.Add("TbM2 : Battery temperature too high"); + if (data.ParseBool(1010, 7)) alarms.Add("VBm2 : Bus voltage too low"); + if (data.ParseBool(1010, 9)) alarms.Add("VBM2 : Bus voltage too high"); + if (data.ParseBool(1010, 11)) alarms.Add("IDM2 : Discharge current too high"); + if (data.ParseBool(1010, 12)) alarms.Add("ISOB : Electrical insulation failure"); + if (data.ParseBool(1010, 13)) alarms.Add("MSWE : Main switch failure"); + if (data.ParseBool(1010, 14)) alarms.Add("FUSE : Main fuse blown"); + if (data.ParseBool(1010, 15)) alarms.Add("HTRE : Battery failed to warm up"); + if (data.ParseBool(1010, 16)) alarms.Add("TCPE : Temperature sensor failure"); + if (data.ParseBool(1010, 17)) alarms.Add("STRE :"); + if (data.ParseBool(1010, 18)) alarms.Add("CME : Current sensor failure"); + if (data.ParseBool(1010, 19)) alarms.Add("HWFL : BMS hardware failure"); + if (data.ParseBool(1010, 20)) alarms.Add("HWEM : Hardware protection tripped"); + if (data.ParseBool(1010, 21)) alarms.Add("ThM : Heatsink temperature too high"); + if (data.ParseBool(1010, 22)) alarms.Add("vsm1 : String voltage too low"); + if (data.ParseBool(1010, 23)) alarms.Add("vsm2 : Low string voltage failure"); + if (data.ParseBool(1010, 25)) alarms.Add("vsM2 : String voltage too high"); + if (data.ParseBool(1010, 27)) alarms.Add("iCM2 : Charge current too high"); + if (data.ParseBool(1010, 29)) alarms.Add("iDM2 : Discharge current too high"); + if (data.ParseBool(1010, 31)) alarms.Add("MID2 : String voltage unbalance too high"); + if (data.ParseBool(1010, 33)) alarms.Add("CCBF : Internal charger hardware failure"); + if (data.ParseBool(1010, 34)) alarms.Add("AhFL :"); + if (data.ParseBool(1010, 36)) alarms.Add("TbCM :"); + if (data.ParseBool(1010, 37)) alarms.Add("BRNF :"); + if (data.ParseBool(1010, 42)) alarms.Add("HTFS : If Heaters Fuse Blown"); + if (data.ParseBool(1010, 43)) alarms.Add("DATA : Parameters out of range"); + if (data.ParseBool(1010, 45)) alarms.Add("CELL2:"); + + +return new Battery48TLStatus( + Dc: new DcConnection + ( + Voltage : data.ReadVoltage(), + Current : data.ReadCurrent()), + + Soc : !eocReached && soc >= 100m ? 99.9m : soc, + Temperature : data.ParseDecimal(register: 1004, scaleFactor: 0.1m, offset: -400), + BusVoltage : data.ParseDecimal(register: 1002, scaleFactor: 0.01m), + GreenLed : data.ParseLedState(register: 1005, led: LedColor.Green), + AmberLed : data.ParseLedState(register: 1006, led: LedColor.Amber), + BlueLed : data.ParseLedState(register: 1005, led: LedColor.Blue), + RedLed : data.ParseLedState(register: 1005, led: LedColor.Red), + Warnings : warnings, + Alarms : alarms, + MainSwitchClosed : data.ParseBool(baseRegister: 1014, bit: 0), + AlarmOutActive : data.ParseBool(baseRegister: 1014, bit: 1), + InternalFanActive : data.ParseBool(baseRegister: 1014, bit: 2), + VoltMeasurementAllowed: data.ParseBool(baseRegister: 1014, bit: 3), + AuxRelay : data.ParseBool(baseRegister: 1014, bit: 4), + RemoteState : data.ParseBool(baseRegister: 1014, bit: 5), + HeaterOn : data.ParseBool(baseRegister: 1014, bit: 6), + EocReached : eocReached, + BatteryCold : data.ParseBatteryCold(), + MaxChargingPower : data.CalcMaxChargePower(), + MaxDischargingPower : data.CalcMaxDischargePower() + ); + } } \ No newline at end of file diff --git a/csharp/lib/Devices/Battery48TL/Battery48TLStatusRecord.cs b/csharp/lib/Devices/Battery48TL/Battery48TLStatusRecord.cs index 38ae8affa..0871f0645 100644 --- a/csharp/lib/Devices/Battery48TL/Battery48TLStatusRecord.cs +++ b/csharp/lib/Devices/Battery48TL/Battery48TLStatusRecord.cs @@ -1,118 +1,39 @@ using System.Diagnostics.CodeAnalysis; using InnovEnergy.Lib.Protocols.Modbus.Conversions; +using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Devices; namespace InnovEnergy.Lib.Devices.Battery48TL; [SuppressMessage("ReSharper", "InconsistentNaming")] -public class Battery48TLStatus +public record Battery48TLStatus +( + DcConnection Dc, + Decimal Soc, + Decimal Temperature, + //Decimal Current, + //Decimal Voltage, + Decimal BusVoltage, + LedState GreenLed, + LedState AmberLed, + LedState BlueLed, + LedState RedLed, + IReadOnlyList Warnings, + IReadOnlyList Alarms, + Boolean MainSwitchClosed, + Boolean AlarmOutActive, + Boolean InternalFanActive, + Boolean VoltMeasurementAllowed, + Boolean AuxRelay, + Boolean RemoteState, + Boolean HeaterOn, + Boolean EocReached, + Boolean BatteryCold, + Decimal MaxChargingPower, + Decimal MaxDischargingPower +) +: Battery(Dc, Soc, Temperature) { - public Decimal Soc { get; } - public Decimal Current { get; } - public Decimal Voltage { get; } - public Decimal Power => Current * Voltage; // TODO do we have to invert the sign here? - public Decimal BusVoltage { get; } - public Decimal BatteryTemperature { get; } - public LedState GreenLed { get; } - public LedState AmberLed { get; } - public LedState BlueLed { get; } - public LedState RedLed { get; } - public IReadOnlyList Warnings { get; } - public IReadOnlyList Alarms { get; } - public Boolean MainSwitchClosed { get; } - public Boolean AlarmOutActive { get; } - public Boolean InternalFanActive { get; } - public Boolean VoltMeasurementAllowed { get; } - public Boolean AuxRelay { get; } - public Boolean RemoteState { get; } - public Boolean HeaterOn { get; } - public Boolean EocReached { get; } - public Boolean BatteryCold { get; } - public Decimal MaxChargingPower { get; } - public Decimal MaxDischargingPower { get; } - - - public Battery48TLStatus(ModbusRegisters data) - { - - var soc = data.ParseDecimal(register: 1054, scaleFactor: 0.1m); - var eocReached = data.ParseEocReached(); - - var warnings = new List(); - - if (data.ParseBool(1006, 1)) warnings.Add("TaM1: BMS temperature high"); - if (data.ParseBool(1006, 4)) warnings.Add("TbM1: Battery temperature high"); - if (data.ParseBool(1006, 6)) warnings.Add("VBm1: Bus voltage low"); - if (data.ParseBool(1006, 8)) warnings.Add("VBM1: Bus voltage high"); - if (data.ParseBool(1006, 10)) warnings.Add("IDM1: Discharge current high"); - if (data.ParseBool(1006, 24)) warnings.Add("vsM1: String voltage high"); - if (data.ParseBool(1006, 26)) warnings.Add("iCM1: Charge current high"); - if (data.ParseBool(1006, 28)) warnings.Add("iDM1: Discharge current high"); - if (data.ParseBool(1006, 30)) warnings.Add("MID1: String voltages unbalanced"); - if (data.ParseBool(1006, 32)) warnings.Add("BLPW: Not enough charging power on bus"); - if (data.ParseBool(1006, 35)) warnings.Add("Ah_W: String SOC low"); - if (data.ParseBool(1006, 38)) warnings.Add("MPMM: Midpoint wiring problem"); - if (data.ParseBool(1006, 39)) warnings.Add("TCMM:"); - if (data.ParseBool(1006, 40)) warnings.Add("TCdi: Temperature difference between strings high"); - if (data.ParseBool(1006, 41)) warnings.Add("WMTO:"); - if (data.ParseBool(1006, 44)) warnings.Add("bit44:"); - if (data.ParseBool(1006, 46)) warnings.Add("CELL1:"); - - var alarms = new List(); - - if (data.ParseBool(1010, 0)) alarms.Add("Tam : BMS temperature too low"); - if (data.ParseBool(1010, 2)) alarms.Add("TaM2 : BMS temperature too high"); - if (data.ParseBool(1010, 3)) alarms.Add("Tbm : Battery temperature too low"); - if (data.ParseBool(1010, 5)) alarms.Add("TbM2 : Battery temperature too high"); - if (data.ParseBool(1010, 7)) alarms.Add("VBm2 : Bus voltage too low"); - if (data.ParseBool(1010, 9)) alarms.Add("VBM2 : Bus voltage too high"); - if (data.ParseBool(1010, 11)) alarms.Add("IDM2 : Discharge current too high"); - if (data.ParseBool(1010, 12)) alarms.Add("ISOB : Electrical insulation failure"); - if (data.ParseBool(1010, 13)) alarms.Add("MSWE : Main switch failure"); - if (data.ParseBool(1010, 14)) alarms.Add("FUSE : Main fuse blown"); - if (data.ParseBool(1010, 15)) alarms.Add("HTRE : Battery failed to warm up"); - if (data.ParseBool(1010, 16)) alarms.Add("TCPE : Temperature sensor failure"); - if (data.ParseBool(1010, 17)) alarms.Add("STRE :"); - if (data.ParseBool(1010, 18)) alarms.Add("CME : Current sensor failure"); - if (data.ParseBool(1010, 19)) alarms.Add("HWFL : BMS hardware failure"); - if (data.ParseBool(1010, 20)) alarms.Add("HWEM : Hardware protection tripped"); - if (data.ParseBool(1010, 21)) alarms.Add("ThM : Heatsink temperature too high"); - if (data.ParseBool(1010, 22)) alarms.Add("vsm1 : String voltage too low"); - if (data.ParseBool(1010, 23)) alarms.Add("vsm2 : Low string voltage failure"); - if (data.ParseBool(1010, 25)) alarms.Add("vsM2 : String voltage too high"); - if (data.ParseBool(1010, 27)) alarms.Add("iCM2 : Charge current too high"); - if (data.ParseBool(1010, 29)) alarms.Add("iDM2 : Discharge current too high"); - if (data.ParseBool(1010, 31)) alarms.Add("MID2 : String voltage unbalance too high"); - if (data.ParseBool(1010, 33)) alarms.Add("CCBF : Internal charger hardware failure"); - if (data.ParseBool(1010, 34)) alarms.Add("AhFL :"); - if (data.ParseBool(1010, 36)) alarms.Add("TbCM :"); - if (data.ParseBool(1010, 37)) alarms.Add("BRNF :"); - if (data.ParseBool(1010, 42)) alarms.Add("HTFS : If Heaters Fuse Blown"); - if (data.ParseBool(1010, 43)) alarms.Add("DATA : Parameters out of range"); - if (data.ParseBool(1010, 45)) alarms.Add("CELL2:"); - - Voltage = data.ReadVoltage(); - Current = data.ReadCurrent(); - Soc = !eocReached && soc >= 100m ? 99.9m : soc; - BusVoltage = data.ParseDecimal(register: 1002, scaleFactor: 0.01m); - BatteryTemperature = data.ParseDecimal(register: 1004, scaleFactor: 0.1m, offset: -400); - GreenLed = data.ParseLedState(register: 1005, led: LedColor.Green); - AmberLed = data.ParseLedState(register: 1006, led: LedColor.Amber); - BlueLed = data.ParseLedState(register: 1005, led: LedColor.Blue); - RedLed = data.ParseLedState(register: 1005, led: LedColor.Red); - Warnings = warnings; - Alarms = alarms; - MainSwitchClosed = data.ParseBool(baseRegister: 1014, bit: 0); - AlarmOutActive = data.ParseBool(baseRegister: 1014, bit: 1); - InternalFanActive = data.ParseBool(baseRegister: 1014, bit: 2); - VoltMeasurementAllowed = data.ParseBool(baseRegister: 1014, bit: 3); - AuxRelay = data.ParseBool(baseRegister: 1014, bit: 4); - RemoteState = data.ParseBool(baseRegister: 1014, bit: 5); - HeaterOn = data.ParseBool(baseRegister: 1014, bit: 6); - EocReached = eocReached; - BatteryCold = data.ParseBatteryCold(); - MaxChargingPower = data.CalcMaxChargePower(); - MaxDischargingPower = data.CalcMaxDischargePower(); - } } diff --git a/csharp/lib/Devices/Battery48TL/BatteryDataParser.cs b/csharp/lib/Devices/Battery48TL/BatteryDataParser.cs index 50e4b4ae1..916c8989c 100644 --- a/csharp/lib/Devices/Battery48TL/BatteryDataParser.cs +++ b/csharp/lib/Devices/Battery48TL/BatteryDataParser.cs @@ -110,6 +110,22 @@ public static class BatteryDataParser return pLimit; } + + + private static Decimal CalcPowerLimitImposedByTempLimit(Decimal t, Decimal maxAllowedTemp, Decimal power , Decimal setpoint) + { + // const Int32 holdZone = 300; + // const Int32 maxAllowedTemp = 315; + + var kp = 0.05m; + var error = setpoint - power; + var controlOutput = (kp * error) *(1 - Math.Abs((t-307.5m)/7.5m)); + + return controlOutput; + + // var a = holdZone - maxAllowedTemp; + // var b = -a * maxAllowedTemp; + } internal static Decimal CalcMaxChargePower(this ModbusRegisters data) { @@ -133,13 +149,15 @@ public static class BatteryDataParser { var v = ReadVoltage(data); var i = ReadCurrent(data); + var t = data.ParseDecimal(register: 1004, scaleFactor: 0.1m, offset: -400); var pLimits = new[] { CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMin, Constants.RIntMin), CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMin, Constants.RIntMax), CalcPowerLimitImposedByCurrentLimit(v, i, -Constants.IMax, Constants.RIntMin), - CalcPowerLimitImposedByCurrentLimit(v, i, -Constants.IMax, Constants.RIntMax) + CalcPowerLimitImposedByCurrentLimit(v, i, -Constants.IMax, Constants.RIntMax), + // CalcPowerLimitImposedByTempLimit(t,315,300) }; var pLimit = pLimits.Max(); diff --git a/csharp/lib/Devices/Battery48TL/Constants.cs b/csharp/lib/Devices/Battery48TL/Constants.cs index 11432630b..44234a09c 100644 --- a/csharp/lib/Devices/Battery48TL/Constants.cs +++ b/csharp/lib/Devices/Battery48TL/Constants.cs @@ -28,8 +28,5 @@ public static class Constants public const Decimal RIntMin = RStringMin / NumberOfStrings; public const Decimal RIntMax = RStringMax / NumberOfStrings; - public const Decimal IMax = NumberOfStrings * IMaxPerString; - - - + public const Decimal IMax = NumberOfStrings * IMaxPerString; } \ No newline at end of file diff --git a/csharp/lib/Devices/EmuMeter/EmuMeter.csproj b/csharp/lib/Devices/EmuMeter/EmuMeter.csproj index 5b129bb85..c05adbe6b 100644 --- a/csharp/lib/Devices/EmuMeter/EmuMeter.csproj +++ b/csharp/lib/Devices/EmuMeter/EmuMeter.csproj @@ -9,6 +9,7 @@ + diff --git a/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj b/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj index d8eb3e3d3..31669d385 100644 --- a/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj +++ b/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj @@ -9,6 +9,7 @@ + diff --git a/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAcControl.cs b/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAcControl.cs index 137549fbf..74fb87c3a 100644 --- a/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAcControl.cs +++ b/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAcControl.cs @@ -31,7 +31,7 @@ public record TruConvertAcControl public AcErrorPolicy ErrorHandlingPolicy { get; init;} = 0; public AcDcGridType GridType { get; init;} = 0; public UInt16 SubSlaveAddress { get; init;} = 0; - public Boolean UseModbusSlaveIdForAddressing { get; init;} = false; + 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, @@ -63,9 +63,9 @@ public record TruConvertAcControl 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;} = 850; - public UInt16 DcLinkMinVoltage { get; init;} = 830; - public UInt16 DcLinkMaxVoltage { get; init;} = 870; + 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; diff --git a/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs b/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs index 255fc91aa..04c1ed26f 100644 --- a/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs +++ b/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAcDevice.cs @@ -2,7 +2,10 @@ using System.Diagnostics.CodeAnalysis; using InnovEnergy.Lib.Devices.Trumpf.TruConvert; using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Connections; +using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Phases; using InnovEnergy.Lib.Utils; +using static DecimalMath.DecimalEx; using static InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.AcControlRegisters; @@ -39,6 +42,8 @@ public class TruConvertAcDevice WriteRegs(CommunicationTimeout, c.CommunicationTimeout.TotalSeconds.ConvertTo()); WriteRegs(ConnectedSystemConfig, c.ConnectedSystemConfig); + + WriteCoils(PowerStageConfig, c.PowerStageEnable, c.SetValueConfig.ConvertTo(), c.ResetsAlarmAndWarning); @@ -91,6 +96,8 @@ public class TruConvertAcDevice 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 TruConvertAcStatus? ReadStatus() { @@ -112,115 +119,171 @@ public class TruConvertAcDevice { // Console.WriteLine("Reading Ac Device"); - 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 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(); + .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; + + + // //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 TruConvertAcStatus - { + ( + Ac: new ThreePhaseAcConnection + ( + AcPhase.FromActiveReactive( + activePower: powerAcL1, + apparentPower: apparentPowerAcL1, + voltage: gridVoltageL1, + current: phaseCurrentL1), + + AcPhase.FromActiveReactive( + activePower: powerAcL2, + apparentPower: apparentPowerAcL2, + voltage: gridVoltageL2, + current: phaseCurrentL2), + + AcPhase.FromActiveReactive( + activePower: powerAcL3, + apparentPower: apparentPowerAcL3, + voltage: gridVoltageL3, + current: phaseCurrentL3), + + 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), - + 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, + 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 - - ApparentPowerAcL1 = acActualAcDc3.GetUInt16(5131) * 1m, // in VA - ApparentPowerAcL2 = acActualAcDc3.GetUInt16(5132) * 1m, // in VA - ApparentPowerAcL3 = acActualAcDc3.GetUInt16(5133) * 1m, // in VA - - AcDcOverloadIntegratorStatusL1 = acActualAcDc3.GetUInt16(5134) * 0.1m, - AcDcOverloadIntegratorStatusL2 = acActualAcDc3.GetUInt16(5135) * 0.1m, - AcDcOverloadIntegratorStatusL3 = acActualAcDc3.GetUInt16(5136) * 0.1m, - - //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, + 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), - - //acActualMeasurement11 - VoltageIntNtoPE = acActualMeasurement9.GetInt16(5221) * 0.1m, - VoltageExtNtoPE = acActualMeasurement9.GetInt16(5222) * 0.1m, - - //acActualTemp - InletAirTemperature = acActualTemp.GetInt16(5501) * 0.1m, + ActualDcLinkVoltageUpperHalf : acActualMeasurement8.GetUInt16(5211), + ActualDcLinkVoltageLowerHalf : acActualMeasurement8.GetUInt16(5212), + ActualDcLinkVoltageUpperHalfExt : acActualMeasurement8.GetUInt16(5213), + ActualDcLinkVoltageLowerHalfExt : acActualMeasurement8.GetUInt16(5214), - Warnings = warnings, - Alarms = alarms, + VoltageIntNtoPe : acActualMeasurement9.GetInt16(5221) * 0.1m, + VoltageExtNtoPe : acActualMeasurement9.GetInt16(5222) * 0.1m, + //acActualTemp + InletAirTemperature : acActualTemp.GetInt16(5501) * 0.1m, - // acSetValues - AcSignedPowerValue = acSetValues.GetInt16(4196) * -1.0m, // this is also used for control - }; + 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 64c5ea4c8..8f2047ebb 100644 --- a/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAcStatus.cs +++ b/csharp/lib/Devices/Trumpf/TruConvertAc/TruConvertAcStatus.cs @@ -1,60 +1,43 @@ -using System.Diagnostics.CodeAnalysis; using InnovEnergy.Lib.Devices.Trumpf.TruConvert; +using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Devices; namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; using AlarmMessages = IReadOnlyList; using WarningMessages = IReadOnlyList; -[SuppressMessage("ReSharper", "InconsistentNaming")] public record TruConvertAcStatus +( + ThreePhaseAcConnection 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) { - public MainState MainState { get; init; } // 5000 - public UInt16 NumberOfConnectedSlaves { get; init; } // 5001 - public UInt16 NumberOfConnectedSubSlaves { get; init; } - public Decimal AcDcNominalGridFrequency { get; init; } - public Decimal AcDcNominalGridVoltage { get; init; } - public Decimal AcDcActNominalPower { get; init; } - public AcDcGridType AcDcActiveGridType { get; init; } - public Decimal AcDcPowerLimitingStatusAct { get; init; } - public Decimal AcDcDcVoltageReference { get; init; } - public Decimal AcDcDcLinkVoltageMinAct { get; init; } - public Decimal AcDcDcLinkVoltageMaxAct { get; init; } - public Decimal AcDcDcLinkChargedMinVoltage { get; init; } - public Decimal AcDcStmActCustomer { get; init; } - public Decimal ApparentPowerAcL1 { get; init; } - public Decimal ApparentPowerAcL2 { get; init; } - public Decimal ApparentPowerAcL3 { get; init; } - public Decimal AcDcOverloadIntegratorStatusL1 { get; init; } - public Decimal AcDcOverloadIntegratorStatusL2 { get; init; } - public Decimal AcDcOverloadIntegratorStatusL3 { get; init; } - public Decimal PowerAcL1 { get; init; } - public Decimal PowerAcL2 { get; init; } - public Decimal PowerAcL3 { get; init; } - public Decimal PhaseCurrentL1 { get; init; } - public Decimal PhaseCurrentL2 { get; init; } - public Decimal PhaseCurrentL3 { get; init; } - public Decimal GridVoltageL1 { get; init; } - public Decimal GridVoltageL2 { get; init; } - public Decimal GridVoltageL3 { get; init; } - public Decimal CosPhiL1 { get; init; } - public Decimal CosPhiL2 { get; init; } - public Decimal CosPhiL3 { get; init; } - public Decimal SumPowerL1 { get; init; } - public Decimal SumPowerL2 { get; init; } - public Decimal SumPowerL3 { get; init; } - public Decimal GridFrequency { get; init; } - public Decimal ActualDcLinkVoltageUpperHalf { get; init; } - public Decimal ActualDcLinkVoltageLowerHalf { get; init; } - public Decimal ActualDcLinkVoltageUpperHalfExt { get; init; } - public Decimal ActualDcLinkVoltageLowerHalfExt { get; init; } - public Decimal VoltageIntNtoPE { get; init; } - public Decimal VoltageExtNtoPE { get; init; } - public Decimal InletAirTemperature { get; init; } - public WarningMessages Warnings { get; init; } = Array.Empty(); - public AlarmMessages Alarms { get; init; } = Array.Empty(); - public Boolean PowerOperation { get; init; } - public Decimal AcSignedPowerValue { get; init; }// this is in control but we also need to read data - //public Int16 AcSignedPowerValue2 { get; init; } = 0; // For Test - } \ No newline at end of file diff --git a/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj b/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj index 1dde32bd0..c2acc0062 100644 --- a/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj +++ b/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj @@ -10,6 +10,7 @@ + diff --git a/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcControl.cs b/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcControl.cs index 9d01f9f8e..82a4e4dcc 100644 --- a/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcControl.cs +++ b/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcControl.cs @@ -12,7 +12,6 @@ public record TruConvertDcControl 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 ; @@ -36,9 +35,9 @@ public record TruConvertDcControl 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;} = 0; // resolution : 0.1 - public Decimal UpperVoltageWindow { get; init;} = 0; // resolution : 0.1 - public Decimal LowerVoltageWindow { get; init;} = 0; // resolution : 0.1 + 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); diff --git a/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcDevice.cs b/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcDevice.cs index f7649a8c0..89cd675ce 100644 --- a/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcDevice.cs +++ b/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcDevice.cs @@ -2,6 +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.Utils; using static InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.DcControlRegisters; @@ -42,6 +43,7 @@ public class TruConvertDcDevice */ // TODO starting from 4000, evaluate what/if needs updating below 4000 + WriteRegs(TimeoutCommunication, c.TimeoutForCommunication.TotalSeconds.ConvertTo()); WriteCoils(PowerStageOperation, c.PowerStageEnable); WriteCoils(ResetsAlarmAndWarning, c.ResetsAlarmAndWarning); @@ -103,18 +105,14 @@ public class TruConvertDcDevice private TruConvertDcStatus TryReadStatus() { // Console.WriteLine("Reading DC Device"); - var dcPrValMain = ModbusTcpClient.ReadInputRegisters(5001, 3); var dcBatteryValue = ModbusTcpClient.ReadInputRegisters(5101, 1); var dcBatteryValue2 = ModbusTcpClient.ReadInputRegisters(5111, 1); var dcBatteryValue3 = ModbusTcpClient.ReadInputRegisters(5114, 2); - var dcBatteryValue4 = ModbusTcpClient.ReadInputRegisters(5121, 1); - + var dcBatteryValue4 = ModbusTcpClient.ReadInputRegisters(5121, 1); var dcPrValDcDc = ModbusTcpClient.ReadInputRegisters(5124, 1); var dcPrValDcDc2 = ModbusTcpClient.ReadInputRegisters(5127, 2); - var dcTempValue = ModbusTcpClient.ReadInputRegisters(5511, 1); - var dcWarningValues = ModbusTcpClient.ReadInputRegisters(2404, 20); var dcAlarmValues = ModbusTcpClient.ReadInputRegisters(2811, 20); var dcSetValues = ModbusTcpClient.ReadInputRegisters(4001, 1); @@ -133,37 +131,34 @@ public class TruConvertDcDevice var dcCurrentLimitState = GetFlags(dcPrValDcDc.GetUInt16(5124)).ToArray(); + var dcLinkVoltage = dcPrValDcDc2.GetUInt16(5128); + + var dcPower = dcBatteryValue4.GetInt16(5121) * 1m; + + var dcCurrent = dcLinkVoltage != 0m ? dcPower / dcLinkVoltage : 0m; + return new TruConvertDcStatus - { - // dcPrValMain - MainState = (MainState) dcPrValMain.GetInt16(5001), - NumberOfConnectedSlaves = dcPrValMain.GetUInt16(5002), - NumberOfConnectedSubSlaves = dcPrValMain.GetUInt16(5003), + ( - // dcBatteryValue - BatteryVoltage = dcBatteryValue.GetUInt16(5101) * 0.1m, - BatteryCurrent = dcBatteryValue2.GetInt16(5111), + Dc: new DcConnection + ( + dcLinkVoltage, + dcCurrent + ), - TotalDcPower = dcBatteryValue3.GetInt32(5114) * 1m, // Resolution is 0.001 (kW) in Tru convert DC doc, but we want it in W - - DcPower = dcBatteryValue4.GetInt16(5121) * 1m, // Resolution is 0.001 (kW) in Tru convert DC doc, but we want it in W - - // dcPrValDcDc - StatusOfCurrentLimiting = dcCurrentLimitState, - - // dcPrValDcDc2 - OverloadCapacity = dcPrValDcDc2.GetUInt16(5127) * 0.1m, - DcLinkVoltage = dcPrValDcDc2.GetUInt16(5128), - - //dcTempValue - DcDcInletTemperature = dcTempValue.GetInt16(5511), - - Warnings = warnings, - Alarms = alarms, - - // dcSetValues - PowerOperation = dcSetValues.GetBoolean(4001) - }; + 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) + ); } } \ 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 ae92598bf..88551dee1 100644 --- a/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcStatus.cs +++ b/csharp/lib/Devices/Trumpf/TruConvertDc/TruConvertDcStatus.cs @@ -1,4 +1,6 @@ using InnovEnergy.Lib.Devices.Trumpf.TruConvert; +using InnovEnergy.Lib.StatusApi.Connections; +using InnovEnergy.Lib.StatusApi.Devices; namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; @@ -6,22 +8,20 @@ using AlarmMessages = IReadOnlyList; using WarningMessages = IReadOnlyList; using DcCurrentLimitStates = IReadOnlyList; -public record TruConvertDcStatus -{ - public MainState MainState { get; init; } - public UInt16 NumberOfConnectedSlaves { get; init; } - public UInt16 NumberOfConnectedSubSlaves { get; init; } - public Decimal BatteryVoltage { get; init; } - public Decimal BatteryCurrent { get; init; } - public Decimal TotalDcPower { get; init; } - public Decimal DcPower { get; init; } - public DcCurrentLimitStates StatusOfCurrentLimiting { get; init; } = Array.Empty(); - public Decimal OverloadCapacity { get; init; } - public Decimal DcLinkVoltage { get; init; } - public Decimal DcDcInletTemperature { get; init; } - public AlarmMessages Alarms { get; init; } = Array.Empty(); - public WarningMessages Warnings { get; init; } = Array.Empty(); - - public Boolean PowerOperation { get; init; } - -} \ No newline at end of file +public record TruConvertDcStatus +( + DcConnection Dc, + MainState MainState, + UInt16 NumberOfConnectedSlaves, + UInt16 NumberOfConnectedSubSlaves, + Decimal BatteryVoltage, + Decimal BatteryCurrent, + Decimal TotalDcPower, + DcCurrentLimitStates StatusOfCurrentLimiting, + Decimal OverloadCapacity, + Decimal DcDcInletTemperature, + AlarmMessages Alarms, + WarningMessages Warnings, + Boolean PowerOperation +):DcDevice(Dc) +{} \ No newline at end of file diff --git a/csharp/lib/StatusApi/Connections/DcConnection.cs b/csharp/lib/StatusApi/Connections/DcConnection.cs index 6810ea291..cac41968d 100644 --- a/csharp/lib/StatusApi/Connections/DcConnection.cs +++ b/csharp/lib/StatusApi/Connections/DcConnection.cs @@ -1,9 +1,8 @@ using InnovEnergy.Lib.StatusApi.Phases; - namespace InnovEnergy.Lib.StatusApi.Connections; public record DcConnection(Decimal Voltage, Decimal Current) : Phase(Voltage, Current) { - public Decimal Power => Current * Voltage; + public Decimal Power => (Current * Voltage).Round3(); } \ No newline at end of file diff --git a/csharp/lib/StatusApi/Connections/SinglePhaseAcConnection.cs b/csharp/lib/StatusApi/Connections/SinglePhaseAcConnection.cs index 2691cc5fa..6b8c57b2d 100644 --- a/csharp/lib/StatusApi/Connections/SinglePhaseAcConnection.cs +++ b/csharp/lib/StatusApi/Connections/SinglePhaseAcConnection.cs @@ -3,10 +3,10 @@ using InnovEnergy.Lib.StatusApi.Phases; namespace InnovEnergy.Lib.StatusApi.Connections; public record SinglePhaseAcConnection - ( - Decimal Voltage, - Decimal Current, - Decimal Phi, - Decimal Frequency - ) - : AcPhase(Voltage, Current, Phi); \ No newline at end of file +( + Decimal Voltage, + Decimal Current, + Decimal Phi, + Decimal Frequency +); + //: AcPhase(Voltage, Current, Phi); \ No newline at end of file diff --git a/csharp/lib/StatusApi/Phases/AcPhase.cs b/csharp/lib/StatusApi/Phases/AcPhase.cs index 8bb7f8e45..1270527f9 100644 --- a/csharp/lib/StatusApi/Phases/AcPhase.cs +++ b/csharp/lib/StatusApi/Phases/AcPhase.cs @@ -21,12 +21,12 @@ public record AcPhase public static AcPhase FromActiveReactive ( Decimal activePower, - Decimal reactivePower, + Decimal apparentPower, Decimal voltage, Decimal current ) { - var apparentPower = Sqrt(activePower * activePower + reactivePower * reactivePower); + var reactivePower = Sqrt(Math.Abs(apparentPower * apparentPower - activePower * activePower )); var phi = ATan2(reactivePower, activePower); return new AcPhase @@ -39,11 +39,10 @@ public record AcPhase ReactivePower: reactivePower, PowerFactor: Cos(phi) ); - } - public static AcPhase FromVoltageCurrentPhi(Decimal voltage, Decimal current, Decimal phi) + public static AcPhase CreateInstance(Decimal voltage, Decimal current, Decimal phi) { var powerFactor = Cos(phi); diff --git a/csharp/lib/StatusApi/Utils.cs b/csharp/lib/StatusApi/Utils.cs new file mode 100644 index 000000000..b86db8478 --- /dev/null +++ b/csharp/lib/StatusApi/Utils.cs @@ -0,0 +1,11 @@ +using InnovEnergy.Lib.Utils; + +namespace InnovEnergy.Lib.StatusApi; + +public static class Utils +{ + public static Decimal Round3(this Decimal d) + { + return d.RoundToSignificantFigures(3); + } +} \ No newline at end of file diff --git a/csharp/lib/Utils/Utils.csproj b/csharp/lib/Utils/Utils.csproj index a645f2431..0ddcddea5 100644 --- a/csharp/lib/Utils/Utils.csproj +++ b/csharp/lib/Utils/Utils.csproj @@ -6,7 +6,7 @@ - +