using HslCommunication;
using HslCommunication.ModBus;
using OrpaonEMS.App.Models;
using OrpaonEMS.Core.DbModel;
using OrpaonEMS.Core.Enums;
using OrpaonEMS.Core.Model;
using Prism.Mvvm;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using System.Windows;
namespace OrpaonEMS.App.Services
{
///
/// PCS数据服务
///
public class InPowerPCSDataService : BindableBase
{
///
/// PCS运行状态模型
///
public PCSStateModel PcsRunState { get; set; }
///
/// 英博ModbusTcp驱动
///
private ModbusTcpNet ModbusTcpNetDrive { get; set; }
///
/// 扫描设备线程数据
///
public Thread ScanDeviceThread { set; get; }
///
/// 扫描线程使能
///
public bool ThreadEnable { get; set; } = true;
///
/// 读取的字节数据集合
///
public OperateResult? OperateResultBytes1 { get; set; }
///
/// 读取的字节数据集合
///
public OperateResult? OperateResultBytes2 { get; set; }
///
/// 读取的布尔数据集合
///
public OperateResult? OperateResultBool3 { get; set; }
private string _Charg_DisChargInfo = string.Empty;
///
/// 充放电信息
///
public string Charg_DisChargInfo
{
get { return _Charg_DisChargInfo; }
set { _Charg_DisChargInfo = value; RaisePropertyChanged(); }
}
///
/// 定时器
///
static System.Timers.Timer CurTimer { get; set; }
public InPowerPCSDataService(ILogService logService,
IFreeSql freeSql,
BmsDataService bmsDataService,
ConfigDataService configDataService)
{
LogService = logService;
FreeSql = freeSql;
BmsDataService = bmsDataService;
ConfigDataService = configDataService;
//ModbusTcpNetDrive = new ModbusTcpNet("192.168.0.20", 502);
ModbusTcpNetDrive = new ModbusTcpNet(ConfigDataService.PCSIP, 502);
ModbusTcpNetDrive.AddressStartWithZero = true;
ModbusTcpNetDrive.SetPersistentConnection();
var DATA = ModbusTcpNetDrive.ConnectServer();
if (!DATA.IsSuccess)
{
MessageBox.Show("PCS 连接失败");
}
PwTranceCmdValues = new TranceCmdValue(2);
PwTranceCmdValues.CmdValueChanged += PwTranceCmdValues_CmdValueChanged;
//CurPcsAlarmModel = new PcsAlarmModel();
//BMS目前通信来自于PCS,所以封装在英博PCS中
//bMSRtCtrCell = bMSRtCtrCellInfo;
//PCS运行状态模型实例化
PcsRunState = new PCSStateModel(this);
ScanDeviceThread = new Thread(new ThreadStart(ScanDeviceThreadMethond));
ScanDeviceThread.Start();
CurPcsAlarmModel = new PcsAlarmModel(ChannelInfo);
CurTimer = new System.Timers.Timer();
CurTimer.Elapsed += CurTimer_Elapsed;//到达时间的时候执行事件;
CurTimer.AutoReset = true;//设置是执行一次(false)还是一直执行(true);
CurTimer.Interval = 600;//设置是时钟
CurTimer.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件;
CurTimer.Start(); //启动定时器
//报警消费
Task.Run(() => AlarmChannelAction());
}
///
/// PCS报警模型
///
public PcsAlarmModel CurPcsAlarmModel { get; set; }
///
/// 扫描方法
/// x=4;201 寄存器信息 只读
/// x=3;301 PCS 读取保持寄存器信息
///
///
private void ScanDeviceThreadMethond()
{
Thread.Sleep(500);
while (ThreadEnable)
{
Thread.Sleep(100);
//地址和手册错位1个字,那么转为Byte后就是2个字节,请参考地址
OperateResultBytes1 = ModbusTcpNetDrive.Read("x=4;201", 100);
if (OperateResultBytes1.IsSuccess)
{
Power = ModbusTcpNetDrive.ByteTransform.TransInt16(OperateResultBytes1.Content, 20) * 0.1;
AVol = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 0) * 0.1;
BVol = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 2) * 0.1;
CVol = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 4) * 0.1;
ACur = ModbusTcpNetDrive.ByteTransform.TransInt16(OperateResultBytes1.Content, 6) * 0.1;
BCur = ModbusTcpNetDrive.ByteTransform.TransInt16(OperateResultBytes1.Content, 8) * 0.1;
CCur = ModbusTcpNetDrive.ByteTransform.TransInt16(OperateResultBytes1.Content, 10) * 0.1;
NetFreq = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 12) * 0.01;
TotalReactivePw = ModbusTcpNetDrive.ByteTransform.TransInt16(OperateResultBytes1.Content, 28) * 0.1;
TotalApparentPw = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 36) * 0.1;
InputVol = ModbusTcpNetDrive.ByteTransform.TransInt16(OperateResultBytes1.Content, 48) * 0.1;
InputCur = ModbusTcpNetDrive.ByteTransform.TransInt16(OperateResultBytes1.Content, 50) * 0.1;
InputPw = ModbusTcpNetDrive.ByteTransform.TransInt16(OperateResultBytes1.Content, 46) * 0.1;
PwNetFactor = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 44) * 0.001;
FinTemp = ModbusTcpNetDrive.ByteTransform.TransInt16(OperateResultBytes1.Content, 52);
CurPcsAlarmModel.AlarmWord1 = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 142);
CurPcsAlarmModel.AlarmWord2 = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 144);
CurPcsAlarmModel.AlarmWord3 = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 146);
CurPcsAlarmModel.AlarmWord4 = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 148);
CurPcsAlarmModel.AlarmWord5 = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 110);
//var dd= ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 50);
//var dd2= ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 52);
//var dd3= ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 54);
//var dd4= ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 56);
//MaxChargePower = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 186) * 0.1;
//MaxDisChargePower = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 188) * 0.1;
//bMSRtCtrCell.BMSStateValue = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 158);
//bMSRtCtrCell.SOC = ModbusTcpNetDrive.ByteTransform.TransUInt16(OperateResultBytes1.Content, 164) * 0.1;
AccChargPw = ModbusTcpNetDrive.ByteTransform.TransUInt32(OperateResultBytes1.Content, 58) * 0.001;
AccDisChargPw = ModbusTcpNetDrive.ByteTransform.TransUInt32(OperateResultBytes1.Content, 62) * 0.001;
//通过PCS交流侧的电压判断交流主断是否闭合
BmsDataService.BmsIO.PcsAcCircuitBreaker = PcsAcCircuitBreaker;
PcsRunState.LinkBitValue = 1;
//PCSLinkState = true;
}
else
{
PcsRunState.LinkBitValue = 2;
//通信失败
//PCSLinkState = false;
}
OperateResultBool3 = ModbusTcpNetDrive.ReadDiscrete("81", 20);
if (OperateResultBool3.IsSuccess)
{
PcsRunState.PCSStateValue = OperateResultBool3.Content.Skip(0).Take(3).ToArray();
PcsRunState.PcsSysFaultStateVaue = OperateResultBool3.Content[3];
PcsRunState.PcsSysAlarmVaue = OperateResultBool3.Content[4];
PcsRunState.PcsRemoteLocationStateValue = OperateResultBool3.Content[5];
PcsRunState.PcsOffLineStateValue = OperateResultBool3.Content[7];
}
}
}
///
/// 指令追踪模型
///
public TranceCmdValue PwTranceCmdValues { get; set; }
///
/// 功率指令的值超过变化的阀值
///
///
///
///
private void PwTranceCmdValues_CmdValueChanged(object sender, double targetpw)
{
//Console.WriteLine($"datetime:{DateTime.Now.ToString()} 指令变化 发送储能功率:{targetpw}");
if (targetpw == 0)
{
//Charg_DisChargInfo = "";
StandbyPwCmd();
}
else if (targetpw > 0)
{
//Charg_DisChargInfo = "充电中";
SendPcsChargCmd(targetpw);
}
else
{
//Charg_DisChargInfo = "放电中";
SendPcsDisChargCmd(targetpw);
}
}
#region Pcs的数据
///
/// PCS 交流侧的主断路器
/// 通过PCS交流侧的电压判断交流主断是否闭合
///
public bool PcsAcCircuitBreaker { get; set; }
private double power;
///
/// 储能PCS的实时功率
/// 正:代表放电
/// 负:代表充电
///
public double Power
{
get { return power; }
set
{
power = value;
if (value > 0)
{
Charg_DisChargInfo = "放电";
}
else if (value < 0)
{
Charg_DisChargInfo = "充电";
}
else
{
Charg_DisChargInfo = "";
}
RaisePropertyChanged();
}
}
private double accChargPw;
///
/// 交流累计充电
///
public double AccChargPw
{
get { return accChargPw; }
set { accChargPw = value; RaisePropertyChanged(); }
}
private double accDisChargPw;
///
/// 交流累计放电
///
public double AccDisChargPw
{
get { return accDisChargPw; }
set { accDisChargPw = value; RaisePropertyChanged(); }
}
private double aVol;
///
/// A相电压
///
public double AVol
{
get { return aVol; }
set
{
aVol = value;
if (value<5)
{
PcsAcCircuitBreaker = false;
}
else
{
PcsAcCircuitBreaker = true;
}
RaisePropertyChanged();
}
}
private double bVol;
///
/// B相电压
///
public double BVol
{
get { return bVol; }
set { bVol = value; RaisePropertyChanged(); }
}
private double cVol;
///
/// C相电压
///
public double CVol
{
get { return cVol; }
set { cVol = value; RaisePropertyChanged(); }
}
private double aCur;
///
/// A相电流
///
public double ACur
{
get { return aCur; }
set { aCur = value; RaisePropertyChanged(); }
}
private double bCur;
///
/// B相电流
///
public double BCur
{
get { return bCur; }
set { bCur = value; RaisePropertyChanged(); }
}
private double cCur;
///
/// C相电流
///
public double CCur
{
get { return cCur; }
set { cCur = value; RaisePropertyChanged(); }
}
private double netFreq;
///
/// 电网频率
///
public double NetFreq
{
get { return netFreq; }
set { netFreq = value; RaisePropertyChanged(); }
}
private double totalReactivePw;
///
/// 电网无功功率
///
public double TotalReactivePw
{
get { return totalReactivePw; }
set { totalReactivePw = value; RaisePropertyChanged(); }
}
private double totalApparentPw;
///
/// 电网视在功率
///
public double TotalApparentPw
{
get { return totalApparentPw; }
set { totalApparentPw = value; RaisePropertyChanged(); }
}
private double inputVol;
///
/// 输入电压
///
public double InputVol
{
get { return inputVol; }
set { inputVol = value; RaisePropertyChanged(); }
}
private double inputCur;
///
/// 输入电流
///
public double InputCur
{
get { return inputCur; }
set { inputCur = value; RaisePropertyChanged(); }
}
private double inputPw;
///
/// 输入功率
///
public double InputPw
{
get { return inputPw; }
set { inputPw = value; RaisePropertyChanged(); }
}
private double pwNetFactor;
///
/// 功率因数
///
public double PwNetFactor
{
get { return pwNetFactor; }
set { pwNetFactor = value; RaisePropertyChanged(); }
}
private double finTemp;
///
/// 散热器温度
///
public double FinTemp
{
get { return finTemp; }
set { finTemp = value; RaisePropertyChanged(); }
}
private double curCmdPw;
///
/// 当前的指令Pw
/// 正为充电
/// 负为放电
///
public double CurCmdPw
{
get { return curCmdPw; }
set { curCmdPw = value; RaisePropertyChanged(); }
}
#endregion
#region PCS实时曲线
public Random rand = new Random();
///
/// 定时器执行方法
///
///
///
///
private void CurTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
{
//如果Execute执行的是一个很耗时的方法,会导致方法未执行完毕,定时器又启动了一个线程来执行Execute方法
CurTimer.Stop(); //先关闭定时器
Application.Current.Dispatcher.Invoke(() =>
{
if (RtTrend.Count < 100)//2分钟
{
RtTrend.Add(new RtPcsPwChartModel() { QPw = Power, CmdPw = CurCmdPw, CurTime = DateTime.Now });//Power
}
else if (RtTrend.Count >= 100)
{
RtTrend.RemoveAt(0);
RtTrend.Add(new RtPcsPwChartModel() { QPw = Power, CmdPw = CurCmdPw, CurTime = DateTime.Now });//Power
}
});
CurTimer.Start(); //执行完毕后再开启器
}
private ObservableCollection _RtTrend = new ObservableCollection();
///
/// 实时曲线 数据集合
///
public ObservableCollection RtTrend
{
get { return _RtTrend; }
set { _RtTrend = value; RaisePropertyChanged(); }
}
public ILogService LogService { get; }
public IFreeSql FreeSql { get; }
public BmsDataService BmsDataService { get; }
public ConfigDataService ConfigDataService { get; }
#endregion
#region PCS封装功能
///
/// 发送PCS充电功率
/// 正是充电
///
///
public void SendPcsChargCmd(double targetpw)
{
CurCmdPw = targetpw;
//Console.WriteLine($"datetime:{DateTime.Now.ToString()} 发送储能功率【充电】:{targetpw}");
var result1 = ModbusTcpNetDrive.Write("309", (short)(targetpw / 3.0 * 10));
if (!result1.IsSuccess)
{
Console.WriteLine($"datetime:{DateTime.Now.ToString()} 发送【充电】储能功率【失败】:{targetpw}");
}
ModbusTcpNetDrive.Write("310", (short)(targetpw / 3.0 * 10));
ModbusTcpNetDrive.Write("311", (short)(targetpw / 3.0 * 10));
}
///
/// 发送PCS充电功率
/// 正是充电
///
///
public async Task SendPcsChargCmdAsync(double targetpw)
{
CurCmdPw = targetpw;
Console.WriteLine($"datetime:{DateTime.Now.ToString()} 发送储能功率【充电】:{targetpw}");
var result1 = await ModbusTcpNetDrive.WriteAsync("309", (short)(targetpw / 3.0 * 10));
if (!result1.IsSuccess)
{
Console.WriteLine($"datetime:{DateTime.Now.ToString()} 发送【充电】储能功率【失败】:{targetpw}");
}
await ModbusTcpNetDrive.WriteAsync("310", (short)(targetpw / 3.0 * 10));
await ModbusTcpNetDrive.WriteAsync("311", (short)(targetpw / 3.0 * 10));
}
///
/// 发送PCS放电功率
/// 负是放电
///
///
public void SendPcsDisChargCmd(double targetpw)
{
CurCmdPw = targetpw;
//Console.WriteLine($"datetime:{DateTime.Now.ToString()} 发送储能功率【放电】:{targetpw}");
var result1 = ModbusTcpNetDrive.Write("309", (short)(targetpw / 3.0 * 10));
if (!result1.IsSuccess)
{
Console.WriteLine($"datetime:{DateTime.Now.ToString()} 发送【放电】储能功率【失败】:{targetpw}");
}
ModbusTcpNetDrive.Write("310", (short)(targetpw / 3.0 * 10));
ModbusTcpNetDrive.Write("311", (short)(targetpw / 3.0 * 10));
}
///
/// 发送PCS放电功率
/// 负是放电
///
///
public async Task SendPcsDisChargCmdAsync(double targetpw)
{
CurCmdPw = targetpw;
Console.WriteLine($"datetime:{DateTime.Now.ToString()} 发送储能功率【放电】:{targetpw}");
var result1 = await ModbusTcpNetDrive.WriteAsync("309", (short)(targetpw / 3.0 * 10));
if (!result1.IsSuccess)
{
Console.WriteLine($"datetime:{DateTime.Now.ToString()} 发送【放电】储能功率【失败】:{targetpw}");
}
await ModbusTcpNetDrive.WriteAsync("310", (short)(targetpw / 3.0 * 10));
await ModbusTcpNetDrive.WriteAsync("311", (short)(targetpw / 3.0 * 10));
}
///
/// 发送PCS待机指令
/// 就是给0的数据值
///
public void StandbyPwCmd()
{
CurCmdPw = 0;
//Console.WriteLine($"时间:{DateTime.Now.ToString()}:发送0功率值,PCS待机数据 ");
ModbusTcpNetDrive.Write("309", (short)(0 / 3.0 * 10));
ModbusTcpNetDrive.Write("310", (short)(0 / 3.0 * 10));
ModbusTcpNetDrive.Write("311", (short)(0 / 3.0 * 10));
}
///
/// 发送PCS待机指令
/// 就是给0的数据值
///
public async Task StandbyPwCmdAsync()
{
CurCmdPw = 0;
Console.WriteLine($"时间:{DateTime.Now.ToString()}:发送0功率值,PCS待机数据 ");
await ModbusTcpNetDrive.WriteAsync("309", (short)(0 / 3.0 * 10));
await ModbusTcpNetDrive.WriteAsync("310", (short)(0 / 3.0 * 10));
await ModbusTcpNetDrive.WriteAsync("311", (short)(0 / 3.0 * 10));
}
///
/// 并离网的配置
///
public void PcsOffLineCmd(PCSOffLineInfo pCSOffLineInfo)
{
switch (pCSOffLineInfo)
{
case PCSOffLineInfo.OnLine:
ModbusTcpNetDrive.Write("306", (short)1);
break;
case PCSOffLineInfo.OffLine:
ModbusTcpNetDrive.Write("306", (short)0);
break;
default:
break;
}
}
///
/// 并离网的配置
///
public async Task PcsOffLineCmdAsync(PCSOffLineInfo pCSOffLineInfo)
{
switch (pCSOffLineInfo)
{
case PCSOffLineInfo.OnLine:
await ModbusTcpNetDrive.WriteAsync("306", (short)1);
break;
case PCSOffLineInfo.OffLine:
await ModbusTcpNetDrive.WriteAsync("306", (short)0);
break;
default:
break;
}
}
///
/// PCS启动 异步
///
public async Task PCSStartAsync()
{
var Result = await ModbusTcpNetDrive.WriteAsync("2", true);
if (Result.IsSuccess)
{
return true;
}
return false;
}
///
/// PCS启动
///
public bool PCSStart()
{
var Result = ModbusTcpNetDrive.Write("2", true);
if (Result.IsSuccess)
{
return true;
}
return false;
}
///
/// PCS停止
///
public bool PCSStop()
{
var Result = ModbusTcpNetDrive.Write("3", true);
if (Result.IsSuccess)
{
return true;
}
return false;
}
///
/// PCS停止 异步
///
public async Task PCSStopAsync()
{
var Result = await ModbusTcpNetDrive.WriteAsync("3", true);
if (Result.IsSuccess)
{
return true;
}
return false;
}
///
/// PCS故障复位
///
public bool PCSFaultReset()
{
var Result = ModbusTcpNetDrive.Write("1", true);
if (Result.IsSuccess)
{
return true;
}
return false;
}
///
/// PCS故障复位
///
public async Task PCSFaultResetAsync()
{
var Result = await ModbusTcpNetDrive.WriteAsync("1", true);
if (Result.IsSuccess)
{
return true;
}
return false;
}
///
/// PCS远程和本地切换
///
public async Task PCSRemoteLocation(bool value)
{
var Result = await ModbusTcpNetDrive.WriteAsync("7", value);
if (Result.IsSuccess)
{
return true;
}
return false;
}
///
/// PCS远程和本地切换
///
public async Task PCSRemoteLocationAsync(bool value)
{
var Result = await ModbusTcpNetDrive.WriteAsync("7", value);
if (Result.IsSuccess)
{
return true;
}
return false;
}
///
///关闭驱动链接
///
public void CloseModbusRtu()
{
ThreadEnable = false;
CurTimer.Stop();
ModbusTcpNetDrive.ConnectClose();
}
///
///关闭驱动链接
///
public async Task CloseModbusRtuAsync()
{
ThreadEnable = false;
await ModbusTcpNetDrive.ConnectCloseAsync();
}
#endregion
#region 报警
///
/// 队列通道
/// 当前队列消费当前产线的报警数据
///
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))
{
//FSqlContext.FDb.Select
//统一的处理报警信息
FreeSql.Insert(new HistoryAlarm()
{
Category = "PCS",
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}");
}
}
}
#endregion
}
}