using HslCommunication; using HslCommunication.ModBus; using NLog; using OrpaonEMS.App.Com; using OrpaonEMS.App.Models; using OrpaonEMS.Core; using OrpaonEMS.Core.DbModel; using OrpaonEMS.Core.Enums; using OrpaonEMS.Core.EventHandMsg; using OrpaonEMS.Core.Model; using Prism.Mvvm; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using System.Windows; namespace OrpaonEMS.App.Services { /// /// 设备实时数据服务 /// public class BmsDataService : BindableBase { /// /// ScanTask扫描Task /// static Task ScanTask { get; set; } /// /// NLog服务集合 /// public ILogService LogService { get; } public IFreeSql FreeSql { get; } public ConfigDataService ConfigDataService { get; } public BmsDataService(ILogService logService,IFreeSql freeSql,ConfigDataService configDataService) { //Log服务实例赋值 LogService = logService; FreeSql = freeSql; ConfigDataService = configDataService; //ModbusTcpNetDrive = new ModbusTcpNet("192.168.10.253", 502); //ModbusTcpNetDrive = new ModbusTcpNet("192.0.1.21", 502); ModbusTcpNetDrive = new ModbusTcpNet(ConfigDataService.BMSIP, 502); ModbusTcpNetDrive.AddressStartWithZero = true; ModbusTcpNetDrive.ReceiveTimeOut = 2000; ModbusTcpNetDrive.SetPersistentConnection(); var LinkResult = ModbusTcpNetDrive.ConnectServer(); if (!LinkResult.IsSuccess) { LogService!.Info($"时间:{DateTime.Now.ToString()}-【Info】:BMS 初始连接失败"); MessageBox.Show("BMS 连接失败"); } //报警数据获取 ListAlarmCell = LoadAlarm.GetAlarms(ChannelInfo); //把报警的单元注入到报警模型中,方便统计 CurAlarmModel = new BmsAlarmModel(ListAlarmCell); CurAlarmModel.BmsAlarmResetEventHandler += CurAlarmModel_BmsAlarmResetEventHandler; ListSoxValue = new ObservableCollection() { new DoughnutModel() {Title="SOC",Value=50,States=""}, new DoughnutModel() {Title="SOH",Value=50,States=""}, new DoughnutModel() {Title="SOX",Value=50,States=""} }; //获取只读数据 ListBmsRoCell = BmsLoadData.GetRoData(); //获取读写数据 ListBmsRwCell = BmsLoadData.GetRWData(); //从集合里找出单独关注的UI数据 BmsCur = ListBmsRoCell.Find(a => a.Name == "电池簇电流值")!; BmsVol = ListBmsRoCell.Find(a => a.Name == "电池簇电压")!; BmsSOC = ListBmsRoCell.Find(a => a.Name == "电池簇总SOC")!; BmsSOH = ListBmsRoCell.Find(a => a.Name == "电池簇总SOH")!; BmsSOE = ListBmsRoCell.Find(a => a.Name == "电池簇总SOE")!; BmsResP = ListBmsRoCell.Find(a => a.Name == "电池簇绝缘电阻R+")!; BmsResN = ListBmsRoCell.Find(a => a.Name == "电池簇绝缘电阻R-")!; BmsMaxBatTemp = ListBmsRoCell.Find(a => a.Name == "电池最高温度")!; BmsMinBatTemp = ListBmsRoCell.Find(a => a.Name == "电池最低温度")!; BmsAccChargCount = ListBmsRoCell.Find(a => a.Name == "累计充电次数")!; BmsAccDisChargCount = ListBmsRoCell.Find(a => a.Name == "累计放电次数")!; BmsAccCharg = ListBmsRoCell.Find(a => a.Name == "累计充电电量")!; BmsAccDisCharg = ListBmsRoCell.Find(a => a.Name == "累计放电电量")!; MaxDisChargePowerCell = ListBmsRoCell.Find(a => a.Name == "最大允许放电功率")!; MaxChargePowerCell = ListBmsRoCell.Find(a => a.Name == "最大允许充电功率")!; ScanStart(); //报警消费 Task.Run(() => AlarmChannelAction()); } /// /// 报警消失后的复位操作一下 /// /// /// /// private void CurAlarmModel_BmsAlarmResetEventHandler(object? sender, string e) { BmsAlarmReset(); Console.WriteLine($"时间:{DateTime.Now.ToString()}-内容:报警复位进行了复位操作"); } /// /// 发布BMS的一些状态信号 /// public event EventHandler PubBmsMsgEventHandler; /// /// 连接状态模型 /// public LinkStateModel LinkStateModels { get; set; } = new LinkStateModel(); /// /// BMS IO的状态 /// public BmsIO BmsIO { get; set; }=new BmsIO(); /// /// BMS是否存在报警 /// 一般这个是2级和3级比较严重的报警触发的 /// 1级的报警不严重, /// /// public bool IsBmsExistAlarm() { //有报警状态的情况下是报警发生了 if (BMSAlarmState == BMSAlarmStateEnum.Alarm) { return true; } return false; } /// /// BMS报警复位 /// public void BmsAlarmReset() { Task.Run(() => { ModbusTcpNetDrive.Write("108", (ushort)1); Thread.Sleep(1000); ModbusTcpNetDrive.Write("108", (ushort)0); }); } /// /// 实时报警数据 /// public List ListAlarmCell { get; set; } /// /// BMS只读实时数据集合 /// public List ListBmsRoCell { get; set; } /// /// BMS读写实时数据集合 /// public ObservableCollection ListBmsRwCell { get; set; } #region 报警 /// /// Bms报警模型 /// 由众多报警集合汇总而来 /// public BmsAlarmModel CurAlarmModel { get; set; } /// /// 队列通道 /// 当前队列消费当前产线的报警数据 /// public Channel ChannelInfo = Channel.CreateUnbounded(new UnboundedChannelOptions() { SingleWriter = false,//允许一次写入多条数据 SingleReader = true //一次只能读取一条消息 }); /// /// 报警通道任务执行 /// /// private async void AlarmChannelAction() { while (await ChannelInfo.Reader.WaitToReadAsync()) { if (ChannelInfo.Reader.TryRead(out var msgData)) { try { //FSqlContext.FDb.Select //统一的处理报警信息 FreeSql.Insert(new HistoryAlarm() { Category = "电池", StartTime = msgData.alarmChannel.StartTime, EndTime = msgData.alarmChannel.EndTime, Level = msgData.alarmChannel.Level, StopDur = msgData.alarmChannel.AlarmDur, Content = msgData.alarmChannel.Content, WorkDay = DateTime.Now.ToString("yyyy-MM-dd") }).ExecuteAffrows(); Console.WriteLine($"时间:{DateTime.Now.ToString()}-内容:{msgData.alarmChannel.Content}"); } catch (Exception ex) { LogService.Info($"时间:{DateTime.Now.ToString()}-【ExitPeakValley】-{ex.Message}"); } } } } #endregion #region 驱动及相关数据 /// /// ModbusTcp驱动 /// private ModbusTcpNet ModbusTcpNetDrive { get; set; } /// /// 扫描设备线程数据 /// public Thread ScanDeviceThread { set; get; } /// /// 扫描线程使能 /// public bool ThreadEnable { get; set; } = true; /// /// 报警状态数据 /// private OperateResult OperateResultBmsAlarm { get; set; } /// /// BMS只读数据-前125字节 /// private OperateResult OperateResultRoRtData1 { get; set; } /// /// BMS只读数据 后125字节 /// private OperateResult OperateResultRoRtData2 { get; set; } /// /// 连接失败次数 /// private int LinkFaultCount { get; set; } /// /// BMS配置数据 /// private OperateResult OperateResultConfigData { get; set; } /// ///扫描BMS设备的线程 /// private void ScanStart() { ScanTask = Task.Run(async () => { while (ThreadEnable) { try { await Task.Delay(200); //BmsVol.SrRtValue = (ushort)new Random().Next(0, 1000); //报警数据 OperateResultBmsAlarm = ModbusTcpNetDrive.ReadDiscrete("1", 200); if (OperateResultBmsAlarm.IsSuccess) { foreach (var itemAlarmCell in ListAlarmCell) { itemAlarmCell.UpdateValue(OperateResultBmsAlarm.Content[itemAlarmCell.BitIndex]); } } //只读数据测试 OperateResultRoRtData1 = ModbusTcpNetDrive.Read("x=4;1", 260); if (OperateResultRoRtData1.IsSuccess) { foreach (var ItembMSRoCell in ListBmsRoCell) { //if (ItembMSRoCell.Index <= 240) //{ if (ItembMSRoCell.Lengh == 2) { ItembMSRoCell.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt32(OperateResultRoRtData1.Content, ItembMSRoCell.Index); } else { ItembMSRoCell.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultRoRtData1.Content, ItembMSRoCell.Index); } //} //一些整型数据转枚举和字符串的处理 switch (ItembMSRoCell.Name) { case "系统告警状态": BMSAlarmStateValue = (int)ItembMSRoCell.SrRtValue; break; case "电池簇电池状态": BmsBatStateVaue = (ushort)ItembMSRoCell.SrRtValue; break; case "DI检测状态": BmsIO.DIValue = (ushort)ItembMSRoCell.SrRtValue; break; case "DO输出状态": BmsIO.DOValue = (ushort)ItembMSRoCell.SrRtValue; break; default: break; } } //BmsBatStateVaue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultRoRtData1.Content, 14); //BmsAccCharg.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt32(OperateResultRoRtData1.Content, BmsAccCharg.Index); //BmsAccDisCharg.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt32(OperateResultRoRtData1.Content, BmsAccDisCharg.Index); //BmsAccChargCount.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultRoRtData1.Content, BmsAccChargCount.Index); //BmsAccDisChargCount.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultRoRtData1.Content, BmsAccDisChargCount.Index); App.Current.Dispatcher.Invoke(() => { ListSoxValue[0].Value = BmsSOC.RtValue; ListSoxValue[1].Value = BmsSOH.RtValue; ListSoxValue[2].Value = BmsSOE.RtValue; }); //MaxChargePowerCell.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultRoRtData1.Content, MaxChargePowerCell.Index); //MaxDisChargePowerCell.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultRoRtData1.Content, MaxDisChargePowerCell.Index); LinkStateModels.LinkState = true; LinkFaultCount = 0; } else { LinkFaultCount = LinkFaultCount + 1; if (LinkFaultCount > 100) { //连接失败 暂时退出 LinkStateModels.LinkState = false; } } //读写数据测试 OperateResultConfigData = ModbusTcpNetDrive.Read("1", 260); if (OperateResultConfigData.IsSuccess) { foreach (var ItembMSRoCell in ListBmsRwCell) { ItembMSRoCell.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransInt16(OperateResultConfigData.Content, ItembMSRoCell.Index); } //FireSmokeTrigVaue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 460); //FireTempTrigVaue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 462); //FireWorkModelVaue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 464); //FireMainPowerStateVaue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 466); //FireSubPowerStateVaue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 468); //FireSolenoidValveStateVaue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 470); //FireInjectionCountdown = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 472); //FirePressSensorStateVaue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 474); ////xxx = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 460); //InPress.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 452); //OutPress.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 454); //OutTemp.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 448); //InTemp.SrRtValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 450); //CoolFaultValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 456); //CoolStateVaue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultConfigData.Content, 446); } } catch (Exception ex) { var dd = 1; } } }); } /// /// 关闭驱动连接 /// public void CloseDrive() { ThreadEnable = false; ModbusTcpNetDrive.ConnectClose(); } public bool WriteValue(BmsRwCell data) { var Result = ModbusTcpNetDrive.Write(data.Address, data.GetWriteDeviceValue()); if (Result.IsSuccess) { return true; } return false; } #endregion #region BMS 集合独立UI关注数据 /// /// BMS的全部状态 /// 这个暂时是统计得出的,逻辑还没有做 /// 根据其他的信号得出的总的状态结果 /// True是好的状态 /// False是差的状态 /// public bool BmsTotalState { get; set; } = true; private string _BmsAlarmStateMsg; /// /// 系统告警状态 /// 告警状态 消息内容 /// public string BmsAlarmStateMsg { get { return _BmsAlarmStateMsg; } set { _BmsAlarmStateMsg = value; RaisePropertyChanged(); } } /// /// 系统告警状态 /// 告警状态 /// public BMSAlarmStateEnum BMSAlarmState { get; set; } private int bMSAlarmStateValue; /// /// BMS报警状态值 /// 系统告警状态 /// public int BMSAlarmStateValue { get { return bMSAlarmStateValue; } set { if (value != bMSAlarmStateValue) { if (ComHelper.GetBitValue(value, 0)) { BMSAlarmState = BMSAlarmStateEnum.StopCharg; BmsAlarmStateMsg = "禁充标志"; BmsTotalState = false; } else if (ComHelper.GetBitValue(value, 1)) { BMSAlarmState = BMSAlarmStateEnum.StopDisCharg; BmsAlarmStateMsg = "禁放标志"; BmsTotalState = false; } else if (ComHelper.GetBitValue(value, 2)) { //当严重的2级和3级别的报警发生时会产生报警状态 BMSAlarmState = BMSAlarmStateEnum.Alarm; BmsAlarmStateMsg = "告警状态"; BmsTotalState = false; //PubBmsMsgEventHandler(this, new BmsEventHandMsg() { MsgType = "Alarm", AlarmState = true }) ; } else if (ComHelper.GetBitValue(value, 3)) { BMSAlarmState = BMSAlarmStateEnum.Full; BmsAlarmStateMsg = "充满状态"; BmsTotalState = true; } else if (ComHelper.GetBitValue(value, 4)) { BMSAlarmState = BMSAlarmStateEnum.Empty; BmsAlarmStateMsg = "放空状态"; BmsTotalState = true; } else { BMSAlarmState = BMSAlarmStateEnum.NoAlarm; BmsAlarmStateMsg = "无报警"; BmsTotalState = true; } bMSAlarmStateValue = value; } } } /// /// 电池簇电池状态 /// public BMSStateEnum BmsState { get; set; } private string _BmsBatStateMsg = ""; /// /// 电池簇电池状态消息内容 /// public string BmsBatStateMsg { get { return _BmsBatStateMsg; } set { _BmsBatStateMsg = value; RaisePropertyChanged(); } } private ushort _BmsBatStateVaue = 100; /// /// 电池簇电池状态状态字 /// public ushort BmsBatStateVaue { get { return _BmsBatStateVaue; } set { if (value != _BmsBatStateVaue) { switch (value) { case 1: BmsBatStateMsg = "初始化状态"; BmsState = BMSStateEnum.Initial; break; case 2: BmsBatStateMsg = "自检"; BmsState = BMSStateEnum.SelfTest; break; case 3: BmsBatStateMsg = "上电"; BmsState = BMSStateEnum.PowerOn; break; case 4: BmsBatStateMsg = "上电完成"; BmsState = BMSStateEnum.PowerOnCom; break; case 5: BmsBatStateMsg = "禁充"; BmsState = BMSStateEnum.StopCharge; break; case 6: BmsBatStateMsg = "禁放"; BmsState = BMSStateEnum.StopDisCharge; break; case 7: BmsBatStateMsg = "待机"; BmsState = BMSStateEnum.Standby; break; case 8: BmsBatStateMsg = "故障下电"; BmsState = BMSStateEnum.FaultPoweOff; break; case 9: BmsBatStateMsg = "故障下电后故障已清除"; BmsState = BMSStateEnum.FaultClear; break; case 10: BmsBatStateMsg = "测试模式"; BmsState = BMSStateEnum.TestMode; break; case 11: BmsBatStateMsg = "单簇维护"; BmsState = BMSStateEnum.SingleMaintenance; break; default: break; } _BmsBatStateVaue = value; } } } private ObservableCollection _ListSoxValue; /// /// Doughnut 数据 SOC/SOH等 /// public ObservableCollection ListSoxValue { get { return _ListSoxValue; } set { _ListSoxValue = value; RaisePropertyChanged(); } } /// /// 最大允许放电功率 /// public BMSRoCell MaxDisChargePowerCell { get; set; }// = new BMSRoCell(name: "电池簇电流值", offset: -1600, ratio: 0.1, index: 2, lengh: 1, address: "2", focus: true, unit: "A"); /// /// 最大允许充电功率 /// public BMSRoCell MaxChargePowerCell { get; set; } //= new BMSRoCell(name: "电池簇电压", offset: 0, ratio: 0.1, index: 0, lengh: 1, address: "1", focus: true, unit: "V"); /// /// 电池簇电流值 /// public BMSRoCell BmsCur { get; set; }// = new BMSRoCell(name: "电池簇电流值", offset: -1600, ratio: 0.1, index: 2, lengh: 1, address: "2", focus: true, unit: "A"); /// /// 电池簇电压 /// public BMSRoCell BmsVol { get; set; } //= new BMSRoCell(name: "电池簇电压", offset: 0, ratio: 0.1, index: 0, lengh: 1, address: "1", focus: true, unit: "V"); /// /// 电池簇总SOC /// public BMSRoCell BmsSOC { get; set; }// = new BMSRoCell(name: "电池簇总SOC", offset: 0, ratio: 0.1, index: 4, lengh: 1, address: "3", focus: true, unit: "%"); /// /// 电池簇总SOH /// public BMSRoCell BmsSOH { get; set; }// = new BMSRoCell(name: "电池簇总SOH", offset: 0, ratio: 1, index: 6, lengh: 1, address: "4", focus: true, unit: "%"); /// /// 电池簇总SOE /// public BMSRoCell BmsSOE { get; set; }// = new BMSRoCell(name: "电池簇总SOE", offset: 0, ratio: 0.1, index: 8, lengh: 1, address: "5", focus: true, unit: "%"); /// /// 电池簇绝缘电阻R+ /// public BMSRoCell BmsResP { get; set; }// = new BMSRoCell(name: "电池簇绝缘电阻R+", offset: 0, ratio: 1, index: 10, lengh: 1, address: "6", focus: true, unit: "kΩ"); /// /// 电池簇绝缘电阻R- /// public BMSRoCell BmsResN { get; set; }// = new BMSRoCell(name: "电池簇绝缘电阻R-", offset: 0, ratio: 1, index: 12, lengh: 1, address: "7", focus: true, unit: "kΩ"); /// /// 最高电池温度 /// public BMSRoCell BmsMaxBatTemp { get; set; }// = new BMSRoCell(name: "电池最高温度", offset: -40, ratio: 0.1, index: 22, lengh: 1, address: "12", focus: true, unit: "℃"); /// /// 最低电池温度 /// public BMSRoCell BmsMinBatTemp { get; set; }// = new BMSRoCell(name: "电池最低温度", offset: -40, ratio: 0.1, index: 28, lengh: 1, address: "15", focus: true, unit: "℃"); /// /// 累计充电次数 /// public BMSRoCell BmsAccChargCount { get; set; }// = new BMSRoCell(name: "累计充电次数", offset: 0, ratio: 1, index: 128, lengh: 1, address: "65", focus: true, unit: "次"); /// /// 累计放电次数 /// public BMSRoCell BmsAccDisChargCount { get; set; }// = new BMSRoCell(name: "累计放电次数", offset: 0, ratio: 1, index: 130, lengh: 1, address: "66", focus: true, unit: "次"); /// /// 累计充电电量 /// public BMSRoCell BmsAccCharg { get; set; }// = new BMSRoCell(name: "累计充电电量", offset: 0, ratio: 0.1, index: 116, lengh: 2, address: "59", focus: true, unit: "KWh"); /// /// 累计放电电量 /// public BMSRoCell BmsAccDisCharg { get; set; }// = new BMSRoCell(name: "累计放电电量", offset: 0, ratio: 0.1, index: 120, lengh: 2, address: "61", focus: true, unit: "KWh"); #endregion #region 公共方法 /// /// Bms是否可以充电 /// /// public bool BmsIsCharg() { if (BMSAlarmState != BMSAlarmStateEnum.StopCharg && BMSAlarmState != BMSAlarmStateEnum.Alarm && BMSAlarmState != BMSAlarmStateEnum.Full) { return true; } return false; } /// /// Bms是否可以放电 /// /// public bool BmsIsDisCharg() { if (BMSAlarmState != BMSAlarmStateEnum.StopDisCharg && BMSAlarmState != BMSAlarmStateEnum.Alarm && BMSAlarmState != BMSAlarmStateEnum.Empty) { return true; } return false; } #endregion } }