Add Calibration charge mode and clean code

This commit is contained in:
atef 2025-05-05 11:59:20 +02:00
parent bf37840d0d
commit bbca604ce9
2 changed files with 120 additions and 169 deletions

View File

@ -11,12 +11,16 @@ public static class Controller
private static readonly Double MaxDischargePower = -8000; // By battery TODO: move to config
private static readonly Double MaxChargePower = 6000; // By battery TODO: move to config
private static Boolean _hasRepetitiveCalibrationChargeChecked = false;
private static DateTime _nextDayAt10Am = DateTime.Now;
public static EssMode SelectControlMode(this StatusRecord s)
{
//return EssMode.OptimizeSelfConsumption;
return s.StateMachine.State != 23 ? EssMode.Off
: s.MustReachMinSoc() ? EssMode.ReachMinSoc
: s.MustDoCalibrationCharge() ? EssMode.CalibrationCharge
: s.GridMeter is null ? EssMode.NoGridMeter
: EssMode.OptimizeSelfConsumption;
}
@ -147,26 +151,15 @@ public static class Controller
EssMode.Off => 0,
EssMode.OffGrid => 0,
EssMode.NoGridMeter => 0,
EssMode.CalibrationCharge => s.ControlInverterPower(chargePower),
_ => throw new ArgumentException(null, nameof(mode))
};
}
// private static Boolean MustHeatBatteries(this StatusRecord s)
// {
// var batteries = s.GetBatteries();
//
// if (batteries.Count <= 0)
// return true; // batteries might be there but BMS is without power
//
// return batteries
// .Select(b => b.Temperatures.State)
// .Contains(TemperatureState.Cold);
// }
private static Double MaxBatteryChargePower(this StatusRecord s)
{
// This introduces a limit when we don't have communication with batteries
// Otherwise the limit will be 0 and the batteries will be not heated
// This introduces a limit when we don't have communication with batteries,
// Otherwise the limit will be 0, and the batteries will be not heated
var batteries = s.GetBatteries();
@ -206,6 +199,54 @@ public static class Controller
return s.Battery?.Devices ?? Array.Empty<BatteryDeligreenRecord>();
}
private static Boolean MustDoCalibrationCharge(this StatusRecord statusRecord)
{
var calibrationChargeForced = statusRecord.Config.ForceCalibrationChargeState;
var additionalCalibrationRequired = AdditionalCalibrationDateHasBeenPassed(statusRecord.Config.DayAndTimeForAdditionalCalibration);
var repetitiveCalibrationRequired = RepetitiveCalibrationDateHasBeenPassed(statusRecord.Config.DayAndTimeForRepetitiveCalibration);
var mustDoCalibrationCharge = calibrationChargeForced == CalibrationChargeType.ChargePermanently ||
(calibrationChargeForced == CalibrationChargeType.AdditionallyOnce && additionalCalibrationRequired) ||
(calibrationChargeForced == CalibrationChargeType.RepetitivelyEvery && repetitiveCalibrationRequired);
Console.WriteLine("Next Repetitive calibration charge date is "+ statusRecord.Config.DayAndTimeForRepetitiveCalibration);
Console.WriteLine("Next Additional calibration charge date is "+ statusRecord.Config.DayAndTimeForAdditionalCalibration);
if (statusRecord.Battery is not null)
{
if (calibrationChargeForced == CalibrationChargeType.AdditionallyOnce && statusRecord.Battery.Eoc )
{
statusRecord.Config.ForceCalibrationChargeState = CalibrationChargeType.RepetitivelyEvery;
}
else if (calibrationChargeForced == CalibrationChargeType.RepetitivelyEvery && statusRecord.Battery.Eoc && _hasRepetitiveCalibrationChargeChecked)
{
statusRecord.Config.DayAndTimeForRepetitiveCalibration = statusRecord.Config.DayAndTimeForRepetitiveCalibration.AddDays(7);
_hasRepetitiveCalibrationChargeChecked = false;
}
}
return mustDoCalibrationCharge;
}
private static Boolean RepetitiveCalibrationDateHasBeenPassed(DateTime calibrationChargeDate)
{
if (DateTime.Now >= calibrationChargeDate )
{
_hasRepetitiveCalibrationChargeChecked = true;
return true;
}
return false;
}
private static Boolean AdditionalCalibrationDateHasBeenPassed(DateTime calibrationChargeDate)
{
if (DateTime.Now >= calibrationChargeDate )
{
return true;
}
return false;
}
private static Double ControlGridPower(this StatusRecord status, Double targetPower)
{
return ControlPower

View File

@ -68,8 +68,7 @@ internal static class Program
private const UInt16 NbrOfFileToConcatenate = 30; // add this to config file
private static UInt16 _fileCounter = 0;
private static SalimaxAlarmState _salimaxAlarmState = SalimaxAlarmState.Green;
private const String Port = "/dev/ttyUSB0";
private static Boolean _oneTimeFlag = false;
private const String Port = "/dev/ttyUSB0"; // move to a config file
static Program()
{
@ -314,108 +313,28 @@ internal static class Program
var bAlarmList = new List<String>();
var bWarningList = new List<String>();
if (record.Battery != null)
{
//_oneTimeFlag.WriteLine(" onetime flag");
if (record.Battery?.MonomerHighVoltageAlarm == true /*&& !_oneTimeFlag*/) //this should be checked: the number 0
{
//_oneTimeFlag = true;
warningList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Charging Battery System",
Description = "dynCCL Active: Max Battery Charging is 10 * N"
});
}
/* if (record.Battery?.MonomerLowVoltageAlarm == true && !_oneTimeFlag) //this should be checked: the number 10
{
_oneTimeFlag = true;
warningList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Battery System",
Description = "dynDCL Active: Max Battery Discharging is 10 * N"
});
}
else
{
_oneTimeFlag = false;
}*/
if (record.Battery is { MonomerHighVoltageAlarm: true })
{
warningList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Charging Battery System",
Description = "dynCCL Active: Max Battery Charging is 10 * N"
});
}
if (record.Battery is { MonomerLowVoltageAlarm: true })
{
warningList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Battery System",
Description = "dynDCL Active: Max Battery Discharging is 10 * N"
});
}
/*
if (record.Battery != null)
{
var i = 0;
foreach (var battery in record.Battery.Devices)
{
var devicesBatteryNode = record.Config.Devices.BatteryNodes[i];
if (battery.LimpBitMap == 0)
{
// "All String are Active".WriteLine();
}
else if (IsPowerOfTwo(battery.LimpBitMap))
{
"1 String is disabled".WriteLine();
Console.WriteLine(" ****************** ");
warningList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Battery node" + devicesBatteryNode,
Description = "1 String is disabled"
});
bWarningList.Add("/"+i+1 + "/1 String is disabled"); // battery id instead ( i +1 ) of node id: requested from the frontend
}
else
{
"2 or more string are disabled".WriteLine();
Console.WriteLine(" ****************** ");
alarmList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Battery node" + devicesBatteryNode,
Description = "2 or more string are disabled"
});
bAlarmList.Add(i +";2 or more string are disabled");
}
foreach (var warning in record.Battery.Warnings)
{
warningList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Battery node" + devicesBatteryNode,
Description = warning
});
bWarningList.Add(i +";" + warning);
}
foreach (var alarm in battery.Alarms)
{
alarmList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Battery node" + devicesBatteryNode,
Description = alarm
});
bWarningList.Add(i +";" + alarm);
}
i++;
}
}*/
if (alarmCondition is not null)
if (alarmCondition is not null)
{
alarmCondition.WriteLine();
@ -428,49 +347,33 @@ internal static class Program
});
}
foreach (var alarm in record.AcDc.Alarms)
{
alarmList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "AcDc",
Description = alarm.ToString()
});
}
alarmList.AddRange(record.AcDc.Alarms
.Select(alarm => new AlarmOrWarning
{ Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "AcDc",
Description = alarm.ToString() }));
foreach (var alarm in record.DcDc.Alarms)
{
alarmList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "DcDc",
Description = alarm.ToString()
});
}
alarmList.AddRange(record.DcDc.Alarms
.Select(alarm => new AlarmOrWarning
{ Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "DcDc",
Description = alarm.ToString() }));
foreach (var warning in record.AcDc.Warnings)
{
warningList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "AcDc",
Description = warning.ToString()
});
}
warningList.AddRange(record.AcDc.Warnings
.Select(warning => new AlarmOrWarning
{ Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "AcDc",
Description = warning.ToString() }));
foreach (var warning in record.DcDc.Warnings)
{
warningList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "DcDc",
Description = warning.ToString()
});
}
warningList.AddRange(record.DcDc.Warnings
.Select(warning => new AlarmOrWarning
{ Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "DcDc",
Description = warning.ToString() }));
_salimaxAlarmState = warningList.Any()
? SalimaxAlarmState.Orange
@ -480,7 +383,7 @@ internal static class Program
? SalimaxAlarmState.Red
: _salimaxAlarmState; // this will be replaced by LedState
TryParse(s3Bucket?.Split("-")[0], out var installationId);
var installationId = GetInstallationId(s3Bucket ?? string.Empty);
var returnedStatus = new StatusMessage
{
@ -494,7 +397,13 @@ internal static class Program
return returnedStatus;
}
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
}
private static String? DetectAlarmStates(this StatusRecord r) => r.Relays switch
{
{ K2ConnectIslandBusToGridBus: false, K2IslandBusIsConnectedToGridBus: true } => " Contradiction: R0 is opening the K2 but the K2 is still close ",
@ -553,7 +462,7 @@ internal static class Program
}
else
{
maxBatteryChargingCurrentLiveByDcDc = 0;
maxBatteryChargingCurrentLiveByDcDc = 0;
maxBatteryDischargingCurrentLivebyDcDc = 0;
}
inverters.ForEach(d => d.Control.Dc.MaxVoltage = devicesConfig.AcDc.MaxDcLinkVoltage);
@ -1001,15 +910,16 @@ internal static class Program
status.Config.MinSoc = config.MinimumSoC;
status.Config.GridSetPoint = config.GridSetPoint * 1000; // converted from kW to W
// status.Config.ForceCalibrationChargeState = config.CalibrationChargeState;
//
// if (config.CalibrationChargeState == CalibrationChargeType.RepetitivelyEvery)
// {
// status.Config.DayAndTimeForRepetitiveCalibration = config.CalibrationChargeDate;
// }
// else if (config.CalibrationChargeState == CalibrationChargeType.AdditionallyOnce)
// {
// status.Config.DayAndTimeForAdditionalCalibration = config.CalibrationChargeDate;
// }
status.Config.ForceCalibrationChargeState = config.CalibrationChargeState;
if (config.CalibrationChargeState == CalibrationChargeType.RepetitivelyEvery)
{
status.Config.DayAndTimeForRepetitiveCalibration = config.CalibrationChargeDate;
}
else if (config.CalibrationChargeState == CalibrationChargeType.AdditionallyOnce)
{
status.Config.DayAndTimeForAdditionalCalibration = config.CalibrationChargeDate;
}
}
}