光伏无法自动起来的问题
This commit is contained in:
@@ -269,12 +269,156 @@ namespace OrpaonEMS.App.Services
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private void SolarCurBackFlow_TrigTimeOutHandler(object? sender, EventArgs e)
|
||||
{
|
||||
//关闭光伏
|
||||
CloseSolar();
|
||||
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}-【月浦】- 软件检测到光伏逆流,关闭光伏逆变器 ");
|
||||
var now = DateTime.Now;
|
||||
_solarBackflowClosePending = true;
|
||||
_lastSolarBackflowCloseTime = now;
|
||||
_solarRecoverImportTrigActive = false;
|
||||
_solarRecoverImportTrigStartTime = DateTime.MinValue;
|
||||
|
||||
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-软件检测到光伏逆流,关闭光伏逆变器");
|
||||
var closeOk = TryCloseSolarThrottled($"逆流触发-并网点功率:{SolarEleMeter5.RtPw}");
|
||||
Console.WriteLine($"时间:{now.ToString("yyyy-MM-dd HH:mm:ss")}-【月浦】- 软件检测到光伏逆流,关闭光伏逆变器 ");
|
||||
LogService.Info($"时间:{now}-【动作】-软件检测到光伏逆流,关闭光伏逆变器,关闭结果:{closeOk},状态:{CurESChargInfo},并网点功率:{SolarEleMeter5.RtPw}");
|
||||
}
|
||||
|
||||
private const int SolarRecoverCooldownSeconds = 60;
|
||||
private const int SolarCmdMinIntervalSeconds = 3;
|
||||
|
||||
private DateTime _lastSolarBackflowCloseTime = DateTime.MinValue;
|
||||
private bool _solarBackflowClosePending = false;
|
||||
private DateTime _lastSolarOpenCmdTime = DateTime.MinValue;
|
||||
private DateTime _lastSolarCloseCmdTime = DateTime.MinValue;
|
||||
private bool _solarRecoverImportTrigActive = false;
|
||||
private DateTime _solarRecoverImportTrigStartTime = DateTime.MinValue;
|
||||
|
||||
/// <summary>
|
||||
/// 判断逆流触发关闭后,是否已经过了冷却时间,允许再次尝试启动光伏。
|
||||
/// </summary>
|
||||
/// <returns>True 表示允许尝试启动光伏</returns>
|
||||
private bool IsSolarOpenAllowedAfterBackflowCooldown()
|
||||
{
|
||||
if (!_solarBackflowClosePending)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return (DateTime.Now - _lastSolarBackflowCloseTime).TotalSeconds >= SolarRecoverCooldownSeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下发启动光伏命令(带节流与异常捕获)。
|
||||
/// </summary>
|
||||
/// <param name="reason">触发原因,用于日志定位</param>
|
||||
/// <returns>命令写入成功返回 True,否则返回 False</returns>
|
||||
private bool TryOpenSolarThrottled(string reason)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
if ((now - _lastSolarOpenCmdTime).TotalSeconds < SolarCmdMinIntervalSeconds)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_lastSolarOpenCmdTime = now;
|
||||
try
|
||||
{
|
||||
var ok = OpenSolar();
|
||||
if (ok)
|
||||
{
|
||||
LogService.Info($"时间:{now}-【光伏启动】-已下发启动命令,原因:{reason},状态:{CurESChargInfo},并网点功率:{SolarEleMeter5.RtPw},通信:{SolarLinkState}");
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
LogService.Info($"时间:{now}-【光伏启动】-失败,原因:{reason},状态:{CurESChargInfo},并网点功率:{SolarEleMeter5.RtPw},通信:{SolarLinkState}");
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Info($"时间:{now}-【光伏启动】-异常,原因:{reason},状态:{CurESChargInfo},{ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryCloseSolarThrottled(string reason)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
if ((now - _lastSolarCloseCmdTime).TotalSeconds < SolarCmdMinIntervalSeconds)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_lastSolarCloseCmdTime = now;
|
||||
try
|
||||
{
|
||||
var ok = CloseSolar();
|
||||
if (!ok)
|
||||
{
|
||||
LogService.Info($"时间:{now}-【光伏关闭】-失败,原因:{reason},状态:{CurESChargInfo},并网点功率:{SolarEleMeter5.RtPw},通信:{SolarLinkState}");
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Info($"时间:{now}-【光伏关闭】-异常,原因:{reason},状态:{CurESChargInfo},{ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 逆流触发关闭光伏后的自动恢复逻辑。
|
||||
/// 目标:避免光伏长期处于关闭状态造成发电损失。
|
||||
/// </summary>
|
||||
private void TryAutoRecoverSolarAfterBackflow()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_solarBackflowClosePending)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!YuPuAutoHand)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurESChargInfo != ESChargInfo.Master && CurESChargInfo != ESChargInfo.Slave)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var now = DateTime.Now;
|
||||
if (!IsSolarOpenAllowedAfterBackflowCooldown())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckSolarState())
|
||||
{
|
||||
_solarBackflowClosePending = false;
|
||||
LogService.Info($"时间:{now}-【光伏自动恢复】-已检测到光伏处于运行状态,清除待恢复标志,状态:{CurESChargInfo},并网点功率:{SolarEleMeter5.RtPw}");
|
||||
return;
|
||||
}
|
||||
|
||||
var openOk = TryOpenSolarThrottled($"逆流后自动恢复-并网点功率:{SolarEleMeter5.RtPw}");
|
||||
LogService.Info($"时间:{now}-【光伏自动恢复】-尝试启动光伏,结果:{openOk},状态:{CurESChargInfo},并网点功率:{SolarEleMeter5.RtPw}");
|
||||
|
||||
if (openOk)
|
||||
{
|
||||
_solarBackflowClosePending = false;
|
||||
_solarRecoverImportTrigActive = false;
|
||||
_solarRecoverImportTrigStartTime = DateTime.MinValue;
|
||||
}
|
||||
|
||||
if (CheckSolarState())
|
||||
{
|
||||
_solarBackflowClosePending = false;
|
||||
LogService.Info($"时间:{now}-【光伏自动恢复】-光伏已恢复运行,状态:{CurESChargInfo},并网点功率:{SolarEleMeter5.RtPw}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Info($"时间:{DateTime.Now}-【光伏自动恢复】-异常,状态:{CurESChargInfo},{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -286,6 +430,8 @@ namespace OrpaonEMS.App.Services
|
||||
/// </summary>
|
||||
public StateMachine<ESChargInfo, ESChargInfoTrig> SysRunStateMachine { get; set; }
|
||||
|
||||
private DateTime _lastAutoAlarmResetTime = DateTime.MinValue;
|
||||
|
||||
///// <summary>
|
||||
///// 夜间充电模型信息
|
||||
///// 标记白天放电信息
|
||||
@@ -320,7 +466,7 @@ namespace OrpaonEMS.App.Services
|
||||
.Permit(ESChargInfoTrig.WaitTrig, ESChargInfo.Wait)
|
||||
.Permit(ESChargInfoTrig.NoSolarTrig, ESChargInfo.NoSolar)
|
||||
.Ignore(ESChargInfoTrig.MasterTrig)
|
||||
.OnEntry(() => EntryMaster())
|
||||
.OnEntry(() => EntryWithAutoAlarmReset(ESChargInfo.Master, EntryMaster))
|
||||
.OnExit(() => ExitMaster());
|
||||
|
||||
//Slave 状态
|
||||
@@ -331,7 +477,7 @@ namespace OrpaonEMS.App.Services
|
||||
.Permit(ESChargInfoTrig.WaitTrig, ESChargInfo.Wait)
|
||||
.Permit(ESChargInfoTrig.NoSolarTrig, ESChargInfo.NoSolar)
|
||||
.Ignore(ESChargInfoTrig.SlaveTrig)
|
||||
.OnEntry(() => EntrySlave())
|
||||
.OnEntry(() => EntryWithAutoAlarmReset(ESChargInfo.Slave, EntrySlave))
|
||||
.OnExit(() => ExitSlave());
|
||||
|
||||
//Night_Master 状态
|
||||
@@ -342,7 +488,7 @@ namespace OrpaonEMS.App.Services
|
||||
.Permit(ESChargInfoTrig.WaitTrig, ESChargInfo.Wait)
|
||||
.Permit(ESChargInfoTrig.NoSolarTrig, ESChargInfo.NoSolar)
|
||||
.Ignore(ESChargInfoTrig.Night_MasterTrig)
|
||||
.OnEntry(() => EntryNight_Master())
|
||||
.OnEntry(() => EntryWithAutoAlarmReset(ESChargInfo.Night_Master, EntryNight_Master))
|
||||
.OnExit(() => ExitNight_Master());
|
||||
|
||||
//Night_Slave 状态
|
||||
@@ -353,7 +499,7 @@ namespace OrpaonEMS.App.Services
|
||||
.Permit(ESChargInfoTrig.NoSolarTrig, ESChargInfo.NoSolar)
|
||||
.Permit(ESChargInfoTrig.Night_MasterTrig, ESChargInfo.Night_Master)
|
||||
.Ignore(ESChargInfoTrig.Night_SlaveTrig)
|
||||
.OnEntry(() => EntryNight_Slave())
|
||||
.OnEntry(() => EntryWithAutoAlarmReset(ESChargInfo.Night_Slave, EntryNight_Slave))
|
||||
.OnExit(() => ExitNight_Slave());
|
||||
|
||||
//Wait 状态
|
||||
@@ -364,7 +510,7 @@ namespace OrpaonEMS.App.Services
|
||||
.Permit(ESChargInfoTrig.Night_SlaveTrig, ESChargInfo.Night_Slave)
|
||||
.Permit(ESChargInfoTrig.NoSolarTrig, ESChargInfo.NoSolar)
|
||||
.Ignore(ESChargInfoTrig.WaitTrig)
|
||||
.OnEntry(() => EntryWait())
|
||||
.OnEntry(() => EntryWithAutoAlarmReset(ESChargInfo.Wait, EntryWait))
|
||||
.OnExit(() => ExitWait());
|
||||
|
||||
//NoSolar 状态
|
||||
@@ -375,13 +521,63 @@ namespace OrpaonEMS.App.Services
|
||||
.Permit(ESChargInfoTrig.Night_SlaveTrig, ESChargInfo.Night_Slave)
|
||||
.Permit(ESChargInfoTrig.WaitTrig, ESChargInfo.Wait)
|
||||
.Ignore(ESChargInfoTrig.NoSolarTrig)
|
||||
.OnEntry(() => EntryNoSolar())
|
||||
.OnEntry(() => EntryWithAutoAlarmReset(ESChargInfo.NoSolar, EntryNoSolar))
|
||||
.OnExit(() => ExitNoSolar());
|
||||
|
||||
PreESChargInfo = ESChargInfo.Master;
|
||||
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
|
||||
}
|
||||
|
||||
private void EntryWithAutoAlarmReset(ESChargInfo enteringState, Action entryAction)
|
||||
{
|
||||
TryAutoResetBmsAndPcsAlarms($"进入状态:{enteringState}", enteringState);
|
||||
entryAction();
|
||||
}
|
||||
|
||||
private void TryAutoResetBmsAndPcsAlarms(string reason, ESChargInfo enteringState)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!YuPuAutoHand)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var now = DateTime.Now;
|
||||
if ((now - _lastAutoAlarmResetTime).TotalSeconds < 30)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastAutoAlarmResetTime = now;
|
||||
|
||||
bool pcsResetOk = false;
|
||||
try
|
||||
{
|
||||
pcsResetOk = InPowerPCSDataService.PCSFaultReset();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Info($"时间:{DateTime.Now}-【报警复位】-PCS复位异常,原因:{reason},状态:{enteringState},{ex.Message}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
BmsDataService.BmsAlarmReset();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Info($"时间:{DateTime.Now}-【报警复位】-BMS复位异常,原因:{reason},状态:{enteringState},{ex.Message}");
|
||||
}
|
||||
|
||||
LogService.Info($"时间:{DateTime.Now}-【报警复位】-已触发复位,原因:{reason},状态:{enteringState},PCS复位结果:{pcsResetOk}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Info($"时间:{DateTime.Now}-【报警复位】-复位流程异常,原因:{reason},状态:{enteringState},{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 进入 NoSolar
|
||||
/// </summary>
|
||||
@@ -420,7 +616,7 @@ namespace OrpaonEMS.App.Services
|
||||
//关闭光伏
|
||||
if (CheckSolarState() == true)
|
||||
{
|
||||
CloseSolar();
|
||||
TryCloseSolarThrottled("EntryNoSolar");
|
||||
}
|
||||
|
||||
TaxRealPw = SolarEleMeter5.AvePw - SolarEleMeter3.AvePw;//光伏和市电供应给税务大楼的负载
|
||||
@@ -615,7 +811,7 @@ namespace OrpaonEMS.App.Services
|
||||
if (CheckSolarState() == true)
|
||||
{
|
||||
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-【Wait】状态-光伏不满足条件,关闭光伏");
|
||||
CloseSolar();
|
||||
TryCloseSolarThrottled("EntryWait");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,9 +1227,9 @@ namespace OrpaonEMS.App.Services
|
||||
}
|
||||
|
||||
//打开光伏
|
||||
if (CheckSolarState() == false)
|
||||
if (CheckSolarState() == false && IsSolarOpenAllowedAfterBackflowCooldown())
|
||||
{
|
||||
OpenSolar();
|
||||
TryOpenSolarThrottled("EntrySlave");
|
||||
}
|
||||
|
||||
//循环执行方法
|
||||
@@ -1239,9 +1435,9 @@ namespace OrpaonEMS.App.Services
|
||||
}
|
||||
|
||||
//打开光伏
|
||||
if (CheckSolarState() == false)
|
||||
if (CheckSolarState() == false && IsSolarOpenAllowedAfterBackflowCooldown())
|
||||
{
|
||||
OpenSolar();
|
||||
TryOpenSolarThrottled("EntryMaster");
|
||||
}
|
||||
|
||||
//循环执行方法
|
||||
@@ -2971,6 +3167,8 @@ namespace OrpaonEMS.App.Services
|
||||
continue;
|
||||
}
|
||||
|
||||
TryAutoRecoverSolarAfterBackflow();
|
||||
|
||||
//实时给当前的SOC数据给夜电白放的模型
|
||||
//CurNightChargEleModel.MasterSoc = MasterClient.ClientInfo!.SOC;
|
||||
//CurNightChargEleModel.SlaveSoc = SlaveClient.ClientInfo!.SOC;
|
||||
|
||||
Reference in New Issue
Block a user