Update Status to inherit from Status Api

This commit is contained in:
atef 2023-02-23 13:45:09 +01:00
parent 5affecda55
commit 175f11fccf
41 changed files with 917 additions and 715 deletions

View File

@ -26,7 +26,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VenusLogger", "app/VenusLog
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meiringen", "app/Meiringen/Meiringen.csproj", "{4C816420-FD19-47BF-87FE-599210CA8384}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meiringen", "app/Meiringen/Meiringen.csproj", "{4C816420-FD19-47BF-87FE-599210CA8384}"
EndProject 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 EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BmsTunnel", "app/BmsTunnel/BmsTunnel.csproj", "{40B45363-BE34-420B-8F87-775EE6EE3513}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BmsTunnel", "app/BmsTunnel/BmsTunnel.csproj", "{40B45363-BE34-420B-8F87-775EE6EE3513}"
EndProject EndProject
@ -34,21 +34,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "app", "app", "{145597B4-3E3
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}"
EndProject 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 EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deprecated", "deprecated", "{D846B46B-46FF-4EF7-9B9D-DDBEF9533C56}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deprecated", "deprecated", "{D846B46B-46FF-4EF7-9B9D-DDBEF9533C56}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deprecated", "deprecated", "{46DE03C4-52D1-47AA-8E60-8BB15361D723}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deprecated", "deprecated", "{46DE03C4-52D1-47AA-8E60-8BB15361D723}"
EndProject 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 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 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 EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GuiFeeder", "app\GuiFeeder\GuiFeeder.csproj", "{5B953EC4-51F3-4A0A-ADF5-BAA3D1570CB2}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusApi", "lib/StatusApi/StatusApi.csproj", "{9D17E78C-8A70-43DB-A619-DC12D20D023D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusApi", "lib\StatusApi\StatusApi.csproj", "{9D17E78C-8A70-43DB-A619-DC12D20D023D}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Devices", "Devices", "{4931A385-24DC-4E78-BFF4-356F8D6D5183}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Devices", "Devices", "{4931A385-24DC-4E78-BFF4-356F8D6D5183}"
EndProject EndProject
@ -58,38 +56,36 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Victron", "Victron", "{BD8C
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Trumpf", "Trumpf", "{DDDBEFD0-5DEA-4C7C-A9F2-FDB4636CF092}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Trumpf", "Trumpf", "{DDDBEFD0-5DEA-4C7C-A9F2-FDB4636CF092}"
EndProject 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 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 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 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 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 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 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 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 EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Battery48TL", "lib\Devices\Battery48TL\Battery48TL.csproj", "{1C3F443A-B339-4B08-80E6-8A84817FFEC9}" 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
EndProject 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 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 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 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 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 EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FossilTui", "app\FossilTui\FossilTui.csproj", "{C40264BB-C834-4C48-9B3F-6BEF8F37C0ED}"
EndProject EndProject
Global Global

View File

@ -6,19 +6,15 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\lib\DBus\DBus.csproj" />
<ProjectReference Include="..\..\lib\Devices\EmuMeter\EmuMeter.csproj" /> <ProjectReference Include="..\..\lib\Devices\EmuMeter\EmuMeter.csproj" />
<ProjectReference Include="..\..\lib\EmuMeter\EmuMeter.csproj" />
<ProjectReference Include="..\..\lib\Modbus\Modbus.csproj" />
<ProjectReference Include="..\..\lib\Protocols\DBus\DBus.csproj" /> <ProjectReference Include="..\..\lib\Protocols\DBus\DBus.csproj" />
<ProjectReference Include="..\..\lib\Protocols\Modbus\Modbus.csproj" /> <ProjectReference Include="..\..\lib\Protocols\Modbus\Modbus.csproj" />
<ProjectReference Include="..\..\lib\Utils\Utils.csproj" /> <ProjectReference Include="..\..\lib\Utils\Utils.csproj" />
<ProjectReference Include="..\..\lib\VeDBus\VeDBus.csproj" />
<ProjectReference Include="..\..\lib\Victron\VeDBus\VeDBus.csproj" /> <ProjectReference Include="..\..\lib\Victron\VeDBus\VeDBus.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CliWrap" Version="3.5.0" /> <PackageReference Include="CliWrap" Version="3.6.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -15,12 +15,16 @@
<ProjectReference Include="../../lib/Devices/Trumpf/TruConvert/TruConvert.csproj" /> <ProjectReference Include="../../lib/Devices/Trumpf/TruConvert/TruConvert.csproj" />
<ProjectReference Include="../../lib/StatusApi/StatusApi.csproj" /> <ProjectReference Include="../../lib/StatusApi/StatusApi.csproj" />
<ProjectReference Include="../../lib/Utils/Utils.csproj" /> <ProjectReference Include="../../lib/Utils/Utils.csproj" />
<PackageReference Include="CliWrap" Version="3.5.0" /> <PackageReference Include="CliWrap" Version="3.6.0" />
<PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" /> <PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" />
<PackageReference Include="Flurl.Http" Version="3.2.4" /> <PackageReference Include="Flurl.Http" Version="3.2.4" />
<PackageReference Include="System.IO.Ports" Version="7.0.0" /> <PackageReference Include="System.IO.Ports" Version="7.0.0" />
<ProjectReference Include="..\..\lib\Time\Time.csproj" /> <ProjectReference Include="..\..\lib\Time\Time.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="src\StatusLog" />
</ItemGroup>
</Project> </Project>

View File

@ -3,7 +3,6 @@
dotnet_version='net6.0' dotnet_version='net6.0'
set -e set -e
echo -e "\n============================ Build ============================\n" echo -e "\n============================ Build ============================\n"
@ -11,21 +10,28 @@ echo -e "\n============================ Build ============================\n"
dotnet publish \ dotnet publish \
./SaliMax.csproj \ ./SaliMax.csproj \
-c Release \ -c Release \
-r linux-arm -r linux-x64
echo -e "\n============================ Deploy ============================\n" echo -e "\n============================ Deploy ============================\n"
rsync -v \ rsync -v \
./bin/Release/$dotnet_version/linux-arm/publish/* \ ./bin/Release/$dotnet_version/linux-x64/publish/* \
debian@10.2.1.87:~/salimax ie-entwicklung@10.2.3.49:~/salimax
echo -e "\n============================ Run ============================\n"
# debian@10.2.1.87:~/salimax
echo -e "\n============================ Restart Salimax sevice ============================\n"
ssh -tt \ ssh -tt \
-o StrictHostKeyChecking=no \ ie-entwicklung@10.2.3.49 \
-o UserKnownHostsFile=/dev/null \ sudo systemctl restart salimax.service
-o ConnectTimeout=2 \
debian@10.2.1.87 \
'~/salimax/SaliMax' \ echo -e "\n============================ Print service output ============================\n"
2>/dev/null
ssh -tt \
ie-entwicklung@10.2.3.49 \
journalctl -f -u salimax.service

View File

@ -13,14 +13,14 @@ public static class Control
public static Decimal ControlInverterPower(this StatusRecord status, Decimal targetInverterPower) public static Decimal ControlInverterPower(this StatusRecord status, Decimal targetInverterPower)
{ {
var s = status.InverterStatus!; var s = status.InverterStatus!;
var totalInverterAcPower = s.PowerAcL1 + s.PowerAcL2 + s.PowerAcL3; var totalInverterAcPower = s.Ac.ActivePower;
return ControlPower(totalInverterAcPower, targetInverterPower,status.SalimaxConfig!.PConstant); 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) 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 LowerLimit(params Decimal[] deltas) => deltas.Max();
public static Decimal UpperLimit(params Decimal[] deltas) => deltas.Min(); 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 // TODO: explain LowSOC curve
var a = -2 * s.SalimaxConfig!.SelfDischargePower / s.SalimaxConfig.HoldSocZone; var a = -2 * s.SalimaxConfig!.SelfDischargePower / s.SalimaxConfig.HoldSocZone;
var b = -a * (s.SalimaxConfig.MinSoc + 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) private static Decimal ControlPower(Decimal measurement, Decimal target, Decimal p)

View File

@ -18,7 +18,7 @@ public static class Controller
private static readonly TimeSpan CommunicationTimeout = TimeSpan.FromSeconds(10); private static readonly TimeSpan CommunicationTimeout = TimeSpan.FromSeconds(10);
private static readonly Int16 MaxmimumAllowedBatteryTemp = 315; public static readonly Int16 MaxmimumAllowedBatteryTemp = 315;
private static UInt16 _numberOfInverters; private static UInt16 _numberOfInverters;
@ -71,7 +71,7 @@ public static class Controller
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
} => 9, } => 9,
{ {
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed, SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open,
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
} => 10, } => 10,
{ {
@ -79,11 +79,11 @@ public static class Controller
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
} => 11, } => 11,
{ {
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed, SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open,
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
} => 12, } => 12,
{ {
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open, SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed,
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
} => 13, } => 13,
{ {
@ -91,7 +91,7 @@ public static class Controller
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
} => 14, } => 14,
{ {
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open, SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed,
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
} => 15, } => 15,
{ {
@ -140,7 +140,10 @@ public static class Controller
public static ControlRecord SaliMaxControl(StatusRecord statusRecord) 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 resetDcAlarm = CheckDcDcAlarms(statusRecord);
var lastEocTime = GetLastEocTime(statusRecord); var lastEocTime = GetLastEocTime(statusRecord);
@ -152,32 +155,48 @@ public static class Controller
var noGridMeter = statusRecord.GridMeterStatus == null; var noGridMeter = statusRecord.GridMeterStatus == null;
var saliMaxConfig = statusRecord.SalimaxConfig with { LastEoc = lastEocTime }; var saliMaxConfig = statusRecord.SalimaxConfig with { LastEoc = lastEocTime };
var currentSaliMaxState = GetSaliMaxState(statusRecord);
ExplainState(currentSaliMaxState); ExplainState(currentSaliMaxState);
const RelayState k2Relay = Closed; 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.BatteryStatus is not null; // this is to check var dcPowerStageEnable = statusRecord.BatteriesStatus is not null; // TODO this is to check, Can be the batteries Status be null?
var salimaxRelay = statusRecord.SaliMaxRelayStatus! with { K2 = k2Relay }; // to check var salimaxRelay = statusRecord.SaliMaxRelayStatus! with { K2 = k2Relay }; // to check // this is must be control
if (resetInverterAlarm)
if (statusRecord.BatteryStatus == null)
{ {
acPowerStageEnable = !resetInverterAlarm ;
acSlaveId = 0;
}
if (resetDcAlarm)
{
dcPowerStageEnable = !resetDcAlarm ;
}
acSlaveId.WriteLine(" AcSlave @");
if (statusRecord.BatteriesStatus == null)
{
Console.WriteLine(" No batteries");
return new ControlRecord return new ControlRecord
{ {
AcControlRecord = Defaults.TruConvertAcControl with AcControlRecord = Defaults.TruConvertAcControl with
{ {
SignedPowerNominalValue = 0, SignedPowerNominalValue = 0,
PowerStageEnable = acPowerStageEnable, PowerStageEnable = acPowerStageEnable,
CommunicationTimeout = CommunicationTimeout,
SlaveAddress = acSlaveId,
ResetsAlarmAndWarning = resetInverterAlarm ResetsAlarmAndWarning = resetInverterAlarm
}, },
DcControlRecord = Defaults.TruConvertDcControl with DcControlRecord = Defaults.TruConvertDcControl with
{ {
PowerStageEnable = dcPowerStageEnable, PowerStageEnable = dcPowerStageEnable,
ResetsAlarmAndWarning = resetDcAlarm ResetsAlarmAndWarning = resetDcAlarm,
TimeoutForCommunication = CommunicationTimeout
}, },
SalimaxConfig = saliMaxConfig, // must create a control of each SalimaxConfig = saliMaxConfig, // must create a control of each
SalimaxRelays = salimaxRelay, // 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(); 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 currentPowerSetPoint = statusRecord.InverterStatus!.AcSignedPowerValue;
var limitReason = "no limit"; var limitReason = "no limit";
@ -212,7 +263,7 @@ public static class Controller
goal = "Calibration Charge"; goal = "Calibration Charge";
delta = statusRecord.ControlInverterPower(statusRecord.SalimaxConfig.MaxInverterPower); 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})"; goal = $"reach min SOC (Min soc: {statusRecord.SalimaxConfig.MinSoc})";
delta = statusRecord.ControlInverterPower(statusRecord.SalimaxConfig delta = statusRecord.ControlInverterPower(statusRecord.SalimaxConfig
@ -234,7 +285,7 @@ public static class Controller
delta = inverterAc2DcLimitPower; delta = inverterAc2DcLimitPower;
} }
var batteryChargingLimitPower = statusRecord.ControlBatteryPower(statusRecord.BatteryStatus!.MaxChargingPower); var batteryChargingLimitPower = statusRecord.ControlBatteryPower(statusRecord.BatteriesStatus[0]!.MaxChargingPower);
if (delta > batteryChargingLimitPower) if (delta > batteryChargingLimitPower)
{ {
@ -253,12 +304,12 @@ public static class Controller
} }
var batteryDischargingLimitPower = var batteryDischargingLimitPower =
statusRecord.ControlBatteryPower(statusRecord.BatteryStatus!.MaxDischargingPower); statusRecord.ControlBatteryPower(statusRecord.BatteriesStatus[0]!.MaxDischargingPower); // TODO change to avg battery
if (delta < batteryDischargingLimitPower) if (delta < batteryDischargingLimitPower)
{ {
limitReason = 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; delta = batteryDischargingLimitPower;
} }
@ -271,13 +322,13 @@ public static class Controller
delta = keepMinSocLimitDelta; delta = keepMinSocLimitDelta;
} }
/* if (statusRecord.BatteryStatus.BatteryTemperature >= 300) must not reduce the delta // if (statusRecord.BatteriesStatus[0]!.Temperature >= 300) //must not reduce the delta
{ // {
var softLandingFactor = (MaxmimumAllowedBatteryTemp - statusRecord.BatteryStatus.BatteryTemperature) / 15; //starting softlanding from 300 degree // var softLandingFactor = (MaxmimumAllowedBatteryTemp - statusRecord.BatteriesStatus[0]!.Temperature) / 15; //starting softlanding from 300 degree
limitReason = // limitReason =
$"limiting discharging power in order to stay keep the battery temp below 315°: {statusRecord.BatteryStatus.BatteryTemperature}°" + " Softlanding factor: " + softLandingFactor; // $"limiting discharging power in order to stay keep the battery temp below 315°: {statusRecord.BatteriesStatus[0]!.Temperature}°" + " Softlanding factor: " + softLandingFactor;
delta *= softLandingFactor; // delta *= softLandingFactor;
}*/ // }
var newPowerSetPoint = var newPowerSetPoint =
DistributePower(currentPowerSetPoint + delta, statusRecord.SalimaxConfig.MaxInverterPower); DistributePower(currentPowerSetPoint + delta, statusRecord.SalimaxConfig.MaxInverterPower);
@ -289,32 +340,7 @@ public static class Controller
limitReason.WriteLine(" Limit reason"); limitReason.WriteLine(" Limit reason");
delta.WriteLine(" Delta"); delta.WriteLine(" Delta");
// "============".WriteLine(); // "============".WriteLine();
return newPowerSetPoint;
////////////////////////// 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
};
} }
private static State TargetState(State currentState) private static State TargetState(State currentState)
@ -423,7 +449,7 @@ public static class Controller
private static UnixTime GetLastEocTime(StatusRecord statusRecord) 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"); Console.WriteLine("battery has reached EOC");
File.AppendAllTextAsync(Config.LogSalimaxLog, String.Join(Environment.NewLine, UnixTime.Now + "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) private static Boolean CheckDcDcAlarms(StatusRecord s)
{ {
s.DcDcStatus?.Alarms.Count.WriteLine(" Dc Alarm count");
if ( s.DcDcStatus?.Alarms.Count > 0 && if ( s.DcDcStatus?.Alarms.Count > 0 &&
s.DcDcStatus?.PowerOperation == false) s.DcDcStatus?.PowerOperation == false)
{ {
@ -452,14 +479,15 @@ public static class Controller
return false; return false;
} }
private static Boolean CheckInverterAlarms(StatusRecord s) private static Boolean CheckInverterAlarms(StatusRecord s, UInt16 state)
{ {
if ( s.InverterStatus?.Alarms.Count > 0 && s.InverterStatus?.Alarms.Count.WriteLine(" Ac Alarm count");
s.InverterStatus?.PowerOperation == false) 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 true;
} }
return false; return false;
} }

View File

@ -5,14 +5,26 @@ public enum State : Int16
{ {
State1 = 1, State1 = 1,
State2 = 2, State2 = 2,
State3 = 3,
State4 = 4, State4 = 4,
State5 = 5,
State6 = 6, State6 = 6,
State7 = 7,
State8 = 8,
State9 = 9, State9 = 9,
State10 = 10,
State11 = 11,
State12 = 12, State12 = 12,
State13 = 13, State13 = 13,
State14 = 14,
State15 = 15, State15 = 15,
State16 = 16, State16 = 16,
State17 = 17, State17 = 17,
State18 = 18,
State19 = 19,
State20 = 20,
State21 = 21, State21 = 21,
State22 = 22, State22 = 22,
State23 = 23,
State24 = 24
} }

View File

@ -3,5 +3,5 @@ namespace InnovEnergy.SaliMax.Controller;
public static class StateConfig public static class StateConfig
{ {
public static readonly IReadOnlyList<Int32> AcPowerStageEnableStates = new[] { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; public static readonly IReadOnlyList<Int32> AcPowerStageEnableStates = new[] {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 };
} }

View File

@ -10,13 +10,13 @@ namespace InnovEnergy.SaliMax.Controller;
public record StatusRecord public record StatusRecord
{ {
public TruConvertAcStatus? InverterStatus { get; init; } public TruConvertAcStatus? InverterStatus { get; init; }
public TruConvertDcStatus? DcDcStatus { get; init; } public TruConvertDcStatus? DcDcStatus { get; init; }
public Battery48TLStatus? BatteryStatus { get; init; } public Battery48TLStatus[]? BatteriesStatus { get; set; } = Array.Empty<Battery48TLStatus>(); // TODO remove static
public EmuMeterStatus? GridMeterStatus { get; init; } public AvgBatteriesStatus? AvgBatteriesStatus { get; init; }
public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; } public EmuMeterStatus? GridMeterStatus { get; init; }
public AmptStatus? AmptStatus { get; init; } public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; }
public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; } public AmptStatus? AmptStatus { get; init; }
public SalimaxConfig SalimaxConfig { get; init; } = null!; public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; }
public SalimaxConfig SalimaxConfig { get; init; } = null!;
} }

View File

@ -11,15 +11,16 @@ public static class Ampt
if (s is null) if (s is null)
return null; return null;
// TODO return one AMPT device to sum all the other
return DeviceType return DeviceType
.PvOnDc .PvOnDc
.CreateDevice("AMPT") .CreateDevice("AMPT")
.AddProp("Current 1", s.Current1) .AddProp("Current 1", s.Devices[0].Dc.Current)
.AddProp("Current 2", s.Current2) .AddProp("Current 2", s.Devices[1].Dc.Current)
.AddProp("Voltage 1", s.Voltage1) .AddProp("Voltage 1", s.Devices[0].Dc.Voltage)
.AddProp("Voltage 2", s.Voltage2) .AddProp("Voltage 2", s.Devices[1].Dc.Voltage)
.AddProp("Power 1", s.Current1 * s.Voltage1) .AddProp("Power 1", s.Devices[0].Dc.Current * s.Devices[0].Dc.Voltage)
.AddProp("Power 2", s.Current2 * s.Voltage2); .AddProp("Power 2", s.Devices[1].Dc.Current * s.Devices[1].Dc.Voltage);
// .AddDcConnection(s.AvgCurrent.Round3(), s.AvgVolatge.Round3());
} }
} }

View File

@ -14,13 +14,13 @@ public static class Battery48Tl
return DeviceType return DeviceType
.Battery .Battery
.CreateDevice("48TL Battery") .CreateDevice("48TL Battery")
.AddDc48Connection(s.Current.Round3(),s.Voltage.Round3()) .AddDc48Connection(s.Dc.Current.Round3(),s.Dc.Voltage.Round3())
.AddAlarms(s.Alarms) .AddAlarms(s.Alarms)
.AddWarnings(s.Warnings) .AddWarnings(s.Warnings)
.AddProp("Soc", s.Soc.Round3()) .AddProp("Soc", s.Soc.Round3())
.AddProp("HeaterOn", s.HeaterOn) .AddProp("HeaterOn", s.HeaterOn)
.AddProp("EocReached", s.EocReached) .AddProp("EocReached", s.EocReached)
.AddProp("BatteryCold", s.BatteryCold) .AddProp("BatteryCold", s.BatteryCold)
.AddProp("Temperature", s.BatteryTemperature); .AddProp("Temperature", s.Temperature);
} }
} }

View File

@ -17,16 +17,16 @@ public static class EmuMeter
// //
var l1 = CreateAcPhase(s.CurrentL1, s.VoltageL1N, ACos(s.PowerFactorL1)); var l1 = CreateAcPhase(s.Ac.L1.Current, s.Ac.L1.Voltage, ACos(s.Ac.L1.PowerFactor));
var l2 = CreateAcPhase(s.CurrentL2, s.VoltageL2N, ACos(s.PowerFactorL2)); var l2 = CreateAcPhase(s.Ac.L2.Current, s.Ac.L2.Voltage, ACos(s.Ac.L2.PowerFactor));
var l3 = CreateAcPhase(s.CurrentL3, s.VoltageL3N, ACos(s.PowerFactorL3)); var l3 = CreateAcPhase(s.Ac.L3.Current, s.Ac.L3.Voltage, ACos(s.Ac.L3.PowerFactor));
var ac = new JsonObject var ac = new JsonObject
{ {
["L1"] = l1, ["L1"] = l1,
["L2"] = l2, ["L2"] = l2,
["L3"] = l3, ["L3"] = l3,
["Frequency"] = s.Frequency ["Frequency"] = s.Ac.Frequency
}; };
var status = new JsonObject var status = new JsonObject
@ -39,8 +39,8 @@ public static class EmuMeter
private static IEnumerable<JsonObject> GetAcPhases(this EmuMeterStatus s) private static IEnumerable<JsonObject> GetAcPhases(this EmuMeterStatus s)
{ {
yield return CreateAcPhase(s.CurrentL1.Round3(),s.VoltageL1N.Round3(),s.PowerFactorL1.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.CurrentL2.Round3(),s.VoltageL2N.Round3(),s.PowerFactorL2.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.CurrentL3.Round3(),s.VoltageL3N.Round3(),s.PowerFactorL3.Apply(ACos).Round3()); yield return CreateAcPhase(s.Ac.L3.Current.Round3(),s.Ac.L3.Voltage.Round3(),s.Ac.L3.PowerFactor.Apply(ACos).Round3());
} }
} }

View File

@ -24,15 +24,16 @@ public static class Salimax
private static IEnumerable<JsonNode?> GetDevices(StatusRecord s) private static IEnumerable<JsonNode?> GetDevices(StatusRecord s)
{ {
yield return s.InverterStatus.Log("1234"); yield return s.InverterStatus.Log();
yield return s.DcDcStatus.Log("3214"); yield return s.DcDcStatus.Log("3214");
yield return s.GridMeterStatus.Log(DeviceType.Grid); yield return s.GridMeterStatus.Log(DeviceType.Grid , "123");
yield return s.AcInToAcOutMeterStatus.Log(DeviceType.AcInToAcOut); yield return s.AcInToAcOutMeterStatus.Log(DeviceType.AcInToAcOut, "123");
yield return s.AmptStatus.Log(); 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 var acInBusJson = JsonUtil.CreateBus
( (

View File

@ -9,13 +9,12 @@ namespace InnovEnergy.SaliMax.Log;
public static class TruConvertAc public static class TruConvertAc
{ {
// TODO: remove serialNb arg, embed TruConvertDcStatus public static JsonObject? Log(this TruConvertAcStatus? s)
public static JsonObject? Log(this TruConvertAcStatus? s, String serialNb)
{ {
if (s is null) if (s is null)
return null; return null;
var dcPower = s.PowerAcL1 + s.PowerAcL2 + s.PowerAcL3; var dcPower = s.Ac.ActivePower;
var dcVoltage = s.ActualDcLinkVoltageLowerHalfExt + s.ActualDcLinkVoltageUpperHalfExt; var dcVoltage = s.ActualDcLinkVoltageLowerHalfExt + s.ActualDcLinkVoltageUpperHalfExt;
var dcCurrent = dcVoltage != 0m var dcCurrent = dcVoltage != 0m
? dcPower / dcVoltage ? dcPower / dcVoltage
@ -25,16 +24,16 @@ public static class TruConvertAc
// TODO: acos quadrant // TODO: acos quadrant
// TODO: total AC power // TODO: total AC power
var l1 = CreateAcPhase(s.PhaseCurrentL1, s.GridVoltageL1, ACos(s.CosPhiL1)); 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.PhaseCurrentL2, s.GridVoltageL2, ACos(s.CosPhiL2)); 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.PhaseCurrentL3, s.GridVoltageL3, ACos(s.CosPhiL3)); 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 var ac = new JsonObject
{ {
["L1"] = l1, ["L1"] = l1,
["L2"] = l2, ["L2"] = l2,
["L3"] = l3, ["L3"] = l3,
["Frequency"] = s.GridFrequency ["Frequency"] = s.Ac.Frequency
}; };
var dc = CreateDcPhase(dcCurrent, dcVoltage); var dc = CreateDcPhase(dcCurrent, dcVoltage);
@ -47,20 +46,20 @@ public static class TruConvertAc
["Alarms"] = s.Alarms.ToJsonArray() , ["Alarms"] = s.Alarms.ToJsonArray() ,
}; };
return new JsonObject { [$"TruConvertAc {serialNb}"] = status }; return new JsonObject { [$"TruConvertAc {s.SerialNumber}"] = status };
} }
private static IEnumerable<JsonObject> GetAcPhases(this TruConvertAcStatus s) private static IEnumerable<JsonObject> GetAcPhases(this TruConvertAcStatus s)
{ {
// Math.Acos return "NaN" if the cos phi < -1 or > 1 // Math.Acos return "NaN" if the cos phi < -1 or > 1
// Decimal.Acos throw an exception // Decimal.Acos throw an exception
yield return JsonUtil.CreateAcPhase(s.PhaseCurrentL1.Round3(), s.GridVoltageL1.Round3(), yield return JsonUtil.CreateAcPhase(s.Ac.L1.Current.Round3(), s.Ac.L1.Voltage.Round3(),
s.CosPhiL1.Clamp(-1m, 1m).Apply(ACos).Round3()); s.Ac.L1.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3());
yield return JsonUtil.CreateAcPhase(s.PhaseCurrentL2.Round3(), s.GridVoltageL2.Round3(), yield return JsonUtil.CreateAcPhase(s.Ac.L2.Current.Round3(), s.Ac.L2.Voltage.Round3(),
s.CosPhiL2.Clamp(-1m, 1m).Apply(ACos).Round3()); s.Ac.L2.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3());
yield return JsonUtil.CreateAcPhase(s.PhaseCurrentL3.Round3(), s.GridVoltageL3.Round3(), yield return JsonUtil.CreateAcPhase(s.Ac.L3.Current.Round3(), s.Ac.L3.Voltage.Round3(),
s.CosPhiL3.Clamp(-1m, 1m).Apply(ACos).Round3()); s.Ac.L3.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3());
} }
} }

View File

@ -14,30 +14,19 @@ public static class TruConvertDc
if (s is null) if (s is null)
return null; return null;
var dcCurrent = s.DcLinkVoltage != 0m var dcCurrent = s.Dc.Current;
? s.DcPower / s.DcLinkVoltage
: 0m;
return new JO return new JO
{ {
{ {
$"TruConvertDc {serialNb}", new JO $"TruConvertDc {serialNb}", new JO
{ {
{ "Dc" , CreateDcPhase(dcCurrent, s.DcLinkVoltage) }, { "Dc" , CreateDcPhase(dcCurrent, s.Dc.Voltage) },
{ "Dc48" , CreateDcPhase(s.BatteryCurrent, s.BatteryVoltage) }, { "Dc48" , CreateDcPhase(s.BatteryCurrent, s.BatteryVoltage) },
{ "Warnings", s.Warnings.ToJsonArray() }, { "Warnings", s.Warnings.ToJsonArray() },
{ "Alarms" , s.Alarms.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);
} }
} }

View File

@ -1,3 +1,6 @@
#undef BatteriesAllowed
using System.Diagnostics; using System.Diagnostics;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
@ -14,9 +17,12 @@ using InnovEnergy.SaliMax.Log;
using InnovEnergy.SaliMax.SaliMaxRelays; using InnovEnergy.SaliMax.SaliMaxRelays;
using InnovEnergy.SaliMax.SystemConfig; using InnovEnergy.SaliMax.SystemConfig;
using InnovEnergy.Time.Unix; using InnovEnergy.Time.Unix;
using Utils = InnovEnergy.Lib.StatusApi.Utils;
#pragma warning disable IL2026 #pragma warning disable IL2026
namespace InnovEnergy.SaliMax; namespace InnovEnergy.SaliMax;
internal static class Program internal static class Program
@ -31,7 +37,8 @@ internal static class Program
} }
catch (Exception e) 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; throw;
} }
} }
@ -51,33 +58,58 @@ internal static class Program
}; };
#if DEBUG #if DEBUG
var inverterDevice = new TruConvertAcDevice("127.0.0.1", 5001); var inverterDevice = new TruConvertAcDevice("127.0.0.1", 5001);
var dcDcDevice = new TruConvertDcDevice("127.0.0.1", 5002); var dcDcDevice = new TruConvertDcDevice("127.0.0.1", 5002);
var gridMeterDevice = new EmuMeterDevice("127.0.0.1", 5003); var gridMeterDevice = new EmuMeterDevice("127.0.0.1", 5003);
var saliMaxRelaysDevice = new SaliMaxRelaysDevice("127.0.0.1", 5004); var saliMaxRelaysDevice = new SaliMaxRelaysDevice("127.0.0.1", 5004);
var amptDevice = new AmptCommunicationUnit("127.0.0.1", 5005); var amptDevice = new AmptCommunicationUnit("127.0.0.1", 5005);
var acInToAcOutMeterDevice = new EmuMeterDevice("127.0.0.1", 5003); // TODO: use real device var acInToAcOutMeterDevice = new EmuMeterDevice("127.0.0.1", 5003); // TODO: use real device
var battery48TlDevice = Battery48TlDevice.Fake(); var secondBattery48TlDevice = Battery48TlDevice.Fake();
var salimaxConfig = new SalimaxConfig(); var firstBattery48TlDevice =Battery48TlDevice.Fake();;
#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 salimaxConfig = new SalimaxConfig(); 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 #endif
var dcDcDevices = new[] { dcDcDevice };
var inverterDevices = new[] { inverterDevice};
StatusRecord ReadStatus() 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 return new StatusRecord
{ {
InverterStatus = inverterDevice.ReadStatus(), InverterStatus = inverterDevice.ReadStatus(),
DcDcStatus = dcDcDevice.ReadStatus(), DcDcStatus = dcDcDevice.ReadStatus(),
BatteryStatus = battery48TlDevice.ReadStatus(), #if BatteriesAllowed
BatteriesStatus = battery48TlStatusArray,
AvgBatteriesStatus = AvgBatteriesStatus.ReadBatteriesStatus(battery48TlStatusArray),
#else
BatteriesStatus = null,
AvgBatteriesStatus = null,
#endif
AcInToAcOutMeterStatus = acInToAcOutMeterDevice.ReadStatus(), AcInToAcOutMeterStatus = acInToAcOutMeterDevice.ReadStatus(),
GridMeterStatus = gridMeterDevice.ReadStatus(), GridMeterStatus = gridMeterDevice.ReadStatus(),
SaliMaxRelayStatus = saliMaxRelaysDevice.ReadStatus(), SaliMaxRelayStatus = saliMaxRelaysDevice.ReadStatus(),
@ -87,10 +119,11 @@ internal static class Program
} }
var startTime = UnixTime.Now; var startTime = UnixTime.Now;
const Int32 delayTime = 10; const Int32 delayTime = 10;
ReleaseWriteTopology(startTime);
await UploadTopology(s3Config, Salimax.TopologyToLog(startTime), startTime);
DebugWriteTopology(startTime); DebugWriteTopology(startTime);
Console.WriteLine("press ctrl-C to stop"); Console.WriteLine("press ctrl-C to stop");
@ -104,16 +137,17 @@ internal static class Program
await Task.Delay(delayTime); await Task.Delay(delayTime);
t = UnixTime.Now; t = UnixTime.Now;
} }
var status = ReadStatus();
//var jsonLog = status.ToLog(t);
//await UploadTimeSeries(s3Config, jsonLog, t); var status = ReadStatus();
#if BatteriesAllowed
var jsonLog = status.ToLog(t);
await UploadTimeSeries(s3Config, jsonLog, t);
var controlRecord = Controller.Controller.SaliMaxControl(status); var controlRecord = Controller.Controller.SaliMaxControl(status);
Controller.Controller.WriteControlRecord(controlRecord, inverterDevice, dcDcDevice, saliMaxRelaysDevice); Controller.Controller.WriteControlRecord(controlRecord, inverterDevice, dcDcDevice, saliMaxRelaysDevice);
// JsonSerializer.Serialize(jsonLog, JsonOptions).WriteLine(ConsoleColor.DarkBlue); //JsonSerializer.Serialize(jsonLog, JsonOptions).WriteLine(ConsoleColor.DarkBlue);
#endif
//ReleaseWriteLog(jsonLog, t);
PrintTopology(status); PrintTopology(status);
while (UnixTime.Now == t) while (UnixTime.Now == t)
@ -127,42 +161,41 @@ internal static class Program
{ {
const String chargingSeparator = ">>>>>>>>>>"; const String chargingSeparator = ">>>>>>>>>>";
const String dischargingSeparator = "<<<<<<<<<"; const String dischargingSeparator = "<<<<<<<<<";
const Int32 height = 25; const Int32 height = 25;
var boxSize = chargingSeparator.Length / 2; 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 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 gridSeparator = s.GridMeterStatus!.ActivePowerL123 > 0 ? chargingSeparator : dischargingSeparator;
var inverterSeparator = -pwr > 0 ? chargingSeparator : dischargingSeparator; var inverterSeparator = -pwr > 0 ? chargingSeparator : dischargingSeparator;
var dcSeparator = -s.DcDcStatus!.DcPower > 0 ? chargingSeparator : dischargingSeparator; var dcSeparator = -s.DcDcStatus!.Dc.Power > 0 ? chargingSeparator : dischargingSeparator;
var batterySeparator = s.BatteryStatus!.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 //////////////////////
////////////////// Grid ////////////////////// var boxGrid = AsciiArt.CreateBox
var boxGrid = AsciiArt.CreateBox
( (
"Grid", "Grid",
s.GridMeterStatus.VoltageL1N.V(), s.GridMeterStatus.Ac.L1.Voltage.V(),
s.GridMeterStatus.VoltageL2N.V(), s.GridMeterStatus.Ac.L2.Voltage.V(),
s.GridMeterStatus.VoltageL3N.V() s.GridMeterStatus.Ac.L3.Voltage.V()
).AlignCenterVertical(height); ).AlignCenterVertical(height);
//var gridBox = CreateRect(0, boxGrid).AlignBottom(height); var gridAcBusArrow = AsciiArt.CreateHorizontalArrow(s.GridMeterStatus!.ActivePowerL123.Round0(), gridSeparator)
var gridAcBusArrow = AsciiArt.CreateHorizontalArrow(s.GridMeterStatus!.ActivePowerL123.Round0(), gridSeparator).AlignCenterVertical(height); .AlignCenterVertical(height);
////////////////// Ac Bus ////////////////////// ////////////////// Ac Bus //////////////////////
var boxAcBus = AsciiArt.CreateBox var boxAcBus = AsciiArt.CreateBox
( (
"AC Bus", "AC Bus",
s.InverterStatus.GridVoltageL1.V(), s.InverterStatus.Ac.L1.Voltage.V(),
s.InverterStatus.GridVoltageL2.V(), s.InverterStatus.Ac.L2.Voltage.V(),
s.InverterStatus.GridVoltageL3.V() s.InverterStatus.Ac.L3.Voltage.V()
); );
var boxLoad = AsciiArt.CreateBox var boxLoad = AsciiArt.CreateBox
@ -172,107 +205,147 @@ internal static class Program
"" ""
); );
var loadRect = CreateRect(loadPower, boxAcBus, boxLoad).AlignBottom(height); var loadRect = CreateRect(boxAcBus, boxLoad, loadPower).AlignBottom(height);
var acBusInvertArrow = AsciiArt.CreateHorizontalArrow(-pwr.Round0(), inverterSeparator).AlignCenterVertical(height); var acBusInvertArrow = AsciiArt.CreateHorizontalArrow(-pwr.Round0(), inverterSeparator)
.AlignCenterVertical(height);
//////////////////// Inverter ///////////////////////// //////////////////// Inverter /////////////////////////
var inverterBox = AsciiArt.CreateBox var inverterBox = AsciiArt.CreateBox
( (
"", "",
"Inverter", "Inverter",
"" ""
).AlignCenterVertical(height); ).AlignCenterVertical(height);
var inverterArrow = AsciiArt.CreateHorizontalArrow(-pwr.Round0(), inverterSeparator).AlignCenterVertical(height); var inverterArrow = AsciiArt.CreateHorizontalArrow(-pwr.Round0(), inverterSeparator)
.AlignCenterVertical(height);
//////////////////// DC Bus ///////////////////////// //////////////////// DC Bus /////////////////////////
var dcBusBox = AsciiArt.CreateBox var dcBusBox = AsciiArt.CreateBox
( (
"DC Bus", "DC Bus",
(s.InverterStatus.ActualDcLinkVoltageLowerHalfExt + s.InverterStatus.ActualDcLinkVoltageUpperHalfExt).V(), (s.InverterStatus.ActualDcLinkVoltageLowerHalfExt + s.InverterStatus.ActualDcLinkVoltageUpperHalfExt).V(),
"" ""
); );
var pvBox = AsciiArt.CreateBox var pvBox = AsciiArt.CreateBox
( (
"", "MPPT",
"MPPT", ((s.AmptStatus!.Devices[0].Dc.Voltage + s.AmptStatus!.Devices[1].Dc.Voltage) / 2).Round0().V(),
"" ""
); );
var pvRect = CreateRect(pvPower, pvBox, dcBusBox).AlignTop(height); var pvRect = CreateRect(pvBox, dcBusBox, pvPower).AlignTop(height);
var dcBusArrow = AsciiArt.CreateHorizontalArrow(-s.DcDcStatus!.DcPower.Round0(), dcSeparator).AlignCenterVertical(height); var dcBusArrow = AsciiArt.CreateHorizontalArrow(-s.DcDcStatus!.Dc.Power, dcSeparator)
.AlignCenterVertical(height);
//////////////////// Dc/Dc ///////////////////////// //////////////////// Dc/Dc /////////////////////////
var dcBox = AsciiArt.CreateBox var dcBox = AsciiArt.CreateBox
( (
"", "Dc/Dc",
"Dc/Dc", s.DcDcStatus.BatteryVoltage.V(),
"" ""
).AlignCenterVertical(height); ).AlignCenterVertical(height);
#if BatteriesAllowed
var dcArrow = AsciiArt.CreateHorizontalArrow(s.BatteryStatus!.Power.Round0(), batterySeparator).AlignCenterVertical(height); var dcArrow1 = AsciiArt.CreateHorizontalArrow(s.BatteriesStatus[0]!.Power.Round0(), battery1Separator);
var dcArrow2 = AsciiArt.CreateHorizontalArrow(s.BatteriesStatus[1]!.Power.Round0(), battery2Separator);
//////////////////// Battery ///////////////////////// #else
var batteryBox = AsciiArt.CreateBox var dcArrow1 ="";
( var dcArrow2 = "";
"Battery", var dcArrowRect = CreateRect(dcArrow1, dcArrow2).AlignCenterVertical(height);
s.BatteryStatus!.Voltage.V(), #endif
""
).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");
var topology = boxGrid.SideBySideWith(gridAcBusArrow,"") #if BatteriesAllowed
.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; //////////////////// 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(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 powerArrow = AsciiArt.CreateVerticalArrow(power);
var boxes = new[] { boxAcBus, loadAcBusArrow, boxLoad }; var boxes = new[] { boxTop, powerArrow, boxBottom };
var maxWidth = boxes.Max(l => l.Width()); var maxWidth = boxes.Max(l => l.Width());
var rect = boxes.Select(l => l.AlignCenterHorizontal(maxWidth)).JoinLines(); var rect = boxes.Select(l => l.AlignCenterHorizontal(maxWidth)).JoinLines();
return rect; 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")] [Conditional("RELEASE")]
private static void ReleaseWriteLog(JsonObject jsonLog, UnixTime timestamp) 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")] // [Conditional("RELEASE")]
private static void ReleaseWriteTopology(UnixTime timestamp) private static JsonObject ReleaseWriteTopology(UnixTime timestamp)
{ {
var topologyJson = Salimax.TopologyToLog(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")] [Conditional("DEBUG")]
@ -318,4 +391,19 @@ internal static class Program
Console.WriteLine(error); 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);
}
}
} }

View File

@ -2,9 +2,6 @@ namespace InnovEnergy.SaliMax.SaliMaxRelays;
public record SaliMaxRelayStatus 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 K1 { get; init; } = RelayState.Closed; // Address on Adam(0X) 00002
public RelayState K2 { get; init; } = RelayState.Closed; // Address on Adam(0X) 00003 public RelayState K2 { get; init; } = RelayState.Closed; // Address on Adam(0X) 00003
public RelayState K3 { get; init; } = RelayState.Closed; // Address on Adam(0X) 00004 public RelayState K3 { get; init; } = RelayState.Closed; // Address on Adam(0X) 00004

View File

@ -2,5 +2,5 @@ namespace InnovEnergy.SaliMax.SystemConfig;
public static class Config 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
} }

View File

@ -13,7 +13,7 @@ public static class Defaults
Subnet = default, //= 0x FFFFFF00; Subnet = default, //= 0x FFFFFF00;
Gateway = default, //= 0x C0A80102; Gateway = default, //= 0x C0A80102;
ResetParamToDefault = false, // Coil ResetParamToDefault = false, // Coil
CommunicationTimeout = default, CommunicationTimeout = TimeSpan.FromSeconds(10),
FactoryResetParameters = false, FactoryResetParameters = false,
ConnectedSystemConfig = Lib.Devices.Trumpf.TruConvert.SystemConfig.AcDcAndDcDc, ConnectedSystemConfig = Lib.Devices.Trumpf.TruConvert.SystemConfig.AcDcAndDcDc,
UpdateSwTrigger = 0, UpdateSwTrigger = 0,
@ -25,7 +25,7 @@ public static class Defaults
// IlBuildnumber = 0, // IlBuildnumber = 0,
PowerStageEnable = true, PowerStageEnable = true,
SetValueConfig = SymmetricAcOperationMode.Symmetric, // Asymmetric = 0, // this is can not be seen in UI SetValueConfig = SymmetricAcOperationMode.Symmetric, // Asymmetric = 0, // this is can not be seen in UI
ResetsAlarmAndWarning = false, ResetsAlarmAndWarning = true,
PreChargeDcLinkConfig = PreChargeDcLinkConfig.Internal, // 1 = internal PreChargeDcLinkConfig = PreChargeDcLinkConfig.Internal, // 1 = internal
PowerFactorConvention = PowerFactorConvention.Producer, // 0 = producer PowerFactorConvention = PowerFactorConvention.Producer, // 0 = producer
SlaveAddress = 1, SlaveAddress = 1,
@ -66,9 +66,9 @@ public static class Defaults
GridFormingMode = 0, // 0 = not grid-forming (grid-tied) ,1 = grid-forming TODO enum GridFormingMode = 0, // 0 = not grid-forming (grid-tied) ,1 = grid-forming TODO enum
//remove DC stuff from AC //remove DC stuff from AC
DcLinkRefVoltage = 850, DcLinkRefVoltage = 800,
DcLinkMinVoltage = 830, DcLinkMinVoltage = 780,
DcLinkMaxVoltage = 870, DcLinkMaxVoltage = 820,
DcVoltageRefUs = 900, DcVoltageRefUs = 900,
DcMinVoltageUs = 880, DcMinVoltageUs = 880,
DcMaxVoltageUs = 920, DcMaxVoltageUs = 920,
@ -88,7 +88,7 @@ public static class Defaults
Subnet = default, Subnet = default,
Gateway = default, Gateway = default,
ResetParamToDefault = false , ResetParamToDefault = false ,
TimeoutForCommunication = default , TimeoutForCommunication = TimeSpan.FromSeconds(10) ,
RestartFlag = false , RestartFlag = false ,
ConnectedSystemConfig = Lib.Devices.Trumpf.TruConvert.SystemConfig.DcDcOnly, ConnectedSystemConfig = Lib.Devices.Trumpf.TruConvert.SystemConfig.DcDcOnly,
UpdateSwTrigger = 0, UpdateSwTrigger = 0,
@ -98,7 +98,7 @@ public static class Defaults
SerialNumberDcDc = 0, SerialNumberDcDc = 0,
MaterialNumberDcDc = 0, MaterialNumberDcDc = 0,
PowerStageEnable = true, PowerStageEnable = true,
ResetsAlarmAndWarning = false, ResetsAlarmAndWarning = false,
SlaveAddress = 1, SlaveAddress = 1,
SubSlaveAddress = 0, SubSlaveAddress = 0,
ModbusSlaveId = false, ModbusSlaveId = false,
@ -112,7 +112,7 @@ public static class Defaults
BatteryCurrentSet = 0, BatteryCurrentSet = 0,
DynamicCurrentPerMillisecond = 2, DynamicCurrentPerMillisecond = 2,
DcLinkControlMode = 1, DcLinkControlMode = 1,
ReferenceVoltage = 850, ReferenceVoltage = 800,
UpperVoltageWindow = 40, UpperVoltageWindow = 40,
LowerVoltageWindow = 40, LowerVoltageWindow = 40,
VoltageDeadBand = 0, VoltageDeadBand = 0,

View File

@ -1,6 +1,7 @@
using DecimalMath; using DecimalMath;
using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Protocols.Modbus.Connections;
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.Devices.Ampt; namespace InnovEnergy.Lib.Devices.Ampt;
@ -48,25 +49,22 @@ public class AmptCommunicationUnit
.ToList(); .ToList();
var amptSt = new AmptStatus var amptSt = new AmptStatus
{ (
Sid = r.GetUInt32(1), Sid : r.GetUInt32(1),
IdSunSpec = r.GetUInt16(3), IdSunSpec : r.GetUInt16(3),
Manufacturer = r.GetString(5, 16), Manufacturer : r.GetString(5, 16),
Model = r.GetString(21, 16), Model : r.GetString(21, 16),
Version = r.GetString(45, 8), Version : r.GetString(45, 8),
SerialNumber = r.GetString(53, 16), SerialNumber : r.GetString(53, 16),
DeviceAddress = r.GetInt16(69), DeviceAddress : r.GetInt16(69),
IdVendor = r.GetUInt16(71), IdVendor : r.GetUInt16(71),
Devices = devices, Devices : devices
Current1 = r.GetInt16(90) * currentFactor, // devices.d Current1 = r.GetInt16(90) * currentFactor,
Current2 = r.GetInt16(106) * currentFactor, // Current2 = r.GetInt16(106) * currentFactor,
Voltage1 = r.GetUInt32(91) * voltageFactor, // Voltage1 = r.GetUInt32(91) * voltageFactor,
Voltage2 = r.GetUInt32(107) * voltageFactor, // Voltage2 = r.GetUInt32(107) * voltageFactor
//AvgVolatge = ReadDevicesVoltage(nbrOfDevices), );
//AvgCurrent = ReadDevicesCurrent(nbrOfDevices)
};
return amptSt; return amptSt;
@ -104,26 +102,30 @@ public class AmptCommunicationUnit
var b = (UInt16)(FirstDeviceOffset + deviceNumber * RegistersPerDevice); // base address var b = (UInt16)(FirstDeviceOffset + deviceNumber * RegistersPerDevice); // base address
return new AmptDeviceStatus return new AmptDeviceStatus
{ (
DeviceId = r.GetInt16 (b) , Dc : new DcConnection
Timestamp = r.GetUInt32((UInt16)(b + 3)), (
Current = r.GetUInt16((UInt16)(b + 5)) * currentFactor, Voltage:r.GetUInt32((UInt16)(b + 6)) * voltageFactor,
Voltage = r.GetUInt32((UInt16)(b + 6)) * voltageFactor, Current:r.GetUInt16((UInt16)(b + 5)) * currentFactor
ProductionToday = r.GetUInt32((UInt16)(b + 12))* energyFactor, ),
Strings = new AmptStringStatus[] DeviceId : r.GetInt16 (b) ,
Timestamp : r.GetUInt32((UInt16)(b + 3)),
ProductionToday : r.GetUInt32((UInt16)(b + 12))* energyFactor,
Strings : new []
{ {
new() new DcConnection
{ (
Voltage = r.GetUInt32((UInt16)(b + 8)) * voltageFactor, Voltage : r.GetUInt32((UInt16)(b + 8)) * voltageFactor,
Current = r.GetUInt16((UInt16)(b + 14)) * currentFactor, Current : r.GetUInt16((UInt16)(b + 14)) * currentFactor
}, ),
new() new DcConnection
{ (
Voltage = r.GetUInt32((UInt16)(b + 9)) * voltageFactor, Voltage : r.GetUInt32((UInt16)(b + 9)) * voltageFactor,
Current = r.GetUInt16((UInt16)(b + 15)) * currentFactor, Current : r.GetUInt16((UInt16)(b + 15)) * currentFactor
} )
} }
}; );
} }
} }
} }

View File

@ -1,14 +1,15 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.StatusApi.Devices;
namespace InnovEnergy.Lib.Devices.Ampt; namespace InnovEnergy.Lib.Devices.Ampt;
public record AmptDeviceStatus public record AmptDeviceStatus
{ (
internal const UInt16 NbrOfStrings = 2; DcConnection Dc,
public Int16 DeviceId { get; init; } // The string number // UInt16 NbrOfStrings,
public UInt32 Timestamp { get; init; } // The UTC timestamp of the measurements Int16 DeviceId, // The string number
UInt32 Timestamp, // The UTC timestamp of the measurements
public Decimal Current { get; init; } // String output current in mA Decimal ProductionToday, // converted to kW in AmptCU class
public Decimal Voltage { get; init; } // String output voltage in mV IReadOnlyList<DcConnection> Strings
): Mppt(Dc, Strings)
public Decimal ProductionToday { get; init; } // converted to kW in AmptCU class {}
public IReadOnlyList<AmptStringStatus> Strings { get; init; } = null!;
}

View File

@ -1,25 +1,27 @@
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.StatusApi.Devices;
namespace InnovEnergy.Lib.Devices.Ampt; namespace InnovEnergy.Lib.Devices.Ampt;
public record AmptStatus 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<AmptDeviceStatus> 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<AmptDeviceStatus> Devices { get; init; } = null!;
} }

View File

@ -9,6 +9,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="../../Utils/Utils.csproj" /> <ProjectReference Include="../../Utils/Utils.csproj" />
<ProjectReference Include="../../Protocols/Modbus/Modbus.csproj" /> <ProjectReference Include="../../Protocols/Modbus/Modbus.csproj" />
<ProjectReference Include="../../StatusApi/StatusApi.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,5 +1,7 @@
using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Protocols.Modbus.Connections;
using InnovEnergy.Lib.Protocols.Modbus.Conversions;
using InnovEnergy.Lib.StatusApi.Connections;
namespace InnovEnergy.Lib.Devices.Battery48TL; namespace InnovEnergy.Lib.Devices.Battery48TL;
@ -33,6 +35,7 @@ public class Battery48TlDevice
{ {
if (Modbus is null) // TODO : remove fake if (Modbus is null) // TODO : remove fake
{ {
Console.WriteLine("Battery is null");
return null; return null;
} }
@ -41,13 +44,101 @@ public class Battery48TlDevice
try try
{ {
var registers = Modbus.ReadInputRegisters(Constants.BaseAddress, Constants.NoOfRegisters); var registers = Modbus.ReadInputRegisters(Constants.BaseAddress, Constants.NoOfRegisters);
return new Battery48TLStatus(registers); return TryReadStatus(registers);
} }
catch (Exception e) catch (Exception e)
{ {
Console.WriteLine(e.Message); Console.WriteLine(e.Message + " Battery ");
Modbus.CloseConnection(); Modbus.CloseConnection();
return null; return null;
} }
} }
private Battery48TLStatus? TryReadStatus(ModbusRegisters data)
{
var soc = data.ParseDecimal(register: 1054, scaleFactor: 0.1m);
var eocReached = data.ParseEocReached();
var warnings = new List<String>();
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<String>();
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()
);
}
} }

View File

@ -1,118 +1,39 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Protocols.Modbus.Conversions; using InnovEnergy.Lib.Protocols.Modbus.Conversions;
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.StatusApi.Devices;
namespace InnovEnergy.Lib.Devices.Battery48TL; namespace InnovEnergy.Lib.Devices.Battery48TL;
[SuppressMessage("ReSharper", "InconsistentNaming")] [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<String> Warnings,
IReadOnlyList<String> 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<String> Warnings { get; }
public IReadOnlyList<String> 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<String>();
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<String>();
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();
}
} }

View File

@ -111,6 +111,22 @@ public static class BatteryDataParser
return pLimit; 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) internal static Decimal CalcMaxChargePower(this ModbusRegisters data)
{ {
var v = ReadVoltage(data); var v = ReadVoltage(data);
@ -133,13 +149,15 @@ public static class BatteryDataParser
{ {
var v = ReadVoltage(data); var v = ReadVoltage(data);
var i = ReadCurrent(data); var i = ReadCurrent(data);
var t = data.ParseDecimal(register: 1004, scaleFactor: 0.1m, offset: -400);
var pLimits = new[] var pLimits = new[]
{ {
CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMin, Constants.RIntMin), CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMin, Constants.RIntMin),
CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMin, Constants.RIntMax), CalcPowerLimitImposedByVoltageLimit(v, i, Constants.VMin, Constants.RIntMax),
CalcPowerLimitImposedByCurrentLimit(v, i, -Constants.IMax, Constants.RIntMin), 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(); var pLimit = pLimits.Max();

View File

@ -29,7 +29,4 @@ public static class Constants
public const Decimal RIntMin = RStringMin / NumberOfStrings; public const Decimal RIntMin = RStringMin / NumberOfStrings;
public const Decimal RIntMax = RStringMax / NumberOfStrings; public const Decimal RIntMax = RStringMax / NumberOfStrings;
public const Decimal IMax = NumberOfStrings * IMaxPerString; public const Decimal IMax = NumberOfStrings * IMaxPerString;
} }

View File

@ -9,6 +9,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="../../Utils/Utils.csproj" /> <ProjectReference Include="../../Utils/Utils.csproj" />
<ProjectReference Include="../../Protocols/Modbus/Modbus.csproj" /> <ProjectReference Include="../../Protocols/Modbus/Modbus.csproj" />
<ProjectReference Include="../../StatusApi/StatusApi.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -9,6 +9,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="../../../Protocols/Modbus/Modbus.csproj" /> <ProjectReference Include="../../../Protocols/Modbus/Modbus.csproj" />
<ProjectReference Include="../../../StatusApi/StatusApi.csproj" />
<ProjectReference Include="../TruConvert/TruConvert.csproj" /> <ProjectReference Include="../TruConvert/TruConvert.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -31,7 +31,7 @@ public record TruConvertAcControl
public AcErrorPolicy ErrorHandlingPolicy { get; init;} = 0; public AcErrorPolicy ErrorHandlingPolicy { get; init;} = 0;
public AcDcGridType GridType { get; init;} = 0; public AcDcGridType GridType { get; init;} = 0;
public UInt16 SubSlaveAddress { 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 UInt16 SubSlaveErrorPolicy { get; init;} = 0; // must be an enum
public Decimal SignedPowerNominalValue { get; init;} = 0; // resolution 0.001 and Unit kva, public Decimal SignedPowerNominalValue { get; init;} = 0; // resolution 0.001 and Unit kva,
public Decimal SignedPowerSetValueL1 { get; init;} = 0; // resolution 0.001 and Unit kva, public Decimal 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 MaxPeakCurrentVoltageControlL2 { get; init;} = 0; // resolution 0.01
public Decimal MaxPeakCurrentVoltageControlL3 { 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 GridFormingMode { get; init;} = 1; // 0 = not grid-forming (grid-tied) ,1 = grid-forming
public UInt16 DcLinkRefVoltage { get; init;} = 850; public UInt16 DcLinkRefVoltage { get; init;} = 800;
public UInt16 DcLinkMinVoltage { get; init;} = 830; public UInt16 DcLinkMinVoltage { get; init;} = 780;
public UInt16 DcLinkMaxVoltage { get; init;} = 870; public UInt16 DcLinkMaxVoltage { get; init;} = 820;
public UInt16 DcVoltageRefUs { get; init;} = 900; public UInt16 DcVoltageRefUs { get; init;} = 900;
public UInt16 DcMinVoltageUs { get; init;} = 880; public UInt16 DcMinVoltageUs { get; init;} = 880;
public UInt16 DcMaxVoltageUs { get; init;} = 920; public UInt16 DcMaxVoltageUs { get; init;} = 920;

View File

@ -2,7 +2,10 @@ using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.TruConvert; using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Protocols.Modbus.Connections;
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.StatusApi.Phases;
using InnovEnergy.Lib.Utils; using InnovEnergy.Lib.Utils;
using static DecimalMath.DecimalEx;
using static InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.AcControlRegisters; using static InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.AcControlRegisters;
@ -39,6 +42,8 @@ public class TruConvertAcDevice
WriteRegs(CommunicationTimeout, c.CommunicationTimeout.TotalSeconds.ConvertTo<UInt16>()); WriteRegs(CommunicationTimeout, c.CommunicationTimeout.TotalSeconds.ConvertTo<UInt16>());
WriteRegs(ConnectedSystemConfig, c.ConnectedSystemConfig); WriteRegs(ConnectedSystemConfig, c.ConnectedSystemConfig);
WriteCoils(PowerStageConfig, c.PowerStageEnable, WriteCoils(PowerStageConfig, c.PowerStageEnable,
c.SetValueConfig.ConvertTo<Boolean>(), c.SetValueConfig.ConvertTo<Boolean>(),
c.ResetsAlarmAndWarning); c.ResetsAlarmAndWarning);
@ -92,6 +97,8 @@ public class TruConvertAcDevice
private void WriteRegs (UInt16 a, params UInt16[] regs) => ModbusTcpClient.WriteRegisters(a, regs); 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 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() public TruConvertAcStatus? ReadStatus()
{ {
try try
@ -112,115 +119,171 @@ public class TruConvertAcDevice
{ {
// Console.WriteLine("Reading Ac Device"); // Console.WriteLine("Reading Ac Device");
var acActualMain = ModbusTcpClient.ReadInputRegisters(5001, 3); var acSerialNumber = ModbusTcpClient.ReadInputRegisters(2009, 2);
var acActualAcDc = ModbusTcpClient.ReadInputRegisters(5021, 9); var acActualMain = ModbusTcpClient.ReadInputRegisters(5001, 3);
var acActualAcDc2 = ModbusTcpClient.ReadInputRegisters(5031, 1); var acActualAcDc = ModbusTcpClient.ReadInputRegisters(5021, 9);
var acActualAcDc3 = ModbusTcpClient.ReadInputRegisters(5131, 6); var acActualAcDc2 = ModbusTcpClient.ReadInputRegisters(5031, 1);
var acActualMeasurement = ModbusTcpClient.ReadInputRegisters(5141, 3); var acActualAcDc3 = ModbusTcpClient.ReadInputRegisters(5131, 6);
var acActualMeasurement1 = ModbusTcpClient.ReadInputRegisters(5151, 3); var acActualMeasurement = ModbusTcpClient.ReadInputRegisters(5141, 3);
var acActualMeasurement2 = ModbusTcpClient.ReadInputRegisters(5161, 3); var acActualMeasurement1 = ModbusTcpClient.ReadInputRegisters(5151, 3);
var acActualMeasurement3 = ModbusTcpClient.ReadInputRegisters(5171, 3); var acActualMeasurement2 = ModbusTcpClient.ReadInputRegisters(5161, 3);
var acActualMeasurement4 = ModbusTcpClient.ReadInputRegisters(5187, 2); var acActualMeasurement3 = ModbusTcpClient.ReadInputRegisters(5171, 3);
var acActualMeasurement5 = ModbusTcpClient.ReadInputRegisters(5189, 2); var acActualMeasurement4 = ModbusTcpClient.ReadInputRegisters(5187, 2);
var acActualMeasurement6 = ModbusTcpClient.ReadInputRegisters(5191, 2); var acActualMeasurement5 = ModbusTcpClient.ReadInputRegisters(5189, 2);
var acActualMeasurement7 = ModbusTcpClient.ReadInputRegisters(5201, 1); var acActualMeasurement6 = ModbusTcpClient.ReadInputRegisters(5191, 2);
var acActualMeasurement8 = ModbusTcpClient.ReadInputRegisters(5211, 4); var acActualMeasurement7 = ModbusTcpClient.ReadInputRegisters(5201, 1);
var acActualMeasurement9 = ModbusTcpClient.ReadInputRegisters(5221, 2); var acActualMeasurement8 = ModbusTcpClient.ReadInputRegisters(5211, 4);
var acActualTemp = ModbusTcpClient.ReadInputRegisters(5501, 1); var acActualMeasurement9 = ModbusTcpClient.ReadInputRegisters(5221, 2);
var acWarningValues = ModbusTcpClient.ReadInputRegisters(2402, 22); var acActualTemp = ModbusTcpClient.ReadInputRegisters(5501, 1);
var acAlarmValues = ModbusTcpClient.ReadInputRegisters(2809, 22); var acWarningValues = ModbusTcpClient.ReadInputRegisters(2402, 22);
var acSetValues = ModbusTcpClient.ReadInputRegisters(4196, 1); var acAlarmValues = ModbusTcpClient.ReadInputRegisters(2809, 22);
var acSetValues = ModbusTcpClient.ReadInputRegisters(4196, 1);
var warnings = Enumerable var warnings = Enumerable
.Range(2404, 20) .Range(2404, 20)
.Select(n => acWarningValues.GetUInt16((UInt16)n).ConvertTo<WarningMessage>()) .Select(n => acWarningValues.GetUInt16((UInt16)n).ConvertTo<WarningMessage>())
.ToArray(); .ToArray();
var alarms = Enumerable var alarms = Enumerable
.Range(2811, 20) .Range(2811, 20)
.Select(n => acAlarmValues.GetUInt16((UInt16)n).ConvertTo<AlarmMessage>()) .Select(n => acAlarmValues.GetUInt16((UInt16)n).ConvertTo<AlarmMessage>())
.Where(m => m != AlarmMessage.NoAlarm) .Where(m => m != AlarmMessage.NoAlarm)
.ToArray(); .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 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 // acActualMainValues
MainState = acActualMain.GetInt16(5001).ConvertTo<MainState>(), MainState : acActualMain.GetInt16(5001).ConvertTo<MainState>(),
NumberOfConnectedSlaves = acActualMain.GetUInt16(5002), NumberOfConnectedSlaves : acActualMain.GetUInt16(5002),
NumberOfConnectedSubSlaves = acActualMain.GetUInt16(5003), NumberOfConnectedSubSlaves : acActualMain.GetUInt16(5003),
//acActualAcDc //acActualAcDc
AcDcNominalGridFrequency = acActualAcDc.GetUInt16(5021) * 0.1m, AcDcNominalGridFrequency : acActualAcDc.GetUInt16(5021) * 0.1m,
AcDcNominalGridVoltage = acActualAcDc.GetUInt16(5022), AcDcNominalGridVoltage : acActualAcDc.GetUInt16(5022),
AcDcActNominalPower = acActualAcDc.GetUInt16(5023), AcDcActNominalPower : acActualAcDc.GetUInt16(5023),
AcDcActiveGridType = acActualAcDc.GetUInt16(5024).ConvertTo<AcDcGridType>(), AcDcActiveGridType : acActualAcDc.GetUInt16(5024).ConvertTo<AcDcGridType>(),
AcDcPowerLimitingStatusAct = acActualAcDc.GetUInt16(5025), AcDcPowerLimitingStatusAct : acActualAcDc.GetUInt16(5025),
AcDcDcVoltageReference = acActualAcDc.GetUInt16(5026), // DC link reference AcDcDcVoltageReference : acActualAcDc.GetUInt16(5026), // DC link reference
AcDcDcLinkVoltageMinAct = acActualAcDc.GetUInt16(5027), // DC link min voltage AcDcDcLinkVoltageMinAct : acActualAcDc.GetUInt16(5027), // DC link min voltage
AcDcDcLinkVoltageMaxAct = acActualAcDc.GetUInt16(5028), // DC link max voltage AcDcDcLinkVoltageMaxAct : acActualAcDc.GetUInt16(5028), // DC link max voltage
AcDcDcLinkChargedMinVoltage = acActualAcDc.GetUInt16(5029) * 0.01m, AcDcDcLinkChargedMinVoltage : acActualAcDc.GetUInt16(5029) * 0.01m,
//ac Actual AcDc 2 //ac Actual AcDc 2
AcDcStmActCustomer = acActualAcDc2.GetUInt16(5031), //need to check AcDcStmActCustomer : acActualAcDc2.GetUInt16(5031), //need to check
AcDcOverloadIntegratorStatusL1 : acActualAcDc3.GetUInt16(5134) * 0.1m,
ApparentPowerAcL1 = acActualAcDc3.GetUInt16(5131) * 1m, // in VA AcDcOverloadIntegratorStatusL2 : acActualAcDc3.GetUInt16(5135) * 0.1m,
ApparentPowerAcL2 = acActualAcDc3.GetUInt16(5132) * 1m, // in VA AcDcOverloadIntegratorStatusL3 : acActualAcDc3.GetUInt16(5136) * 0.1m,
ApparentPowerAcL3 = acActualAcDc3.GetUInt16(5133) * 1m, // in VA AcSignedPowerValue : acSetValues.GetInt16(4196) * -1.0m, // this is also used for control
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,
//acActualMeasurement10 //acActualMeasurement10
ActualDcLinkVoltageUpperHalf = acActualMeasurement8.GetUInt16(5211), ActualDcLinkVoltageUpperHalf : acActualMeasurement8.GetUInt16(5211),
ActualDcLinkVoltageLowerHalf = acActualMeasurement8.GetUInt16(5212), ActualDcLinkVoltageLowerHalf : acActualMeasurement8.GetUInt16(5212),
ActualDcLinkVoltageUpperHalfExt = acActualMeasurement8.GetUInt16(5213), ActualDcLinkVoltageUpperHalfExt : acActualMeasurement8.GetUInt16(5213),
ActualDcLinkVoltageLowerHalfExt = acActualMeasurement8.GetUInt16(5214), ActualDcLinkVoltageLowerHalfExt : acActualMeasurement8.GetUInt16(5214),
//acActualMeasurement11
VoltageIntNtoPE = acActualMeasurement9.GetInt16(5221) * 0.1m,
VoltageExtNtoPE = acActualMeasurement9.GetInt16(5222) * 0.1m,
VoltageIntNtoPe : acActualMeasurement9.GetInt16(5221) * 0.1m,
VoltageExtNtoPe : acActualMeasurement9.GetInt16(5222) * 0.1m,
//acActualTemp //acActualTemp
InletAirTemperature = acActualTemp.GetInt16(5501) * 0.1m, InletAirTemperature : acActualTemp.GetInt16(5501) * 0.1m,
Warnings = warnings, Warnings : warnings,
Alarms = alarms, Alarms : alarms
);
// acSetValues
AcSignedPowerValue = acSetValues.GetInt16(4196) * -1.0m, // this is also used for control
};
} }
} }

View File

@ -1,60 +1,43 @@
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.TruConvert; using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.StatusApi.Devices;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
using AlarmMessages = IReadOnlyList<AlarmMessage>; using AlarmMessages = IReadOnlyList<AlarmMessage>;
using WarningMessages = IReadOnlyList<WarningMessage>; using WarningMessages = IReadOnlyList<WarningMessage>;
[SuppressMessage("ReSharper", "InconsistentNaming")]
public record TruConvertAcStatus 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<WarningMessage>();
public AlarmMessages Alarms { get; init; } = Array.Empty<AlarmMessage>();
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
} }

View File

@ -10,6 +10,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="../../../Protocols/Modbus/Modbus.csproj" /> <ProjectReference Include="../../../Protocols/Modbus/Modbus.csproj" />
<ProjectReference Include="../TruConvert/TruConvert.csproj" /> <ProjectReference Include="../TruConvert/TruConvert.csproj" />
<ProjectReference Include="../../../StatusApi/StatusApi.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -12,7 +12,6 @@ public record TruConvertDcControl
public Boolean ResetParamToDefault { get; init;} = false ; // Coil public Boolean ResetParamToDefault { get; init;} = false ; // Coil
public TimeSpan TimeoutForCommunication { get; init;} = DefaultCommunicationTimeOut; public TimeSpan TimeoutForCommunication { get; init;} = DefaultCommunicationTimeOut;
public Boolean RestartFlag { get; init;} = false ; // Coil public Boolean RestartFlag { get; init;} = false ; // Coil
public SystemConfig ConnectedSystemConfig { get; init;} = SystemConfig.NoConfig ; public SystemConfig ConnectedSystemConfig { get; init;} = SystemConfig.NoConfig ;
public UInt16 UpdateSwTrigger { get; init;} = 0 ; public UInt16 UpdateSwTrigger { get; init;} = 0 ;
public UInt16 AutomaticSwUpdate { 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 BatteryCurrentSet { get; init;} = 0; // resolution 1.0
public Decimal DynamicCurrentPerMillisecond { get; init;} = 0; // resolution : 0.01 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 DcLinkControlMode { get; init;} = 0; // Parameter aktiviert/deaktiviert "DC link voltage droop mode"
public Decimal ReferenceVoltage { get; init;} = 0; // resolution : 0.1 public Decimal ReferenceVoltage { get; init;} = 800; // resolution : 0.1
public Decimal UpperVoltageWindow { get; init;} = 0; // resolution : 0.1 public Decimal UpperVoltageWindow { get; init;} = 40; // resolution : 0.1
public Decimal LowerVoltageWindow { get; init;} = 0; // resolution : 0.1 public Decimal LowerVoltageWindow { get; init;} = 40; // resolution : 0.1
public Decimal VoltageDeadBand { get; init;} = 0; // resolution : 0.1 public Decimal VoltageDeadBand { get; init;} = 0; // resolution : 0.1
private static readonly TimeSpan DefaultCommunicationTimeOut = TimeSpan.FromMinutes(10); private static readonly TimeSpan DefaultCommunicationTimeOut = TimeSpan.FromMinutes(10);

View File

@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Trumpf.TruConvert; using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Clients;
using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Protocols.Modbus.Connections;
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.Utils; using InnovEnergy.Lib.Utils;
using static InnovEnergy.Lib.Devices.Trumpf.TruConvertDc.DcControlRegisters; 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 // TODO starting from 4000, evaluate what/if needs updating below 4000
WriteRegs(TimeoutCommunication, c.TimeoutForCommunication.TotalSeconds.ConvertTo<UInt16>());
WriteCoils(PowerStageOperation, c.PowerStageEnable); WriteCoils(PowerStageOperation, c.PowerStageEnable);
WriteCoils(ResetsAlarmAndWarning, c.ResetsAlarmAndWarning); WriteCoils(ResetsAlarmAndWarning, c.ResetsAlarmAndWarning);
@ -103,18 +105,14 @@ public class TruConvertDcDevice
private TruConvertDcStatus TryReadStatus() private TruConvertDcStatus TryReadStatus()
{ {
// Console.WriteLine("Reading DC Device"); // Console.WriteLine("Reading DC Device");
var dcPrValMain = ModbusTcpClient.ReadInputRegisters(5001, 3); var dcPrValMain = ModbusTcpClient.ReadInputRegisters(5001, 3);
var dcBatteryValue = ModbusTcpClient.ReadInputRegisters(5101, 1); var dcBatteryValue = ModbusTcpClient.ReadInputRegisters(5101, 1);
var dcBatteryValue2 = ModbusTcpClient.ReadInputRegisters(5111, 1); var dcBatteryValue2 = ModbusTcpClient.ReadInputRegisters(5111, 1);
var dcBatteryValue3 = ModbusTcpClient.ReadInputRegisters(5114, 2); 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 dcPrValDcDc = ModbusTcpClient.ReadInputRegisters(5124, 1);
var dcPrValDcDc2 = ModbusTcpClient.ReadInputRegisters(5127, 2); var dcPrValDcDc2 = ModbusTcpClient.ReadInputRegisters(5127, 2);
var dcTempValue = ModbusTcpClient.ReadInputRegisters(5511, 1); var dcTempValue = ModbusTcpClient.ReadInputRegisters(5511, 1);
var dcWarningValues = ModbusTcpClient.ReadInputRegisters(2404, 20); var dcWarningValues = ModbusTcpClient.ReadInputRegisters(2404, 20);
var dcAlarmValues = ModbusTcpClient.ReadInputRegisters(2811, 20); var dcAlarmValues = ModbusTcpClient.ReadInputRegisters(2811, 20);
var dcSetValues = ModbusTcpClient.ReadInputRegisters(4001, 1); var dcSetValues = ModbusTcpClient.ReadInputRegisters(4001, 1);
@ -133,37 +131,34 @@ public class TruConvertDcDevice
var dcCurrentLimitState = GetFlags(dcPrValDcDc.GetUInt16(5124)).ToArray(); 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 return new TruConvertDcStatus
{ (
// dcPrValMain
MainState = (MainState) dcPrValMain.GetInt16(5001),
NumberOfConnectedSlaves = dcPrValMain.GetUInt16(5002),
NumberOfConnectedSubSlaves = dcPrValMain.GetUInt16(5003),
// dcBatteryValue Dc: new DcConnection
BatteryVoltage = dcBatteryValue.GetUInt16(5101) * 0.1m, (
BatteryCurrent = dcBatteryValue2.GetInt16(5111), dcLinkVoltage,
dcCurrent
),
TotalDcPower = dcBatteryValue3.GetInt32(5114) * 1m, // Resolution is 0.001 (kW) in Tru convert DC doc, but we want it in W MainState : (MainState)dcPrValMain.GetInt16(5001),
NumberOfConnectedSlaves : dcPrValMain.GetUInt16(5002),
DcPower = dcBatteryValue4.GetInt16(5121) * 1m, // Resolution is 0.001 (kW) in Tru convert DC doc, but we want it in W NumberOfConnectedSubSlaves : dcPrValMain.GetUInt16(5003),
BatteryVoltage : dcBatteryValue.GetUInt16(5101) * 0.1m,
// dcPrValDcDc BatteryCurrent : dcBatteryValue2.GetInt16(5111),
StatusOfCurrentLimiting = dcCurrentLimitState, TotalDcPower : dcBatteryValue3.GetInt32(5114) * 1m, // Resolution is 0.001 (kW) in Tru convert DC doc, but we want it in W
StatusOfCurrentLimiting : dcCurrentLimitState,
// dcPrValDcDc2 OverloadCapacity : dcPrValDcDc2.GetUInt16(5127) * 0.1m,
OverloadCapacity = dcPrValDcDc2.GetUInt16(5127) * 0.1m, DcDcInletTemperature : dcTempValue.GetInt16(5511),
DcLinkVoltage = dcPrValDcDc2.GetUInt16(5128), Warnings : warnings,
Alarms : alarms,
//dcTempValue PowerOperation : dcSetValues.GetBoolean(4001)
DcDcInletTemperature = dcTempValue.GetInt16(5511), );
Warnings = warnings,
Alarms = alarms,
// dcSetValues
PowerOperation = dcSetValues.GetBoolean(4001)
};
} }
} }

View File

@ -1,4 +1,6 @@
using InnovEnergy.Lib.Devices.Trumpf.TruConvert; using InnovEnergy.Lib.Devices.Trumpf.TruConvert;
using InnovEnergy.Lib.StatusApi.Connections;
using InnovEnergy.Lib.StatusApi.Devices;
namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; namespace InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
@ -7,21 +9,19 @@ using WarningMessages = IReadOnlyList<WarningMessage>;
using DcCurrentLimitStates = IReadOnlyList<DcCurrentLimitState>; using DcCurrentLimitStates = IReadOnlyList<DcCurrentLimitState>;
public record TruConvertDcStatus public record TruConvertDcStatus
{ (
public MainState MainState { get; init; } DcConnection Dc,
public UInt16 NumberOfConnectedSlaves { get; init; } MainState MainState,
public UInt16 NumberOfConnectedSubSlaves { get; init; } UInt16 NumberOfConnectedSlaves,
public Decimal BatteryVoltage { get; init; } UInt16 NumberOfConnectedSubSlaves,
public Decimal BatteryCurrent { get; init; } Decimal BatteryVoltage,
public Decimal TotalDcPower { get; init; } Decimal BatteryCurrent,
public Decimal DcPower { get; init; } Decimal TotalDcPower,
public DcCurrentLimitStates StatusOfCurrentLimiting { get; init; } = Array.Empty<DcCurrentLimitState>(); DcCurrentLimitStates StatusOfCurrentLimiting,
public Decimal OverloadCapacity { get; init; } Decimal OverloadCapacity,
public Decimal DcLinkVoltage { get; init; } Decimal DcDcInletTemperature,
public Decimal DcDcInletTemperature { get; init; } AlarmMessages Alarms,
public AlarmMessages Alarms { get; init; } = Array.Empty<AlarmMessage>(); WarningMessages Warnings,
public WarningMessages Warnings { get; init; } = Array.Empty<WarningMessage>(); Boolean PowerOperation
):DcDevice(Dc)
public Boolean PowerOperation { get; init; } {}
}

View File

@ -1,9 +1,8 @@
using InnovEnergy.Lib.StatusApi.Phases; using InnovEnergy.Lib.StatusApi.Phases;
namespace InnovEnergy.Lib.StatusApi.Connections; namespace InnovEnergy.Lib.StatusApi.Connections;
public record DcConnection(Decimal Voltage, Decimal Current) : Phase(Voltage, Current) public record DcConnection(Decimal Voltage, Decimal Current) : Phase(Voltage, Current)
{ {
public Decimal Power => Current * Voltage; public Decimal Power => (Current * Voltage).Round3();
} }

View File

@ -3,10 +3,10 @@ using InnovEnergy.Lib.StatusApi.Phases;
namespace InnovEnergy.Lib.StatusApi.Connections; namespace InnovEnergy.Lib.StatusApi.Connections;
public record SinglePhaseAcConnection public record SinglePhaseAcConnection
( (
Decimal Voltage, Decimal Voltage,
Decimal Current, Decimal Current,
Decimal Phi, Decimal Phi,
Decimal Frequency Decimal Frequency
) );
: AcPhase(Voltage, Current, Phi); //: AcPhase(Voltage, Current, Phi);

View File

@ -21,12 +21,12 @@ public record AcPhase
public static AcPhase FromActiveReactive public static AcPhase FromActiveReactive
( (
Decimal activePower, Decimal activePower,
Decimal reactivePower, Decimal apparentPower,
Decimal voltage, Decimal voltage,
Decimal current Decimal current
) )
{ {
var apparentPower = Sqrt(activePower * activePower + reactivePower * reactivePower); var reactivePower = Sqrt(Math.Abs(apparentPower * apparentPower - activePower * activePower ));
var phi = ATan2(reactivePower, activePower); var phi = ATan2(reactivePower, activePower);
return new AcPhase return new AcPhase
@ -39,11 +39,10 @@ public record AcPhase
ReactivePower: reactivePower, ReactivePower: reactivePower,
PowerFactor: Cos(phi) 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); var powerFactor = Cos(phi);

View File

@ -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);
}
}

View File

@ -6,7 +6,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CliWrap" Version="3.3.1" /> <PackageReference Include="CliWrap" Version="3.6.0" />
<PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" /> <PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" />
<PackageReference Include="System.Reactive.Linq" Version="5.0.0" /> <PackageReference Include="System.Reactive.Linq" Version="5.0.0" />
</ItemGroup> </ItemGroup>