Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
76e23d579f
|
@ -1,3 +1,4 @@
|
||||||
|
using InnovEnergy.Lib.Units;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax;
|
namespace InnovEnergy.App.SaliMax;
|
||||||
|
@ -68,39 +69,6 @@ public static class AsciiArt
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String CreateVerticalPad(String value, Int32 contentVerticalWidth, Boolean direction, String name)
|
|
||||||
{
|
|
||||||
var v = value.PadLeft(contentVerticalWidth);
|
|
||||||
var n = name.PadLeft(contentVerticalWidth);
|
|
||||||
|
|
||||||
if (direction) // up
|
|
||||||
{
|
|
||||||
var horizontal = "".PadLeft(contentVerticalWidth - 4, ' ').V();
|
|
||||||
|
|
||||||
return StringUtils.JoinLines(
|
|
||||||
n,
|
|
||||||
horizontal,
|
|
||||||
horizontal,
|
|
||||||
v,
|
|
||||||
horizontal,
|
|
||||||
horizontal
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else // down
|
|
||||||
{
|
|
||||||
var horizontal = "".PadLeft(contentVerticalWidth - 4, ' ').V();
|
|
||||||
|
|
||||||
return StringUtils.JoinLines(
|
|
||||||
horizontal,
|
|
||||||
horizontal,
|
|
||||||
v,
|
|
||||||
horizontal,
|
|
||||||
horizontal,
|
|
||||||
n
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String CreateVerticalArrow(Decimal power, Int32 width = 0)
|
public static String CreateVerticalArrow(Decimal power, Int32 width = 0)
|
||||||
{
|
{
|
||||||
var flow = "V".NewLine() + "V".NewLine() + power.W().NewLine() + "V".NewLine() + "V";
|
var flow = "V".NewLine() + "V".NewLine() + power.W().NewLine() + "V".NewLine() + "V";
|
||||||
|
|
|
@ -42,6 +42,9 @@ public static class AvgBatteriesStatus
|
||||||
? OperatingTemperature
|
? OperatingTemperature
|
||||||
: Cold,
|
: Cold,
|
||||||
|
|
||||||
|
TotalCurrent = stati.Average(b => b.TotalCurrent),
|
||||||
|
|
||||||
|
EocReached = stati.All(b => b.EocReached),
|
||||||
};
|
};
|
||||||
|
|
||||||
return new CombinedStatus<Battery48TLStatus>
|
return new CombinedStatus<Battery48TLStatus>
|
||||||
|
|
|
@ -5,7 +5,7 @@ public static class Control
|
||||||
|
|
||||||
public static Decimal ControlGridPower(this StatusRecord status, Decimal targetPower)
|
public static Decimal ControlGridPower(this StatusRecord status, Decimal targetPower)
|
||||||
{
|
{
|
||||||
return ControlPower(status.GridMeterStatus!.ActivePowerL123, targetPower, status.SalimaxConfig!.PConstant);
|
return ControlPower(status.GridMeterStatus!.Ac.ActivePower, targetPower, status.SalimaxConfig!.PConstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Decimal ControlInverterPower(this StatusRecord status, Decimal targetInverterPower)
|
public static Decimal ControlInverterPower(this StatusRecord status, Decimal targetInverterPower)
|
||||||
|
@ -18,7 +18,7 @@ public static class Control
|
||||||
|
|
||||||
public static Decimal ControlBatteryPower(this StatusRecord status, Decimal targetBatteryPower, UInt16 i = 0) //this will use the avg batteries
|
public static Decimal ControlBatteryPower(this StatusRecord status, Decimal targetBatteryPower, UInt16 i = 0) //this will use the avg batteries
|
||||||
{
|
{
|
||||||
return ControlPower(status.BatteriesStatus![i].Dc.Power, targetBatteryPower, status.SalimaxConfig!.PConstant);
|
return ControlPower(status.BatteriesStatus!.Combined.Dc.Power, targetBatteryPower, status.SalimaxConfig!.PConstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Decimal ControlLowBatterySoc(this StatusRecord status)
|
public static Decimal ControlLowBatterySoc(this StatusRecord status)
|
||||||
|
@ -29,14 +29,14 @@ public static class Control
|
||||||
public static Decimal LowerLimit(params Decimal[] deltas) => deltas.Max();
|
public static Decimal LowerLimit(params Decimal[] deltas) => deltas.Max();
|
||||||
public static Decimal UpperLimit(params Decimal[] deltas) => deltas.Min();
|
public static Decimal UpperLimit(params Decimal[] deltas) => deltas.Min();
|
||||||
|
|
||||||
private static Decimal HoldMinSocCurve(StatusRecord s, UInt16 i = 0)
|
private static Decimal HoldMinSocCurve(StatusRecord s)
|
||||||
{
|
{
|
||||||
// TODO: explain LowSOC curve
|
// TODO: explain LowSOC curve
|
||||||
|
|
||||||
var a = -2 * s.SalimaxConfig!.SelfDischargePower / s.SalimaxConfig.HoldSocZone;
|
var a = -2 * s.SalimaxConfig!.SelfDischargePower / s.SalimaxConfig.HoldSocZone;
|
||||||
var b = -a * (s.SalimaxConfig.MinSoc + s.SalimaxConfig.HoldSocZone);
|
var b = -a * (s.SalimaxConfig.MinSoc + s.SalimaxConfig.HoldSocZone);
|
||||||
|
|
||||||
return s.BatteriesStatus![i].Soc * a + b; //this will use the avg batteries
|
return s.BatteriesStatus!.Combined.Soc * a + b; //this will use the avg batteries
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Decimal ControlPower(Decimal measurement, Decimal target, Decimal p)
|
private static Decimal ControlPower(Decimal measurement, Decimal target, Decimal p)
|
||||||
|
|
|
@ -5,6 +5,9 @@ using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
|
||||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
|
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
|
||||||
using InnovEnergy.Lib.Time.Unix;
|
using InnovEnergy.Lib.Time.Unix;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
|
|
||||||
|
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.Enums;
|
||||||
|
|
||||||
using static InnovEnergy.App.SaliMax.SaliMaxRelays.RelayState;
|
using static InnovEnergy.App.SaliMax.SaliMaxRelays.RelayState;
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,69 +71,69 @@ public static class Controller
|
||||||
//Grid-Tied 400V/50 Hz
|
//Grid-Tied 400V/50 Hz
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open,
|
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
|
InverterStatus.GridType: AcDcGridType.GridTied400V50Hz
|
||||||
} => 9,
|
} => 9,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open,
|
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
|
InverterStatus.GridType: AcDcGridType.GridTied400V50Hz
|
||||||
} => 10,
|
} => 10,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open,
|
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
|
InverterStatus.GridType: AcDcGridType.GridTied400V50Hz
|
||||||
} => 11,
|
} => 11,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open,
|
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
|
InverterStatus.GridType: AcDcGridType.GridTied400V50Hz
|
||||||
} => 12,
|
} => 12,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed,
|
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
|
InverterStatus.GridType: AcDcGridType.GridTied400V50Hz
|
||||||
} => 13,
|
} => 13,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed,
|
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
|
InverterStatus.GridType: AcDcGridType.GridTied400V50Hz
|
||||||
} => 14,
|
} => 14,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed,
|
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
|
InverterStatus.GridType: AcDcGridType.GridTied400V50Hz
|
||||||
} => 15,
|
} => 15,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed,
|
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.GridTied400V50Hz
|
InverterStatus.GridType: AcDcGridType.GridTied400V50Hz
|
||||||
} => 16,
|
} => 16,
|
||||||
|
|
||||||
//Island 400V / 50Hz
|
//Island 400V / 50Hz
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open,
|
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.Island400V50Hz
|
InverterStatus.GridType: AcDcGridType.Island400V50Hz
|
||||||
} => 17,
|
} => 17,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open,
|
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Open,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.Island400V50Hz
|
InverterStatus.GridType: AcDcGridType.Island400V50Hz
|
||||||
} => 18,
|
} => 18,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open,
|
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.Island400V50Hz
|
InverterStatus.GridType: AcDcGridType.Island400V50Hz
|
||||||
} => 19,
|
} => 19,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open,
|
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Open,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.Island400V50Hz
|
InverterStatus.GridType: AcDcGridType.Island400V50Hz
|
||||||
} => 20,
|
} => 20,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed, //this is wrong
|
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed, //this is wrong
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.Island400V50Hz
|
InverterStatus.GridType: AcDcGridType.Island400V50Hz
|
||||||
} => 21,
|
} => 21,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed,
|
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Open, SaliMaxRelayStatus.K3: Closed,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.Island400V50Hz
|
InverterStatus.GridType: AcDcGridType.Island400V50Hz
|
||||||
} => 22,
|
} => 22,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed,
|
SaliMaxRelayStatus.K1: Open, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.Island400V50Hz
|
InverterStatus.GridType: AcDcGridType.Island400V50Hz
|
||||||
} => 23,
|
} => 23,
|
||||||
{
|
{
|
||||||
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed,
|
SaliMaxRelayStatus.K1: Closed, SaliMaxRelayStatus.K2: Closed, SaliMaxRelayStatus.K3: Closed,
|
||||||
InverterStatus.AcDcActiveGridType: AcDcGridType.Island400V50Hz
|
InverterStatus.GridType: AcDcGridType.Island400V50Hz
|
||||||
} => 24,
|
} => 24,
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,7 +152,7 @@ public static class Controller
|
||||||
var lastEocTime = GetLastEocTime(statusRecord);
|
var lastEocTime = GetLastEocTime(statusRecord);
|
||||||
var timeSinceLastEoc = UnixTime.Now - lastEocTime;
|
var timeSinceLastEoc = UnixTime.Now - lastEocTime;
|
||||||
|
|
||||||
_numberOfInverters = statusRecord.InverterStatus!.NumberOfConnectedSlaves;
|
_numberOfInverters = (UInt16)statusRecord.InverterStatus!.NumberOfConnectedSlaves ;
|
||||||
_mustChargeFlag = timeSinceLastEoc > MaxTimeWithoutEoc;
|
_mustChargeFlag = timeSinceLastEoc > MaxTimeWithoutEoc;
|
||||||
|
|
||||||
var noGridMeter = statusRecord.GridMeterStatus == null;
|
var noGridMeter = statusRecord.GridMeterStatus == null;
|
||||||
|
@ -263,7 +266,7 @@ public static class Controller
|
||||||
goal = "Calibration Charge";
|
goal = "Calibration Charge";
|
||||||
delta = statusRecord.ControlInverterPower(statusRecord.SalimaxConfig.MaxInverterPower);
|
delta = statusRecord.ControlInverterPower(statusRecord.SalimaxConfig.MaxInverterPower);
|
||||||
}
|
}
|
||||||
else if (statusRecord.AvgBatteriesStatus!.Soc < statusRecord.SalimaxConfig.MinSoc) // TODO
|
else if (statusRecord.BatteriesStatus!.Combined.Soc < statusRecord.SalimaxConfig.MinSoc) // TODO
|
||||||
{
|
{
|
||||||
goal = $"reach min SOC (Min soc: {statusRecord.SalimaxConfig.MinSoc})";
|
goal = $"reach min SOC (Min soc: {statusRecord.SalimaxConfig.MinSoc})";
|
||||||
delta = statusRecord.ControlInverterPower(statusRecord.SalimaxConfig
|
delta = statusRecord.ControlInverterPower(statusRecord.SalimaxConfig
|
||||||
|
@ -285,7 +288,7 @@ public static class Controller
|
||||||
delta = inverterAc2DcLimitPower;
|
delta = inverterAc2DcLimitPower;
|
||||||
}
|
}
|
||||||
|
|
||||||
var batteryChargingLimitPower = statusRecord.ControlBatteryPower(statusRecord.BatteriesStatus[0]!.MaxChargingPower);
|
var batteryChargingLimitPower = statusRecord.ControlBatteryPower(statusRecord.BatteriesStatus!.Combined.MaxChargingPower);
|
||||||
|
|
||||||
if (delta > batteryChargingLimitPower)
|
if (delta > batteryChargingLimitPower)
|
||||||
{
|
{
|
||||||
|
@ -304,12 +307,12 @@ public static class Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
var batteryDischargingLimitPower =
|
var batteryDischargingLimitPower =
|
||||||
statusRecord.ControlBatteryPower(statusRecord.BatteriesStatus[0]!.MaxDischargingPower); // TODO change to avg battery
|
statusRecord.ControlBatteryPower(statusRecord.BatteriesStatus.Combined.MaxDischargingPower); // TODO change to avg battery
|
||||||
|
|
||||||
if (delta < batteryDischargingLimitPower)
|
if (delta < batteryDischargingLimitPower)
|
||||||
{
|
{
|
||||||
limitReason =
|
limitReason =
|
||||||
$"limited by max battery discharging power: {statusRecord.BatteriesStatus[0]!.MaxDischargingPower}";// TODO change to avg battery
|
$"limited by max battery discharging power: {statusRecord.BatteriesStatus.Combined.MaxDischargingPower}";// TODO change to avg battery
|
||||||
|
|
||||||
delta = batteryDischargingLimitPower;
|
delta = batteryDischargingLimitPower;
|
||||||
}
|
}
|
||||||
|
@ -448,14 +451,21 @@ public static class Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UnixTime GetLastEocTime(StatusRecord statusRecord)
|
private static UnixTime GetLastEocTime(StatusRecord statusRecord)
|
||||||
{
|
{ if (statusRecord.BatteriesStatus != null)
|
||||||
if (statusRecord.BatteriesStatus[0]!.Soc >= 100 && statusRecord.BatteriesStatus[1]!.Soc >= 100 )
|
|
||||||
{
|
{
|
||||||
Console.WriteLine("battery has reached EOC");
|
if (statusRecord.BatteriesStatus!.Combined.EocReached)
|
||||||
File.AppendAllTextAsync(Config.LogSalimaxLog, String.Join(Environment.NewLine, UnixTime.Now + "battery has reached EOC"));
|
{
|
||||||
return UnixTime.Now;
|
Console.WriteLine("battery has reached EOC");
|
||||||
|
File.AppendAllTextAsync(Config.LogSalimaxLog,
|
||||||
|
String.Join(Environment.NewLine,
|
||||||
|
UnixTime.Now + "battery has reached EOC"));
|
||||||
|
return UnixTime.Now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("No battery Detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
return statusRecord.SalimaxConfig.LastEoc;
|
return statusRecord.SalimaxConfig.LastEoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ public record StatusRecord
|
||||||
|
|
||||||
public EmuMeterStatus? GridMeterStatus { get; init; }
|
public EmuMeterStatus? GridMeterStatus { get; init; }
|
||||||
public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; }
|
public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; }
|
||||||
public AmptStatus? AmptStatus { get; init; }
|
public AmptCommunicationUnitStatus? AmptStatus { get; init; }
|
||||||
public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; }
|
public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; }
|
||||||
public SalimaxConfig SalimaxConfig { get; init; } = null!;
|
public SalimaxConfig SalimaxConfig { get; init; } = null!;
|
||||||
}
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
using InnovEnergy.Lib.Devices.AMPT;
|
|
||||||
using InnovEnergy.Lib.StatusApi;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.Log;
|
|
||||||
|
|
||||||
public static class Ampt
|
|
||||||
{
|
|
||||||
public static JsonObject? Log(this AmptStatus? s)
|
|
||||||
{
|
|
||||||
if (s is null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// TODO return one AMPT device to sum all the other
|
|
||||||
|
|
||||||
return DeviceType
|
|
||||||
.PvOnDc
|
|
||||||
.CreateDevice("AMPT")
|
|
||||||
.AddProp("Current 1", s.Devices[0].Dc.Current)
|
|
||||||
.AddProp("Current 2", s.Devices[1].Dc.Current)
|
|
||||||
.AddProp("Voltage 1", s.Devices[0].Dc.Voltage)
|
|
||||||
.AddProp("Voltage 2", s.Devices[1].Dc.Voltage)
|
|
||||||
.AddProp("Power 1", s.Devices[0].Dc.Current * s.Devices[0].Dc.Voltage)
|
|
||||||
.AddProp("Power 2", s.Devices[1].Dc.Current * s.Devices[1].Dc.Voltage);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
using InnovEnergy.Lib.Devices.Battery48TL;
|
|
||||||
using InnovEnergy.Lib.StatusApi;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.Log;
|
|
||||||
|
|
||||||
public static class Battery48Tl
|
|
||||||
{
|
|
||||||
public static JsonObject? Log(this Battery48TLStatus? s)
|
|
||||||
{
|
|
||||||
if (s is null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return DeviceType
|
|
||||||
.Battery
|
|
||||||
.CreateDevice("48TL Battery")
|
|
||||||
.AddDc48Connection(s.Dc.Current.Round3(),s.Dc.Voltage.Round3())
|
|
||||||
.AddAlarms(s.Alarms)
|
|
||||||
.AddWarnings(s.Warnings)
|
|
||||||
.AddProp("Soc", s.Soc.Round3())
|
|
||||||
.AddProp("HeaterOn", s.HeaterOn)
|
|
||||||
.AddProp("EocReached", s.EocReached)
|
|
||||||
.AddProp("BatteryCold", s.BatteryCold)
|
|
||||||
.AddProp("Temperature", s.Temperature);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
using InnovEnergy.Lib.Devices.EmuMeter;
|
|
||||||
using InnovEnergy.Lib.StatusApi;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
|
||||||
using static DecimalMath.DecimalEx;
|
|
||||||
using static InnovEnergy.App.SaliMax.Log.JsonUtil;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.Log;
|
|
||||||
|
|
||||||
public static class EmuMeter
|
|
||||||
{
|
|
||||||
public static JsonObject? Log(this EmuMeterStatus? s, DeviceType type, String serialNb)
|
|
||||||
{
|
|
||||||
if (s is null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
var l1 = CreateAcPhase(s.Ac.L1.Current, s.Ac.L1.Voltage, ACos(s.Ac.L1.PowerFactor));
|
|
||||||
var l2 = CreateAcPhase(s.Ac.L2.Current, s.Ac.L2.Voltage, ACos(s.Ac.L2.PowerFactor));
|
|
||||||
var l3 = CreateAcPhase(s.Ac.L3.Current, s.Ac.L3.Voltage, ACos(s.Ac.L3.PowerFactor));
|
|
||||||
|
|
||||||
var ac = new JsonObject
|
|
||||||
{
|
|
||||||
["L1"] = l1,
|
|
||||||
["L2"] = l2,
|
|
||||||
["L3"] = l3,
|
|
||||||
["Frequency"] = s.Ac.Frequency
|
|
||||||
};
|
|
||||||
|
|
||||||
var status = new JsonObject
|
|
||||||
{
|
|
||||||
["Ac"] = ac,
|
|
||||||
};
|
|
||||||
|
|
||||||
return new JsonObject { [$"EmuMeter {serialNb}"] = status };
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<JsonObject> GetAcPhases(this EmuMeterStatus s)
|
|
||||||
{
|
|
||||||
yield return CreateAcPhase(s.Ac.L1.Current.Round3(),s.Ac.L1.Voltage.Round3(),s.Ac.L1.PowerFactor.Apply(ACos).Round3());
|
|
||||||
yield return CreateAcPhase(s.Ac.L2.Current.Round3(),s.Ac.L2.Voltage.Round3(),s.Ac.L2.PowerFactor.Apply(ACos).Round3());
|
|
||||||
yield return CreateAcPhase(s.Ac.L3.Current.Round3(),s.Ac.L3.Voltage.Round3(),s.Ac.L3.PowerFactor.Apply(ACos).Round3());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
using InnovEnergy.Lib.StatusApi;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.Log;
|
|
||||||
|
|
||||||
public static class JsonUtil
|
|
||||||
{
|
|
||||||
public static JsonObject CreateDevice(this DeviceType deviceType, String name)
|
|
||||||
{
|
|
||||||
return new JsonObject
|
|
||||||
{
|
|
||||||
{ "Name", name },
|
|
||||||
{ "Type", deviceType.ToString() }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static JsonObject AddAcConnection(this JsonObject json, Decimal frequency, IEnumerable<JsonNode> acPhases)
|
|
||||||
{
|
|
||||||
return json.AddAcConnection(frequency, acPhases.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JsonObject AddAcConnection(this JsonObject json, Decimal frequency, params JsonNode[] acPhases)
|
|
||||||
{
|
|
||||||
return json
|
|
||||||
.AddProp("Ac", new JsonArray(acPhases))
|
|
||||||
.AddProp("Frequency", frequency);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JsonObject AddAlarms<T>(this JsonObject json, IEnumerable<T> alarms)
|
|
||||||
{
|
|
||||||
return json.AddProp("Alarms", alarms.ToJsonArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JsonObject AddWarnings<T>(this JsonObject json, IEnumerable<T> warnings)
|
|
||||||
{
|
|
||||||
return json.AddProp("Warnings", warnings.ToJsonArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static JsonObject AddProp(this JsonObject json, String key, JsonNode? value)
|
|
||||||
{
|
|
||||||
json.Add(key, value);
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static JsonObject AddDcConnection(this JsonObject json, Decimal current, Decimal voltage)
|
|
||||||
{
|
|
||||||
return json.AddProp("Dc", CreateDcPhase(current, voltage));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JsonObject AddDc48Connection(this JsonObject json, Decimal current, Decimal voltage)
|
|
||||||
{
|
|
||||||
return json.AddProp("Dc48", CreateDcPhase(current, voltage));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JsonObject CreateAcPhase(Decimal current, Decimal voltage, Decimal phi)
|
|
||||||
{
|
|
||||||
return new JsonObject
|
|
||||||
{
|
|
||||||
["Current"] = current,
|
|
||||||
["Voltage"] = voltage,
|
|
||||||
["Phi" ] = phi,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static JsonObject CreateDcPhase(Decimal current, Decimal voltage)
|
|
||||||
{
|
|
||||||
return new JsonObject
|
|
||||||
{
|
|
||||||
["Current"] = current ,
|
|
||||||
["Voltage"] = voltage ,
|
|
||||||
["Power"] = current * voltage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Decimal Round3(this Decimal val)
|
|
||||||
{
|
|
||||||
return Decimal.Round(val, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Decimal Round0(this Decimal val)
|
|
||||||
{
|
|
||||||
return Decimal.Round(val, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JsonObject CreateBus(String left, String top, String bottom, String right, String name)
|
|
||||||
{
|
|
||||||
return new JsonObject
|
|
||||||
{
|
|
||||||
["Name"] = name,
|
|
||||||
["Left"] = left,
|
|
||||||
["Top"] = top,
|
|
||||||
["Bottom"] = bottom,
|
|
||||||
["Right"] = right
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String Port(DeviceType dt, BusPort bp, Boolean display = true)
|
|
||||||
{
|
|
||||||
return $"{Enum.GetName(dt)}:{Enum.GetName(bp)}:{(display ? "show" : "hide")}";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static JsonArray ToJsonArray<T>(this IEnumerable<T> things)
|
|
||||||
{
|
|
||||||
var jsonValues = things
|
|
||||||
.Select(t => t!.ToString())
|
|
||||||
.Select(t => JsonValue.Create(t))
|
|
||||||
.OfType<JsonNode>()
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
return new JsonArray(jsonValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
using InnovEnergy.App.SaliMax.Controller;
|
|
||||||
using InnovEnergy.Lib.StatusApi;
|
|
||||||
using InnovEnergy.Lib.Time.Unix;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.Log;
|
|
||||||
|
|
||||||
public static class Salimax
|
|
||||||
{
|
|
||||||
public static JsonObject ToLog(this StatusRecord s, UnixTime timestamp)
|
|
||||||
{
|
|
||||||
return new JsonObject
|
|
||||||
{
|
|
||||||
{ "TimeStamp", timestamp.ToString()! },
|
|
||||||
{ "Devices", CreateDevices(s) }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static JsonArray CreateDevices(StatusRecord s)
|
|
||||||
{
|
|
||||||
var devices = GetDevices(s).Where(d => d != null).ToArray();
|
|
||||||
return new JsonArray(devices);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<JsonNode?> GetDevices(StatusRecord s)
|
|
||||||
{
|
|
||||||
yield return s.InverterStatus.Log();
|
|
||||||
yield return s.DcDcStatus.Log("3214");
|
|
||||||
yield return s.GridMeterStatus.Log(DeviceType.Grid , "123");
|
|
||||||
yield return s.AcInToAcOutMeterStatus.Log(DeviceType.AcInToAcOut, "123");
|
|
||||||
yield return s.AmptStatus.Log();
|
|
||||||
yield return s.BatteriesStatus![0].Log();
|
|
||||||
yield return s.BatteriesStatus[1].Log();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static JsonArray CreateTopology()
|
|
||||||
{
|
|
||||||
var acInBusJson = JsonUtil.CreateBus
|
|
||||||
(
|
|
||||||
name: "AcIn",
|
|
||||||
left: JsonUtil.Port(DeviceType.Grid, BusPort.Ac),
|
|
||||||
top: JsonUtil.Port(DeviceType.PvOnAcIn, BusPort.Ac),
|
|
||||||
bottom: JsonUtil.Port(DeviceType.Load, BusPort.Infer),
|
|
||||||
right: JsonUtil.Port(DeviceType.AcInToAcOut, BusPort.Ac, false)
|
|
||||||
);
|
|
||||||
|
|
||||||
var acOutBusJson = JsonUtil.CreateBus
|
|
||||||
(
|
|
||||||
name: "AcOut",
|
|
||||||
left: JsonUtil.Port(DeviceType.AcInToAcOut, BusPort.Ac, false),
|
|
||||||
top: JsonUtil.Port(DeviceType.PvOnAcOut, BusPort.Ac),
|
|
||||||
bottom: JsonUtil.Port(DeviceType.CriticalLoad, BusPort.Infer),
|
|
||||||
right: JsonUtil.Port(DeviceType.Inverter, BusPort.Ac)
|
|
||||||
);
|
|
||||||
|
|
||||||
var inverterJson = JsonUtil.CreateBus
|
|
||||||
(
|
|
||||||
name: "Inverter",
|
|
||||||
left: JsonUtil.Port(DeviceType.Inverter, BusPort.Ac),
|
|
||||||
top: JsonUtil.Port(DeviceType.None, BusPort.None),
|
|
||||||
bottom: JsonUtil.Port(DeviceType.Losses, BusPort.Infer),
|
|
||||||
right: JsonUtil.Port(DeviceType.Inverter, BusPort.Dc)
|
|
||||||
);
|
|
||||||
|
|
||||||
var dcBusJson = JsonUtil.CreateBus
|
|
||||||
(
|
|
||||||
name: "Dc",
|
|
||||||
left: JsonUtil.Port(DeviceType.Inverter, BusPort.Dc),
|
|
||||||
top: JsonUtil.Port(DeviceType.PvOnDc, BusPort.Dc),
|
|
||||||
bottom: JsonUtil.Port(DeviceType.DcLoad, BusPort.Infer),
|
|
||||||
right: JsonUtil.Port(DeviceType.DcDc, BusPort.Dc)
|
|
||||||
);
|
|
||||||
|
|
||||||
var dcDcJson = JsonUtil.CreateBus
|
|
||||||
(
|
|
||||||
name: "DcDc",
|
|
||||||
left: JsonUtil.Port(DeviceType.DcDc, BusPort.Dc),
|
|
||||||
top: JsonUtil.Port(DeviceType.None, BusPort.None),
|
|
||||||
bottom: JsonUtil.Port(DeviceType.Losses, BusPort.Infer),
|
|
||||||
right: JsonUtil.Port(DeviceType.Battery, BusPort.Dc)
|
|
||||||
);
|
|
||||||
|
|
||||||
return new JsonArray(acInBusJson, acOutBusJson, inverterJson, dcBusJson, dcDcJson);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JsonObject TopologyToLog(UnixTime timestamp)
|
|
||||||
{
|
|
||||||
return new JsonObject
|
|
||||||
{
|
|
||||||
{ "Topology", CreateTopology() }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
|
||||||
using static DecimalMath.DecimalEx;
|
|
||||||
using static InnovEnergy.App.SaliMax.Log.JsonUtil;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.Log;
|
|
||||||
|
|
||||||
public static class TruConvertAc
|
|
||||||
{
|
|
||||||
|
|
||||||
public static JsonObject? Log(this TruConvertAcStatus? s)
|
|
||||||
{
|
|
||||||
if (s is null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var dcPower = s.Ac.ActivePower;
|
|
||||||
var dcVoltage = s.ActualDcLinkVoltageLowerHalfExt + s.ActualDcLinkVoltageUpperHalfExt;
|
|
||||||
var dcCurrent = dcVoltage != 0m
|
|
||||||
? dcPower / dcVoltage
|
|
||||||
: 0m;
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: acos quadrant
|
|
||||||
// TODO: total AC power
|
|
||||||
|
|
||||||
var l1 = CreateAcPhase(s.Ac.L1.Current.Round3(), s.Ac.L1.Voltage.Round3(), s.Ac.L1.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3());
|
|
||||||
var l2 = CreateAcPhase(s.Ac.L2.Current.Round3(), s.Ac.L2.Voltage.Round3(), s.Ac.L1.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3());
|
|
||||||
var l3 = CreateAcPhase(s.Ac.L3.Current.Round3(), s.Ac.L3.Voltage.Round3(), s.Ac.L1.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3());
|
|
||||||
|
|
||||||
var ac = new JsonObject
|
|
||||||
{
|
|
||||||
["L1"] = l1,
|
|
||||||
["L2"] = l2,
|
|
||||||
["L3"] = l3,
|
|
||||||
["Frequency"] = s.Ac.Frequency
|
|
||||||
};
|
|
||||||
|
|
||||||
var dc = CreateDcPhase(dcCurrent, dcVoltage);
|
|
||||||
|
|
||||||
var status = new JsonObject
|
|
||||||
{
|
|
||||||
["Ac"] = ac ,
|
|
||||||
["Dc"] = dc ,
|
|
||||||
["Warnings"] = s.Warnings.ToJsonArray() ,
|
|
||||||
["Alarms"] = s.Alarms.ToJsonArray() ,
|
|
||||||
};
|
|
||||||
|
|
||||||
return new JsonObject { [$"TruConvertAc {s.SerialNumber}"] = status };
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<JsonObject> GetAcPhases(this TruConvertAcStatus s)
|
|
||||||
{
|
|
||||||
// Math.Acos return "NaN" if the cos phi < -1 or > 1
|
|
||||||
// Decimal.Acos throw an exception
|
|
||||||
yield return JsonUtil.CreateAcPhase(s.Ac.L1.Current.Round3(), s.Ac.L1.Voltage.Round3(),
|
|
||||||
s.Ac.L1.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3());
|
|
||||||
|
|
||||||
yield return JsonUtil.CreateAcPhase(s.Ac.L2.Current.Round3(), s.Ac.L2.Voltage.Round3(),
|
|
||||||
s.Ac.L2.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3());
|
|
||||||
|
|
||||||
yield return JsonUtil.CreateAcPhase(s.Ac.L3.Current.Round3(), s.Ac.L3.Voltage.Round3(),
|
|
||||||
s.Ac.L3.PowerFactor.Clamp(-1m, 1m).Apply(ACos).Round3());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
|
|
||||||
using static InnovEnergy.App.SaliMax.Log.JsonUtil;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax.Log;
|
|
||||||
|
|
||||||
using JO = JsonObject;
|
|
||||||
|
|
||||||
public static class TruConvertDc
|
|
||||||
{
|
|
||||||
// TODO: remove serialNb arg, embed TruConvertDcStatus
|
|
||||||
public static JsonObject? Log(this TruConvertDcStatus? s, String serialNb)
|
|
||||||
{
|
|
||||||
if (s is null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var dcCurrent = s.Dc.Current;
|
|
||||||
|
|
||||||
return new JO
|
|
||||||
{
|
|
||||||
{
|
|
||||||
$"TruConvertDc {serialNb}", new JO
|
|
||||||
{
|
|
||||||
{ "Dc" , CreateDcPhase(dcCurrent, s.Dc.Voltage) },
|
|
||||||
{ "Dc48" , CreateDcPhase(s.BatteryCurrent, s.BatteryVoltage) },
|
|
||||||
{ "Warnings", s.Warnings.ToJsonArray() },
|
|
||||||
{ "Alarms" , s.Alarms.ToJsonArray() },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ using System.Text.Json.Nodes;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Flurl.Http;
|
using Flurl.Http;
|
||||||
using InnovEnergy.App.SaliMax.Controller;
|
using InnovEnergy.App.SaliMax.Controller;
|
||||||
using InnovEnergy.App.SaliMax.Log;
|
|
||||||
using InnovEnergy.App.SaliMax.SaliMaxRelays;
|
using InnovEnergy.App.SaliMax.SaliMaxRelays;
|
||||||
using InnovEnergy.App.SaliMax.SystemConfig;
|
using InnovEnergy.App.SaliMax.SystemConfig;
|
||||||
using InnovEnergy.Lib.Devices.AMPT;
|
using InnovEnergy.Lib.Devices.AMPT;
|
||||||
|
@ -109,7 +108,6 @@ internal static class Program
|
||||||
{
|
{
|
||||||
InverterStatus = inverterDevice.ReadStatus(),
|
InverterStatus = inverterDevice.ReadStatus(),
|
||||||
DcDcStatus = dcDcDevice.ReadStatus(),
|
DcDcStatus = dcDcDevice.ReadStatus(),
|
||||||
|
|
||||||
BatteriesStatus = combinedBatteryStatus,
|
BatteriesStatus = combinedBatteryStatus,
|
||||||
AcInToAcOutMeterStatus = acInToAcOutMeterDevice.ReadStatus(),
|
AcInToAcOutMeterStatus = acInToAcOutMeterDevice.ReadStatus(),
|
||||||
GridMeterStatus = gridMeterDevice.ReadStatus(),
|
GridMeterStatus = gridMeterDevice.ReadStatus(),
|
||||||
|
@ -123,10 +121,6 @@ internal static class Program
|
||||||
var startTime = UnixTime.Now;
|
var startTime = UnixTime.Now;
|
||||||
const Int32 delayTime = 10;
|
const Int32 delayTime = 10;
|
||||||
|
|
||||||
|
|
||||||
await UploadTopology(s3Config, Salimax.TopologyToLog(startTime), startTime);
|
|
||||||
DebugWriteTopology(startTime);
|
|
||||||
|
|
||||||
Console.WriteLine("press ctrl-C to stop");
|
Console.WriteLine("press ctrl-C to stop");
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,21 +161,6 @@ internal static class Program
|
||||||
// WriteToFile(jsonLog, "/home/debian/DataSaliMax/" + timestamp); // this is was for beaglebone TODO
|
// WriteToFile(jsonLog, "/home/debian/DataSaliMax/" + timestamp); // this is was for beaglebone TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Conditional("RELEASE")]
|
|
||||||
private static JsonObject ReleaseWriteTopology(UnixTime timestamp)
|
|
||||||
{
|
|
||||||
var topologyJson = Salimax.TopologyToLog(timestamp);
|
|
||||||
|
|
||||||
// WriteToFile(topologyJson, "/home/debian/DataSaliMax/topology" + timestamp); // this is was for beaglebone
|
|
||||||
return topologyJson;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Conditional("DEBUG")]
|
|
||||||
private static void DebugWriteTopology(UnixTime timestamp)
|
|
||||||
{
|
|
||||||
var topologyJson = Salimax.TopologyToLog(timestamp);
|
|
||||||
WriteToFile(topologyJson, "/home/atef/JsonData/topology" + timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Conditional("DEBUG")]
|
[Conditional("DEBUG")]
|
||||||
private static void DebugWriteLog(JsonObject jsonLog, UnixTime timestamp)
|
private static void DebugWriteLog(JsonObject jsonLog, UnixTime timestamp)
|
||||||
|
|
|
@ -1,42 +1,67 @@
|
||||||
#undef BatteriesAllowed
|
#define BatteriesAllowed
|
||||||
|
|
||||||
using InnovEnergy.App.SaliMax.Controller;
|
using InnovEnergy.App.SaliMax.Controller;
|
||||||
using InnovEnergy.App.SaliMax.Log;
|
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
|
using InnovEnergy.Lib.Units;
|
||||||
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax;
|
namespace InnovEnergy.App.SaliMax;
|
||||||
|
|
||||||
public static class Topology
|
public static class Topology
|
||||||
{
|
{
|
||||||
public static void Print(StatusRecord s)
|
private static String Separator(Decimal power)
|
||||||
{
|
{
|
||||||
const String chargingSeparator = ">>>>>>>>>>";
|
const String chargingSeparator = ">>>>>>>>>>";
|
||||||
const String dischargingSeparator = "<<<<<<<<<";
|
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;
|
const Int32 height = 25;
|
||||||
|
|
||||||
|
var calculatedActivePwr = - s.InverterStatus!.Ac.ActivePower;
|
||||||
|
var measuredActivePwr = (s.InverterStatus.SumActivePowerL1 + s.InverterStatus.SumActivePowerL2 +
|
||||||
|
s.InverterStatus.SumActivePowerL3) * -1;
|
||||||
|
|
||||||
var pwr = s.InverterStatus!.Ac.ActivePower;
|
measuredActivePwr.WriteLine(" : measured Sum of Active Pwr ");
|
||||||
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
|
|
||||||
var loadPower = Utils.Round3((s.GridMeterStatus!.ActivePowerL123 + pwr)); // it's a + because the pwr is inverted
|
|
||||||
|
|
||||||
var gridSeparator = s.GridMeterStatus!.ActivePowerL123 > 0 ? chargingSeparator : dischargingSeparator;
|
var setValueCosPhi = s.InverterStatus.CosPhiSetValue;
|
||||||
var inverterSeparator = -pwr > 0 ? chargingSeparator : dischargingSeparator;
|
var setValueApparentPower = s.InverterStatus.ApparentPowerSetValue;
|
||||||
var dcSeparator = -s.DcDcStatus!.Dc.Power > 0 ? chargingSeparator : dischargingSeparator;
|
|
||||||
#if BatteriesAllowed
|
|
||||||
var battery1Separator = s.BatteriesStatus[0]!.Power > 0 ? chargingSeparator : dischargingSeparator;
|
#if AmptAvailable
|
||||||
var battery2Separator = s.BatteriesStatus[1]!.Power > 0 ? chargingSeparator : dischargingSeparator;
|
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
|
#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 //////////////////////
|
////////////////// Grid //////////////////////
|
||||||
var boxGrid = AsciiArt.CreateBox
|
var boxGrid = AsciiArt.CreateBox
|
||||||
(
|
(
|
||||||
"Grid",
|
"Grid",
|
||||||
s.GridMeterStatus.Ac.L1.Voltage.V(),
|
s.GridMeterStatus.Ac.L1.Voltage.Value.V(),
|
||||||
s.GridMeterStatus.Ac.L2.Voltage.V(),
|
s.GridMeterStatus.Ac.L2.Voltage.Value.V(),
|
||||||
s.GridMeterStatus.Ac.L3.Voltage.V()
|
s.GridMeterStatus.Ac.L3.Voltage.Value.V()
|
||||||
).AlignCenterVertical(height);
|
).AlignCenterVertical(height);
|
||||||
|
|
||||||
var gridAcBusArrow = AsciiArt.CreateHorizontalArrow(s.GridMeterStatus!.ActivePowerL123.Round0(), gridSeparator)
|
var gridAcBusArrow = AsciiArt.CreateHorizontalArrow(s.GridMeterStatus!.Ac.ActivePower, gridSeparator)
|
||||||
.AlignCenterVertical(height);
|
.AlignCenterVertical(height);
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,9 +69,9 @@ public static class Topology
|
||||||
var boxAcBus = AsciiArt.CreateBox
|
var boxAcBus = AsciiArt.CreateBox
|
||||||
(
|
(
|
||||||
"AC Bus",
|
"AC Bus",
|
||||||
s.InverterStatus.Ac.L1.Voltage.V(),
|
s.InverterStatus.Ac.L1.Voltage.Value.V(),
|
||||||
s.InverterStatus.Ac.L2.Voltage.V(),
|
s.InverterStatus.Ac.L2.Voltage.Value.V(),
|
||||||
s.InverterStatus.Ac.L3.Voltage.V()
|
s.InverterStatus.Ac.L3.Voltage.Value.V()
|
||||||
);
|
);
|
||||||
|
|
||||||
var boxLoad = AsciiArt.CreateBox
|
var boxLoad = AsciiArt.CreateBox
|
||||||
|
@ -56,9 +81,9 @@ public static class Topology
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
|
||||||
var loadRect = StringUtils.AlignBottom(CreateRect(boxAcBus, boxLoad, loadPower), height);
|
var loadRect = StringUtils.AlignBottom(CreateRect(boxAcBus, boxLoad, gridLoadPower), height);
|
||||||
|
|
||||||
var acBusInvertArrow = AsciiArt.CreateHorizontalArrow(-pwr.Round0(), inverterSeparator)
|
var acBusInvertArrow = AsciiArt.CreateHorizontalArrow(measuredActivePwr, inverterSeparator)
|
||||||
.AlignCenterVertical(height);
|
.AlignCenterVertical(height);
|
||||||
|
|
||||||
//////////////////// Inverter /////////////////////////
|
//////////////////// Inverter /////////////////////////
|
||||||
|
@ -69,7 +94,7 @@ public static class Topology
|
||||||
""
|
""
|
||||||
).AlignCenterVertical(height);
|
).AlignCenterVertical(height);
|
||||||
|
|
||||||
var inverterArrow = AsciiArt.CreateHorizontalArrow(-pwr.Round0(), inverterSeparator)
|
var inverterArrow = AsciiArt.CreateHorizontalArrow(measuredActivePwr, inverterSeparator)
|
||||||
.AlignCenterVertical(height);
|
.AlignCenterVertical(height);
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,90 +102,113 @@ public static class Topology
|
||||||
var dcBusBox = AsciiArt.CreateBox
|
var dcBusBox = AsciiArt.CreateBox
|
||||||
(
|
(
|
||||||
"DC Bus",
|
"DC Bus",
|
||||||
(s.InverterStatus.ActualDcLinkVoltageLowerHalfExt + s.InverterStatus.ActualDcLinkVoltageUpperHalfExt).V(),
|
(s.InverterStatus.ActualDcLinkVoltageLowerHalfExt.Value + s.InverterStatus.ActualDcLinkVoltageUpperHalfExt.Value).V(),
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
|
||||||
var pvBox = AsciiArt.CreateBox
|
var pvBox = AsciiArt.CreateBox
|
||||||
(
|
(
|
||||||
"MPPT",
|
"MPPT",
|
||||||
((s.AmptStatus!.Devices[0].Dc.Voltage + s.AmptStatus!.Devices[1].Dc.Voltage) / 2).Round0().V(),
|
((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 pvRect = StringUtils.AlignTop(CreateRect(pvBox, dcBusBox, pvPower), height);
|
||||||
|
|
||||||
var dcBusArrow = AsciiArt.CreateHorizontalArrow(-s.DcDcStatus!.Dc.Power, dcSeparator)
|
var dcBusArrow = AsciiArt.CreateHorizontalArrow(-s.DcDcStatus!.Left.Power, dcSeparator)
|
||||||
.AlignCenterVertical(height);
|
.AlignCenterVertical(height);
|
||||||
|
|
||||||
//////////////////// Dc/Dc /////////////////////////
|
//////////////////// Dc/Dc /////////////////////////
|
||||||
var dcBox = AsciiArt.CreateBox
|
|
||||||
(
|
var dcBox = AsciiArt.CreateBox( "Dc/Dc", s.DcDcStatus.Right.Voltage.Value.V(), "").AlignCenterVertical(height);
|
||||||
"Dc/Dc",
|
|
||||||
s.DcDcStatus.BatteryVoltage.V(),
|
var topology = "";
|
||||||
""
|
|
||||||
).AlignCenterVertical(height);
|
if (s.BatteriesStatus != null)
|
||||||
#if BatteriesAllowed
|
{
|
||||||
var dcArrow1 = AsciiArt.CreateHorizontalArrow(s.BatteriesStatus[0]!.Power.Round0(), battery1Separator);
|
var numBatteries = s.BatteriesStatus.Children.Count;
|
||||||
var dcArrow2 = AsciiArt.CreateHorizontalArrow(s.BatteriesStatus[1]!.Power.Round0(), battery2Separator);
|
|
||||||
#else
|
// Create an array of battery arrows using LINQ
|
||||||
var dcArrow1 ="";
|
var dcArrows = s
|
||||||
var dcArrow2 = "";
|
.BatteriesStatus.Children
|
||||||
var dcArrowRect = StringUtils.AlignCenterVertical(CreateRect(dcArrow1, dcArrow2), height);
|
.Select(b => AsciiArt.CreateHorizontalArrow(b.Dc.Power, Separator(b.Dc.Power)))
|
||||||
#endif
|
.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);
|
||||||
|
|
||||||
|
|
||||||
#if BatteriesAllowed
|
var avgBatteryBox = "";
|
||||||
|
|
||||||
//////////////////// Batteries /////////////////////////
|
if (s.BatteriesStatus.Combined != null)
|
||||||
var battery1Box = AsciiArt.CreateBox
|
{
|
||||||
(
|
avgBatteryBox = AsciiArt.CreateBox
|
||||||
"Battery 1",
|
(
|
||||||
s.BatteriesStatus[0].Voltage.V(),
|
"Batteries",
|
||||||
s.BatteriesStatus[0].Soc.Percent(),
|
s.BatteriesStatus.Combined.CellsVoltage,
|
||||||
s.BatteriesStatus[0].Temperature.Celsius()
|
s.BatteriesStatus.Combined.Soc,
|
||||||
);
|
s.BatteriesStatus.Combined.Temperature,
|
||||||
|
s.BatteriesStatus.Combined.Dc.Current,
|
||||||
var battery2Box = AsciiArt.CreateBox
|
s.BatteriesStatus.Combined.Alarms.Count > 0 ? String.Join(Environment.NewLine, s.BatteriesStatus.Combined.Alarms) : "No Alarm"
|
||||||
(
|
).AlignCenterVertical(height);
|
||||||
"Battery 2",
|
}
|
||||||
s.BatteriesStatus[1].Voltage.V(),
|
|
||||||
s.BatteriesStatus[1].Soc.Percent(),
|
|
||||||
s.BatteriesStatus[1].Temperature.Celsius()
|
|
||||||
);
|
|
||||||
|
|
||||||
var batteryRect = CreateRect(battery1Box, battery2Box).AlignCenterVertical(height);
|
|
||||||
|
|
||||||
var avgBatteryBox = AsciiArt.CreateBox
|
|
||||||
(
|
|
||||||
"Batteries",
|
|
||||||
s.AvgBatteriesStatus!.Voltage.V(),
|
|
||||||
s.AvgBatteriesStatus.Soc.Percent(),
|
|
||||||
s.AvgBatteriesStatus.Temperature.Celsius()
|
|
||||||
).AlignCenterVertical(height);
|
|
||||||
|
|
||||||
|
|
||||||
var topology = boxGrid.SideBySideWith(gridAcBusArrow, "")
|
topology = boxGrid.SideBySideWith(gridAcBusArrow, "")
|
||||||
.SideBySideWith(loadRect, "")
|
.SideBySideWith(loadRect, "")
|
||||||
.SideBySideWith(acBusInvertArrow, "")
|
.SideBySideWith(acBusInvertArrow, "")
|
||||||
.SideBySideWith(inverterBox, "")
|
.SideBySideWith(inverterBox, "")
|
||||||
.SideBySideWith(inverterArrow, "")
|
.SideBySideWith(inverterArrow, "")
|
||||||
.SideBySideWith(pvRect, "")
|
.SideBySideWith(pvRect, "")
|
||||||
.SideBySideWith(dcBusArrow, "")
|
.SideBySideWith(dcBusArrow, "")
|
||||||
.SideBySideWith(dcBox, "")
|
.SideBySideWith(dcBox, "")
|
||||||
.SideBySideWith(dcArrowRect, "")
|
.SideBySideWith(dcArrowRect, "")
|
||||||
.SideBySideWith(batteryRect, "")
|
.SideBySideWith(batteryRect, "")
|
||||||
.SideBySideWith(avgBatteryBox, "")+ "\n";
|
.SideBySideWith(avgBatteryBox, "")+ "\n";
|
||||||
#else
|
|
||||||
var topology = boxGrid.SideBySideWith(gridAcBusArrow, "")
|
}
|
||||||
.SideBySideWith(loadRect, "")
|
else
|
||||||
.SideBySideWith(acBusInvertArrow, "")
|
{
|
||||||
.SideBySideWith(inverterBox, "")
|
topology = boxGrid.SideBySideWith(gridAcBusArrow, "")
|
||||||
.SideBySideWith(inverterArrow, "")
|
.SideBySideWith(loadRect, "")
|
||||||
.SideBySideWith(pvRect, "")
|
.SideBySideWith(acBusInvertArrow, "")
|
||||||
.SideBySideWith(dcBusArrow, "")
|
.SideBySideWith(inverterBox, "")
|
||||||
.SideBySideWith(dcBox, "")+ "\n";
|
.SideBySideWith(inverterArrow, "")
|
||||||
#endif
|
.SideBySideWith(pvRect, "")
|
||||||
|
.SideBySideWith(dcBusArrow, "")
|
||||||
|
.SideBySideWith(dcBox, "") + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
Console.WriteLine(topology);
|
Console.WriteLine(topology);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,4 +231,11 @@ public static class Topology
|
||||||
return rect;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
using InnovEnergy.Lib.Utils;
|
|
||||||
|
|
||||||
namespace InnovEnergy.App.SaliMax;
|
|
||||||
|
|
||||||
public static class Utils
|
|
||||||
{
|
|
||||||
public static Decimal Round3(this Decimal d)
|
|
||||||
{
|
|
||||||
return DecimalUtils.RoundToSignificantDigits(d, 3);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
host=debian@10.2.1.87
|
host=ie-entwicklung@10.2.3.104
|
||||||
|
|
||||||
tunnel() {
|
tunnel() {
|
||||||
name=$1
|
name=$1
|
||||||
|
@ -22,11 +22,11 @@ tunnel() {
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
tunnel "Trumpf Inverter (http) " 192.168.1.2 80 8001
|
tunnel "Trumpf Inverter (http) " 192.168.1.2 80 7001
|
||||||
tunnel "Trumpf DCDC (http) " 192.168.1.3 80 8002
|
tunnel "Trumpf DCDC (http) " 192.168.1.3 80 7002
|
||||||
tunnel "Emu Meter (http) " 192.168.1.241 80 8003
|
tunnel "Emu Meter (http) " 192.168.1.241 80 7003
|
||||||
tunnel "ADAM (http) " 192.168.1.242 80 8004
|
tunnel "ADAM (http) " 192.168.1.242 80 7004
|
||||||
tunnel "AMPT (http) " 192.168.1.249 8080 8005
|
tunnel "AMPT (http) " 192.168.1.249 8080 7005
|
||||||
|
|
||||||
tunnel "Trumpf Inverter (modbus)" 192.168.1.2 502 5001
|
tunnel "Trumpf Inverter (modbus)" 192.168.1.2 502 5001
|
||||||
tunnel "Trumpf DCDC (modbus) " 192.168.1.3 502 5002
|
tunnel "Trumpf DCDC (modbus) " 192.168.1.3 502 5002
|
||||||
|
|
|
@ -22,10 +22,13 @@ public record Battery48TLStatus : BatteryStatus
|
||||||
public IReadOnlyList<String> Warnings { get; init; } = Array.Empty<String>();
|
public IReadOnlyList<String> Warnings { get; init; } = Array.Empty<String>();
|
||||||
public IReadOnlyList<String> Alarms { get; init; } = Array.Empty<String>();
|
public IReadOnlyList<String> Alarms { get; init; } = Array.Empty<String>();
|
||||||
|
|
||||||
|
public Boolean EocReached { get; init; }
|
||||||
public Boolean ConnectedToDc { get; init; }
|
public Boolean ConnectedToDc { get; init; }
|
||||||
public Boolean Heating { get; init; }
|
public Boolean Heating { get; init; }
|
||||||
public TemperatureState TemperatureState { get; init; } // cold | operating temperature | overheated
|
public TemperatureState TemperatureState { get; init; } // cold | operating temperature | overheated
|
||||||
|
|
||||||
|
public Current TotalCurrent { get; init; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: strings
|
// TODO: strings
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Text;
|
||||||
using InnovEnergy.Lib.Protocols.Modbus.Conversions;
|
using InnovEnergy.Lib.Protocols.Modbus.Conversions;
|
||||||
using InnovEnergy.Lib.Units.Composite;
|
using InnovEnergy.Lib.Units.Composite;
|
||||||
using InnovEnergy.Lib.Utils;
|
using InnovEnergy.Lib.Utils;
|
||||||
|
@ -17,9 +18,11 @@ public static class ModbusParser
|
||||||
|
|
||||||
var soc = data.ParseSoc();
|
var soc = data.ParseSoc();
|
||||||
|
|
||||||
var eoc = greenLed is On
|
// var eoc = greenLed is On
|
||||||
&& amberLed is Off
|
// && amberLed is Off
|
||||||
&& blueLed is Off;
|
// && blueLed is Off;
|
||||||
|
|
||||||
|
var eoc = data.ParseEocReached();
|
||||||
|
|
||||||
var maxSoc = eoc ? 100m : 99.9m;
|
var maxSoc = eoc ? 100m : 99.9m;
|
||||||
|
|
||||||
|
@ -48,6 +51,8 @@ public static class ModbusParser
|
||||||
MaxChargingPower = data.CalcMaxChargePower(),
|
MaxChargingPower = data.CalcMaxChargePower(),
|
||||||
MaxDischargingPower = data.CalcMaxDischargePower(),
|
MaxDischargingPower = data.CalcMaxDischargePower(),
|
||||||
CellsVoltage = data.ParseDecimal(register: 1000, scaleFactor: 0.01m),
|
CellsVoltage = data.ParseDecimal(register: 1000, scaleFactor: 0.01m),
|
||||||
|
TotalCurrent = data.ReadTotalCurrent(),
|
||||||
|
EocReached = eoc
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +77,19 @@ public static class ModbusParser
|
||||||
return data.ParseDecimal(register: 1002, scaleFactor: 0.01m);
|
return data.ParseDecimal(register: 1002, scaleFactor: 0.01m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static Decimal ReadTotalCurrent(this ModbusRegisters data)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return ParseDecimal(data, register: 1063, scaleFactor: 0.01m, offset: -100);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e + " Read Total current fail ");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static Boolean ParseBool(this ModbusRegisters data, Int32 baseRegister, Int16 bit)
|
internal static Boolean ParseBool(this ModbusRegisters data, Int32 baseRegister, Int16 bit)
|
||||||
{
|
{
|
||||||
var x = bit / 16;
|
var x = bit / 16;
|
||||||
|
@ -96,6 +114,21 @@ public static class ModbusParser
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static String ParseString(this ModbusRegisters data, Int32 register, Int16 count)
|
||||||
|
{
|
||||||
|
return Enumerable
|
||||||
|
.Range(register, count)
|
||||||
|
.Select(i => data[i])
|
||||||
|
.Select(BitConverter.GetBytes)
|
||||||
|
.Select(Encoding.ASCII.GetString)
|
||||||
|
.Aggregate("", (a, b) => a + b[1] + b[0]); // endian swap
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Boolean ParseEocReached(this ModbusRegisters data)
|
||||||
|
{
|
||||||
|
var s = ParseString(data, 1061, 2);
|
||||||
|
return "EOC_" == s;
|
||||||
|
}
|
||||||
|
|
||||||
internal static Decimal ParseSoc(this ModbusRegisters data)
|
internal static Decimal ParseSoc(this ModbusRegisters data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,7 @@ public static class Units
|
||||||
public static Angle Rad (this Decimal value) => value;
|
public static Angle Rad (this Decimal value) => value;
|
||||||
public static Temperature Celsius(this Decimal value) => value;
|
public static Temperature Celsius(this Decimal value) => value;
|
||||||
public static Energy KWh (this Decimal value) => value;
|
public static Energy KWh (this Decimal value) => value;
|
||||||
|
public static Percent Percent(this Decimal value) => value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Prefixes
|
public static class Prefixes
|
||||||
|
|
|
@ -44,7 +44,8 @@
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"testcafe": "^2.4.0",
|
"testcafe": "^2.4.0",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4",
|
||||||
|
"yup": "^1.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@formatjs/cli": "^6.0.3",
|
"@formatjs/cli": "^6.0.3",
|
||||||
|
@ -18173,6 +18174,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/property-expr": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
|
||||||
|
},
|
||||||
"node_modules/protocol-buffers-schema": {
|
"node_modules/protocol-buffers-schema": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
||||||
|
@ -21580,6 +21586,11 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tiny-case": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
|
||||||
|
},
|
||||||
"node_modules/tiny-warning": {
|
"node_modules/tiny-warning": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||||
|
@ -21691,6 +21702,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/toposort": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
|
||||||
|
},
|
||||||
"node_modules/tough-cookie": {
|
"node_modules/tough-cookie": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
||||||
|
@ -23353,6 +23369,28 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/yup": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yup/-/yup-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-CtpEHWiIMwWJBJ+zX8xWImXXdvJ10X/sKkYYTXfVocHj087e9zhP0GNkU7HlXBBI4T9BtHQxs8n2jLzmo/X8Yg==",
|
||||||
|
"dependencies": {
|
||||||
|
"property-expr": "^2.0.5",
|
||||||
|
"tiny-case": "^1.0.3",
|
||||||
|
"toposort": "^2.0.2",
|
||||||
|
"type-fest": "^2.19.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yup/node_modules/type-fest": {
|
||||||
|
"version": "2.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
|
||||||
|
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.20"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/zustand": {
|
"node_modules/zustand": {
|
||||||
"version": "4.3.3",
|
"version": "4.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.3.tgz",
|
||||||
|
@ -36715,6 +36753,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"property-expr": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
|
||||||
|
},
|
||||||
"protocol-buffers-schema": {
|
"protocol-buffers-schema": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
||||||
|
@ -39376,6 +39419,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz",
|
||||||
"integrity": "sha512-pqqJOi1rF5zNs/ps4vmbE4SFCrM4iR7LW+GHAsHqO/EumqbIWceioevYLM5xZRgQSH6gFgL9J/uB7EcJhQ9niQ=="
|
"integrity": "sha512-pqqJOi1rF5zNs/ps4vmbE4SFCrM4iR7LW+GHAsHqO/EumqbIWceioevYLM5xZRgQSH6gFgL9J/uB7EcJhQ9niQ=="
|
||||||
},
|
},
|
||||||
|
"tiny-case": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
|
||||||
|
},
|
||||||
"tiny-warning": {
|
"tiny-warning": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||||
|
@ -39472,6 +39520,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"toposort": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
|
||||||
|
},
|
||||||
"tough-cookie": {
|
"tough-cookie": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
||||||
|
@ -40789,6 +40842,24 @@
|
||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
|
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
|
||||||
},
|
},
|
||||||
|
"yup": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yup/-/yup-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-CtpEHWiIMwWJBJ+zX8xWImXXdvJ10X/sKkYYTXfVocHj087e9zhP0GNkU7HlXBBI4T9BtHQxs8n2jLzmo/X8Yg==",
|
||||||
|
"requires": {
|
||||||
|
"property-expr": "^2.0.5",
|
||||||
|
"tiny-case": "^1.0.3",
|
||||||
|
"toposort": "^2.0.2",
|
||||||
|
"type-fest": "^2.19.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"type-fest": {
|
||||||
|
"version": "2.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
|
||||||
|
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"zustand": {
|
"zustand": {
|
||||||
"version": "4.3.3",
|
"version": "4.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.3.tgz",
|
||||||
|
|
|
@ -39,7 +39,8 @@
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"testcafe": "^2.4.0",
|
"testcafe": "^2.4.0",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4",
|
||||||
|
"yup": "^1.1.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
|
|
@ -13,6 +13,7 @@ import Users from "./components/Users/Users";
|
||||||
import NavigationButtons from "./components/Layout/NavigationButtons";
|
import NavigationButtons from "./components/Layout/NavigationButtons";
|
||||||
import InstallationPage from "./components/Installations/InstallationPage";
|
import InstallationPage from "./components/Installations/InstallationPage";
|
||||||
import { UserContext } from "./components/Context/UserContextProvider";
|
import { UserContext } from "./components/Context/UserContextProvider";
|
||||||
|
import ResetPassword from "./ResetPassword";
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const { token, setToken, removeToken } = useToken();
|
const { token, setToken, removeToken } = useToken();
|
||||||
|
@ -30,10 +31,9 @@ const App = () => {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return <Login setToken={setToken} setLanguage={setLanguage} />;
|
return <Login setToken={setToken} setLanguage={setLanguage} />;
|
||||||
}
|
}
|
||||||
|
if (token && currentUser?.mustResetPassword) {
|
||||||
/* TODO create reset page if (token && currentUser?.mustResetPassword) {
|
return <ResetPassword />;
|
||||||
return <div>Reset page</div>;
|
}
|
||||||
} */
|
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<IntlProvider
|
<IntlProvider
|
||||||
|
|
|
@ -32,28 +32,33 @@ const Login = ({ setToken, setLanguage }: I_LoginProps) => {
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
loginUser(username, password).then(({ data }) => {
|
loginUser(username, password)
|
||||||
// TODO change this if they return err codes from backend
|
.then(({ data }) => {
|
||||||
if (data && data.token) {
|
// TODO change this if they return err codes from backend
|
||||||
verifyToken(data.token)
|
if (data && data.token) {
|
||||||
.then(() => {
|
verifyToken(data.token)
|
||||||
setToken(data.token);
|
.then(() => {
|
||||||
setCurrentUser(data.user);
|
setToken(data.token);
|
||||||
setLoading(false);
|
setCurrentUser(data.user);
|
||||||
setLanguage(data.user.language);
|
setLoading(false);
|
||||||
})
|
setLanguage(data.user.language);
|
||||||
.catch((err) => {
|
})
|
||||||
setError(err);
|
.catch((err) => {
|
||||||
setLoading(false);
|
setError(err);
|
||||||
});
|
setLoading(false);
|
||||||
}
|
});
|
||||||
setError(data);
|
}
|
||||||
setLoading(false);
|
setError(data);
|
||||||
});
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
setError(err);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xs" sx={{ p: 2, alignContent: "center" }}>
|
<Container maxWidth="sm" sx={{ p: 2, alignContent: "center" }}>
|
||||||
<InnovenergyTextfield
|
<InnovenergyTextfield
|
||||||
id="username-textfield"
|
id="username-textfield"
|
||||||
label="Username"
|
label="Username"
|
||||||
|
|
|
@ -1,73 +1,79 @@
|
||||||
import React, { useContext, useState } from "react";
|
import React, { useContext, useState } from "react";
|
||||||
import { Alert, CircularProgress, Grid } from "@mui/material";
|
import { Alert, CircularProgress, Grid, Typography } from "@mui/material";
|
||||||
import Container from "@mui/material/Container";
|
import Container from "@mui/material/Container";
|
||||||
import { axiosConfigWithoutToken } from "./config/axiosConfig";
|
import axiosConfig from "./config/axiosConfig";
|
||||||
import InnovenergyTextfield from "./components/Layout/InnovenergyTextfield";
|
import InnovenergyTextfield from "./components/Layout/InnovenergyTextfield";
|
||||||
import InnovenergyButton from "./components/Layout/InnovenergyButton";
|
import InnovenergyButton from "./components/Layout/InnovenergyButton";
|
||||||
import { UserContext } from "./components/Context/UserContextProvider";
|
import { UserContext } from "./components/Context/UserContextProvider";
|
||||||
|
import { useFormik } from "formik";
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
|
||||||
const loginUser = async (username: string, password: string) => {
|
const ResetPassword = () => {
|
||||||
return axiosConfigWithoutToken.post("/Login", null, {
|
|
||||||
params: { username, password },
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface I_LoginProps {
|
|
||||||
setToken: (value: string) => void;
|
|
||||||
setLanguage: (value: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ResetPassword = ({ setToken, setLanguage }: I_LoginProps) => {
|
|
||||||
const [username, setUsername] = useState("");
|
|
||||||
const [password, setPassword] = useState("");
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState();
|
const [error, setError] = useState<AxiosError>();
|
||||||
const { setCurrentUser } = useContext(UserContext);
|
const { setCurrentUser } = useContext(UserContext);
|
||||||
|
|
||||||
const verifyToken = async (token: string) => {
|
const validationSchema = Yup.object().shape({
|
||||||
axiosConfigWithoutToken.get("/GetAllInstallations", {
|
password: Yup.string().required("*Password is required"),
|
||||||
params: { authToken: token },
|
verifyPassword: Yup.string()
|
||||||
});
|
.oneOf([Yup.ref("password")], "Passwords must match")
|
||||||
};
|
.required(),
|
||||||
|
});
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const formik = useFormik({
|
||||||
setLoading(true);
|
initialValues: {
|
||||||
loginUser(username, password).then(({ data }) => {
|
password: "",
|
||||||
// TODO change this if they return err codes from backend
|
verifyPassword: "",
|
||||||
if (data && data.token) {
|
},
|
||||||
verifyToken(data.token)
|
onSubmit: (formikValues) => {
|
||||||
.then(() => {
|
setLoading(true);
|
||||||
setToken(data.token);
|
axiosConfig
|
||||||
setCurrentUser(data.user);
|
.put("/UpdatePassword", undefined, {
|
||||||
setLoading(false);
|
params: { newPassword: formikValues.verifyPassword },
|
||||||
setLanguage(data.user.language);
|
})
|
||||||
})
|
.then((res) => {
|
||||||
.catch((err) => {
|
setCurrentUser(res.data);
|
||||||
setError(err);
|
setLoading(false);
|
||||||
setLoading(false);
|
})
|
||||||
});
|
.catch((err) => setError(err));
|
||||||
}
|
},
|
||||||
setError(data);
|
validationSchema,
|
||||||
setLoading(false);
|
});
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xs" sx={{ p: 2, alignContent: "center" }}>
|
<Container maxWidth="sm" sx={{ p: 2, alignContent: "center" }}>
|
||||||
<InnovenergyTextfield
|
<Typography variant="h6" marginBottom="20px" textAlign="center">
|
||||||
id="username-textfield"
|
Change password
|
||||||
label="Username"
|
</Typography>
|
||||||
name="email"
|
<form onSubmit={formik.handleSubmit}>
|
||||||
value={username}
|
<InnovenergyTextfield
|
||||||
handleChange={(e) => setUsername(e.target.value)}
|
id="password-textfield"
|
||||||
/>
|
label="Password"
|
||||||
{error && <Alert severity="error">Incorrect username or password</Alert>}
|
name="password"
|
||||||
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
|
value={formik.values.password}
|
||||||
<InnovenergyButton onClick={handleSubmit} sx={{ my: 1 }}>
|
handleChange={formik.handleChange}
|
||||||
Login
|
type="password"
|
||||||
</InnovenergyButton>
|
/>
|
||||||
</Grid>
|
<InnovenergyTextfield
|
||||||
{loading && <CircularProgress />}
|
id="verify-password-textfield"
|
||||||
|
label="Verify password"
|
||||||
|
name="verifyPassword"
|
||||||
|
value={formik.values.verifyPassword}
|
||||||
|
handleChange={formik.handleChange}
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
{formik.errors.verifyPassword && formik.touched.verifyPassword && (
|
||||||
|
<Alert severity="error">{formik.errors.verifyPassword}</Alert>
|
||||||
|
)}
|
||||||
|
{error && <Alert severity="error">{error.name}</Alert>}
|
||||||
|
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
|
||||||
|
<InnovenergyButton type="submit" sx={{ my: 1 }}>
|
||||||
|
Submit
|
||||||
|
</InnovenergyButton>
|
||||||
|
</Grid>
|
||||||
|
{loading && <CircularProgress />}
|
||||||
|
</form>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import Plot from "react-plotly.js";
|
import Plot from "react-plotly.js";
|
||||||
import exampleLogData, {
|
import { TimeSeries, timeSeries } from "../ExampleLogData";
|
||||||
Datum,
|
|
||||||
TimeSeries,
|
|
||||||
timeSeries,
|
|
||||||
} from "../ExampleLogData";
|
|
||||||
import { I_GraphData } from "../../../util/types";
|
|
||||||
|
|
||||||
const ScalarGraph = () => {
|
const ScalarGraph = () => {
|
||||||
const transformToGraphData = (timeStampData: TimeSeries) => {
|
const transformToGraphData = (timeStampData: TimeSeries) => {
|
||||||
|
@ -70,6 +65,17 @@ const ScalarGraph = () => {
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
layout={{ width: 1000, height: 500, title: path }}
|
layout={{ width: 1000, height: 500, title: path }}
|
||||||
|
config={{
|
||||||
|
modeBarButtonsToRemove: [
|
||||||
|
"lasso2d",
|
||||||
|
"select2d",
|
||||||
|
"pan2d",
|
||||||
|
"autoScale2d",
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
onUpdate={(figure) => {
|
||||||
|
console.log(figure);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue