Introduce CombinedStatus

This commit is contained in:
atef 2023-04-04 16:37:37 +02:00
parent d564b3c3b6
commit 840643f069
9 changed files with 170 additions and 105 deletions

View File

@ -2,23 +2,23 @@
<Import Project="../InnovEnergy.App.props" /> <Import Project="../InnovEnergy.App.props" />
<ItemGroup> <ItemGroup>
<ProjectReference Include="../../Lib/Devices/Adam6060/Adam6060.csproj"/> <ProjectReference Include="../../Lib/Devices/Adam6060/Adam6060.csproj" />
<ProjectReference Include="../../Lib/Devices/AMPT/Ampt.csproj"/> <ProjectReference Include="../../Lib/Devices/AMPT/Ampt.csproj" />
<ProjectReference Include="../../Lib/Devices/Battery48TL/Battery48TL.csproj"/> <ProjectReference Include="../../Lib/Devices/Battery48TL/Battery48TL.csproj" />
<ProjectReference Include="../../Lib/Devices/EmuMeter/EmuMeter.csproj"/> <ProjectReference Include="../../Lib/Devices/EmuMeter/EmuMeter.csproj" />
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj"/> <ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj" />
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj"/> <ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj" />
<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" />
<ProjectReference Include="../../Lib/Time/Time.csproj"/> <ProjectReference Include="../../Lib/Time/Time.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CliWrap" Version="3.6.0"/> <PackageReference Include="CliWrap" Version="3.6.0" />
<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" />
<PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2"/> <PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" />
</ItemGroup> </ItemGroup>

View File

@ -1,51 +1,53 @@
using InnovEnergy.Lib.Devices.Battery48TL; using InnovEnergy.Lib.Devices.Battery48TL;
using InnovEnergy.Lib.StatusApi;
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Units.Composite;
using static InnovEnergy.Lib.Devices.Battery48TL.TemperatureState;
namespace InnovEnergy.App.SaliMax.Controller; namespace InnovEnergy.App.SaliMax.Controller;
public class AvgBatteriesStatus public static class AvgBatteriesStatus
{ {
public Decimal Soc { get; set; } public static CombinedStatus<Battery48TLStatus>? Combine(this IReadOnlyList<Battery48TLStatus> stati)
public Decimal Current { get; set; }
public Decimal Voltage { get; set; }
public Decimal Power { get; set; }
public Decimal BusVoltage { get; set; }
public Decimal BatteryTemperature { get; set; }
public IReadOnlyList<String> Warnings { get; set; }
public IReadOnlyList<String> Alarms { get; set; }
public Boolean HeaterOn { get; set; }
public Boolean EocReached { get; set; }
public Boolean BatteryCold { get; set; }
public Decimal MaxChargingPower { get; set; }
public Decimal MaxDischargingPower { get; set; }
public static AvgBatteriesStatus ReadBatteriesStatus(IReadOnlyList<Battery48TLStatus> batteriesStatus)
{ {
var soc = batteriesStatus.Any() ? batteriesStatus.Average(b => b.Soc) : 0; var combined = stati.Count == 0
var current = batteriesStatus.Select(b => b.Dc.Current).Aggregate(0m,(a, b) => a + b); ? null
var voltage = batteriesStatus.Any() ? batteriesStatus.Average(b => b.Dc.Voltage) : 0; : new Battery48TLStatus
var power = batteriesStatus.Select(b => b.Dc.Power).Aggregate(0m,(a, b) => a + b);
var busVoltage = batteriesStatus.Any() ? batteriesStatus.Average(b => b.BusVoltage): 0;
var batteryTemperature = batteriesStatus.Any() ? batteriesStatus.Average(b => b.Temperature): 0;
var heaterOn = batteriesStatus.Any() && batteriesStatus.Select(b => b.HeaterOn).Aggregate((a, b) => a | b);
var eocReached = batteriesStatus.All(b => b.EocReached);
var batteryCold = batteriesStatus.Any(b => b.BatteryCold);
var maxChargingPower = batteriesStatus.Select(b => b.MaxChargingPower).Aggregate(0m, (a, b) => a + b);
var maxDischargingPower = batteriesStatus.Select(b => b.MaxDischargingPower).Aggregate(0m, (a, b) => a + b);
return new AvgBatteriesStatus
{ {
Soc = soc, Soc = stati.Min(b => b.Soc),
Current = current, Temperature = stati.Average(b => b.Temperature),
Voltage = voltage, Dc = new DcBus
Power = power, {
BusVoltage = busVoltage, Voltage = stati.Average(b => b.Dc.Voltage),
BatteryTemperature = batteryTemperature, Current = stati.Sum(b => b.Dc.Current),
HeaterOn = heaterOn, },
EocReached = eocReached,
BatteryCold = batteryCold, Alarms = stati.SelectMany(b => b.Alarms).Distinct().ToList(),
MaxChargingPower = maxChargingPower, Warnings = stati.SelectMany(b => b.Warnings).Distinct().ToList(),
MaxDischargingPower = maxDischargingPower
MaxChargingPower = stati.Sum(b => b.MaxChargingPower),
MaxDischargingPower = stati.Sum(b => b.MaxDischargingPower),
Heating = stati.Any(b => b.Heating),
AmberLed = LedState.Off, // not used for combined battery
BlueLed = LedState.Off,
RedLed = LedState.Off,
GreenLed = LedState.Off,
CellsVoltage = stati.Average(b => b.CellsVoltage),
ConnectedToDc = stati.Any(b => b.ConnectedToDc),
TemperatureState = stati.Any(b => b.TemperatureState == OperatingTemperature) // TODO: revisit when we have the overheated state
? OperatingTemperature
: Cold,
};
return new CombinedStatus<Battery48TLStatus>
{
Combined = combined!,
Children = stati
}; };
} }
} }

View File

@ -5,6 +5,7 @@ using InnovEnergy.Lib.Devices.Battery48TL;
using InnovEnergy.Lib.Devices.EmuMeter; using InnovEnergy.Lib.Devices.EmuMeter;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
using InnovEnergy.Lib.StatusApi;
namespace InnovEnergy.App.SaliMax.Controller; namespace InnovEnergy.App.SaliMax.Controller;
@ -12,8 +13,8 @@ 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[]? BatteriesStatus { get; set; } = Array.Empty<Battery48TLStatus>(); // TODO remove static public CombinedStatus<Battery48TLStatus>? BatteriesStatus { get; init; }
public AvgBatteriesStatus? AvgBatteriesStatus { get; init; }
public EmuMeterStatus? GridMeterStatus { get; init; } public EmuMeterStatus? GridMeterStatus { get; init; }
public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; } public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; }
public AmptStatus? AmptStatus { get; init; } public AmptStatus? AmptStatus { get; init; }

View File

@ -13,6 +13,7 @@ using InnovEnergy.Lib.Devices.EmuMeter;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
using InnovEnergy.Lib.Time.Unix; using InnovEnergy.Lib.Time.Unix;
using InnovEnergy.Lib.Utils;
#pragma warning disable IL2026 #pragma warning disable IL2026
@ -41,6 +42,18 @@ internal static class Program
{ {
Console.WriteLine("Starting SaliMax"); Console.WriteLine("Starting SaliMax");
var batteryNodes = new Byte[] { 2, 3 };
var batteryTty = "/dev/ttyUSB0";
var relaysIp = "10.0.1.1";
var truConvertAcIp = "10.0.2.1";
var truConvertDcIp = "10.0.3.1";
var gridMeterIp = "10.0.4.1";
var internalMeter = "10.0.4.2";
var amptIp = "10.0.5.1";
var s3Config = new S3Config var s3Config = new S3Config
{ {
Bucket = "saliomameiringen", Bucket = "saliomameiringen",
@ -62,33 +75,33 @@ internal static class Program
var firstBattery48TlDevice =Battery48TlDevice.Fake();; var firstBattery48TlDevice =Battery48TlDevice.Fake();;
var salimaxConfig = new SalimaxConfig(); var salimaxConfig = new SalimaxConfig();
#else #else
#if BatteriesAllowed
var firstBattery48TlDevice = new Battery48TlDevice("/dev/ttyUSB0", 2); var batteries = batteryNodes.Select(n => new Battery48TlDevice(batteryTty, n)).ToList();
var secondBattery48TlDevice = new Battery48TlDevice("/dev/ttyUSB0", 3);
#endif
var inverterDevice = new TruConvertAcDevice("192.168.1.2"); var inverterDevice = new TruConvertAcDevice(truConvertAcIp);
var dcDcDevice = new TruConvertDcDevice("192.168.1.3"); var dcDcDevice = new TruConvertDcDevice(truConvertDcIp);
var gridMeterDevice = new EmuMeterDevice("192.168.1.241");
var acInToAcOutMeterDevice = new EmuMeterDevice("192.168.1.241"); // TODO: use real device var gridMeterDevice = new EmuMeterDevice(gridMeterIp);
var amptDevice = new AmptCommunicationUnit("192.168.1.249"); var acInToAcOutMeterDevice = new EmuMeterDevice(internalMeter); // TODO: use real device
var saliMaxRelaysDevice = new SaliMaxRelaysDevice("192.168.1.242");
var amptDevice = new AmptCommunicationUnit(amptIp);
var saliMaxRelaysDevice = new SaliMaxRelaysDevice(relaysIp);
var salimaxConfig = new SalimaxConfig(); var salimaxConfig = new SalimaxConfig();
#endif #endif
// This is will be always add manually ? or do we need to read devices automatically in a range of IP @ // This is will be always add manually ? or do we need to read devices automatically in a range of IP @
#if BatteriesAllowed
var battery48TlDevices = new[] { firstBattery48TlDevice, secondBattery48TlDevice };
#endif
var dcDcDevices = new[] { dcDcDevice };
var inverterDevices = new[] { inverterDevice};
StatusRecord ReadStatus() StatusRecord ReadStatus()
{ {
#if BatteriesAllowed var combinedBatteryStatus = batteries
.Select(b => b.ReadStatus())
.NotNull()
.ToList()
.Combine();
var battery48TlStatusArray = battery48TlDevices.Select(b => b.ReadStatus()).NotNull().ToArray();
#endif
// var dcDcStatusArray = dcDcDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); // var dcDcStatusArray = dcDcDevices.Select(b => b.ReadStatus()).NotNull().ToArray();
// var inverterStatusArray = inverterDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); // var inverterStatusArray = inverterDevices.Select(b => b.ReadStatus()).NotNull().ToArray();
@ -96,14 +109,8 @@ internal static class Program
{ {
InverterStatus = inverterDevice.ReadStatus(), InverterStatus = inverterDevice.ReadStatus(),
DcDcStatus = dcDcDevice.ReadStatus(), DcDcStatus = dcDcDevice.ReadStatus(),
#if BatteriesAllowed
BatteriesStatus = battery48TlStatusArray, BatteriesStatus = combinedBatteryStatus,
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(),

View File

@ -0,0 +1,43 @@
#!/bin/bash
host=ie-entwicklung@10.2.3.115
tunnel() {
name=$1
ip=$2
rPort=$3
lPort=$4
echo -n "localhost:$lPort $name "
ssh -nNTL "$lPort:$ip:$rPort" "$host" 2> /dev/null &
until nc -vz 127.0.0.1 $lPort 2> /dev/null
do
echo -n .
sleep 0.3
done
echo "ok"
}
echo ""
tunnel "Trumpf Inverter (http) " 10.0.2.1 80 8001
tunnel "Trumpf DCDC (http) " 10.0.3.1 80 8002
tunnel "Ext Emu Meter (http) " 10.0.4.1 80 8003
tunnel "Int Emu Meter (http) " 10.0.4.2 80 8004
tunnel "AMPT (http) " 10.0.5.1 8080 8005
tunnel "Trumpf Inverter (modbus)" 10.0.2.1 502 5001
tunnel "Trumpf DCDC (modbus) " 10.0.3.1 502 5002
tunnel "Ext Emu Meter (modbus) " 10.0.4.1 502 5003
tunnel "Int Emu Meter " 10.0.4.2 502 5004
tunnel "AMPT (modbus) " 10.0.5.1 502 5005
echo
echo "press any key to close the tunnels ..."
read -r -n 1 -s
kill $(jobs -p)
echo "done"

View File

@ -1,5 +1,6 @@
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 static InnovEnergy.Lib.Devices.Battery48TL.Constants;
namespace InnovEnergy.Lib.Devices.Battery48TL; namespace InnovEnergy.Lib.Devices.Battery48TL;
@ -10,10 +11,10 @@ public class Battery48TlDevice
public Battery48TlDevice(String device, Byte nodeId) public Battery48TlDevice(String device, Byte nodeId)
{ {
var serialConnection = new ModbusSerialConnection(device, var serialConnection = new ModbusSerialConnection(device,
Constants.BaudRate, BaudRate,
Constants.Parity, Parity,
Constants.DataBits, DataBits,
Constants.StopBits, StopBits,
Constants.Timeout); Constants.Timeout);
Modbus = new ModbusRtuClient(serialConnection, nodeId); Modbus = new ModbusRtuClient(serialConnection, nodeId);
@ -34,7 +35,7 @@ public class Battery48TlDevice
try try
{ {
return Modbus return Modbus
.ReadInputRegisters(Constants.BaseAddress, Constants.NoOfRegisters) .ReadInputRegisters(BaseAddress, NoOfRegisters)
.ParseBatteryStatus(); .ParseBatteryStatus();
} }
catch (Exception e) catch (Exception e)

View File

@ -4,5 +4,5 @@ public enum TemperatureState
{ {
Cold = 0, Cold = 0,
OperatingTemperature = 1, OperatingTemperature = 1,
Overheated =2, Overheated = 2,
} }

View File

@ -13,4 +13,3 @@ public record BatteryStatus : IDcConnection
public Percent Soc { get; init; } public Percent Soc { get; init; }
public Temperature Temperature { get; init; } public Temperature Temperature { get; init; }
} }

View File

@ -0,0 +1,12 @@
namespace InnovEnergy.Lib.StatusApi;
#pragma warning disable CS8618
public record CombinedStatus<T>
{
public T Combined { get; init; }
public IReadOnlyList<T> Children { get; init; }
public Boolean Available => Children.Any();
}