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 { /// /// 储能服务 /// https://blog.csdn.net/zwcslj/article/details/136363261 /// public class EnergyStorageService : BindableBase { ///// ///// 负载仪表数据 /// 伊顿客户提供的仪表 ///// //public KEMeter kEMeter { get; set; } = new KEMeter(); /// /// 安科瑞仪表数据 /// 储能本身的计量数据 /// public AcrelMeterDataService AcrelMeters { get; set; } public PwAnalyzeService PwAnalyzeService { get; } ///// ///// 分布式控制 ///// 主从站通信 ///// //public EMSService MasterSlave { get; set; } /// /// NLog服务集合 /// public ILogService LogService { get; } /// /// 储能统计分析 /// public PwAnalyzeService pwAnalyze { get; set; } /// /// 是否为主站 /// public bool IsMaster { get; set; } /// /// 实例化 /// 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(); //获取配置服务实例 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 ///// ///// ModbusTcp服务 ///// //public EsModbusTcpServer esModbusTcpServer { get; set; } = null; //public MqttClientDrive mqttClientDrive { get; set; } ///// ///// ModbusTcp 的服务周期 ///// //public Task ModbusTcpServerTask = null; ///// ///// 循环赋值 ///// ///// //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 /// /// 线程启用的标志位 /// 退出关闭标志位 /// public bool ThreadEnable { get; set; } = true; /// /// 当前系统报警消息内容 /// 不是来自设备实际报警 /// 来自软件判断 /// public string CurSysAlarmMsg { get; set; } #region 储能指令函数 //MasterSlave /// /// 储能充电指令 /// 可实时调用这个方法 /// 英博PCS 正从电网充电 /// 可实时给值 /// /// 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; } ///// ///// 计算或者获取Pcs的目标指令值 ///// //private double PcsTargetPw { get; set; } /// /// 储能放电指令 /// 英博PCS 负给电网放电 /// 可实时给值 /// /// 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); } /// /// 发送全功率放电 /// 可实时给值 /// public void SendFullDisChargePwValueCmd(double cmdValue) { //指令状态 这里只是标记状态 //EsSysCmdState = EnergyStoryageCmdState.FullDischarge; //发送全功率的功率值给Pcs InPowerPCSDataService.PwTranceCmdValues.CmdValue = -Math.Abs(cmdValue) / 1.0; } /// /// 发送全功率充电 /// 可实时给值 /// public void SendFullChargePwCmd(double cmdValue) { //指令状态 这里只是标记状态 //EsSysCmdState = EnergyStoryageCmdState.FullCharge; //发送全功率的功率值给Pcs InPowerPCSDataService.PwTranceCmdValues.CmdValue = Math.Abs(cmdValue) / 1.0 + 0; } /// /// 待机指令 /// 其实给PCS发送0的功率值则就是待机指令 /// 可实时给值 /// public void SendStandby() { //指令状态 无指令的状态,PCS待机状态 为0的功率值 //EsSysCmdState = EnergyStoryageCmdState.Standby; InPowerPCSDataService.PwTranceCmdValues.CmdValue = 0; } #endregion #region 储能的状态机 /// /// 储能状态机初始化配置 /// private void StateMachineInitial() { //初始状态是这个状态,不然同一个状态会重复进入导致状态机报错 _EsSysRunState = EnergyStorageState.Inital; EnergyStorageStateMachine = new StateMachine(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; } /// /// 削峰填谷的线程取消操作 /// private CancellationTokenSource ReadyCmdTokenSource { get; set; } /// /// 报警的线程取消操作 /// private CancellationTokenSource AlarmTokenSource; /// /// 待机的线程取消操作 /// private CancellationTokenSource StandbyTokenSource; /// /// 进入手动模式 /// 手动模式的优先级比较高,在当前模式下,即使报警了,也不自动跳转。其跳转由人工手动触发, /// 手动模式和自动模式,手动模式是一个确定的模式,没有确定和具体的自动模式,自动模式是跳转到包括报警和待机和等待指令的任何一个模式(具体要看当时的情况) /// /// 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; /// /// 手自动值 /// 手动为False /// 自动为True /// public bool AutoHandValue { get { return _AutoHandValue; } set { _AutoHandValue = value; RaisePropertyChanged(); } } /// /// 退出手动模式 /// /// private void ExitHand() { HandAutoState = "自动模式"; AutoHandValue = true; Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能离开【手动】模式 "); } /// /// 离开命令等待的模式 /// /// 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}"); } } /// /// 进入储能的等待指令的状态 /// 则此时需要接受通信的数据 /// 如果和EMS通信的状态是OK的话,直接执行EMS的指令 /// 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}"); } } /// /// 进入初始化状态 /// 开始检查各个系统的状态 /// 确保连接成功和没有报警 /// /// 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)模块运行状态符合要求 /////////////////////////////////////////////////////////////// /// /// 检查模块通信状态 /// /// 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 }; } } /// /// 检查模块的报警状态 /// /// 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 = "" }; } } /// /// 检查储能的运行状态 /// 报警的优先级更高 /// /// 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 /// /// 进入储能待机状态 /// /// 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); } /// /// 退出待机状态 /// /// private void ExitStandby() { StandbyTokenSource.Cancel(); Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能离开【待机】模式 "); } /// /// 进入储能的报警状态 /// /// 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); } /// /// 储能离开报警 /// /// private void ExitAlarm() { AlarmTokenSource.Cancel(); Console.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}:储能离开【报警】模式 "); } /// /// 其他状态退出后暂时还没有状态分配 /// 这里进行状态分配一下 /// 策略分配 /// 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 光伏的开关和电能逻辑 /// /// 是否可以充电 /// 1) 电池状态允许 /// 2) 电池Soc允许 /// 3)PCS运行状态 /// /// 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; /// /// 是否可以充电文本 /// public string IsCanChargMsg { get { return _IsCanChargMsg; } set { _IsCanChargMsg = value; RaisePropertyChanged(); } } private string _IsCanDisChargMsg; /// /// 是否可以放电文本 /// public string IsCanDisChargMsg { get { return _IsCanDisChargMsg; } set { _IsCanDisChargMsg = value; RaisePropertyChanged(); } } /// /// 是否可以放电 /// 1) 电池状态允许 /// 2) 电池Soc允许 /// 3)PCS运行状态 /// /// 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; } /// /// 最大允许充电功率 /// /// public double GetMaxChargPw() { return BmsDataService.MaxChargePowerCell.RtValue; } /// /// 最大允许放电电功率 /// /// public double GetMaxDisChargPw() { return BmsDataService.MaxDisChargePowerCell.RtValue; } #endregion /// /// 切换到手动模式 手动模式等于待机模式 暂时这么定义 /// 进度待机模式 /// public string HandModel() { // if (EsSysRunState == EnergyStorageState.Alarm) { return "当前处于报警状态,无法切换到手动模式,请报警结束后再重试"; } else { EnergyStorageStateMachine.Fire(EnergyStorageStateTrig.StandbyTrig); return "OK"; } } /// /// 英博PCS实例 /// public InPowerPCSDataService InPowerPCSDataService { get; set; } public IFreeSql FreeSql { get; } public ACService ACService { get; } /// /// 系统的配置服务实例 /// public ConfigDataService ConfigDataService { get; } /// /// BMS模型实例 /// public BmsDataService BmsDataService { get; set; } /// /// 光伏的数据服务 /// public SolarEnergyService SolarEnergyService { get; } ///// ///// 电表数据 ///// //public PwMeter PwMeters { get; set; } /// /// 储能系统的状态机 /// public StateMachine EnergyStorageStateMachine { get; set; } private string _HandAutoState = "自动模式"; /// /// 手自动模式 /// public string HandAutoState { get { return _HandAutoState; } set { _HandAutoState = value; RaisePropertyChanged(); } } private string _EsSysRunStateMsg = "待机状态"; /// /// 储能系统运行状态 /// public string EsSysRunStateMsg { get { return _EsSysRunStateMsg; } set { _EsSysRunStateMsg = value; RaisePropertyChanged(); } } private EnergyStorageState _EsSysRunState; /// /// 储能当前的状态 /// 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; } } } ///// ///// 储能系统的指令状态 ///// //public StateMachine EnergyStoryageCmdStateMachine { get; set; } /// /// 获取储能系统的状态 /// /// public EnergyStorageState GetEnergyStorageState() { //return EnergyStorageState.Charge; return EsSysRunState; } #region Slave Client 本站 /// /// 驱动扫描线程 /// static Task mainTask = null; /// /// 线程使能 /// public bool WebSocketThreadEnable { get; set; } = true; /// /// 当前的客户端状态指令内容 /// private ClientInfo CurClientInfo { get; set; } = new ClientInfo(); /// /// 当前站号 /// public ushort ClientStation { get; set; } //客户端考虑是否可以充放电的时候,除了状态,把SOC的情况放进去 private EnergyStoryageCmdState _EsSysCmdState; /// /// 储能的指令状态 /// 只是监视全功率的指令的变化 这个有问题,就是全功率实时发送一次,但是全功率的功率值根据SOC是改变的,可能需要监视全功率值,然后多次触发全功率数据???? /// 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; /// /// 储能的指令状态 /// 只是监视全功率的指令的变化 这个有问题,就是全功率实时发送一次,但是全功率的功率值根据SOC是改变的,可能需要监视全功率值,然后多次触发全功率数据???? /// public string EsSysCmdStateMsg { get { return _EsSysCmdStateMsg; } set { _EsSysCmdStateMsg = value; RaisePropertyChanged(); } } /// /// WebSocketClient /// private WebSocketClient wsClient { get; set; } /// /// WebSocketClient 的状态 /// public EMSClientConState EMSSocketClientConState { get; set; } = new EMSClientConState(); /// /// WebSocket Url /// public string WebUrl { get; set; } = "ws://127.0.0.1:1883"; /// /// 当前服务侧发送给客户端的指令 /// public ServerCmd CurServerCmd { get; set; } = new ServerCmd(); /// /// WebSocketClient初始化函数 /// 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(); } /// /// 判定跟EMS通信失败触发的事件 /// 因为状态机里面有实时获取状态判断了 /// 这里不需要事件触发纸执行,暂时舍弃 /// /// /// /// 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); //} } } /// /// 连接服务的结果 /// private OperateResult ConnectResult { get; set; } /// /// 实时客户端的状态消息 /// /// 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; } } } } }); } /// /// 客户端连接成功触发事件,重新连接也会触发 /// /// private void WsClient_OnClientConnected() { EMSSocketClientConState.ClientState = true; LogService.Info($"时间:{DateTime.Now.ToString()}-【WebSocket客户端连接成功】"); } /// /// 发送消息数据 /// /// /// public bool ClientSendMsg(ClientInfo msg) { return wsClient.SendServer(JsonSerializer.Serialize(msg)).IsSuccess; } /// /// 关闭连接 /// public void ClientCloseLink() { LogService.Info($"时间:{DateTime.Now.ToString()}-【WebSocket关闭连接】"); EMSSocketClientConState.ClientState = false; wsClient?.ConnectClose(); } /// /// 网络通信失败 /// /// /// /// private void WsClient_OnNetworkError(object? sender, EventArgs e) { LogService.Info($"时间:{DateTime.Now.ToString()}-【WebSocket网络通信失败】"); EMSSocketClientConState.ClientState = false; } /// /// WebSoketClient 接收到数据 /// /// private void WebSocket_OnWebSocketMessageReceived(WebSocketMessage message) { try { //if (EsSysRunState == EnergyStorageState.ReadyCmd) //{ EMSSocketClientConState.ClientRecvState = true; //反序列化数据 var data = JsonSerializer.Deserialize>(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 } }