226 lines
9.7 KiB
C#
226 lines
9.7 KiB
C#
using System.Globalization;
|
|
using InnovEnergy.App.KacoCommunication.Devices;
|
|
using InnovEnergy.App.KacoCommunication.ESS;
|
|
using InnovEnergy.Lib.Devices.BatteryDeligreen;
|
|
using InnovEnergy.Lib.Units.Power;
|
|
using InnovEnergy.Lib.Utils;
|
|
|
|
namespace InnovEnergy.App.KacoCommunication;
|
|
|
|
|
|
//
|
|
// ┌────┐
|
|
// │ Pv │
|
|
// └────┘
|
|
// V
|
|
// V
|
|
// (i) 13.2 kW ┌────────────┐ ┌────────────┐ ┌────────────┐
|
|
// V │ Battery K1│ │ Battery K2│ │ Battery K3│
|
|
// ┌─────────┐ ┌─────────┐ V ├────────────┤ ├────────────┤ ├────────────┤
|
|
// │ Grid │ │ AC/DC │ ┌────────┐ ┌───────┐ │ 52.3 V │ │ 52.3 V │ │ 52.3 V │
|
|
// ├─────────┤ -10.3 kW├─────────┤ -11.7 kW │ Dc Bus │ 1008 W │ DC/DC │ 1008 W │ 99.1 % │ │ 99.1 % │ │ 99.1 % │
|
|
// │ -3205 W │<<<<<<<<<│ -6646 W │<<<<<<<<<<├────────┤>>>>>>>>>>├───────┤>>>>>>>>>>│ 490 mA │ │ 490 mA │ │ 490 mA │
|
|
// │ -3507 W │ (a) │ -5071 W │ (h) │ 776 V │ (k) │ 56 V │ (l) │ 250 °C │ │ 250 °C │ │ 250 °C │
|
|
// │ -3605 W │ └─────────┘ └────────┘ └───────┘ │ 445 A │ │ 445 A │ │ 445 A │
|
|
// └─────────┘ V │ │ │ │ │ │
|
|
// V │ │ │ │ │ │
|
|
// (j) 0 W └────────────┘ └────────────┘ └────────────┘
|
|
// V
|
|
// V
|
|
// ┌──────┐
|
|
// │ Load │
|
|
// └──────┘
|
|
//
|
|
|
|
|
|
public static class SimpleTopology
|
|
{
|
|
public static TextBlock CreateSimpleTopologyTextBlock(this StatusRecord status)
|
|
{
|
|
// Keep the same variable letters as your diagrams (where possible)
|
|
var a = status.GridMeterRecord?.ActivePowerTotal;
|
|
|
|
// and "h" is a separate link (AcDcToDcLink?.Power.Value).
|
|
var h = status.InverterRecord?.ActivePowerW;
|
|
|
|
var i = 0;
|
|
var j = 0;
|
|
|
|
var k = status.DcDc?.Dc.Battery.Power.Value;
|
|
|
|
// You mentioned this changed: l is now equal total battery power
|
|
|
|
var l = status.ListOfBatteriesRecord?.Sum(r => r.Power);
|
|
|
|
var grid = status.CreateGridColumn(a);
|
|
var acdc = status.CreateAcDcColumn(h);
|
|
var dcBus = status.CreateDcBusColumn(i, j, k);
|
|
var dcdc = status.CreateDcDcColumn(l);
|
|
var batteries = status.CreateBatteriesRow();
|
|
|
|
return TextBlock.AlignCenterVertical(
|
|
grid,
|
|
acdc,
|
|
dcBus,
|
|
dcdc,
|
|
batteries
|
|
);
|
|
}
|
|
|
|
private static TextBlock CreateGridColumn(this StatusRecord status, ActivePower? a)
|
|
{
|
|
// ┌─────────┐
|
|
// │ Grid │
|
|
// ├─────────┤
|
|
// │ L1 P │
|
|
// │ L2 P │
|
|
// │ L3 P │
|
|
// └─────────┘ (a) flow to AC/DC
|
|
|
|
var gridMeterAc = status.GridMeterRecord;
|
|
|
|
var gridBox = TextBlock
|
|
.AlignLeft(
|
|
gridMeterAc?.ActivePowerL1.Value.ToString(CultureInfo.InvariantCulture) ?? "???",
|
|
gridMeterAc?.ActivePowerL2.Value.ToString(CultureInfo.InvariantCulture) ?? "???",
|
|
gridMeterAc?.ActivePowerL3.Value.ToString(CultureInfo.InvariantCulture) ?? "???"
|
|
)
|
|
.TitleBox("Grid");
|
|
|
|
// Flow from Grid to AC/DC in the picture is horizontal (left -> right), using <<<<<< for export/import.
|
|
// Your Flow.Horizontal(power) already handles arrow direction by sign (based on your existing outputs).
|
|
var flow = Flow.Horizontal(a);
|
|
|
|
return TextBlock.AlignCenterVertical(gridBox, flow);
|
|
}
|
|
|
|
private static TextBlock CreateAcDcColumn(this StatusRecord status, ActivePower? h)
|
|
{
|
|
// ┌─────────┐
|
|
// │ AC/DC │
|
|
// ├─────────┤
|
|
// │ dev1 P │
|
|
// │ dev2 P │
|
|
// └─────────┘ (h) flow to DC Bus
|
|
|
|
var acdcBox = TextBlock
|
|
.AlignLeft(status.InverterRecord?.ActivePowerW.ToString() ?? "???")
|
|
.TitleBox("AC/DC");
|
|
|
|
var flowToDcBus = Flow.Horizontal(h);
|
|
|
|
return TextBlock.AlignCenterVertical(acdcBox, flowToDcBus);
|
|
}
|
|
|
|
private static TextBlock CreateDcBusColumn(
|
|
this StatusRecord status,
|
|
ActivePower? i,
|
|
ActivePower? j,
|
|
ActivePower? k)
|
|
{
|
|
// ┌────┐
|
|
// │ PV │
|
|
// └────┘
|
|
// V
|
|
// (i) 13.2 kW
|
|
// V
|
|
// ┌────────┐ (k) >>>>>>>>> to DC/DC
|
|
// │ Dc Bus │>>>>>>>>>>>>>>>>>>>
|
|
// ├────────┤
|
|
// │ 776 V │
|
|
// └────────┘
|
|
// V
|
|
// (j) 0 W
|
|
// V
|
|
// ┌──────┐
|
|
// │ Load │
|
|
// └──────┘
|
|
|
|
// PV box + vertical flow
|
|
var pvBox = TextBlock.FromString("PV").Box();
|
|
var pvToBus = Flow.Vertical(i);
|
|
|
|
// DC bus box (voltage from your DcDc record matches your existing code)
|
|
var dcBusVoltage = status.DcDc.Dc.Link.Voltage.Value;
|
|
var dcBusBox = dcBusVoltage
|
|
.ToString(CultureInfo.InvariantCulture)
|
|
.Apply(TextBlock.FromString)
|
|
.TitleBox("Dc Bus");
|
|
|
|
// Horizontal flow from DC Bus to DC/DC
|
|
var busToDcDc = Flow.Horizontal(k);
|
|
|
|
// Load box + vertical flow
|
|
var busToLoad = Flow.Vertical(j);
|
|
var loadBox = TextBlock.FromString("Load").Box();
|
|
|
|
// Assemble: put PV above DC Bus, Load below DC Bus, and the (k) flow beside the bus.
|
|
return TextBlock.AlignCenterVertical(
|
|
TextBlock.AlignCenterHorizontal(pvBox, pvToBus, dcBusBox, busToLoad, loadBox),
|
|
busToDcDc
|
|
);
|
|
}
|
|
|
|
private static TextBlock CreateDcDcColumn(this StatusRecord status, ActivePower? l)
|
|
{
|
|
// ┌───────┐
|
|
// │ DC/DC │
|
|
// ├───────┤
|
|
// │ 56 V │
|
|
// └───────┘ (l) flow to batteries
|
|
|
|
var dc48Voltage = status.DcDc?.Dc.Battery.Voltage;
|
|
|
|
var dcdcBox = TextBlock
|
|
.AlignLeft(dc48Voltage)
|
|
.TitleBox("DC/DC");
|
|
|
|
var flowToBattery = Flow.Horizontal(l);
|
|
|
|
return TextBlock.AlignCenterVertical(dcdcBox, flowToBattery);
|
|
}
|
|
|
|
private static TextBlock CreateBatteriesRow(this StatusRecord status)
|
|
{
|
|
// Battery K1 | Battery K2 | Battery K3 (side-by-side)
|
|
// Each box: voltage, soc, current, temp, etc. (you can tailor)
|
|
|
|
var bat = status.ListOfBatteriesRecord;
|
|
if (bat is null)
|
|
return TextBlock.AlignLeft("no battery").Box();
|
|
|
|
// If you actually have relay names K1/K2/K3 per battery, wire them here.
|
|
// For now we label by index as "Battery K{n}" to match your picture.
|
|
var boxes = bat
|
|
.Select((b, idx) => CreateBatteryKBox(b, idx))
|
|
.ToReadOnlyList();
|
|
|
|
// Align horizontally to match the diagram
|
|
return boxes.Any()
|
|
? TextBlock.AlignTop(boxes)
|
|
: TextBlock.AlignLeft("no battery devices").Box();
|
|
}
|
|
|
|
private static TextBlock CreateBatteryKBox(BatteryDeligreenRecords battery, int idx)
|
|
{
|
|
|
|
// Some of your sample screen values look like:
|
|
// 52.3 V, 99.1 %, 490 mA, 250 °C, 445 A
|
|
// Map these to whatever fields you trust in your record.
|
|
var voltage = battery.Voltage.ToDisplayString();
|
|
var soc = battery.Soc.ToDisplayString();
|
|
var current = battery.Current.ToDisplayString();
|
|
var count = battery.Devices.Count;
|
|
|
|
|
|
return TextBlock
|
|
.AlignLeft(
|
|
voltage,
|
|
soc,
|
|
current,
|
|
count
|
|
)
|
|
.TitleBox($"Battery K{idx + 1}");
|
|
}
|
|
}
|