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()
{
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
}
}