This commit is contained in:
2025-12-17 14:58:09 +08:00
parent 325b24c99f
commit 51e4d5add4
5 changed files with 434 additions and 31 deletions

View File

@@ -955,7 +955,6 @@ namespace OrpaonEMS.App.Services
/// <summary>
/// 在线客户端个数
///
/// </summary>
public ushort OnLineClientNum { get; set; }

View File

@@ -139,8 +139,6 @@ namespace OrpaonEMS.App.Services
SolarCurBackFlow.TrigTimeOutHandler += SolarCurBackFlow_TrigTimeOutHandler;
}
}
/// <summary>
@@ -2300,6 +2298,130 @@ namespace OrpaonEMS.App.Services
set { _SlaveControlMsg = value; RaisePropertyChanged(); }
}
private double _SolarToEsAsFullSoc = 97;
/// <summary>
/// 光伏给储能充电 作为满的比值
/// 90-97
/// </summary>
public double SolarToEsAsFullSoc
{
get { return _SolarToEsAsFullSoc; }
set { _SolarToEsAsFullSoc = value; RaisePropertyChanged(); }
}
private double _Master_ToSlaveByMasterSoc = 5;
/// <summary>
/// Master模式切换到Slave模式时MasterSOC的阀值
/// 两个同时考虑
/// </summary>
public double Master_ToSlaveByMasterSoc
{
get { return _Master_ToSlaveByMasterSoc; }
set { _Master_ToSlaveByMasterSoc = value; RaisePropertyChanged(); }
}
private double _Master_ToSlaveBySlaveSoc = 15;
/// <summary>
/// Master模式切换到Slave模式时Slave SOC的阀值
/// 两个同时考虑
/// </summary>
public double Master_ToSlaveBySlaveSoc
{
get { return _Master_ToSlaveBySlaveSoc; }
set { _Master_ToSlaveBySlaveSoc = value; RaisePropertyChanged(); }
}
private double _Master_SolarToSlaveEsFullByMasterSoc = 95;
/// <summary>
/// Master模式光伏给从储能充满了是否切换到Slave模式但是此时需要判断主储能MasterSOC是否满了主储能也满的话也无法接收光伏的电否则不切换
/// 主要考虑尽可能的不浪费光伏的电,主从储能只要有余量就要接受光伏的电,也要防止频繁的切换
/// < SolarToEsAsFullSoc
/// </summary>
public double Master_SolarToSlaveEsFullByMasterSoc
{
get { return _Master_SolarToSlaveEsFullByMasterSoc; }
set { _Master_SolarToSlaveEsFullByMasterSoc = value; RaisePropertyChanged(); }
}
private double _Slave_ToMasterBySlaveSoc = 5;
/// <summary>
/// Slave模式切换到Master模式时SOC的阀值
/// 两个同时考虑
/// </summary>
public double Slave_ToMasterBySlaveSoc
{
get { return _Slave_ToMasterBySlaveSoc; }
set { _Slave_ToMasterBySlaveSoc = value; RaisePropertyChanged(); }
}
private double _Slave_ToMasterByMasterSoc = 15;
/// <summary>
/// Slave模式切换到Master模式时SOC的阀值
/// 两个同时考虑
/// </summary>
public double Slave_ToMasterByMasterSoc
{
get { return _Slave_ToMasterByMasterSoc; }
set { _Slave_ToMasterByMasterSoc = value; RaisePropertyChanged(); }
}
private double _Slave_SolarToMasterEsFullBySlaverSoc = 95;
/// <summary>
/// Slave模式光伏给主储能充满了是否切换到Master模式但是此时需要判断从储能SOC是否满了从储能也满的话也无法接收光伏的电否则不切换
/// 主要考虑尽可能的不浪费光伏的电,主从储能只要有余量就要接受光伏的电,也要防止频繁的切换
/// < SolarToEsAsFullSoc
/// </summary>
public double Slave_SolarToMasterEsFullBySlaverSoc
{
get { return _Slave_SolarToMasterEsFullBySlaverSoc; }
set { _Slave_SolarToMasterEsFullBySlaverSoc = value; RaisePropertyChanged(); }
}
private double _NightMaster_ToMasterFullSoc = 98;
/// <summary>
/// 晚上,主储能充满的标志,也是切换到从储能的控制标志
/// </summary>
public double NightMaster_ToMasterFullSoc
{
get { return _NightMaster_ToMasterFullSoc; }
set { _NightMaster_ToMasterFullSoc = value; RaisePropertyChanged(); }
}
private double _NightSlave_ToSlaveFullSoc = 98;
/// <summary>
/// 晚上,从储能充满的标志,也是切换到主储能的控制标志
/// </summary>
public double NightSlave_ToSlaveFullSoc
{
get { return _NightSlave_ToSlaveFullSoc; }
set { _NightSlave_ToSlaveFullSoc = value; RaisePropertyChanged(); }
}
private string _LogicMsg;
/// <summary>
/// 逻辑消息
/// </summary>
public string LogicMsg
{
get { return _LogicMsg; }
set
{
if (value != _LogicMsg)
{
RaisePropertyChanged();
_LogicMsg = value;
}
}
}
/// <summary>
/// 逻辑扫描1
@@ -2708,7 +2830,8 @@ namespace OrpaonEMS.App.Services
//依据当前的状态判断是否需要切换到其他状态
switch (CurESChargInfo)
{
case ESChargInfo.Master:
case ESChargInfo.Master://当前是白天Master状态
///////////////////////////获取当前的是白天还是夜晚,依据时间判断,留有余量,有可能实际已经晚上了,但是负载全部没有了
if (IsBetweenTime(DateTime.Now.ToString(), SunriseTimeStr, SunsetTimeStr))
{
@@ -2722,27 +2845,52 @@ namespace OrpaonEMS.App.Services
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Master】-Master->Night_Master 白天Master 到晚上Night_Master的切换");
DayNight = DayNightEnum.Night;
PreESChargInfo = ESChargInfo.Night_Master;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
//var SolarCur = SolarEleMeter3.RtPw + SolarEleMeter2.RtPw;
//根据日落和日出时间判断当前是晚上
continue;
}
//判断光伏把储能是否充满,充满的话进入无光伏阶段 新策略
if (SlaveClient.ClientInfo!.SOC >= 97)
//?????? 如果昨晚充满了,今天的话,早上就要进入到无光伏的模式了,因为两个都满了 ,设置的数据不要太冲突
//从储能箱晚上充电的SOC NightSlave_ToSlaveFullSoc 90 > SolarToEsAsFullSoc 97
//
//能到这里说明是白天,也要判断光伏把储能是否充满,充满的话进入无光伏阶段 新策略 是否可以切换
if (SlaveClient.ClientInfo!.SOC >= SolarToEsAsFullSoc)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Master】-光伏把从储能充满SOC:{SlaveClient.ClientInfo!.SOC},充满的话进入无光伏阶段 新策略");
PreESChargInfo = ESChargInfo.NoSolar;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
continue;
//光伏把从储能充满,此时需要判断主储能是否满,满的话就是都满了进入无光伏阶段
if (MasterClient.ClientInfo!.SOC >= Master_SolarToSlaveEsFullByMasterSoc)
{
//两个储能都满了,进行切换
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Master】-光伏把【从储能】充满SOC:{SlaveClient.ClientInfo!.SOC},主储能也满了,充满的话进入无光伏阶段 新策略");
PreESChargInfo = ESChargInfo.NoSolar;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
continue;
}
else
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Master】-从储能箱体被光伏充满SOC:{SlaveClient.ClientInfo!.SOC},主储能箱体还有余量:{MasterClient.ClientInfo!.SOC}切换到Slave让主储能箱接受光伏电量");
//主储能箱体放完,从储能箱体还有电,则可以切换
//先进入等待状态,为切换准备条件
PreESChargInfo = ESChargInfo.Slave;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
continue;
}
}
//主储能箱体放完为止策略 新策略
if (MasterClient.ClientInfo!.SOC <= 5)
if (MasterClient.ClientInfo!.SOC <= Master_ToSlaveByMasterSoc)
{
//此时切换到从储能箱体需要查看从储能箱体的SOC
if (SlaveClient.ClientInfo!.SOC >= 15)
if (SlaveClient.ClientInfo!.SOC >= Master_ToSlaveBySlaveSoc)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Master】-主储能箱体放完SOC:{MasterClient.ClientInfo!.SOC}从储能箱体还有电SOC:{SlaveClient.ClientInfo!.SOC}切换到Slave");
@@ -2750,15 +2898,18 @@ namespace OrpaonEMS.App.Services
//先进入等待状态,为切换准备条件
PreESChargInfo = ESChargInfo.Slave;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
continue;
}
else
{
LogicMsg = "主储能箱电放完,从储能箱还有电,暂不切换,维持当前状态";
//主储能箱体放完,从储能箱体也没有电,维持当前状态
}
}
else
{
//主储能箱维持当前的状态,
LogicMsg = "主储能箱电没有放完,维持当前状态";
}
@@ -2810,30 +2961,49 @@ namespace OrpaonEMS.App.Services
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Slave】-Slave->Night_Master 白天Slave 到晚上Night_Master的切换");
DayNight = DayNightEnum.Night;
PreESChargInfo = ESChargInfo.Night_Master;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
//var SolarCur = SolarEleMeter3.RtPw + SolarEleMeter2.RtPw;
//根据日落和日出时间判断当前是晚上
continue;
}
//判断光伏把储能是否充满,充满的话进入无光伏阶段 新策略
if (MasterClient.ClientInfo!.SOC >= 97)
//判断光伏把储能是否充满,充满的话进入无光伏阶段 新策略
if (MasterClient.ClientInfo!.SOC >= SolarToEsAsFullSoc)
{
//判断从储能箱放电程度
if (SlaveClient.ClientInfo!.SOC >= Slave_SolarToMasterEsFullBySlaverSoc)
{
//主从储能箱都充满了,无论出于什么原因,都不应该让光伏发电了,进入无光伏阶段
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Slave】-光伏把主储能充满SOC:{MasterClient.ClientInfo!.SOC},充满的话进入无光伏阶段 新策略");
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Slave】-光伏把主储能充满SOC:{MasterClient.ClientInfo!.SOC},充满的话进入无光伏阶段 新策略");
PreESChargInfo = ESChargInfo.NoSolar;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
continue;
PreESChargInfo = ESChargInfo.NoSolar;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
continue;
}
else
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Slave】-主储能箱体被光伏充满SOC:{MasterClient.ClientInfo!.SOC},从储能箱体还有余量:{SlaveClient.ClientInfo!.SOC}切换到Master让从储能箱接受光伏电量");
//主储能箱体放完,从储能箱体还有电,则可以切换
//先进入等待状态,为切换准备条件
PreESChargInfo = ESChargInfo.Master;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
continue;
}
}
//储能箱体放完为止策略 新策略
if (SlaveClient.ClientInfo!.SOC <= 5)
//储能箱体放完为止策略 新策略
if (SlaveClient.ClientInfo!.SOC <= Slave_ToMasterBySlaveSoc)
{
//此时切换到从储能箱体需要查看从储能箱体的SOC
if (MasterClient.ClientInfo!.SOC >= 15)
if (MasterClient.ClientInfo!.SOC >= Slave_ToMasterByMasterSoc)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Slave】-从储能箱体放完SOC:{SlaveClient.ClientInfo!.SOC}主储能箱体还有电SOC:{MasterClient.ClientInfo!.SOC}切换到Master");
@@ -2841,15 +3011,18 @@ namespace OrpaonEMS.App.Services
//先进入等待状态,为切换准备条件
PreESChargInfo = ESChargInfo.Master;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
continue;
}
else
{
//主储能箱体放完,从储能箱体也没有电,维持当前状态
LogicMsg = "从储能箱电放完,主储能箱还有电,暂不切换,维持当前状态";
}
}
else
{
//主储能箱维持当前的状态
//主储能箱维持当前的状态
LogicMsg = "从储能箱电没有放完,维持当前状态";
}
@@ -2904,12 +3077,12 @@ namespace OrpaonEMS.App.Services
//晚上切换到白天的话直接到Master模式
PreESChargInfo = ESChargInfo.Master;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
continue;
}
else
{
//可能转到Night_Slave模式本身充满Night没有充满
if (MasterClient.ClientInfo!.SOC >= ConfigDataService.energyStorageRunConfig.BMSSocUpSignLimitValue && SlaveClient.ClientInfo!.SOC <= 55)
if (MasterClient.ClientInfo!.SOC >= NightMaster_ToMasterFullSoc && SlaveClient.ClientInfo!.SOC <= (NightSlave_ToSlaveFullSoc - 10))
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Night_Master】-主储能箱体充满SOC:{MasterClient.ClientInfo!.SOC}从储能箱体SOC:{SlaveClient.ClientInfo!.SOC}切换到Night_Slave");
@@ -2917,12 +3090,15 @@ namespace OrpaonEMS.App.Services
//切换到Night_Slave模式
PreESChargInfo = ESChargInfo.Night_Slave;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
continue;
}
else
{
//继续维持当前的状态
MasterControlMsg = "【主储能】夜晚充电";
SlaveControlMsg = "【从储能】夜晚待机";
LogicMsg = "【主储能】夜晚充电,【从储能】夜晚待机";
}
}
@@ -2950,7 +3126,7 @@ namespace OrpaonEMS.App.Services
else
{
//可能转到Night_Master模式本身充到SOC=60算充满
if (SlaveClient.ClientInfo!.SOC >= 90 && MasterClient.ClientInfo!.SOC <= ConfigDataService.energyStorageRunConfig.BMSSocUpSignLimitValue * 0.9)
if (SlaveClient.ClientInfo!.SOC >= NightSlave_ToSlaveFullSoc && MasterClient.ClientInfo!.SOC <= (NightMaster_ToMasterFullSoc - 10))
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【Night_Slave】-从储能箱体充满SOC:{SlaveClient.ClientInfo!.SOC}主储能箱体SOC:{MasterClient.ClientInfo!.SOC}切换到Night_Master");
//切换到Night_Slave模式
@@ -2962,10 +3138,13 @@ namespace OrpaonEMS.App.Services
//继续维持当前的状态
MasterControlMsg = "【主储能】夜晚待机";
SlaveControlMsg = "【从储能】夜晚充电";
LogicMsg = "【主储能】夜晚待机,【从储能】夜晚充电";
}
}
break;
case ESChargInfo.Wait:
LogicMsg = "模式切换中";
//切换中
break;
case ESChargInfo.NoSolar:
@@ -2983,8 +3162,10 @@ namespace OrpaonEMS.App.Services
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【NoSolar】-NoSolar->Night_Master NoSolar切换晚上Night_Master");
DayNight = DayNightEnum.Night;
PreESChargInfo = ESChargInfo.Night_Master;
SysRunStateMachine.Fire(ESChargInfoTrig.WaitTrig);
//var SolarCur = SolarEleMeter3.RtPw + SolarEleMeter2.RtPw;
//根据日落和日出时间判断当前是晚上
continue;
@@ -2992,7 +3173,7 @@ namespace OrpaonEMS.App.Services
//用Soc小的吸收光伏能量
if (SlaveClient.ClientInfo!.SOC <= 50)
if (SlaveClient.ClientInfo!.SOC <= (SolarToEsAsFullSoc-10))
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【NoSolar】-从储能箱体SOC:{SlaveClient.ClientInfo!.SOC}主储能箱体SOC:{MasterClient.ClientInfo!.SOC}切换到Master");
@@ -3002,7 +3183,7 @@ namespace OrpaonEMS.App.Services
continue;
}
if (MasterClient.ClientInfo!.SOC <= 50)
if (MasterClient.ClientInfo!.SOC <= (SolarToEsAsFullSoc - 10))
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-当前是【NoSolar】-从储能箱体SOC:{SlaveClient.ClientInfo!.SOC}主储能箱体SOC:{MasterClient.ClientInfo!.SOC}切换到Slave");
@@ -3434,12 +3615,29 @@ namespace OrpaonEMS.App.Services
/// </summary>
private string SunsetTimeStr { get; set; } = "23:00";
//public DayNightEnum DayNight { get; set; }
private DayNightEnum _DayNight;
/// <summary>
/// 白天和晚上
/// Day
/// Night
/// </summary>
public DayNightEnum DayNight { get; set; }
public DayNightEnum DayNight
{
get { return _DayNight; }
set
{
if (_DayNight != value)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【动作】-【DayNight】-【{_DayNight.ToString()}】->【{value.ToString()}】 白天和晚上的切换");
_DayNight = value;
}
}
}
/// <summary>
/// 开关1