Add the downward calibration
This commit is contained in:
parent
3b43090b84
commit
6fbec18a00
|
|
@ -7,6 +7,8 @@ public class Configuration
|
|||
public Double MinimumSoC { get; set; }
|
||||
public Double GridSetPoint { get; set; }
|
||||
public CalibrationChargeType CalibrationChargeState { get; set; }
|
||||
public CalibrationDischargeType CalibrationDischargeState { get; set; }
|
||||
public DateTime CalibrationChargeDate { get; set; }
|
||||
public DateTime CalibrationDischargeDate { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ public static class Controller
|
|||
private static readonly Double MaxChargePower = 6000; // By battery TODO: move to config
|
||||
|
||||
private static Boolean _hasRepetitiveCalibrationChargeChecked = false;
|
||||
private static Boolean _hasRepetitiveCalibrationDischargeChecked = false;
|
||||
|
||||
private static DateTime _nextDayAt10Am = DateTime.Now;
|
||||
|
||||
public static EssMode SelectControlMode(this StatusRecord s)
|
||||
|
|
@ -19,13 +21,13 @@ public static class Controller
|
|||
//return EssMode.OptimizeSelfConsumption;
|
||||
|
||||
return s.StateMachine.State != 23 ? EssMode.Off
|
||||
: s.MustDoCalibrationCharge() ? EssMode.UpwardsCalibrationCharge
|
||||
: s.MustDoDownwardsCalibrationCharge() ? EssMode.DownwardsCalibrationCharge
|
||||
: s.MustReachMinSoc() ? EssMode.ReachMinSoc
|
||||
: s.MustDoCalibrationCharge() ? EssMode.CalibrationCharge
|
||||
: s.GridMeter is null ? EssMode.NoGridMeter
|
||||
: EssMode.OptimizeSelfConsumption;
|
||||
}
|
||||
|
||||
|
||||
public static EssControl ControlEss(this StatusRecord s)
|
||||
{
|
||||
var mode = s.SelectControlMode().WriteLine();
|
||||
|
|
@ -45,8 +47,9 @@ public static class Controller
|
|||
return EssControl.Default;
|
||||
}
|
||||
|
||||
// if we have no reading from the Grid meter, but we have a grid power (K1 is close),
|
||||
// then we do only heat the battery to avoid discharging the battery and the oscillation between reach min soc and off mode
|
||||
/* if we have no reading from the Grid meter, but we have a grid power (K1 is close), then we do only heat the battery
|
||||
to avoid discharging the battery and the oscillation between reach min soc and off mode
|
||||
This should be reconsidered for deligreen */
|
||||
if (mode is EssMode.NoGridMeter)
|
||||
return new EssControl
|
||||
{
|
||||
|
|
@ -117,7 +120,6 @@ public static class Controller
|
|||
|
||||
private static EssControl LimitChargePower(this EssControl control, StatusRecord s)
|
||||
{
|
||||
|
||||
//var maxInverterChargePower = s.ControlInverterPower(s.Config.MaxInverterPower);
|
||||
var maxBatteryChargePower = s.MaxBatteryChargePower();
|
||||
maxBatteryChargePower.WriteLine(" Max Battery Charge Power");
|
||||
|
|
@ -125,7 +127,6 @@ public static class Controller
|
|||
return control
|
||||
//.LimitChargePower(, EssLimit.ChargeLimitedByInverterPower)
|
||||
.LimitChargePower(maxBatteryChargePower, EssLimit.ChargeLimitedByBatteryPower);
|
||||
|
||||
}
|
||||
|
||||
private static EssControl LimitDischargePower(this EssControl control, StatusRecord s)
|
||||
|
|
@ -134,7 +135,11 @@ public static class Controller
|
|||
var keepMinSocLimitDelta = s.ControlBatteryPower(s.HoldMinSocPower());
|
||||
maxBatteryDischargeDelta.WriteLine(" Max Battery Discharge Power");
|
||||
|
||||
|
||||
if (control.Mode == EssMode.DownwardsCalibrationCharge )
|
||||
{
|
||||
return control
|
||||
.LimitDischargePower(maxBatteryDischargeDelta, EssLimit.DischargeLimitedByBatteryPower);
|
||||
}
|
||||
return control
|
||||
.LimitDischargePower(maxBatteryDischargeDelta , EssLimit.DischargeLimitedByBatteryPower)
|
||||
.LimitDischargePower(keepMinSocLimitDelta , EssLimit.DischargeLimitedByMinSoc);
|
||||
|
|
@ -143,6 +148,7 @@ public static class Controller
|
|||
private static Double ComputePowerDelta(this StatusRecord s, EssMode mode)
|
||||
{
|
||||
var chargePower = s.AcDc.Devices.Sum(d => d.Status.Nominal.Power.Value);
|
||||
var batteryDischargePower = s.Battery?.Devices.Count * MaxDischargePower ?? 0 ;
|
||||
|
||||
return mode switch
|
||||
{
|
||||
|
|
@ -151,7 +157,8 @@ public static class Controller
|
|||
EssMode.Off => 0,
|
||||
EssMode.OffGrid => 0,
|
||||
EssMode.NoGridMeter => 0,
|
||||
EssMode.CalibrationCharge => s.ControlInverterPower(chargePower),
|
||||
EssMode.UpwardsCalibrationCharge => s.ControlInverterPower(chargePower),
|
||||
EssMode.DownwardsCalibrationCharge => s.ControlInverterPower(batteryDischargePower),
|
||||
_ => throw new ArgumentException(null, nameof(mode))
|
||||
};
|
||||
}
|
||||
|
|
@ -229,6 +236,36 @@ public static class Controller
|
|||
return mustDoCalibrationCharge;
|
||||
}
|
||||
|
||||
private static Boolean MustDoDownwardsCalibrationCharge(this StatusRecord statusRecord)
|
||||
{
|
||||
var calibrationDischargeForced = statusRecord.Config.ForceCalibrationDischargeState;
|
||||
var additionalCalibrationRequired = DownAdditionalCalibrationDateHasBeenPassed(statusRecord.Config.DownDayAndTimeForAdditionalCalibration);
|
||||
var repetitiveCalibrationRequired = DownRepetitiveCalibrationDateHasBeenPassed(statusRecord.Config.DownDayAndTimeForRepetitiveCalibration);
|
||||
|
||||
var mustDoCalibrationDischarge = calibrationDischargeForced == CalibrationDischargeType.DischargePermanently ||
|
||||
(calibrationDischargeForced == CalibrationDischargeType.AdditionallyOnce && additionalCalibrationRequired) ||
|
||||
(calibrationDischargeForced == CalibrationDischargeType.RepetitivelyEvery && repetitiveCalibrationRequired);
|
||||
|
||||
Console.WriteLine("Next Repetitive calibration charge date is "+ statusRecord.Config.DownDayAndTimeForRepetitiveCalibration);
|
||||
Console.WriteLine("Next Additional calibration charge date is "+ statusRecord.Config.DownDayAndTimeForAdditionalCalibration);
|
||||
|
||||
if (statusRecord.Battery is not null)
|
||||
{
|
||||
if (calibrationDischargeForced == CalibrationDischargeType.AdditionallyOnce && statusRecord.Battery.Eod )
|
||||
{
|
||||
statusRecord.Config.ForceCalibrationDischargeState = CalibrationDischargeType.RepetitivelyEvery;
|
||||
|
||||
}
|
||||
else if (calibrationDischargeForced == CalibrationDischargeType.RepetitivelyEvery && statusRecord.Battery.Eod && _hasRepetitiveCalibrationDischargeChecked)
|
||||
{
|
||||
statusRecord.Config.DownDayAndTimeForRepetitiveCalibration = statusRecord.Config.DownDayAndTimeForRepetitiveCalibration.AddDays(7);
|
||||
_hasRepetitiveCalibrationDischargeChecked = false;
|
||||
}
|
||||
}
|
||||
|
||||
return mustDoCalibrationDischarge;
|
||||
}
|
||||
|
||||
private static Boolean RepetitiveCalibrationDateHasBeenPassed(DateTime calibrationChargeDate)
|
||||
{
|
||||
if (DateTime.Now >= calibrationChargeDate )
|
||||
|
|
@ -247,6 +284,23 @@ public static class Controller
|
|||
return false;
|
||||
}
|
||||
|
||||
private static Boolean DownRepetitiveCalibrationDateHasBeenPassed(DateTime calibrationDischargeDate)
|
||||
{
|
||||
if (DateTime.Now >= calibrationDischargeDate )
|
||||
{
|
||||
_hasRepetitiveCalibrationDischargeChecked = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static Boolean DownAdditionalCalibrationDateHasBeenPassed(DateTime calibrationDischargeDate)
|
||||
{
|
||||
if (DateTime.Now >= calibrationDischargeDate )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static Double ControlGridPower(this StatusRecord status, Double targetPower)
|
||||
{
|
||||
return ControlPower
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ public enum EssMode
|
|||
Off,
|
||||
OffGrid,
|
||||
HeatBatteries,
|
||||
CalibrationCharge,
|
||||
UpwardsCalibrationCharge,
|
||||
DownwardsCalibrationCharge,
|
||||
ReachMinSoc,
|
||||
NoGridMeter,
|
||||
OptimizeSelfConsumption
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ using System.Security;
|
|||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using Flurl.Http;
|
||||
using InnovEnergy.App.SodiStoreMax;
|
||||
using InnovEnergy.App.SodiStoreMax.Devices;
|
||||
|
|
@ -33,10 +32,11 @@ using InnovEnergy.Lib.Units;
|
|||
using InnovEnergy.Lib.Utils;
|
||||
using InnovEnergy.App.SodiStoreMax.DataTypes;
|
||||
using Newtonsoft.Json;
|
||||
using static System.Int32;
|
||||
using static InnovEnergy.App.SodiStoreMax.AggregationService.Aggregator;
|
||||
using static InnovEnergy.App.SodiStoreMax.MiddlewareClasses.MiddlewareAgent;
|
||||
using static InnovEnergy.Lib.Devices.Trumpf.SystemControl.DataTypes.SystemConfig;
|
||||
|
||||
using Controller = InnovEnergy.App.SodiStoreMax.System.Controller;
|
||||
using DeviceState = InnovEnergy.App.SodiStoreMax.Devices.DeviceState;
|
||||
// ReSharper disable PossibleLossOfFraction
|
||||
|
||||
|
|
@ -60,6 +60,7 @@ internal static class Program
|
|||
private static readonly Channel RelaysChannel;
|
||||
private static readonly Channel BatteriesChannel;
|
||||
|
||||
//
|
||||
private static Boolean _curtailFlag = false;
|
||||
private const String VpnServerIp = "10.2.0.11";
|
||||
private static Boolean _subscribedToQueue = false;
|
||||
|
|
@ -69,6 +70,7 @@ internal static class Program
|
|||
private static UInt16 _fileCounter = 0;
|
||||
private static SalimaxAlarmState _salimaxAlarmState = SalimaxAlarmState.Green;
|
||||
private const String Port = "/dev/ttyUSB0"; // move to a config file
|
||||
private static Int32 _failsCounter = 0; // move to a config file
|
||||
|
||||
static Program()
|
||||
{
|
||||
|
|
@ -240,14 +242,32 @@ internal static class Program
|
|||
record.ControlConstants();
|
||||
record.ControlSystemState();
|
||||
|
||||
record.AcDc.SystemControl.ApplyAcDcDefaultSettings();
|
||||
record.DcDc.SystemControl.ApplyDcDcDefaultSettings();
|
||||
|
||||
/* Console.WriteLine(" Fails Counter = " + _failsCounter);
|
||||
|
||||
// Retries Control
|
||||
if (record.StateMachine.State is not (28 or 23) )
|
||||
{
|
||||
if (_failsCounter > 60) // 2 min
|
||||
{
|
||||
Console.WriteLine(" Fails retries reached threshold");
|
||||
record.EnableSafeDefaults();
|
||||
return record;
|
||||
}
|
||||
_failsCounter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
_failsCounter = 0;
|
||||
}*/
|
||||
//record.ControlPvPower(record.Config.CurtailP, record.Config.PvInstalledPower);
|
||||
|
||||
var essControl = record.ControlEss().WriteLine();
|
||||
|
||||
record.EssControl = essControl;
|
||||
|
||||
record.AcDc.SystemControl.ApplyAcDcDefaultSettings();
|
||||
record.DcDc.SystemControl.ApplyDcDcDefaultSettings();
|
||||
|
||||
DistributePower(record, essControl);
|
||||
|
||||
|
|
@ -310,8 +330,6 @@ internal static class Program
|
|||
|
||||
var alarmList = new List<AlarmOrWarning>();
|
||||
var warningList = new List<AlarmOrWarning>();
|
||||
var bAlarmList = new List<String>();
|
||||
var bWarningList = new List<String>();
|
||||
|
||||
if (record.Battery is { MonomerHighVoltageAlarm: true })
|
||||
{
|
||||
|
|
@ -401,7 +419,7 @@ internal static class Program
|
|||
private static Int32 GetInstallationId(String s3Bucket)
|
||||
{
|
||||
var part = s3Bucket.Split('-').FirstOrDefault();
|
||||
return TryParse(part, out var id) ? id : 0; // is 0 a default safe value? check with Marios
|
||||
return int.TryParse(part, out var id) ? id : 0; // is 0 a default safe value? check with Marios
|
||||
}
|
||||
|
||||
private static String? DetectAlarmStates(this StatusRecord r) => r.Relays switch
|
||||
|
|
@ -766,7 +784,6 @@ internal static class Program
|
|||
{
|
||||
var csv = status.ToCsv();
|
||||
Dictionary<string, object> jsonData = new Dictionary<string, object>();
|
||||
//Console.WriteLine(csv);
|
||||
|
||||
foreach (var line in csv.Split('\n'))
|
||||
{
|
||||
|
|
@ -842,8 +859,8 @@ internal static class Program
|
|||
private static void Heartbit(DateTime timeStamp)
|
||||
{
|
||||
var s3Bucket = Config.Load().S3?.Bucket;
|
||||
var tryParse = TryParse(s3Bucket?.Split("-")[0], out var installationId);
|
||||
var parse = TryParse(timeStamp.ToUnixTime().ToString(), out var nameOfJsonFile);
|
||||
var tryParse = int.TryParse(s3Bucket?.Split("-")[0], out var installationId);
|
||||
var parse = int.TryParse(timeStamp.ToUnixTime().ToString(), out var nameOfJsonFile);
|
||||
|
||||
if (tryParse)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -550,7 +550,6 @@ public static class Controller
|
|||
s.Relays.DisconnectIslandBusFromGrid();
|
||||
|
||||
return false;
|
||||
|
||||
// => 13
|
||||
}
|
||||
|
||||
|
|
@ -636,7 +635,7 @@ public static class Controller
|
|||
//this is must be deleted
|
||||
private static void Disable(this DcDcDevicesRecord dcDc)
|
||||
{
|
||||
// For Test purpose, The transition from island mode to grid tier and vis versa , may not need to disable Dc/Dc.
|
||||
// For Test purpose, The transition from island mode to grid tier and vis versa may not need to disable Dc/Dc.
|
||||
// This will keep the Dc link powered.
|
||||
|
||||
// dcDc.Devices
|
||||
|
|
@ -687,9 +686,9 @@ public static class Controller
|
|||
}
|
||||
|
||||
|
||||
private static Boolean EnableSafeDefaults(this StatusRecord s)
|
||||
public static Boolean EnableSafeDefaults(this StatusRecord s)
|
||||
{
|
||||
// After some tests, the safe state is switch off inverter and keep the last state of K2 , Dc/Dc and Grid type to avoid conflict.
|
||||
// After some tests, the safe state is switch off inverter and keep the last state of K2, Dc/Dc and Grid type to avoid conflict.
|
||||
|
||||
// s.DcDc.Disable();
|
||||
s.AcDc.Disable(); // Maybe comment this to avoid opening/closing K3
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@ public record StateMachine
|
|||
public required String Message { get; set; } // TODO: init only
|
||||
public required Int32 State { get; set; } // TODO: init only
|
||||
|
||||
public static StateMachine Default { get; } = new StateMachine { State = 100, Message = "Unknown State" };
|
||||
public static StateMachine Default { get; } = new StateMachine { State = 100, Message = "Default State" };
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
namespace InnovEnergy.App.SodiStoreMax.SystemConfig;
|
||||
|
||||
public enum CalibrationDischargeType
|
||||
{
|
||||
RepetitivelyEvery,
|
||||
AdditionallyOnce,
|
||||
DischargePermanently
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -18,9 +18,15 @@ public class Config //TODO: let IE choose from config files (Json) and connect t
|
|||
public required Double MinSoc { get; set; }
|
||||
public required UInt16 CurtailP { get; set; }// in Kw
|
||||
public required UInt16 PvInstalledPower { get; set; }// in Kw
|
||||
|
||||
public required CalibrationChargeType ForceCalibrationChargeState { get; set; }
|
||||
public required DateTime DayAndTimeForRepetitiveCalibration { get; set; }
|
||||
public required DateTime DayAndTimeForAdditionalCalibration { get; set; }
|
||||
|
||||
public required CalibrationDischargeType ForceCalibrationDischargeState { get; set; }
|
||||
public required DateTime DownDayAndTimeForRepetitiveCalibration { get; set; }
|
||||
public required DateTime DownDayAndTimeForAdditionalCalibration { get; set; }
|
||||
|
||||
public required Boolean DisplayIndividualBatteries { get; set; }
|
||||
public required Double PConstant { get; set; }
|
||||
public required Double GridSetPoint { get; set; }
|
||||
|
|
@ -132,6 +138,9 @@ public class Config //TODO: let IE choose from config files (Json) and connect t
|
|||
ForceCalibrationChargeState = CalibrationChargeType.RepetitivelyEvery,
|
||||
DayAndTimeForRepetitiveCalibration = DefaultDatetime,
|
||||
DayAndTimeForAdditionalCalibration = DefaultDatetime,
|
||||
ForceCalibrationDischargeState = CalibrationDischargeType.RepetitivelyEvery,
|
||||
DownDayAndTimeForAdditionalCalibration = DefaultDatetime,
|
||||
DownDayAndTimeForRepetitiveCalibration = DefaultDatetime,
|
||||
DisplayIndividualBatteries = false,
|
||||
PConstant = .5,
|
||||
GridSetPoint = 0,
|
||||
|
|
|
|||
Loading…
Reference in New Issue