Cleanup text based Topology

This commit is contained in:
ig 2023-08-16 15:15:45 +02:00
parent 829732a7ba
commit df9de4c9ed
2 changed files with 136 additions and 125 deletions

View File

@ -12,7 +12,9 @@ public static class Flow
private static readonly String DownArrowChar = "V"; private static readonly String DownArrowChar = "V";
private static readonly String UpArrowChar = "^"; private static readonly String UpArrowChar = "^";
public static TextBlock Horizontal(Unit amount, Int32 width = 10) public static TextBlock Horizontal(Unit amount) => Horizontal(amount, 10);
public static TextBlock Horizontal(Unit amount, Int32 width)
{ {
var label = amount.ToDisplayString(); var label = amount.ToDisplayString();
var arrowChar = amount.Value < 0 ? LeftArrowChar : RightArrowChar; var arrowChar = amount.Value < 0 ? LeftArrowChar : RightArrowChar;
@ -22,18 +24,20 @@ public static class Flow
return TextBlock.AlignCenterHorizontal(label, arrow, ""); return TextBlock.AlignCenterHorizontal(label, arrow, "");
} }
public static TextBlock Vertical(Unit amount) => Vertical(amount, 4);
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
[SuppressMessage("ReSharper", "CoVariantArrayConversion")] [SuppressMessage("ReSharper", "CoVariantArrayConversion")]
public static TextBlock Vertical(Unit amount, Int32 height = 4) public static TextBlock Vertical(Unit amount, Int32 height)
{ {
var label = amount.ToDisplayString(); var label = amount.ToDisplayString();
var arrowChar = amount.Value < 0 ? UpArrowChar : DownArrowChar; var arrowChar = amount.Value < 0 ? UpArrowChar : DownArrowChar;
var halfArrow = Enumerable.Repeat(arrowChar, height/2); var halfArrow = Enumerable.Repeat(arrowChar, height/2);
var lines = halfArrow var lines = halfArrow
.Append(label) .Append(label)
.Concat(halfArrow) .Concat(halfArrow)
.ToArray(height / 2 * 2 + 1); .ToArray(height / 2 * 2 + 1);
return TextBlock.AlignCenterHorizontal(lines); return TextBlock.AlignCenterHorizontal(lines);
} }

View File

@ -1,6 +1,5 @@
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reactive.Threading.Tasks; using System.Reactive.Threading.Tasks;
using System.Runtime.InteropServices;
using Flurl.Http; using Flurl.Http;
using InnovEnergy.App.SaliMax.Ess; using InnovEnergy.App.SaliMax.Ess;
using InnovEnergy.App.SaliMax.SaliMaxRelays; using InnovEnergy.App.SaliMax.SaliMaxRelays;
@ -211,7 +210,7 @@ internal static class Program
WriteControl(record); WriteControl(record);
PrintTopology(record); CreateTopology(record).WriteLine();
//await UploadCsv(record, t); //await UploadCsv(record, t);
@ -225,133 +224,144 @@ internal static class Program
// ReSharper disable once FunctionNeverReturns // ReSharper disable once FunctionNeverReturns
} }
private static void PrintTopology(StatusRecord s) private static TextBlock CreateTopology(StatusRecord s)
{ {
// Power Measurement Values // Power Measurement Values
var gridPower = s.GridMeter is not null ? s.GridMeter!.Ac.Power.Active : 0; var gridPower = s.GridMeter is not null ? s.GridMeter!.Ac.Power.Active : 0;
var inverterPower = s.AcDc.Ac.Power.Active; var ac = s.AcDc.Ac;
var islandLoadPower = s.LoadOnAcIsland is not null ? s.LoadOnAcIsland.Ac.Power.Active : 0; var inverterPower = ac.Power.Active;
var dcBatteryPower = s.DcDc.Dc.Battery.Power; var islandLoadPower = s.LoadOnAcIsland is not null ? s.LoadOnAcIsland.Ac.Power.Active : 0;
var dcdcPower = s.DcDc.Dc.Link.Power; var dcBatteryPower = s.DcDc.Dc.Battery.Power;
var pvOnDcPower = s.PvOnDc.Dc!.Power.Value; var dcdcPower = s.DcDc.Dc.Link.Power;
var pvOnDcPower = s.PvOnDc.Dc!.Power.Value;
// Power Calculated Values // Power Calculated Values
var islandToGridBusPower = inverterPower + islandLoadPower; ActivePower islandToGridBusPower = inverterPower + islandLoadPower;
var gridLoadPower = s.LoadOnAcGrid is null ? 0: s.LoadOnAcGrid.Power.Active;
TextBlock gridBusColumn; var islandBusData = TextBlock.AlignLeft(ac.L1.Power.Active.ToDisplayString(),
TextBlock gridBox; ac.L2.Power.Active.ToDisplayString(),
TextBlock totalBoxes; ac.L3.Power.Active.ToDisplayString());
var dc48Voltage = s.DcDc.Dc.Battery.Voltage.ToDisplayString();
if (s.GridMeter is not null) var islandBusPv = 0.W(); // TODO
{ var islandBusColumn = ColumnBox("Pv" , islandBusPv,
var gridPowerByPhase = TextBlock.AlignLeft(s.GridMeter.Ac.L1.Power.Active.ToDisplayString(), "Island Bus", islandBusData,
s.GridMeter.Ac.L2.Power.Active.ToDisplayString(), "Load" , islandLoadPower);
s.GridMeter.Ac.L3.Power.Active.ToDisplayString());
var gridVoltageByPhase = TextBlock.AlignLeft(s.GridMeter.Ac.L1.Voltage.ToDisplayString(), var dcBusLoad = 0.W(); // TODO
s.GridMeter.Ac.L2.Voltage.ToDisplayString(), var dcLinkVoltage = s.DcDc.Dc.Link.Voltage.ToDisplayString();
s.GridMeter.Ac.L3.Voltage.ToDisplayString()); var dcBusColumn = ColumnBox("Pv" , pvOnDcPower,
"Dc Bus", dcLinkVoltage,
"Load" , dcBusLoad);
gridBusColumn = ColumnBox("Pv", "Grid Bus", "Load" , gridVoltageByPhase , gridLoadPower); var inverterAcPhases = s
gridBox = TextBlock.AlignLeft(gridPowerByPhase).TitleBox("Grid"); .AcDc
.Devices
.Select(d => d.Status.Ac.Power)
.ToArray(s.AcDc.Devices.Count)
.AsReadOnlyList();
} var inverterBox = TextBlock.AlignLeft(inverterAcPhases).TitleBox("AC/DC");
else var dcDcBox = TextBlock.AlignLeft(dc48Voltage) .TitleBox("DC/DC");
{
gridBusColumn = TextBlock.Spacer(0);
gridBox = TextBlock.Spacer(0);
}
var bat = s.Battery;
var batteryAvgBox = CreateAveragedBatteryBox(bat);
var batteryBoxes = bat
var inverterPowerByPhase = TextBlock.AlignLeft(s.AcDc.Ac.L1.Power.Active.ToDisplayString(), .Devices
s.AcDc.Ac.L2.Power.Active.ToDisplayString(), .Select(CreateIndividualBattery)
s.AcDc.Ac.L3.Power.Active.ToDisplayString()); .ToArray(bat.Devices.Count)
.AsReadOnlyList();
// ReSharper disable once CoVariantArrayConversion
var inverterPowerByAcDc = TextBlock.AlignLeft(s.AcDc.Devices
.Select(s1 => s1.Status.Ac.Power)
.ToArray());
var dcLinkVoltage = TextBlock.AlignCenterHorizontal("",
s.DcDc.Dc.Link.Voltage.ToDisplayString(),
"");
var dc48Voltage = s.DcDc.Dc.Battery.Voltage.ToDisplayString();
var batteryVoltage = s.Battery.Dc.Voltage.Value.RoundToSignificantDigits(3);
var batterySoc = s.Battery.Devices.Any()? s.Battery.Devices.Average(b=>b.Soc).Percent().ToDisplayString() : "0";
var batteryCurrent = s.Battery.Dc.Current.ToDisplayString();
var batteryTemp = s.Battery.Temperature.ToDisplayString();
var batteryHeatingCurrent = s.Battery.HeatingCurrent.ToDisplayString();
var anyBatteryAlarm = s.Battery.Alarms.Any();
var anyBatteryWarning = s.Battery.Warnings.Any();
var islandBusColumn = ColumnBox("Pv", "Island Bus", "Load" , inverterPowerByPhase, islandLoadPower);
var dcBusColumn = ColumnBox("Pv", "Dc Bus", "Load" , dcLinkVoltage, 0, pvOnDcPower);
var gridBusFlow = Flow.Horizontal(gridPower);
var flowGridBusToIslandBus = Flow.Horizontal((ActivePower)islandToGridBusPower);
var flowIslandBusToInverter = Flow.Horizontal(inverterPower);
var flowInverterToDcBus = Flow.Horizontal(inverterPower);
var flowDcBusToDcDc = Flow.Horizontal(dcdcPower);
var flowDcDcToBattery = Flow.Horizontal(dcBatteryPower);
var inverterBox = TextBlock.AlignLeft(inverterPowerByAcDc).TitleBox("AC/DC");
var dcDcBox = TextBlock.AlignLeft(dc48Voltage).TitleBox("DC/DC");
var batteryAvgBox = TextBlock.AlignLeft(batteryVoltage,
batterySoc,
batteryCurrent,
batteryTemp,
batteryHeatingCurrent,
anyBatteryWarning,
anyBatteryAlarm)
.TitleBox("Battery");
//////////////////// Batteries /////////////////////////
IReadOnlyList<TextBlock> batteryBoxes = s.Battery
.Devices
.Select(CreateIndividualBattery)
.ToArray(s.Battery.Devices.Count);
var individualBatteries = batteryBoxes.Any() var individualBatteries = batteryBoxes.Any()
? TextBlock.AlignLeft(batteryBoxes) ? TextBlock.AlignLeft(batteryBoxes)
: TextBlock.Spacer(1); : TextBlock.Spacer(1);
if (s.GridMeter is not null) var flowIslandBusToInverter = Flow.Horizontal(inverterPower);
{ var flowInverterToDcBus = Flow.Horizontal(inverterPower);
totalBoxes = TextBlock.AlignCenterVertical(gridBox, var flowDcBusToDcDc = Flow.Horizontal(dcdcPower);
gridBusFlow, var flowDcDcToBattery = Flow.Horizontal(dcBatteryPower);
gridBusColumn,
flowGridBusToIslandBus,
islandBusColumn,
flowIslandBusToInverter,
inverterBox,
flowInverterToDcBus,
dcBusColumn,
flowDcBusToDcDc,
dcDcBox,
flowDcDcToBattery,
batteryAvgBox,
individualBatteries);
}
else
{
totalBoxes = TextBlock.AlignCenterVertical(islandBusColumn,
flowIslandBusToInverter,
inverterBox,
flowInverterToDcBus,
dcBusColumn,
flowDcBusToDcDc,
dcDcBox,
flowDcDcToBattery,
batteryAvgBox,
individualBatteries);
}
totalBoxes.WriteLine(); var islandTopology = TextBlock
.AlignCenterVertical
(
islandBusColumn,
flowIslandBusToInverter,
inverterBox,
flowInverterToDcBus,
dcBusColumn,
flowDcBusToDcDc,
dcDcBox,
flowDcDcToBattery,
batteryAvgBox,
individualBatteries
);
if (s.GridMeter is null)
return islandTopology;
var gridBox = CreateGridBox(s);
var gridToGridBus = Flow.Horizontal(gridPower);
var gridBusColumn = GridBusColumn(s);
var gridBusToIslandBus = Flow.Horizontal(islandToGridBusPower);
return TextBlock
.AlignCenterVertical
(
gridBox,
gridToGridBus,
gridBusColumn,
gridBusToIslandBus,
islandTopology
);
}
private static TextBlock CreateAveragedBatteryBox(Battery48TlRecords bat)
{
var batteryVoltage = bat.Dc.Voltage.ToDisplayString();
var batterySoc = bat.Devices.Any() ? bat.Devices.Average(b => b.Soc).Percent().ToDisplayString() : "0";
var batteryCurrent = bat.Dc.Current.ToDisplayString();
var batteryTemp = bat.Temperature.ToDisplayString();
var batteryHeatingCurrent = bat.HeatingCurrent.ToDisplayString();
var alarms = bat.Alarms.Count + " Alarms";
var warnings = bat.Warnings.Count + " Warnings";
return TextBlock
.AlignLeft
(
batteryVoltage,
batterySoc,
batteryCurrent,
batteryTemp,
batteryHeatingCurrent,
warnings,
alarms
)
.TitleBox("Battery");
}
private static TextBlock GridBusColumn(StatusRecord s)
{
var gridLoadPower = s.LoadOnAcGrid is not null
? s.LoadOnAcGrid.Power.Active
: 0; // TODO: show that LoadOnAcGrid is actually not available and not 0
var ac = s.GridMeter!.Ac;
var gridVoltageByPhase = TextBlock.AlignLeft(ac.L1.Voltage.ToDisplayString(),
ac.L2.Voltage.ToDisplayString(),
ac.L3.Voltage.ToDisplayString());
return ColumnBox("Pv", 0, "Grid Bus", gridVoltageByPhase, "Load", gridLoadPower);
}
private static TextBlock CreateGridBox(StatusRecord s)
{
return TextBlock.AlignLeft(s.GridMeter!.Ac.L1.Power.Active.ToDisplayString(),
s.GridMeter!.Ac.L2.Power.Active.ToDisplayString(),
s.GridMeter!.Ac.L3.Power.Active.ToDisplayString())
.TitleBox("Grid");
} }
private static TextBlock CreateIndividualBattery(Battery48TlRecord battery, Int32 i) private static TextBlock CreateIndividualBattery(Battery48TlRecord battery, Int32 i)
@ -375,16 +385,13 @@ internal static class Program
return TextBlock.AlignCenterVertical(flow, box); return TextBlock.AlignCenterVertical(flow, box);
} }
private static TextBlock ColumnBox(String pvTitle, String busTitle, String loadTitle, TextBlock dataBox, ActivePower loadPower) private static TextBlock ColumnBox(String pvTitle , ActivePower pvPower,
{ String busTitle , Object busData,
return ColumnBox(pvTitle, busTitle, loadTitle, dataBox, loadPower, 0); String loadTitle, ActivePower loadPower)
}
private static TextBlock ColumnBox(String pvTitle, String busTitle, String loadTitle, TextBlock dataBox, ActivePower loadPower, ActivePower pvPower)
{ {
var pvBox = TextBlock.FromString(pvTitle).Box(); var pvBox = TextBlock.FromString(pvTitle).Box();
var pvToBus = Flow.Vertical(pvPower); var pvToBus = Flow.Vertical(pvPower);
var busBox = TextBlock.AlignLeft(dataBox).TitleBox(busTitle); var busBox = TextBlock.AlignLeft(busData).TitleBox(busTitle);
var busToLoad = Flow.Vertical(loadPower); var busToLoad = Flow.Vertical(loadPower);
var loadBox = TextBlock.FromString(loadTitle).Box(); var loadBox = TextBlock.FromString(loadTitle).Box();