Files
YuPu-OrpaonEMS/OrpaonEMS.App/Services/EnergyStorageService.cs
Tyrone CT 325b24c99f 更改了周五和周六晚上不充电
关闭后进程不关闭的操作
Mqtt的发布,关闭这个功能
2025-03-01 00:19:51 +08:00

1657 lines
69 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using HslCommunication.ModBus;
using NLog;
using OrpaonEMS.App.Models;
using OrpaonEMS.Core.DbModel;
using OrpaonEMS.Core.Enums;
using OrpaonEMS.Core;
using Stateless;
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Prism.Mvvm;
using OrpaonEMS.Model;
using OrpaonEMS.Model.Enums;
using Prism.Events;
using OrpaonEMS.App.PrismEvent;
using OrpaonEMS.App.Com;
using NLog.Targets;
using System.Diagnostics.Eventing.Reader;
using HslCommunication.WebSocket;
using HslCommunication;
using OrpaonEMS.Model.MasterSlave;
using System.Text.Json;
using Windows.ApplicationModel.Contacts;
namespace OrpaonEMS.App.Services
{
/// <summary>
/// 储能服务
/// https://blog.csdn.net/zwcslj/article/details/136363261
/// </summary>
public class EnergyStorageService : BindableBase
{
///// <summary>
///// 负载仪表数据
/// 伊顿客户提供的仪表
///// </summary>
//public KEMeter kEMeter { get; set; } = new KEMeter();
/// <summary>
/// 安科瑞仪表数据
/// 储能本身的计量数据
/// </summary>
public AcrelMeterDataService AcrelMeters { get; set; }
public PwAnalyzeService PwAnalyzeService { get; }
///// <summary>
///// 分布式控制
///// 主从站通信
///// </summary>
//public EMSService MasterSlave { get; set; }
/// <summary>
/// NLog服务集合
/// </summary>
public ILogService LogService { get; }
/// <summary>
/// 储能统计分析
/// </summary>
public PwAnalyzeService pwAnalyze { get; set; }
/// <summary>
/// 是否为主站
/// </summary>
public bool IsMaster { get; set; }
/// <summary>
/// 实例化
/// </summary>
public EnergyStorageService(ILogService logService,
BmsDataService bmsDataService,
SolarEnergyService solarEnergyService,
InPowerPCSDataService inPowerPCSDataService,
IFreeSql freeSql,
ACService aCService,
AcrelMeterDataService acrelMeterDataService,
PwAnalyzeService pwAnalyzeService,
ConfigDataService configDataService)
{
//Log服务实例赋值
LogService = logService;
AcrelMeters = acrelMeterDataService;
//获取Bms服务实例
BmsDataService = bmsDataService;
//获取太阳储能的服务
SolarEnergyService = solarEnergyService;
//获取英博PCS服务实例
InPowerPCSDataService = inPowerPCSDataService;
//FreeSQL实例
FreeSql = freeSql;
ACService = aCService;
//ListEnergyStoragePeakValleyTimeConfig = new List<PeakValleyConfig>();
//获取配置服务实例
ConfigDataService = configDataService;
WebUrl = ConfigDataService.ServerUrl;
IsMaster = ConfigDataService.IsMaster;
if (IsMaster)
{
//作为服务时,站号是固定的
ClientStation = 0;
}
else
{
ClientStation = ConfigDataService.Station;
}
CurClientInfo.Station = ClientStation;
//PCS的追踪模型初始值设置为0
InPowerPCSDataService.PwTranceCmdValues.CmdValue = 0;
//伊顿电表服务 特制
//PwMeters = new PwMeter();
//状态机初始化参数配置
StateMachineInitial();
//注入当前的实例
TrigModuleStartRunActions = new TrigModuleStartRunAction(this);
//云服务实例化
////服务实例化
//esModbusTcpServer = new EsModbusTcpServer();
//esModbusTcpServer.StartServer();
//ModbusTcpServerTask = Task.Run(() => ModbusTcpServerCycle());
//mqttClientDrive = new MqttClientDrive("139.224.230.213", "1883", "b1955190-d471-11ee-a961-354c6e00783a", "ter354uyQbK81JF6xWH9", "", "v1/devices/me/telemetry");
//mqttClientDrive.CurMsg = "{\r\n \"stringKey\": \"value1\",\r\n \"booleanKey\": true,\r\n \"doubleKey\": 42.0,\r\n \"longKey\": 73,\r\n \"jsonKey\": {\r\n \"someNumber\": 42,\r\n \"someArray\": [1,2,3],\r\n \"someNestedObject\": {\"key\": \"value\"}\r\n }\r\n}";
//实例化能耗统计分析模型
PwAnalyzeService = pwAnalyzeService;
//pwAnalyze = new PwAnalyze(this, LogService, FreeSql, ConfigDataService);
//MasterSlave = new EMSService(LogService, InPowerPCSDataService, BmsDataService, ConfigDataService, this);
WebSocketClientInit();
}
#region ModbusTcpServer
///// <summary>
///// ModbusTcp服务
///// </summary>
//public EsModbusTcpServer esModbusTcpServer { get; set; } = null;
//public MqttClientDrive mqttClientDrive { get; set; }
///// <summary>
///// ModbusTcp 的服务周期
///// </summary>
//public Task ModbusTcpServerTask = null;
///// <summary>
///// 循环赋值
///// </summary>
///// <returns></returns>
//private async Task ModbusTcpServerCycle()
//{
// Thread.Sleep(10000);
// while (ThreadEnable)
// {
// try
// {
// if (esModbusTcpServer.IsOpenServer())
// {
// //BMS
// esModbusTcpServer.busTcpServer.Write("x=4;1", BmsDataService.ListBMSRoCell.Find(a => a.Name == "电池簇总SOC").SrRtValue);
// esModbusTcpServer.busTcpServer.Write("x=4;2", BmsDataService.ListBMSRoCell.Find(a => a.Name == "电池簇总SOH").SrRtValue);
// esModbusTcpServer.busTcpServer.Write("x=4;3", BmsDataService.ListBMSRoCell.Find(a => a.Name == "电池最高温度").SrRtValue);
// esModbusTcpServer.busTcpServer.Write("x=4;4", BmsDataService.ListBMSRoCell.Find(a => a.Name == "电池最高温度所在模块号").SrRtValue);
// esModbusTcpServer.busTcpServer.Write("x=4;5", BmsDataService.ListBMSRoCell.Find(a => a.Name == "电池最低温度").SrRtValue);
// esModbusTcpServer.busTcpServer.Write("x=4;6", BmsDataService.ListBMSRoCell.Find(a => a.Name == "电池最低温度所在模块号").SrRtValue);
// //PCS
// esModbusTcpServer.busTcpServer.Write("x=4;7", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(InPowerPCSDataService.OperateResultBytes1.Content, 0));
// esModbusTcpServer.busTcpServer.Write("x=4;8", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(InPowerPCSDataService.OperateResultBytes1.Content, 2));
// esModbusTcpServer.busTcpServer.Write("x=4;9", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(InPowerPCSDataService.OperateResultBytes1.Content, 4));
// esModbusTcpServer.busTcpServer.Write("x=4;10", esModbusTcpServer.busTcpServer.ByteTransform.TransInt16(InPowerPCSDataService.OperateResultBytes1.Content, 6));
// esModbusTcpServer.busTcpServer.Write("x=4;11", esModbusTcpServer.busTcpServer.ByteTransform.TransInt16(InPowerPCSDataService.OperateResultBytes1.Content, 8));
// esModbusTcpServer.busTcpServer.Write("x=4;12", esModbusTcpServer.busTcpServer.ByteTransform.TransInt16(InPowerPCSDataService.OperateResultBytes1.Content, 10));
// esModbusTcpServer.busTcpServer.Write("x=4;13", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(InPowerPCSDataService.OperateResultBytes1.Content, 12));
// esModbusTcpServer.busTcpServer.Write("x=4;14", esModbusTcpServer.busTcpServer.ByteTransform.TransInt16(InPowerPCSDataService.OperateResultBytes1.Content, 20));
// esModbusTcpServer.busTcpServer.Write("x=4;15", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(InPowerPCSDataService.OperateResultBytes1.Content, 36));
// esModbusTcpServer.busTcpServer.Write("x=4;16", esModbusTcpServer.busTcpServer.ByteTransform.TransInt16(InPowerPCSDataService.OperateResultBytes1.Content, 28));
// esModbusTcpServer.busTcpServer.Write("x=4;17", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(InPowerPCSDataService.OperateResultBytes1.Content, 44));
// esModbusTcpServer.busTcpServer.Write("x=4;18", esModbusTcpServer.busTcpServer.ByteTransform.TransInt16(InPowerPCSDataService.OperateResultBytes1.Content, 52));
// //电表数据
// esModbusTcpServer.busTcpServer.Write("x=4;20", esModbusTcpServer.busTcpServer.ByteTransform.TransSingle(AcrelMeters.OperateResultBytes1.Content, 52));
// esModbusTcpServer.busTcpServer.Write("x=4;22", esModbusTcpServer.busTcpServer.ByteTransform.TransSingle(AcrelMeters.OperateResultBytes1.Content, 68));
// esModbusTcpServer.busTcpServer.Write("x=4;24", esModbusTcpServer.busTcpServer.ByteTransform.TransSingle(AcrelMeters.OperateResultBytes1.Content, 0));
// esModbusTcpServer.busTcpServer.Write("x=4;26", esModbusTcpServer.busTcpServer.ByteTransform.TransSingle(AcrelMeters.OperateResultBytes1.Content, 4));
// esModbusTcpServer.busTcpServer.Write("x=4;28", esModbusTcpServer.busTcpServer.ByteTransform.TransSingle(AcrelMeters.OperateResultBytes1.Content, 8));
// esModbusTcpServer.busTcpServer.Write("x=4;30", esModbusTcpServer.busTcpServer.ByteTransform.TransSingle(AcrelMeters.OperateResultBytes1.Content, 24));
// esModbusTcpServer.busTcpServer.Write("x=4;32", esModbusTcpServer.busTcpServer.ByteTransform.TransSingle(AcrelMeters.OperateResultBytes1.Content, 28));
// esModbusTcpServer.busTcpServer.Write("x=4;34", esModbusTcpServer.busTcpServer.ByteTransform.TransSingle(AcrelMeters.OperateResultBytes1.Content, 32));
// esModbusTcpServer.busTcpServer.Write("x=4;36", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt32(AcrelMeters.OperateResultBytes3.Content, 0));
// esModbusTcpServer.busTcpServer.Write("x=4;38", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt32(AcrelMeters.OperateResultBytes3.Content, 72));
// esModbusTcpServer.busTcpServer.Write("x=4;40", esModbusTcpServer.busTcpServer.ByteTransform.TransSingle(AcrelMeters.OperateResultBytes1.Content, 100));
// esModbusTcpServer.busTcpServer.Write("x=4;42", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(AcrelMeters.OperateResultBytes2.Content, 0));
// esModbusTcpServer.busTcpServer.Write("x=4;43", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(AcrelMeters.OperateResultBytes2.Content, 2));
// esModbusTcpServer.busTcpServer.Write("x=4;44", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(AcrelMeters.OperateResultBytes2.Content, 4));
// esModbusTcpServer.busTcpServer.Write("x=4;45", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(AcrelMeters.OperateResultBytes2.Content, 6));
// esModbusTcpServer.busTcpServer.Write("x=4;46", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(AcrelMeters.OperateResultBytes2.Content, 8));
// esModbusTcpServer.busTcpServer.Write("x=4;47", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt16(AcrelMeters.OperateResultBytes2.Content, 10));
// esModbusTcpServer.busTcpServer.Write("x=4;50", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt32(AcrelMeters.OperateResultBytes3.Content, 8));
// esModbusTcpServer.busTcpServer.Write("x=4;52", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt32(AcrelMeters.OperateResultBytes3.Content, 16));
// esModbusTcpServer.busTcpServer.Write("x=4;54", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt32(AcrelMeters.OperateResultBytes3.Content, 24));
// esModbusTcpServer.busTcpServer.Write("x=4;56", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt32(AcrelMeters.OperateResultBytes3.Content, 32));
// esModbusTcpServer.busTcpServer.Write("x=4;58", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt32(AcrelMeters.OperateResultBytes3.Content, 0));
// esModbusTcpServer.busTcpServer.Write("x=4;60", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt32(AcrelMeters.OperateResultBytes3.Content, 88));
// esModbusTcpServer.busTcpServer.Write("x=4;62", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt32(AcrelMeters.OperateResultBytes3.Content, 96));
// esModbusTcpServer.busTcpServer.Write("x=4;64", esModbusTcpServer.busTcpServer.ByteTransform.TransUInt32(AcrelMeters.OperateResultBytes3.Content, 104));
// }
// }
// catch (Exception ex)
// {
// LogService.Info($"时间:{DateTime.Now.ToString()}-【ExitPeakValley】-{ex.Message}");
// }
// await Task.Delay(2000);
// }
//}
#endregion
/// <summary>
/// 线程启用的标志位
/// 退出关闭标志位
/// </summary>
public bool ThreadEnable { get; set; } = true;
/// <summary>
/// 当前系统报警消息内容
/// 不是来自设备实际报警
/// 来自软件判断
/// </summary>
public string CurSysAlarmMsg { get; set; }
#region
//MasterSlave
/// <summary>
/// 储能充电指令
/// 可实时调用这个方法
/// 英博PCS 正从电网充电
/// 可实时给值
/// </summary>
/// <param name="targetpw"></param>
public void ChargPwCmd(double targetpw)
{
//指令状态
//EsSysCmdState = EnergyStoryageCmdState.ChargeValue;
if (BmsDataService.MaxChargePowerCell.RtValue * ConfigDataService.energyStorageRunConfig.MaxBatChargRatio < Math.Abs(targetpw))//超过了限值
{
//超过了限值就按照最大的限值发送
InPowerPCSDataService.PwTranceCmdValues.CmdValue = Math.Abs(BmsDataService.MaxChargePowerCell.RtValue * ConfigDataService.energyStorageRunConfig.MaxBatChargRatio) + 0;
return;
}
//实时写入到追踪模型中变化大于阀值则发数据给PCS 让总关口电表为正不能为0
InPowerPCSDataService.PwTranceCmdValues.CmdValue = Math.Abs(targetpw) / 1.0 + ConfigDataService.energyStorageRunConfig.PcsChargOffset;
////指令状态 没有分布式之前
//EsSysCmdState = EnergyStoryageCmdState.ChargeValue;
//if (BmsDataService.MaxChargePowerCell.RtValue * ConfigDataService.energyStorageRunConfig.MaxBatChargRatio < Math.Abs(targetpw))//超过了限值
//{
// //超过了限值就按照最大的限值发送
// InPowerPCSDataService.PwTranceCmdValues.CmdValue = Math.Abs(BmsDataService.MaxChargePowerCell.RtValue * ConfigDataService.energyStorageRunConfig.MaxBatChargRatio) + 0;
// return;
//}
////实时写入到追踪模型中变化大于阀值则发数据给PCS 让总关口电表为正不能为0
//InPowerPCSDataService.PwTranceCmdValues.CmdValue = Math.Abs(targetpw) / 1.0 + ConfigDataService.energyStorageRunConfig.PcsChargOffset;
}
///// <summary>
///// 计算或者获取Pcs的目标指令值
///// </summary>
//private double PcsTargetPw { get; set; }
/// <summary>
/// 储能放电指令
/// 英博PCS 负给电网放电
/// 可实时给值
/// </summary>
/// <param name="targetpw"></param>
public void DisChargPwCmd(double targetpw)
{
//指令状态
//EsSysCmdState = EnergyStoryageCmdState.DischargeValue;
if (BmsDataService.MaxDisChargePowerCell.RtValue * ConfigDataService.energyStorageRunConfig.MaxBatDisChargRatio < Math.Abs(targetpw))//超过了限值
{
//超过了限值就按照最大的限值发送
InPowerPCSDataService.PwTranceCmdValues.CmdValue = -(Math.Abs(BmsDataService.MaxDisChargePowerCell.RtValue * ConfigDataService.energyStorageRunConfig.MaxBatDisChargRatio) + 0);
return;
}
//实时写入到追踪模型中变化大于阀值则发数据给PCS
InPowerPCSDataService.PwTranceCmdValues.CmdValue = -(Math.Abs(targetpw) / 1.0 + ConfigDataService.energyStorageRunConfig.PcsDisChargOffset);
////指令状态 没有分布式之前
//EsSysCmdState = EnergyStoryageCmdState.DischargeValue;
//if (BmsDataService.MaxDisChargePowerCell.RtValue * ConfigDataService.energyStorageRunConfig.MaxBatDisChargRatio < Math.Abs(targetpw))//超过了限值
//{
// //超过了限值就按照最大的限值发送
// InPowerPCSDataService.PwTranceCmdValues.CmdValue = -(Math.Abs(BmsDataService.MaxDisChargePowerCell.RtValue * ConfigDataService.energyStorageRunConfig.MaxBatDisChargRatio) + 0);
// return;
//}
////实时写入到追踪模型中变化大于阀值则发数据给PCS
//InPowerPCSDataService.PwTranceCmdValues.CmdValue = -(Math.Abs(targetpw) / 1.0 + ConfigDataService.energyStorageRunConfig.PcsDisChargOffset);
}
/// <summary>
/// 发送全功率放电
/// 可实时给值
/// </summary>
public void SendFullDisChargePwValueCmd(double cmdValue)
{
//指令状态 这里只是标记状态
//EsSysCmdState = EnergyStoryageCmdState.FullDischarge;
//发送全功率的功率值给Pcs
InPowerPCSDataService.PwTranceCmdValues.CmdValue = -Math.Abs(cmdValue) / 1.0;
}
/// <summary>
/// 发送全功率充电
/// 可实时给值
/// </summary>
public void SendFullChargePwCmd(double cmdValue)
{
//指令状态 这里只是标记状态
//EsSysCmdState = EnergyStoryageCmdState.FullCharge;
//发送全功率的功率值给Pcs
InPowerPCSDataService.PwTranceCmdValues.CmdValue = Math.Abs(cmdValue) / 1.0 + 0;
}
/// <summary>
/// 待机指令
/// 其实给PCS发送0的功率值则就是待机指令
/// 可实时给值
/// </summary>
public void SendStandby()
{
//指令状态 无指令的状态PCS待机状态 为0的功率值
//EsSysCmdState = EnergyStoryageCmdState.Standby;
InPowerPCSDataService.PwTranceCmdValues.CmdValue = 0;
}
#endregion
#region
/// <summary>
/// 储能状态机初始化配置
/// </summary>
private void StateMachineInitial()
{
//初始状态是这个状态,不然同一个状态会重复进入导致状态机报错
_EsSysRunState = EnergyStorageState.Inital;
EnergyStorageStateMachine = new StateMachine<EnergyStorageState, EnergyStorageStateTrig>(EnergyStorageState.Inital);
//初始状态
EnergyStorageStateMachine.Configure(EnergyStorageState.Inital)
.Permit(EnergyStorageStateTrig.HandTrig, EnergyStorageState.Hand)
.Permit(EnergyStorageStateTrig.StandbyTrig, EnergyStorageState.Standby)
.Permit(EnergyStorageStateTrig.ReadyCmdTrig, EnergyStorageState.ReadyCmd)
.Permit(EnergyStorageStateTrig.AlarmTrig, EnergyStorageState.Alarm)
.Ignore(EnergyStorageStateTrig.InitalTrig);
//待机状态
EnergyStorageStateMachine.Configure(EnergyStorageState.Standby)
.Permit(EnergyStorageStateTrig.HandTrig, EnergyStorageState.Hand)
.Permit(EnergyStorageStateTrig.AlarmTrig, EnergyStorageState.Alarm)
.Permit(EnergyStorageStateTrig.ReadyCmdTrig, EnergyStorageState.ReadyCmd)
.Ignore(EnergyStorageStateTrig.StandbyTrig)
.OnEntry(() => EntryStandby())
.OnExit(() => ExitStandby());
//峰谷模式/命令等待 状态
EnergyStorageStateMachine.Configure(EnergyStorageState.ReadyCmd)
.Permit(EnergyStorageStateTrig.HandTrig, EnergyStorageState.Hand)
.Permit(EnergyStorageStateTrig.StandbyTrig, EnergyStorageState.Standby)
.Permit(EnergyStorageStateTrig.AlarmTrig, EnergyStorageState.Alarm)
.Ignore(EnergyStorageStateTrig.ReadyCmdTrig)
.OnEntry(() => EntryReadyCmd())
.OnExit(() => ExitReadyCmd());
//报警状态
EnergyStorageStateMachine.Configure(EnergyStorageState.Alarm)
.Permit(EnergyStorageStateTrig.HandTrig, EnergyStorageState.Hand)
.Permit(EnergyStorageStateTrig.StandbyTrig, EnergyStorageState.Standby)
.Permit(EnergyStorageStateTrig.ReadyCmdTrig, EnergyStorageState.ReadyCmd)
.Ignore(EnergyStorageStateTrig.AlarmTrig)
.OnEntry(() => EntryAlarm())
.OnExit(() => ExitAlarm());
//手动状态
EnergyStorageStateMachine.Configure(EnergyStorageState.Hand)
.Permit(EnergyStorageStateTrig.AlarmTrig, EnergyStorageState.Alarm)
.Permit(EnergyStorageStateTrig.StandbyTrig, EnergyStorageState.Standby)
.Permit(EnergyStorageStateTrig.ReadyCmdTrig, EnergyStorageState.ReadyCmd)
.Ignore(EnergyStorageStateTrig.HandTrig)
.OnEntry(() => EntryHand())
.OnExit(() => ExitHand());
//初始的储能检查
EnergyStorageCheck();
}
public TrigModuleStartRunAction TrigModuleStartRunActions { get; set; }
/// <summary>
/// 削峰填谷的线程取消操作
/// </summary>
private CancellationTokenSource ReadyCmdTokenSource { get; set; }
/// <summary>
/// 报警的线程取消操作
/// </summary>
private CancellationTokenSource AlarmTokenSource;
/// <summary>
/// 待机的线程取消操作
/// </summary>
private CancellationTokenSource StandbyTokenSource;
/// <summary>
/// 进入手动模式
/// 手动模式的优先级比较高,在当前模式下,即使报警了,也不自动跳转。其跳转由人工手动触发,
/// 手动模式和自动模式,手动模式是一个确定的模式,没有确定和具体的自动模式,自动模式是跳转到包括报警和待机和等待指令的任何一个模式(具体要看当时的情况)
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void EntryHand()
{
HandAutoState = "手动模式";
EsSysRunState = EnergyStorageState.Hand;
CurClientInfo.SysState = "Hand";
AutoHandValue = false;
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能进入【手动】模式 ");
}
private bool _AutoHandValue = true;
/// <summary>
/// 手自动值
/// 手动为False
/// 自动为True
/// </summary>
public bool AutoHandValue
{
get { return _AutoHandValue; }
set { _AutoHandValue = value; RaisePropertyChanged(); }
}
/// <summary>
/// 退出手动模式
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void ExitHand()
{
HandAutoState = "自动模式";
AutoHandValue = true;
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能离开【手动】模式 ");
}
/// <summary>
/// 离开命令等待的模式
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void ExitReadyCmd()
{
try
{
//线程取消,防止一直运行和后面的冲突
ReadyCmdTokenSource.Cancel();
//离开命令等待之前可能有遗漏的指令防止其他的状态残留那么需要发送PCS待机指令 可能退出之前还是大功率充电
SendStandby();
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能离开【命令等待】模式 ");
}
catch (Exception ex)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【ExitPeakValley】-{ex.Message}");
}
}
/// <summary>
/// 进入储能的等待指令的状态
/// 则此时需要接受通信的数据
/// 如果和EMS通信的状态是OK的话直接执行EMS的指令
/// </summary>
private void EntryReadyCmd()
{
try
{
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能进入【等待指令】模式 ");
//EsSysRunStateMsg = "峰谷状态";
EsSysRunState = EnergyStorageState.ReadyCmd;
CurClientInfo.SysState = "ReadyCmd";
ReadyCmdTokenSource = new CancellationTokenSource();
//等待EMS指令的状态
Task.Run(() =>
{
//判断储能的状态是否正确
while (EsSysRunState == EnergyStorageState.ReadyCmd)
{
try
{
Thread.Sleep(200);
//检查储能的状态
if (!CheckEnergyStorageModuleLink().Result || !CheckEnergyStorageModuleAlarm().Result)//产生报警
{
//产生报警把自动触发PCS运行关闭掉
//可能运行自动触发PCS运行的循环先关闭循环没触发也可以关闭
TrigModuleStartRunActions.PcsAutoTrigClose();
//EsSysRunState=EnergyStorageState.Alarm;
//产生报警
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能待机状态判断 产生报警 跳转-开始进入重新策略分配 ");
StrategyAllocate(EnergyStorageState.Alarm);
break;
}
else if (!CheckEnergyStorageModuleRunState().Result)
{
//储能的状态出现问题,跳转到待机状态
//可能运行自动触发PCS运行的循环先关闭循环没触发也可以关闭
TrigModuleStartRunActions.PcsAutoTrigClose();
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能的状态出现问题,-开始进入待机状态 ");
StrategyAllocate(EnergyStorageState.Standby);
break;
}
else//依旧存在未正常运行状态,维持当前状态机
{
//当处于待机状态时,主要组件没有运行,那么可以通过自动执行指令进行运行指令的操作
if (true)
{
}
}
if (ReadyCmdTokenSource.IsCancellationRequested)
{
break;
}
//先检查跟服务器的状态,服务器的状态没有跟储能本体的状态绑定,分开,方便拆分状态逻辑
if (EMSSocketClientConState.ConResult)
{
switch (CurServerCmd.CmdType)
{
case "Charg"://充电
ChargPwCmd(CurServerCmd.CmdPw);
break;
case "DisCharg"://放电
DisChargPwCmd(CurServerCmd.CmdPw);
break;
default:
break;
}
//液冷控制
if (CurServerCmd.CoolOnOffCmd)
{
ACService.SetCoolCtrModel(CoolState.Auto);
}
else
{
ACService.SetCoolCtrModel(CoolState.Stop);
}
}
else//和服务器的通信状态失败那么指令就没有意义了防止之前的指令残留设置为0
{
switch (CurServerCmd.CmdType)
{
case "Charg"://充电
ChargPwCmd(0);
break;
case "DisCharg"://放电
DisChargPwCmd(0);
break;
default:
break;
}
}
}
catch (Exception ex)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【EntryAlarm】-{ex.Message}");
}
}
}, ReadyCmdTokenSource.Token);
}
catch (Exception ex)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【EntryReadyCmd】-{ex.Message}");
}
}
/// <summary>
/// 进入初始化状态
/// 开始检查各个系统的状态
/// 确保连接成功和没有报警
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void EnergyStorageCheck()
{
try
{
//确保通信连接正常 BMS和PCS 电表
var LinkData = CheckEnergyStorageModuleLink();
if (!LinkData.Result)
{
//触发报警
//if (EnergyStorageStateMachine.State != EnergyStorageState.Alarm)
//{
EnergyStorageStateMachine.Fire(EnergyStorageStateTrig.AlarmTrig);
//}
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能初始检查【通信连接失败】");
CurSysAlarmMsg = LinkData.Msg;
return;
}
var AlarmData = CheckEnergyStorageModuleAlarm();
if (!AlarmData.Result)
{
//if (EnergyStorageStateMachine.State != EnergyStorageState.Alarm)
//{
//触发报警
EnergyStorageStateMachine.Fire(EnergyStorageStateTrig.AlarmTrig);
//}
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能初始检查【报警发生】");
CurSysAlarmMsg = AlarmData.Msg;
}
if (ConfigDataService.IsStartAuto)
{
//如果到这里的话 没有问题的话则进入待机模式
EnergyStorageStateMachine.Fire(EnergyStorageStateTrig.StandbyTrig);
}
else
{
EnergyStorageStateMachine.Fire(EnergyStorageStateTrig.HandTrig);
}
}
catch (Exception ex)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【PeakValleyCycle】-{ex.Message}");
}
}
#region
///////////////////////////////////////////////////////////////
///进入储能的削峰填谷的状态模式,需要具备
///1模块连接正常
///2模块没有报警
///3模块运行状态符合要求
///////////////////////////////////////////////////////////////
/// <summary>
/// 检查模块通信状态
/// </summary>
/// <returns></returns>
private ResultInfo CheckEnergyStorageModuleLink()
{
try
{
////Test
if (ConfigDataService.IsDebug)
{
return new ResultInfo() { Result = true, Msg = "" };
}
//检查BMS通信
if (!BmsDataService.LinkStateModels.LinkState)
{
//Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}储能检查【BMS通信失败】");
return new ResultInfo() { Result = false, Msg = "BMS通信失败" };
}
//检查PCS通信
if (InPowerPCSDataService.PcsRunState.PcsLinkState == LinkState.LinkNG)
{
//Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}储能检查【PCS通信失败】");
return new ResultInfo() { Result = false, Msg = "PCS通信失败" };
}
//检查电表通信
if (!AcrelMeters.MeterLinkState)
{
//Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能检查【电表通信失败】");
return new ResultInfo() { Result = false, Msg = "电表通信失败" };
}
//通信成功
return new ResultInfo() { Result = true, Msg = null };
}
catch (Exception ex)
{
//LogService.Info($"时间:{DateTime.Now.ToString()}-【CheckEnergyStorageModuleLink】-{ex.Message}");
//通信成功
return new ResultInfo() { Result = false, Msg = null };
}
}
/// <summary>
/// 检查模块的报警状态
/// </summary>
/// <returns></returns>
private ResultInfo CheckEnergyStorageModuleAlarm()
{
try
{
////Test
if (ConfigDataService.IsDebug)
{
return new ResultInfo() { Result = true, Msg = "" };
}
//return new ResultInfo() { Result = true, Msg = "BMS通信失败" };
//检查BMS报警
if (BmsDataService.BMSAlarmState == BMSAlarmStateEnum.Alarm)
{
//Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}储能检查【BMS报警】");
return new ResultInfo() { Result = false, Msg = "BMS报警" };
}
//检查PCS报警
if (InPowerPCSDataService.PcsRunState.PcsSysAlarmState == PcsAlarmState.Alarm)
{
//Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}储能检查【PCS报警】");
return new ResultInfo() { Result = false, Msg = "PCS报警" };
}
//检查PCS故障
if (InPowerPCSDataService.PcsRunState.PcsSysFaultState == PcsFaultState.Fault)
{
//Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}储能检查【PCS故障】");
return new ResultInfo() { Result = false, Msg = "PCS故障" };
}
////检查液冷故障
//if (BmsDataService.CoolAlarmState)
//{
// Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能检查【液冷报警】");
// return new ResultInfo() { Result = false, Msg = "液冷报警" };
//}
//没有故障发生
return new ResultInfo() { Result = true, Msg = "" };
}
catch (Exception ex)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【CheckEnergyStorageModuleAlarm】-{ex.Message}");
//没有故障发生
return new ResultInfo() { Result = true, Msg = "" };
}
}
/// <summary>
/// 检查储能的运行状态
/// 报警的优先级更高
/// </summary>
/// <returns></returns>
private ResultInfo CheckEnergyStorageModuleRunState()
{
try
{
////Test
if (ConfigDataService.IsDebug)
{
return new ResultInfo() { Result = true, Msg = "" };
}
//检查BMS运行状态
if (!BmsDataService.BmsTotalState)
{
//Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}储能检查【BMS未正常运行】");
return new ResultInfo() { Result = false, Msg = "BMS未正常运行" };
}
//检查PCS运行状态
if (InPowerPCSDataService.PcsRunState.PcsStateInfo == PCSState.Stop)
{
//Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}储能检查【PCS未运行】");
return new ResultInfo() { Result = false, Msg = "PCS未运行" };
}
//检查液冷运行状态
//液冷并不总是运行,根据温度进行逻辑判断,并且液冷不直接影响削峰填谷的执行,报警状态已经能概括液冷的运行状态了
//if (xxx)
//{
// Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}储能检查【PCS未运行】");
// return new ResultInfo() { Result = false, Msg = "PCS未运行" };
//}
//检查消防运行状态
//消防没有运行与否负状态,并且液冷不直接影响削峰填谷的执行,报警状态已经能概括消防的运行状态了
//if (xxx)
//{
// Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}储能检查【PCS未运行】");
// return new ResultInfo() { Result = false, Msg = "PCS未运行" };
//}
//正常运行
return new ResultInfo() { Result = true, Msg = null };
}
catch (Exception ex)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【PeakValleyCycle】-{ex.Message}");
//正常运行
return new ResultInfo() { Result = true, Msg = null };
}
}
#endregion
/// <summary>
/// 进入储能待机状态
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void EntryStandby()
{
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能进入【待机】模式 ");
//EsSysRunStateMsg = "待机状态";
EsSysRunState = EnergyStorageState.Standby;
CurClientInfo.SysState = "Standby";
StandbyTokenSource = new CancellationTokenSource();
//报警任务循环
Task.Run(() =>
{
//待机状态时如果是PCS的停止了那么需要自动触发PCS运行
if (InPowerPCSDataService.PcsRunState.PcsStateInfo == PCSState.Stop)
{
TrigModuleStartRunActions.PcsAutoTrigRun();
}
//判断储能的状态是否正确
while (EsSysRunState == EnergyStorageState.Standby)
{
try
{
Thread.Sleep(100);
if (StandbyTokenSource.IsCancellationRequested)
{
break;
}
//待机状态,可能转到报警,可能转到削峰填谷 报警优先判断
//循环获取系统的状态
if (!CheckEnergyStorageModuleLink().Result || !CheckEnergyStorageModuleAlarm().Result)//产生报警
{
//可能运行自动触发PCS运行的循环先关闭循环没触发也可以关闭
TrigModuleStartRunActions.PcsAutoTrigClose();
//EsSysRunState=EnergyStorageState.Alarm;
//产生报警
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能待机状态判断 产生报警 跳转-开始进入重新策略分配 ");
StrategyAllocate(EnergyStorageState.Alarm);
break;
}
else if (CheckEnergyStorageModuleRunState().Result)
{
//可能运行自动触发PCS运行的循环先关闭循环没触发也可以关闭
TrigModuleStartRunActions.PcsAutoTrigClose();
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:未正常运行状态消失-储能待机状态判断,-开始进入重新策略分配 ");
StrategyAllocate(EnergyStorageState.ReadyCmd);
break;
}
else//依旧存在未正常运行状态,维持当前状态机
{
//当处于待机状态时,主要组件没有运行,那么可以通过自动执行指令进行运行指令的操作
}
}
catch (Exception ex)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【EntryStandby】-{ex.Message}");
}
}
}, StandbyTokenSource.Token);
}
/// <summary>
/// 退出待机状态
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void ExitStandby()
{
StandbyTokenSource.Cancel();
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能离开【待机】模式 ");
}
/// <summary>
/// 进入储能的报警状态
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void EntryAlarm()
{
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能进入【报警】模式 ");
//EsSysRunStateMsg = "报警状态";
EsSysRunState = EnergyStorageState.Alarm;
CurClientInfo.SysState = "Alarm";
AlarmTokenSource = new CancellationTokenSource();
//报警任务循环
var AlarmTask = Task.Run(() =>
{
//判断储能的状态是否正确
while (EsSysRunState == EnergyStorageState.Alarm)
{
try
{
Thread.Sleep(100);
if (AlarmTokenSource.IsCancellationRequested)
{
break;
}
//循环获取系统的状态
//State = CheckEnergyStorageAlarmState();
if (CheckEnergyStorageModuleLink().Result && CheckEnergyStorageModuleAlarm().Result)//没有报警状态
{
//报警消失,再判断模块的运行状态是否正常
if (CheckEnergyStorageModuleRunState().Result)
{
//报警消失
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能报警消失-判断到削峰填谷-开始进入重新策略分配 ");
StrategyAllocate(EnergyStorageState.ReadyCmd);
break;
}
else
{
//报警消失
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能报警消失-判断到待机状态-开始进入重新策略分配 ");
StrategyAllocate(EnergyStorageState.Standby);
break;
}
}
else//依旧存在报警状态,维持状态机
{
}
}
catch (Exception ex)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【EntryAlarm】-{ex.Message}");
}
}
}, AlarmTokenSource.Token);
}
/// <summary>
/// 储能离开报警
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void ExitAlarm()
{
AlarmTokenSource.Cancel();
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能离开【报警】模式 ");
}
/// <summary>
/// 其他状态退出后暂时还没有状态分配
/// 这里进行状态分配一下
/// 策略分配
/// </summary>
private void StrategyAllocate(EnergyStorageState newState)
{
//如果有切换到手自动的话,则进入到待机状态,否则进入削峰填谷的模式
//当然报警的等级是最高的,报警出来后才能接受外面的最新的状态
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能开始【策略分配】 新判断:{newState.ToString()}");
try
{
// 【newState】是新的判断后的状态
switch (newState)
{
case EnergyStorageState.Inital:
break;
case EnergyStorageState.Standby:
EnergyStorageStateMachine.Fire(EnergyStorageStateTrig.StandbyTrig);
break;
case EnergyStorageState.Alarm:
EnergyStorageStateMachine.Fire(EnergyStorageStateTrig.AlarmTrig);
break;
case EnergyStorageState.ReadyCmd:
EnergyStorageStateMachine.Fire(EnergyStorageStateTrig.ReadyCmdTrig);
break;
default:
break;
}
}
catch (Exception ex)
{
LogService.Error($"错误信息,策略分配处的状态机出现错误 {ex.Message}");
StrategyAllocate(newState);
}
}
#endregion
#region
/// <summary>
/// 是否可以充电
/// 1) 电池状态允许
/// 2) 电池Soc允许
/// 3PCS运行状态
/// </summary>
/// <returns></returns>
public bool IsCanCharg()
{
//电池
if (BmsDataService.BmsAlarmStateMsg == "禁充标志")
{
IsCanChargMsg = "禁止";
return false;
}
if (BmsDataService.BmsAlarmStateMsg == "充满状态")
{
IsCanChargMsg = "禁止";
return false;
}
if (BmsDataService.BmsAlarmStateMsg == "告警状态")
{
IsCanChargMsg = "禁止";
return false;
}
//模式判断 模式不是命令等待模式时给Server状态不进行充放电
if (EsSysRunState != EnergyStorageState.ReadyCmd)
{
IsCanChargMsg = "禁止";
return false;
}
//PCS
if (InPowerPCSDataService.PcsRunState.PcsStateMsg == "停止")
{
IsCanChargMsg = "禁止";
return false;
}
//SOC处于运行的范围之内
if (BmsDataService.BmsSOC.RtValue <= ConfigDataService.energyStorageRunConfig.BMSSocUpSignLimitValue)
{
IsCanChargMsg = "允许";
return true;
}
else
{
IsCanChargMsg = "禁止";
return false;
}
//IsCanChargMsg = "禁止";
//return false;
}
private string _IsCanChargMsg;
/// <summary>
/// 是否可以充电文本
/// </summary>
public string IsCanChargMsg
{
get { return _IsCanChargMsg; }
set { _IsCanChargMsg = value; RaisePropertyChanged(); }
}
private string _IsCanDisChargMsg;
/// <summary>
/// 是否可以放电文本
/// </summary>
public string IsCanDisChargMsg
{
get { return _IsCanDisChargMsg; }
set { _IsCanDisChargMsg = value; RaisePropertyChanged(); }
}
/// <summary>
/// 是否可以放电
/// 1) 电池状态允许
/// 2) 电池Soc允许
/// 3PCS运行状态
/// </summary>
/// <returns></returns>
public bool IsCanDisCharg()
{
//电池
if (BmsDataService.BmsAlarmStateMsg == "禁放标志")
{
IsCanDisChargMsg = "禁止";
return false;
}
if (BmsDataService.BmsAlarmStateMsg == "放空状态")
{
IsCanDisChargMsg = "禁止";
return false;
}
if (BmsDataService.BmsAlarmStateMsg == "告警状态")
{
IsCanDisChargMsg = "禁止";
return false;
}
//PCS
if (InPowerPCSDataService.PcsRunState.PcsStateMsg == "停止")
{
IsCanDisChargMsg = "禁止";
return false;
}
//模式判断 模式不是命令等待模式时给Server状态不进行充放电
if (EsSysRunState != EnergyStorageState.ReadyCmd)
{
IsCanChargMsg = "禁止";
return false;
}
if (BmsDataService.BmsSOC.RtValue >= ConfigDataService.energyStorageRunConfig.BMSSocDownSignLimitValue)
{
IsCanDisChargMsg = "允许";
return true;
}
else
{
IsCanDisChargMsg = "禁止";
return false;
}
//IsCanDisChargMsg = "禁止";
//return false;
}
/// <summary>
/// 最大允许充电功率
/// </summary>
/// <returns></returns>
public double GetMaxChargPw()
{
return BmsDataService.MaxChargePowerCell.RtValue;
}
/// <summary>
/// 最大允许放电电功率
/// </summary>
/// <returns></returns>
public double GetMaxDisChargPw()
{
return BmsDataService.MaxDisChargePowerCell.RtValue;
}
#endregion
/// <summary>
/// 切换到手动模式 手动模式等于待机模式 暂时这么定义
/// 进度待机模式
/// </summary>
public string HandModel()
{
//
if (EsSysRunState == EnergyStorageState.Alarm)
{
return "当前处于报警状态,无法切换到手动模式,请报警结束后再重试";
}
else
{
EnergyStorageStateMachine.Fire(EnergyStorageStateTrig.StandbyTrig);
return "OK";
}
}
/// <summary>
/// 英博PCS实例
/// </summary>
public InPowerPCSDataService InPowerPCSDataService { get; set; }
public IFreeSql FreeSql { get; }
public ACService ACService { get; }
/// <summary>
/// 系统的配置服务实例
/// </summary>
public ConfigDataService ConfigDataService { get; }
/// <summary>
/// BMS模型实例
/// </summary>
public BmsDataService BmsDataService { get; set; }
/// <summary>
/// 光伏的数据服务
/// </summary>
public SolarEnergyService SolarEnergyService { get; }
///// <summary>
///// 电表数据
///// </summary>
//public PwMeter PwMeters { get; set; }
/// <summary>
/// 储能系统的状态机
/// </summary>
public StateMachine<EnergyStorageState, EnergyStorageStateTrig> EnergyStorageStateMachine { get; set; }
private string _HandAutoState = "自动模式";
/// <summary>
/// 手自动模式
/// </summary>
public string HandAutoState
{
get { return _HandAutoState; }
set { _HandAutoState = value; RaisePropertyChanged(); }
}
private string _EsSysRunStateMsg = "待机状态";
/// <summary>
/// 储能系统运行状态
/// </summary>
public string EsSysRunStateMsg
{
get { return _EsSysRunStateMsg; }
set { _EsSysRunStateMsg = value; RaisePropertyChanged(); }
}
private EnergyStorageState _EsSysRunState;
/// <summary>
/// 储能当前的状态
/// </summary>
public EnergyStorageState EsSysRunState
{
get { return _EsSysRunState; }
set
{
if (_EsSysRunState != value)//储能的状态改变了
{
switch (value)
{
case EnergyStorageState.Inital:
EsSysRunStateMsg = "初始化";
break;
case EnergyStorageState.Standby:
EsSysRunStateMsg = "待机";
break;
case EnergyStorageState.Alarm:
EsSysRunStateMsg = "报警";
break;
case EnergyStorageState.ReadyCmd:
EsSysRunStateMsg = "命令等待";
break;
case EnergyStorageState.Hand:
EsSysRunStateMsg = "手动";
break;
default:
break;
}
_EsSysRunState = value;
}
}
}
///// <summary>
///// 储能系统的指令状态
///// </summary>
//public StateMachine<EnergyStoryageCmdState, EnergyStoryageCmdStateTrig> EnergyStoryageCmdStateMachine { get; set; }
/// <summary>
/// 获取储能系统的状态
/// </summary>
/// <returns></returns>
public EnergyStorageState GetEnergyStorageState()
{
//return EnergyStorageState.Charge;
return EsSysRunState;
}
#region Slave Client
/// <summary>
/// 驱动扫描线程
/// </summary>
static Task mainTask = null;
/// <summary>
/// 线程使能
/// </summary>
public bool WebSocketThreadEnable { get; set; } = true;
/// <summary>
/// 当前的客户端状态指令内容
/// </summary>
private ClientInfo CurClientInfo { get; set; } = new ClientInfo();
/// <summary>
/// 当前站号
/// </summary>
public ushort ClientStation { get; set; }
//客户端考虑是否可以充放电的时候除了状态把SOC的情况放进去
private EnergyStoryageCmdState _EsSysCmdState;
/// <summary>
/// 储能的指令状态
/// 只是监视全功率的指令的变化 这个有问题就是全功率实时发送一次但是全功率的功率值根据SOC是改变的可能需要监视全功率值然后多次触发全功率数据????
/// </summary>
public EnergyStoryageCmdState EsSysCmdState
{
get { return _EsSysCmdState; }
set
{
if (value != _EsSysCmdState)
{
switch (value)
{
case EnergyStoryageCmdState.NoCmd://指令是实时的值
EsSysCmdStateMsg = "无指令";
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:进入平衡阶段,不需要调整[维持上一个指令] ");
break;
case EnergyStoryageCmdState.Standby://指令是实时的值
EsSysCmdStateMsg = "待机指令";
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}储能PCS待机指令 ");
//InPowerPCSDataService.StandbyPwCmd();
break;
case EnergyStoryageCmdState.ChargeValue://指令是实时的值
EsSysCmdStateMsg = "充电指令";
break;
case EnergyStoryageCmdState.DischargeValue://指令是实时的值
EsSysCmdStateMsg = "放电指令";
break;
case EnergyStoryageCmdState.FullCharge://全功率充电 变化时发送一次数据
EsSysCmdStateMsg = "全功率充电指令";
//这里只是标记状态,因为最大功率是变化的,这里只能执行一次,那么在赋值的时候做一个处理
break;
case EnergyStoryageCmdState.FullDischarge://全功率放电 变化时发送一次数据
EsSysCmdStateMsg = "全功率放电指令";
//这里只是标记状态,因为最大功率是变化的,这里只能执行一次,那么在赋值的时候做一个处理
Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:全功率放电指令 ");
break;
default:
break;
}
_EsSysCmdState = value;
}
}
}
private string _EsSysCmdStateMsg;
/// <summary>
/// 储能的指令状态
/// 只是监视全功率的指令的变化 这个有问题就是全功率实时发送一次但是全功率的功率值根据SOC是改变的可能需要监视全功率值然后多次触发全功率数据????
/// </summary>
public string EsSysCmdStateMsg
{
get { return _EsSysCmdStateMsg; }
set { _EsSysCmdStateMsg = value; RaisePropertyChanged(); }
}
/// <summary>
/// WebSocketClient
/// </summary>
private WebSocketClient wsClient { get; set; }
/// <summary>
/// WebSocketClient 的状态
/// </summary>
public EMSClientConState EMSSocketClientConState { get; set; } = new EMSClientConState();
/// <summary>
/// WebSocket Url
/// </summary>
public string WebUrl { get; set; } = "ws://127.0.0.1:1883";
/// <summary>
/// 当前服务侧发送给客户端的指令
/// </summary>
public ServerCmd CurServerCmd { get; set; } = new ServerCmd();
/// <summary>
/// WebSocketClient初始化函数
/// </summary>
private void WebSocketClientInit()
{
EMSSocketClientConState = new EMSClientConState();
EMSSocketClientConState.EMSClientConErrEventHandler += EMSSocketClientConState_EMSClientConErrEventHandler;
wsClient?.ConnectClose();
//ws://183.6.55.87:8036/dev-api/mesWebSocket
//wsClient = new WebSocketClient( textBox1.Text, int.Parse( textBox2.Text ), textBox5.Text );//( textBox1.Text, int.Parse(textBox2.Text), textBox5.Text );
//wsClient = new WebSocketClient("ws://183.6.55.87:8036/dev-api/mesWebSocket");//( textBox1.Text, int.Parse(textBox2.Text), textBox5.Text );
wsClient = new WebSocketClient(WebUrl);//( textBox1.Text, int.Parse(textBox2.Text), textBox5.Text );
//wsClient.LogNet = new HslCommunication.LogNet.LogNetSingle(string.Empty);
//wsClient.LogNet.BeforeSaveToFile += LogNet_BeforeSaveToFile;
wsClient.OnClientApplicationMessageReceive += WebSocket_OnWebSocketMessageReceived;
wsClient.OnNetworkError += WsClient_OnNetworkError; // 这里使用内置的处理方式,一般也就够用了。
wsClient.OnClientConnected += WsClient_OnClientConnected;
//connect = wsClient.ConnectServer();
//if (string.IsNullOrEmpty(textBox3.Text))
ConnectResult = wsClient.ConnectServer();
if (ConnectResult.IsSuccess)
{
EMSSocketClientConState.ClientSendState = true;
EMSSocketClientConState.ClientRecvState = true;
}
else
{
EMSSocketClientConState.ClientSendState = false;
EMSSocketClientConState.ClientRecvState = false;
}
//扫描开始
WebSocketScanStart();
}
/// <summary>
/// 判定跟EMS通信失败触发的事件
/// 因为状态机里面有实时获取状态判断了
/// 这里不需要事件触发纸执行,暂时舍弃
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
private void EMSSocketClientConState_EMSClientConErrEventHandler(object? sender, EMSConErrEventArgs data)
{
if (data.Result)//
{
}
else//连接失败
{
////跟EMS通信失败后立刻进入待机状态如果当前处于待机状态也要先给PCS指令为0
//if (EnergyStorageStateMachine.State != EnergyStorageState.Standby)
//{
// SendStandby();//防止其他的状态残留先给0功率
// EnergyStorageStateMachine.Fire(EnergyStorageStateTrig.StandbyTrig);
//}
}
}
/// <summary>
/// 连接服务的结果
/// </summary>
private OperateResult ConnectResult { get; set; }
/// <summary>
/// 实时客户端的状态消息
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void WebSocketScanStart()
{
mainTask = Task.Run(async () =>
{
while (WebSocketThreadEnable)
{
await Task.Delay(100);
//定期发送数据需要连接状态OK否则实时主动连接Server直到成功
if (EMSSocketClientConState.ClientState)
{
CurClientInfo.MaxChargPw = BmsDataService.MaxChargePowerCell.RtValue;
CurClientInfo.MaxDisChargPw = BmsDataService.MaxDisChargePowerCell.RtValue;
CurClientInfo.SOC = BmsDataService.BmsSOC.RtValue;
CurClientInfo.CurActionCmdPw = InPowerPCSDataService.CurCmdPw;
CurClientInfo.IsCharg = IsCanCharg();
CurClientInfo.IsDisCharg = IsCanDisCharg();
CurClientInfo.CoolState=ACService.CapState== "开启"?true:false;
CurClientInfo.SOE = BmsDataService.BmsSOE.RtValue;
CurClientInfo.SOH = BmsDataService.BmsSOH.RtValue;
//开始发送数据
//发送数据成功则代表发送状态OK
EMSSocketClientConState.ClientSendState = ClientSendMsg(CurClientInfo);
}
else
{
ConnectResult = wsClient.ConnectServer();
if (ConnectResult.IsSuccess)
{
if (ConnectResult.IsSuccess)
{
EMSSocketClientConState.ClientState = true;
}
else
{
EMSSocketClientConState.ClientState = false;
}
}
}
}
});
}
/// <summary>
/// 客户端连接成功触发事件,重新连接也会触发
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void WsClient_OnClientConnected()
{
EMSSocketClientConState.ClientState = true;
LogService.Info($"时间:{DateTime.Now.ToString()}-【WebSocket客户端连接成功】");
}
/// <summary>
/// 发送消息数据
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public bool ClientSendMsg(ClientInfo msg)
{
return wsClient.SendServer(JsonSerializer.Serialize<ClientInfo>(msg)).IsSuccess;
}
/// <summary>
/// 关闭连接
/// </summary>
public void ClientCloseLink()
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【WebSocket关闭连接】");
EMSSocketClientConState.ClientState = false;
wsClient?.ConnectClose();
}
/// <summary>
/// 网络通信失败
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
private void WsClient_OnNetworkError(object? sender, EventArgs e)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【WebSocket网络通信失败】");
EMSSocketClientConState.ClientState = false;
}
/// <summary>
/// WebSoketClient 接收到数据
/// </summary>
/// <param name="message"></param>
private void WebSocket_OnWebSocketMessageReceived(WebSocketMessage message)
{
try
{
//if (EsSysRunState == EnergyStorageState.ReadyCmd)
//{
EMSSocketClientConState.ClientRecvState = true;
//反序列化数据
var data = JsonSerializer.Deserialize<List<ServerCmd>>(Encoding.UTF8.GetString(message.Payload)).Find(a => a.Station == ClientStation);
//充放电的指令
CurServerCmd.CmdPw = data!.CmdPw;
CurServerCmd.CmdType = data.CmdType;
//液冷的开关
CurServerCmd.CoolOnOffCmd = data!.CoolOnOffCmd;
//Pcs的开关
CurServerCmd.PcsOnOffCmd = data!.PcsOnOffCmd;
}
catch (Exception Ex)
{
LogService.Error($"时间:{DateTime.Now.ToString()}-【WebSocket接收到数据】ErrMessage{Ex.Message}");
}
}
#endregion
}
}