241 lines
8.6 KiB
C#
241 lines
8.6 KiB
C#
#define BatteriesAllowed
|
|
|
|
using InnovEnergy.App.SaliMax.Controller;
|
|
using InnovEnergy.Lib.Utils;
|
|
using InnovEnergy.Lib.Units;
|
|
|
|
|
|
namespace InnovEnergy.App.SaliMax;
|
|
|
|
public static class Topology
|
|
{
|
|
private static String Separator(Decimal power)
|
|
{
|
|
const String chargingSeparator = ">>>>>>>>>>";
|
|
const String dischargingSeparator = "<<<<<<<<<";
|
|
|
|
return power > 0 ? chargingSeparator : dischargingSeparator;
|
|
}
|
|
|
|
public static Decimal Round3(this Decimal d)
|
|
{
|
|
return d.RoundToSignificantDigits(3);
|
|
}
|
|
|
|
public static void Print(StatusRecord s)
|
|
{
|
|
const Int32 height = 25;
|
|
|
|
var calculatedActivePwr = - s.InverterStatus!.Ac.ActivePower;
|
|
var measuredActivePwr = (s.InverterStatus.SumActivePowerL1 + s.InverterStatus.SumActivePowerL2 +
|
|
s.InverterStatus.SumActivePowerL3) * -1;
|
|
|
|
measuredActivePwr.WriteLine(" : measured Sum of Active Pwr ");
|
|
|
|
var setValueCosPhi = s.InverterStatus.CosPhiSetValue;
|
|
var setValueApparentPower = s.InverterStatus.ApparentPowerSetValue;
|
|
|
|
|
|
#if AmptAvailable
|
|
var pvPower = (s.AmptStatus!.Devices[0].Dc.Voltage * s.AmptStatus.Devices[0].Dc.Current + s.AmptStatus!.Devices[1].Dc.Voltage * s.AmptStatus.Devices[1].Dc.Current).Round0(); // TODO using one Ampt
|
|
#else
|
|
var pvPower = 0;
|
|
#endif
|
|
var criticalLoadPower = (s.AcInToAcOutMeterStatus!.Ac.ActivePower.Value).Round3();
|
|
|
|
var dcTotalPower = -s.DcDcStatus!.TotalDcPower;
|
|
var gridSeparator = Separator(s.GridMeterStatus!.Ac.ActivePower);
|
|
var inverterSeparator = Separator(measuredActivePwr);
|
|
var dcSeparator = Separator(dcTotalPower);
|
|
var something = measuredActivePwr + criticalLoadPower;
|
|
var gridLoadPower = (s.GridMeterStatus!.Ac.ActivePower - something).Value.Round3();
|
|
|
|
|
|
|
|
////////////////// Grid //////////////////////
|
|
var boxGrid = AsciiArt.CreateBox
|
|
(
|
|
"Grid",
|
|
s.GridMeterStatus.Ac.L1.Voltage.Value.V(),
|
|
s.GridMeterStatus.Ac.L2.Voltage.Value.V(),
|
|
s.GridMeterStatus.Ac.L3.Voltage.Value.V()
|
|
).AlignCenterVertical(height);
|
|
|
|
var gridAcBusArrow = AsciiArt.CreateHorizontalArrow(s.GridMeterStatus!.Ac.ActivePower, gridSeparator)
|
|
.AlignCenterVertical(height);
|
|
|
|
|
|
////////////////// Ac Bus //////////////////////
|
|
var boxAcBus = AsciiArt.CreateBox
|
|
(
|
|
"AC Bus",
|
|
s.InverterStatus.Ac.L1.Voltage.Value.V(),
|
|
s.InverterStatus.Ac.L2.Voltage.Value.V(),
|
|
s.InverterStatus.Ac.L3.Voltage.Value.V()
|
|
);
|
|
|
|
var boxLoad = AsciiArt.CreateBox
|
|
(
|
|
"",
|
|
"LOAD",
|
|
""
|
|
);
|
|
|
|
var loadRect = StringUtils.AlignBottom(CreateRect(boxAcBus, boxLoad, gridLoadPower), height);
|
|
|
|
var acBusInvertArrow = AsciiArt.CreateHorizontalArrow(measuredActivePwr, inverterSeparator)
|
|
.AlignCenterVertical(height);
|
|
|
|
//////////////////// Inverter /////////////////////////
|
|
var inverterBox = AsciiArt.CreateBox
|
|
(
|
|
"",
|
|
"Inverter",
|
|
""
|
|
).AlignCenterVertical(height);
|
|
|
|
var inverterArrow = AsciiArt.CreateHorizontalArrow(measuredActivePwr, inverterSeparator)
|
|
.AlignCenterVertical(height);
|
|
|
|
|
|
//////////////////// DC Bus /////////////////////////
|
|
var dcBusBox = AsciiArt.CreateBox
|
|
(
|
|
"DC Bus",
|
|
(s.InverterStatus.ActualDcLinkVoltageLowerHalfExt.Value + s.InverterStatus.ActualDcLinkVoltageUpperHalfExt.Value).V(),
|
|
""
|
|
);
|
|
|
|
var pvBox = AsciiArt.CreateBox
|
|
(
|
|
"MPPT",
|
|
((s.AmptStatus!.Devices[0].Strings[0].Voltage.Value + s.AmptStatus!.Devices[0].Strings[1].Voltage.Value) / 2).V(),
|
|
""
|
|
);
|
|
|
|
var pvRect = StringUtils.AlignTop(CreateRect(pvBox, dcBusBox, pvPower), height);
|
|
|
|
var dcBusArrow = AsciiArt.CreateHorizontalArrow(-s.DcDcStatus!.Left.Power, dcSeparator)
|
|
.AlignCenterVertical(height);
|
|
|
|
//////////////////// Dc/Dc /////////////////////////
|
|
|
|
var dcBox = AsciiArt.CreateBox( "Dc/Dc", s.DcDcStatus.Right.Voltage.Value.V(), "").AlignCenterVertical(height);
|
|
|
|
var topology = "";
|
|
|
|
if (s.BatteriesStatus != null)
|
|
{
|
|
var numBatteries = s.BatteriesStatus.Children.Count;
|
|
|
|
// Create an array of battery arrows using LINQ
|
|
var dcArrows = s
|
|
.BatteriesStatus.Children
|
|
.Select(b => AsciiArt.CreateHorizontalArrow(b.Dc.Power, Separator(b.Dc.Power)))
|
|
.ToArray();
|
|
|
|
// Create a rectangle from the array of arrows and align it vertically
|
|
var dcArrowRect = CreateRect(dcArrows).AlignCenterVertical(height);
|
|
|
|
//////////////////// Batteries /////////////////////////
|
|
|
|
var batteryBox = new String[numBatteries];
|
|
|
|
for (var i = 0; i < numBatteries; i++)
|
|
{
|
|
if (s.BatteriesStatus.Children[i] != null)
|
|
{
|
|
batteryBox[i] = AsciiArt.CreateBox
|
|
(
|
|
"Battery " + (i+1),
|
|
s.BatteriesStatus.Children[i].Dc.Voltage .Value.V(),
|
|
s.BatteriesStatus.Children[i].Soc .Value.Percent(),
|
|
s.BatteriesStatus.Children[i].Temperature .Value.Celsius(),
|
|
s.BatteriesStatus.Children[i].Dc.Current .Value.A(),
|
|
s.BatteriesStatus.Children[i].TotalCurrent.Value.A()
|
|
);
|
|
}
|
|
else
|
|
{
|
|
batteryBox[i] = AsciiArt.CreateBox
|
|
(
|
|
"Battery " + (i+1),
|
|
"not detected"
|
|
);
|
|
}
|
|
}
|
|
|
|
var batteryRect = CreateRect(batteryBox).AlignCenterVertical(height);
|
|
|
|
|
|
var avgBatteryBox = "";
|
|
|
|
if (s.BatteriesStatus.Combined != null)
|
|
{
|
|
avgBatteryBox = AsciiArt.CreateBox
|
|
(
|
|
"Batteries",
|
|
s.BatteriesStatus.Combined.CellsVoltage,
|
|
s.BatteriesStatus.Combined.Soc,
|
|
s.BatteriesStatus.Combined.Temperature,
|
|
s.BatteriesStatus.Combined.Dc.Current,
|
|
s.BatteriesStatus.Combined.Alarms.Count > 0 ? String.Join(Environment.NewLine, s.BatteriesStatus.Combined.Alarms) : "No Alarm"
|
|
).AlignCenterVertical(height);
|
|
}
|
|
|
|
|
|
topology = boxGrid.SideBySideWith(gridAcBusArrow, "")
|
|
.SideBySideWith(loadRect, "")
|
|
.SideBySideWith(acBusInvertArrow, "")
|
|
.SideBySideWith(inverterBox, "")
|
|
.SideBySideWith(inverterArrow, "")
|
|
.SideBySideWith(pvRect, "")
|
|
.SideBySideWith(dcBusArrow, "")
|
|
.SideBySideWith(dcBox, "")
|
|
.SideBySideWith(dcArrowRect, "")
|
|
.SideBySideWith(batteryRect, "")
|
|
.SideBySideWith(avgBatteryBox, "")+ "\n";
|
|
|
|
}
|
|
else
|
|
{
|
|
topology = boxGrid.SideBySideWith(gridAcBusArrow, "")
|
|
.SideBySideWith(loadRect, "")
|
|
.SideBySideWith(acBusInvertArrow, "")
|
|
.SideBySideWith(inverterBox, "")
|
|
.SideBySideWith(inverterArrow, "")
|
|
.SideBySideWith(pvRect, "")
|
|
.SideBySideWith(dcBusArrow, "")
|
|
.SideBySideWith(dcBox, "") + "\n";
|
|
}
|
|
|
|
Console.WriteLine(topology);
|
|
}
|
|
|
|
private static String CreateRect(String boxTop, String boxBottom, Decimal power)
|
|
{
|
|
var powerArrow = AsciiArt.CreateVerticalArrow(power);
|
|
var boxes = new[] { boxTop, powerArrow, boxBottom };
|
|
var maxWidth = boxes.Max(l => l.Width());
|
|
|
|
var rect = boxes.Select(l => l.AlignCenterHorizontal(maxWidth)).JoinLines();
|
|
return rect;
|
|
}
|
|
|
|
private static String CreateRect(String boxTop, String boxBottom)
|
|
{
|
|
var boxes = new[] { boxTop, boxBottom };
|
|
var maxWidth = boxes.Max(l => l.Width());
|
|
|
|
var rect = boxes.Select(l => l.AlignCenterHorizontal(maxWidth)).JoinLines();
|
|
return rect;
|
|
}
|
|
|
|
private static String CreateRect(String[] boxes)
|
|
{
|
|
var maxWidth = boxes.Max(l => l.Width());
|
|
var rect = boxes.Select(l => l.AlignCenterHorizontal(maxWidth)).JoinLines();
|
|
return rect;
|
|
}
|
|
|
|
} |