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" />
<ItemGroup>
<ProjectReference Include="../../Lib/Devices/Adam6060/Adam6060.csproj"/>
<ProjectReference Include="../../Lib/Devices/AMPT/Ampt.csproj"/>
<ProjectReference Include="../../Lib/Devices/Battery48TL/Battery48TL.csproj"/>
<ProjectReference Include="../../Lib/Devices/EmuMeter/EmuMeter.csproj"/>
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj"/>
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj"/>
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvert/TruConvert.csproj"/>
<ProjectReference Include="../../Lib/StatusApi/StatusApi.csproj"/>
<ProjectReference Include="../../Lib/Utils/Utils.csproj"/>
<ProjectReference Include="../../Lib/Time/Time.csproj"/>
<ProjectReference Include="../../Lib/Devices/Adam6060/Adam6060.csproj" />
<ProjectReference Include="../../Lib/Devices/AMPT/Ampt.csproj" />
<ProjectReference Include="../../Lib/Devices/Battery48TL/Battery48TL.csproj" />
<ProjectReference Include="../../Lib/Devices/EmuMeter/EmuMeter.csproj" />
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj" />
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj" />
<ProjectReference Include="../../Lib/Devices/Trumpf/TruConvert/TruConvert.csproj" />
<ProjectReference Include="../../Lib/StatusApi/StatusApi.csproj" />
<ProjectReference Include="../../Lib/Utils/Utils.csproj" />
<ProjectReference Include="../../Lib/Time/Time.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CliWrap" Version="3.6.0"/>
<PackageReference Include="Flurl.Http" Version="3.2.4"/>
<PackageReference Include="System.IO.Ports" Version="7.0.0"/>
<PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2"/>
<PackageReference Include="CliWrap" Version="3.6.0" />
<PackageReference Include="Flurl.Http" Version="3.2.4" />
<PackageReference Include="System.IO.Ports" Version="7.0.0" />
<PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" />
</ItemGroup>

View File

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

View File

@ -5,18 +5,19 @@ using InnovEnergy.Lib.Devices.Battery48TL;
using InnovEnergy.Lib.Devices.EmuMeter;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
using InnovEnergy.Lib.StatusApi;
namespace InnovEnergy.App.SaliMax.Controller;
public record StatusRecord
{
public TruConvertAcStatus? InverterStatus { get; init; }
public TruConvertDcStatus? DcDcStatus { get; init; }
public Battery48TLStatus[]? BatteriesStatus { get; set; } = Array.Empty<Battery48TLStatus>(); // TODO remove static
public AvgBatteriesStatus? AvgBatteriesStatus { get; init; }
public EmuMeterStatus? GridMeterStatus { get; init; }
public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; }
public AmptStatus? AmptStatus { get; init; }
public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; }
public SalimaxConfig SalimaxConfig { get; init; } = null!;
public TruConvertAcStatus? InverterStatus { get; init; }
public TruConvertDcStatus? DcDcStatus { get; init; }
public CombinedStatus<Battery48TLStatus>? BatteriesStatus { get; init; }
public EmuMeterStatus? GridMeterStatus { get; init; }
public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; }
public AmptStatus? AmptStatus { get; init; }
public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; }
public SalimaxConfig SalimaxConfig { get; init; } = null!;
}

View File

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

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

View File

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

View File

@ -12,5 +12,4 @@ public record BatteryStatus : IDcConnection
public DcBus Dc { get; init; }
public Percent Soc { 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();
}