Cleanup text based Topology
This commit is contained in:
parent
829732a7ba
commit
df9de4c9ed
|
@ -12,7 +12,9 @@ public static class Flow
|
|||
private static readonly String DownArrowChar = "V";
|
||||
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 arrowChar = amount.Value < 0 ? LeftArrowChar : RightArrowChar;
|
||||
|
@ -21,19 +23,21 @@ public static class Flow
|
|||
// note : appending "fake label" below to make it vertically symmetric
|
||||
return TextBlock.AlignCenterHorizontal(label, arrow, "");
|
||||
}
|
||||
|
||||
|
||||
public static TextBlock Vertical(Unit amount) => Vertical(amount, 4);
|
||||
|
||||
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
|
||||
[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 arrowChar = amount.Value < 0 ? UpArrowChar : DownArrowChar;
|
||||
var halfArrow = Enumerable.Repeat(arrowChar, height/2);
|
||||
|
||||
var lines = halfArrow
|
||||
.Append(label)
|
||||
.Concat(halfArrow)
|
||||
.ToArray(height / 2 * 2 + 1);
|
||||
.Append(label)
|
||||
.Concat(halfArrow)
|
||||
.ToArray(height / 2 * 2 + 1);
|
||||
|
||||
return TextBlock.AlignCenterHorizontal(lines);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System.Reactive.Linq;
|
||||
using System.Reactive.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
using Flurl.Http;
|
||||
using InnovEnergy.App.SaliMax.Ess;
|
||||
using InnovEnergy.App.SaliMax.SaliMaxRelays;
|
||||
|
@ -211,7 +210,7 @@ internal static class Program
|
|||
|
||||
WriteControl(record);
|
||||
|
||||
PrintTopology(record);
|
||||
CreateTopology(record).WriteLine();
|
||||
|
||||
//await UploadCsv(record, t);
|
||||
|
||||
|
@ -225,133 +224,144 @@ internal static class Program
|
|||
// ReSharper disable once FunctionNeverReturns
|
||||
}
|
||||
|
||||
private static void PrintTopology(StatusRecord s)
|
||||
private static TextBlock CreateTopology(StatusRecord s)
|
||||
{
|
||||
// Power Measurement Values
|
||||
var gridPower = s.GridMeter is not null ? s.GridMeter!.Ac.Power.Active : 0;
|
||||
var inverterPower = s.AcDc.Ac.Power.Active;
|
||||
var islandLoadPower = s.LoadOnAcIsland is not null ? s.LoadOnAcIsland.Ac.Power.Active : 0;
|
||||
var dcBatteryPower = s.DcDc.Dc.Battery.Power;
|
||||
var dcdcPower = s.DcDc.Dc.Link.Power;
|
||||
var pvOnDcPower = s.PvOnDc.Dc!.Power.Value;
|
||||
var gridPower = s.GridMeter is not null ? s.GridMeter!.Ac.Power.Active : 0;
|
||||
var ac = s.AcDc.Ac;
|
||||
var inverterPower = ac.Power.Active;
|
||||
var islandLoadPower = s.LoadOnAcIsland is not null ? s.LoadOnAcIsland.Ac.Power.Active : 0;
|
||||
var dcBatteryPower = s.DcDc.Dc.Battery.Power;
|
||||
var dcdcPower = s.DcDc.Dc.Link.Power;
|
||||
var pvOnDcPower = s.PvOnDc.Dc!.Power.Value;
|
||||
|
||||
// Power Calculated Values
|
||||
var islandToGridBusPower = inverterPower + islandLoadPower;
|
||||
var gridLoadPower = s.LoadOnAcGrid is null ? 0: s.LoadOnAcGrid.Power.Active;
|
||||
ActivePower islandToGridBusPower = inverterPower + islandLoadPower;
|
||||
|
||||
TextBlock gridBusColumn;
|
||||
TextBlock gridBox;
|
||||
TextBlock totalBoxes;
|
||||
var islandBusData = TextBlock.AlignLeft(ac.L1.Power.Active.ToDisplayString(),
|
||||
ac.L2.Power.Active.ToDisplayString(),
|
||||
ac.L3.Power.Active.ToDisplayString());
|
||||
|
||||
var dc48Voltage = s.DcDc.Dc.Battery.Voltage.ToDisplayString();
|
||||
|
||||
var islandBusPv = 0.W(); // TODO
|
||||
var islandBusColumn = ColumnBox("Pv" , islandBusPv,
|
||||
"Island Bus", islandBusData,
|
||||
"Load" , islandLoadPower);
|
||||
|
||||
if (s.GridMeter is not null)
|
||||
{
|
||||
var gridPowerByPhase = TextBlock.AlignLeft(s.GridMeter.Ac.L1.Power.Active.ToDisplayString(),
|
||||
s.GridMeter.Ac.L2.Power.Active.ToDisplayString(),
|
||||
s.GridMeter.Ac.L3.Power.Active.ToDisplayString());
|
||||
|
||||
var gridVoltageByPhase = TextBlock.AlignLeft(s.GridMeter.Ac.L1.Voltage.ToDisplayString(),
|
||||
s.GridMeter.Ac.L2.Voltage.ToDisplayString(),
|
||||
s.GridMeter.Ac.L3.Voltage.ToDisplayString());
|
||||
|
||||
gridBusColumn = ColumnBox("Pv", "Grid Bus", "Load" , gridVoltageByPhase , gridLoadPower);
|
||||
gridBox = TextBlock.AlignLeft(gridPowerByPhase).TitleBox("Grid");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
gridBusColumn = TextBlock.Spacer(0);
|
||||
gridBox = TextBlock.Spacer(0);
|
||||
}
|
||||
|
||||
var dcBusLoad = 0.W(); // TODO
|
||||
var dcLinkVoltage = s.DcDc.Dc.Link.Voltage.ToDisplayString();
|
||||
var dcBusColumn = ColumnBox("Pv" , pvOnDcPower,
|
||||
"Dc Bus", dcLinkVoltage,
|
||||
"Load" , dcBusLoad);
|
||||
|
||||
|
||||
var inverterPowerByPhase = TextBlock.AlignLeft(s.AcDc.Ac.L1.Power.Active.ToDisplayString(),
|
||||
s.AcDc.Ac.L2.Power.Active.ToDisplayString(),
|
||||
s.AcDc.Ac.L3.Power.Active.ToDisplayString());
|
||||
|
||||
// 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 inverterAcPhases = s
|
||||
.AcDc
|
||||
.Devices
|
||||
.Select(d => d.Status.Ac.Power)
|
||||
.ToArray(s.AcDc.Devices.Count)
|
||||
.AsReadOnlyList();
|
||||
|
||||
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(inverterAcPhases).TitleBox("AC/DC");
|
||||
var dcDcBox = TextBlock.AlignLeft(dc48Voltage) .TitleBox("DC/DC");
|
||||
|
||||
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");
|
||||
var bat = s.Battery;
|
||||
var batteryAvgBox = CreateAveragedBatteryBox(bat);
|
||||
|
||||
|
||||
//////////////////// Batteries /////////////////////////
|
||||
|
||||
IReadOnlyList<TextBlock> batteryBoxes = s.Battery
|
||||
.Devices
|
||||
.Select(CreateIndividualBattery)
|
||||
.ToArray(s.Battery.Devices.Count);
|
||||
var batteryBoxes = bat
|
||||
.Devices
|
||||
.Select(CreateIndividualBattery)
|
||||
.ToArray(bat.Devices.Count)
|
||||
.AsReadOnlyList();
|
||||
|
||||
var individualBatteries = batteryBoxes.Any()
|
||||
? TextBlock.AlignLeft(batteryBoxes)
|
||||
: TextBlock.Spacer(1);
|
||||
|
||||
if (s.GridMeter is not null)
|
||||
{
|
||||
totalBoxes = TextBlock.AlignCenterVertical(gridBox,
|
||||
gridBusFlow,
|
||||
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);
|
||||
}
|
||||
var flowIslandBusToInverter = Flow.Horizontal(inverterPower);
|
||||
var flowInverterToDcBus = Flow.Horizontal(inverterPower);
|
||||
var flowDcBusToDcDc = Flow.Horizontal(dcdcPower);
|
||||
var flowDcDcToBattery = Flow.Horizontal(dcBatteryPower);
|
||||
|
||||
var islandTopology = TextBlock
|
||||
.AlignCenterVertical
|
||||
(
|
||||
islandBusColumn,
|
||||
flowIslandBusToInverter,
|
||||
inverterBox,
|
||||
flowInverterToDcBus,
|
||||
dcBusColumn,
|
||||
flowDcBusToDcDc,
|
||||
dcDcBox,
|
||||
flowDcDcToBattery,
|
||||
batteryAvgBox,
|
||||
individualBatteries
|
||||
);
|
||||
|
||||
totalBoxes.WriteLine();
|
||||
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)
|
||||
|
@ -375,16 +385,13 @@ internal static class Program
|
|||
return TextBlock.AlignCenterVertical(flow, box);
|
||||
}
|
||||
|
||||
private static TextBlock ColumnBox(String pvTitle, String busTitle, String loadTitle, TextBlock dataBox, ActivePower loadPower)
|
||||
{
|
||||
return ColumnBox(pvTitle, busTitle, loadTitle, dataBox, loadPower, 0);
|
||||
}
|
||||
|
||||
private static TextBlock ColumnBox(String pvTitle, String busTitle, String loadTitle, TextBlock dataBox, ActivePower loadPower, ActivePower pvPower)
|
||||
private static TextBlock ColumnBox(String pvTitle , ActivePower pvPower,
|
||||
String busTitle , Object busData,
|
||||
String loadTitle, ActivePower loadPower)
|
||||
{
|
||||
var pvBox = TextBlock.FromString(pvTitle).Box();
|
||||
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 loadBox = TextBlock.FromString(loadTitle).Box();
|
||||
|
||||
|
|
Loading…
Reference in New Issue