Innovenergy_trunk/csharp/App/KacoCommunication/Topology.cs

266 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 │
// └──────┘
//
// New (simplified) topology:
//
// ┌────┐
// │ PV │
// └────┘
// V
// V
// (i) 13.2 kW
// V
// V
// ┌─────────┐ ┌─────────┐ (h) ┌────────┐ (k) ┌───────┐ (l) ┌────────────┐ ┌────────────┐ ┌────────────┐
// │ Grid │<<<│ AC/DC │<<<<<<<<<<<<<│ Dc Bus │>>>>>>>>│ DC/DC │>>>>>>>>│ Battery K1 │ │ Battery K2 │ │ Battery K3 │
// ├─────────┤ ├─────────┤ ├────────┤ ├───────┤ ├────────────┤ ├────────────┤ ├────────────┤
// │ -3205 W │ │ -6646 W │ │ 776 V │ │ 56 V │ │ 52.3 V ... │ │ 52.3 V ... │ │ 52.3 V ... │
// │ -3507 W │ │ -5071 W │ └────────┘ └───────┘ └────────────┘ └────────────┘ └────────────┘
// │ -3605 W │
// └─────────┘
//
// V
// V
// (j) 0 W
// V
// V
// ┌──────┐
// │ Load │
// └──────┘
//
// Notes:
// - (a) is grid power (to/from grid)
// - (h) is AC/DC -> DC link power (or your chosen link variable)
// - (i) PV -> DC bus
// - (j) DC load
// - (k) DC bus -> DC/DC link
// - (l) DC/DC -> battery power (or total battery power)
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;
// In your existing code, "AC/DC column" shows per-device AC power;
// and "h" is a separate link (AcDcToDcLink?.Power.Value).
var h = 0;
var i = 0;
var j = 0;
var k = 0;
// You mentioned this changed: l is now equal total battery power
var l = status.BatteryKabinet1.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?.ActivePowerSetPercent.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 = 0.0;
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 =0.0;
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.BatteryKabinet1;
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.Devices
.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(BatteryDeligreenRecord battery, int idx)
{
// Minimal “K-style” battery box matching your diagram fields
var data = battery.BatteryDeligreenDataRecord;
// 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 = data.BusVoltage.ToDisplayString();
var soc = data.Soc.ToDisplayString();
var current = data.BusCurrent.ToDisplayString();
var temp = data.TemperaturesList.PowerTemperature.ToDisplayString();
// If you have a better “pack current” field, replace this line.
// Keeping it as a separate line to mimic the pictures extra current-like line.
var extraCurrent = data.BusCurrent.ToDisplayString();
return TextBlock
.AlignLeft(
voltage,
soc,
current,
temp,
extraCurrent
)
.TitleBox($"Battery K{idx + 1}");
}
}