Innovenergy_trunk/csharp/App/KacoCommunication/Topology.cs

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}");
}
}