Introduce CombinedStatus
This commit is contained in:
parent
d564b3c3b6
commit
840643f069
|
@ -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>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,18 +5,19 @@ 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;
|
||||||
|
|
||||||
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[]? 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; }
|
||||||
public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; }
|
public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; }
|
||||||
public SalimaxConfig SalimaxConfig { get; init; } = null!;
|
public SalimaxConfig SalimaxConfig { get; init; } = null!;
|
||||||
}
|
}
|
|
@ -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,14 +42,26 @@ 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",
|
||||||
Region = "sos-ch-dk-2",
|
Region = "sos-ch-dk-2",
|
||||||
Provider = "exo.io",
|
Provider = "exo.io",
|
||||||
ContentType = "text/plain; charset=utf-8",
|
ContentType = "text/plain; charset=utf-8",
|
||||||
Key = "EXO2bf0cbd97fbfa75aa36ed46f",
|
Key = "EXO2bf0cbd97fbfa75aa36ed46f",
|
||||||
Secret = "Bn1CDPqOG-XpDSbYjfIJxojcHTm391vZTc8z8l_fEPs"
|
Secret = "Bn1CDPqOG-XpDSbYjfIJxojcHTm391vZTc8z8l_fEPs"
|
||||||
};
|
};
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -62,48 +75,42 @@ 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())
|
||||||
var battery48TlStatusArray = battery48TlDevices.Select(b => b.ReadStatus()).NotNull().ToArray();
|
.NotNull()
|
||||||
#endif
|
.ToList()
|
||||||
// var dcDcStatusArray = dcDcDevices.Select(b => b.ReadStatus()).NotNull().ToArray();
|
.Combine();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
return new StatusRecord
|
return new StatusRecord
|
||||||
{
|
{
|
||||||
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(),
|
||||||
|
|
|
@ -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"
|
|
@ -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)
|
||||||
|
|
|
@ -4,5 +4,5 @@ public enum TemperatureState
|
||||||
{
|
{
|
||||||
Cold = 0,
|
Cold = 0,
|
||||||
OperatingTemperature = 1,
|
OperatingTemperature = 1,
|
||||||
Overheated =2,
|
Overheated = 2,
|
||||||
}
|
}
|
|
@ -12,5 +12,4 @@ public record BatteryStatus : IDcConnection
|
||||||
public DcBus Dc { get; init; }
|
public DcBus Dc { get; init; }
|
||||||
public Percent Soc { get; init; }
|
public Percent Soc { get; init; }
|
||||||
public Temperature Temperature { get; init; }
|
public Temperature Temperature { get; init; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue