using DevExpress.XtraCharts; using DevExpress.XtraEditors; using GCAS.Code; using GCAS.Dto; using GCAS.Localization; using GCAS.Model; using HslCommunication; using HslCommunication.Core; using HslCommunication.ModBus; using HslCommunication.Profinet.Siemens; using System; using System.Collections.Generic; using System.Configuration; using System.Drawing; using System.Linq; using System.Media; using System.Speech.Synthesis; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace GCAS { public partial class RealTimeOneCarTwoEntanceForm : XtraForm { private List viewDatas; private bool isThreadRun = false; private Thread clientAThread = null; private Thread clientBThread = null; private Thread teamThread = null; private List busTcpClients = null; //private SiemensS7Net siemensS7Net = null; private DeviceRepository deviceRepository; private ReverseWordTrans reverseWord; private ConfigRepository configRepository; private RecordRepository recordRepository; private TeamRepository teamRepository; public OperatorModel currentUser; private List devices; private List teams; private int interval = 50;//读取寄存器间隔ms毫秒 private Series series1; //private Series series2; private ConfigDto config; private TeamModel currentTeam; private List dataPicks; private List L; private ModbusTcpServer busTcpServer; private List entrances; private EntranceRepository entranceRepository; private bool isBindChart = false; private int frontTimes = 100; private int effectCount = 6; private List WeightDatas = new List() { new WeightDataDto { DeviceId = 1, Records = new List { } } }; private SpeechSynthesizer speech; private SoundPlayer playerIn; private SoundPlayer playerOut; private string startModbus = "false"; public RealTimeOneCarTwoEntanceForm() { InitializeComponent(); playerIn = new SoundPlayer { SoundLocation = AppDomain.CurrentDomain.BaseDirectory + @"\Resources\in.wav" }; Task.Run(() => playerIn.LoadAsync()); //同步加载声音 playerOut = new SoundPlayer { SoundLocation = AppDomain.CurrentDomain.BaseDirectory + @"\Resources\out.wav" }; Task.Run(() => playerOut.LoadAsync()); //同步加载声音 speech = new SpeechSynthesizer(); DoubleBuffered = true; L = LocalizationHelper.GetSource(Thread.CurrentThread.CurrentUICulture); deviceRepository = new DeviceRepository(); devices = deviceRepository.GetList(); dataPicks = new List(); configRepository = new ConfigRepository(); recordRepository = new RecordRepository(); teamRepository = new TeamRepository(); entranceRepository = new EntranceRepository(); entrances = entranceRepository.GetList(); teams = teamRepository.GetList(); reverseWord = new ReverseWordTrans(DataFormat.CDAB) { IsStringReverse = true }; config = configRepository.Get(); InitTeam(); startModbus = ConfigurationManager.AppSettings["startModbus"]; if (bool.TryParse(startModbus, out bool isStartModbus) && isStartModbus) { busTcpServer = ModbusServerHelper.StartModbusServer(); if (busTcpServer != null) { Task.Run(() => RefreshModbusServerAsync()); } } series1 = chartControl1.Series[0]; //series2 = chartControl2.Series[0]; ConnectModbusTcp(); var siemensType = Tools.ToEnum(ConfigurationManager.AppSettings["plcType"]); var plcAddess = ConfigurationManager.AppSettings["plcAddress"]; //siemensS7Net = new SiemensS7Net(siemensType, plcAddess) { ConnectTimeOut = 1000, ReceiveTimeOut = 1000 }; interval = int.Parse(ConfigurationManager.AppSettings["readInterval"]); frontTimes = int.Parse(ConfigurationManager.AppSettings["frontTime"]); effectCount = int.Parse(ConfigurationManager.AppSettings["effectCount"]); //siemensS7Net.ConnectServer(); BindTable(currentTeam?.Id ?? 0); } private void ConnectModbusTcp() { busTcpClients = new List(); foreach (var device in devices) { var client = new ModbusTcpNet(device.Ip, device.Port, 1) { ConnectTimeOut = 1000, ReceiveTimeOut = 1000, ConnectionId = device.Id.ToString(), }; var result = client.ConnectServer(); busTcpClients.Add(client); } MainThreadRun(); } public void ChangeDeviceInfo() { devices = deviceRepository.GetList(); foreach (var device in devices) { viewDatas.Single(c => c.DeviceId == device.Id).DeviceName = device.Name; var client = busTcpClients.Single(c => c.ConnectionId == device.Id.ToString()); client.ConnectClose(); client.Port = device.Port; client.IpAddress = device.Ip; client.ConnectServer(); } } public void ChangeEntranceInfo() { entrances = entranceRepository.GetList(); lbl_1_entrance_1_name.Text = lbl_all_entrance_1_name.Text = entrances.Single(c => c.Id == 1).Name; lbl_1_entrance_2_name.Text = lbl_all_entrance_2_name.Text = entrances.Single(c => c.Id == 2).Name; //lbl_1_entrance_3_name.Text = lbl_2_entrance_3_name.Text = lbl_all_entrance_3_name.Text = entrances.Single(c => c.Id == 3).Name; } public void ChangeTeamInfo() { teams = teamRepository.GetList(); InitTeam(); } public void ChangeConfigInfo() { config = configRepository.Get(); } private void MainThreadRun() { if (!isThreadRun) { if (viewDatas == null) { viewDatas = new List(); } isThreadRun = true; clientAThread = new Thread(ThreadAReadServer) { IsBackground = true }; clientAThread.Start(); teamThread = new Thread(ThreadTeamChange) { IsBackground = true }; teamThread.Start(); } else { isThreadRun = false; } } private void ThreadTeamChange() { InitTeam(); while (isThreadRun) { Thread.Sleep(1000 * 60); if (IsHandleCreated) { Invoke(new EventHandler(delegate { InitTeam(); })); } } } private void InitTeam() { DateTime now = DateTime.Now; TeamModel nextTeam = new TeamModel(); var query = from team in teams let sp1 = TimeSpan.Parse(team.StartTime) let sp2 = TimeSpan.Parse(team.EndTime) let start = sp1 > sp2 ? (now.TimeOfDay > sp1 ? now.Date + sp1 : now.AddDays(-1).Date + sp1) : now.Date + sp1 let end = sp1 > sp2 ? (now.TimeOfDay > sp1 ? now.AddDays(1).Date + sp2 : now.Date + sp2) : now.Date + sp2 where now >= start && now < end select team; var nextTeams = query.ToList(); ////获取符合时间的班组 //var nextTeams = teams.Where(c => now > DateTime.Parse(now.ToShortDateString() + " " + c.StartTime) && now < DateTime.Parse(now.AddDays(c.NextDay).ToShortDateString() + " " + c.EndTime)).ToList(); nextTeam = nextTeams[0]; if (nextTeam != null) { var span = DateTime.Parse(now.ToShortDateString() + " " + nextTeam.EndTime) - now; if (span.TotalMinutes < 10) { lbl_changeTeam1.Visible = true; lbl_changeTeam1.Text = string.Format(L.GetString("changeTeam"), (int)span.TotalMinutes); } else { lbl_changeTeam1.Visible = false; } lbl_team_1.Text = nextTeam.Name; } else { lbl_changeTeam1.Visible =false; lbl_team_1.Text = L.GetString("leisure"); } if (currentTeam != nextTeam) { BindTable(nextTeam?.Id ?? 0); currentTeam = nextTeam; } } private void ThreadAReadServer() { while (true) { if (isThreadRun) { Thread.Sleep(interval); ReadValueDataAsync(1); } else { break; } // 再次检测连接是否关闭 if (!isThreadRun) { Thread.Sleep(50); break; } } } private void ThreadBReadServer() { while (true) { if (isThreadRun) { Thread.Sleep(interval); ReadValueDataAsync(2); } else { break; } // 再次检测连接是否关闭 if (!isThreadRun) { Thread.Sleep(50); break; } } } private void ReadValueDataAsync(int deviceId) { OperateResult modbusRead; ValueDataModel data; DataPickDto dataPick; int weight = 0; string recordWeight = string.Empty, effectWeight = string.Empty; bool isExist; int maxTakeWeightCount = frontTimes / interval * 20; var client = busTcpClients.Single(c => c.ConnectionId == deviceId.ToString()); isExist = true; deviceId = int.Parse(client.ConnectionId); //判读是否存在 data = viewDatas.FirstOrDefault(c => c.DeviceId == deviceId); if (data == null) { data = new ValueDataModel(deviceId, devices.Single(c => c.Id == deviceId).Name); isExist = false; } //读取PLC就位信号 //var readQ = siemensS7Net.Read("Q0", 1); //if (readQ.IsSuccess) //{ // var signals = siemensS7Net.ByteTransform.TransBool(readQ.Content, 0, 1); // if (deviceId == 1) // { // data.E1 = signals[0]; // data.E2 = signals[1]; // //data.E3 = signals[2]; // } //} //var readI = siemensS7Net.ReadBool(deviceId == 1 ? "I0.4" : "I0.6"); //if (readI.IsSuccess) //{ // data.OP = readI.Content; //} data.DeviceName = devices.Single(c => c.Id == deviceId).Name; dataPick = dataPicks.FirstOrDefault(c => c.DeviceId == deviceId); if (dataPick == null) { dataPick = new DataPickDto { DeviceId = deviceId, Weights = new List() }; dataPicks.Add(dataPick); } modbusRead = client.Read("x=4;0000", 7); if (modbusRead.IsSuccess) { data.IsOnline = true; var stateBytes = modbusRead.Content.Skip(0).Take(2).ToArray(); var stateChars = Convert.ToString(reverseWord.TransInt16(stateBytes, 0), 2).PadLeft(8, '0').ToCharArray().Select(c => c == '1').Reverse().ToArray(); data.YJ = stateChars[0]; data.BJ = stateChars[1]; data.LW = stateChars[4]; data.WD = stateChars[5]; var statusBytes = modbusRead.Content.Skip(2).Take(2).ToArray(); var statuChars = Convert.ToString(reverseWord.TransInt16(statusBytes, 0), 2).PadLeft(8, '0').Select(c => c == '1').Reverse().ToArray(); data.E1 = statuChars[0]; data.E2 = statuChars[1]; data.OP = statuChars[2]; var netBytes = modbusRead.Content.Skip(4).Take(4).ToArray(); data.NetWeight = reverseWord.TransInt32(netBytes, 0); var tareBytes = modbusRead.Content.Skip(8).Take(4).ToArray(); data.TareWeight = reverseWord.TransInt32(tareBytes, 0); var ratedBytes = modbusRead.Content.Skip(12).Take(2).ToArray(); data.RatedWeight = (ushort)(reverseWord.TransUInt16(ratedBytes, 0) * 10); #region 重量计算 var weightData = WeightDatas.Single(c => c.DeviceId == deviceId); dataPick.Weights.Add(new WeightDto { Weight = data.NetWeight, Time = DateTime.Now }); if (dataPick.Weights.Count > 100) { dataPick.Weights.RemoveAt(0); } //就位任意料口 1# 2# 3# //if (data.E1 || data.E2 || data.E3) if (data.E1 || data.E2) { var entranceId = data.E1 ? 1 : 2 ; if (weightData.EntranceId == 0) { Task.Run(() => playerIn.PlaySync()); //启用新线程播放 weightData.EntranceId = entranceId; } dataPick.EntranceId = entranceId; // 抓斗打开 且上次抓斗状态为闭合 即为投料 if (data.OP && !weightData.OpenState) { Measure(dataPick, weightData); } } else { if (weightData.EntranceId != 0) { Task.Run(() => playerOut.PlaySync()); //启用新线程播放 weightData.EntranceId = 0; } if (weightData.Records.Any()) { Measure(dataPick, weightData); var firstRecord = weightData.Records.First(); var lastRecord = weightData.Records.Count >= 2 ? weightData.Records.Last() : null; weight = firstRecord.Weight - (lastRecord?.Weight ?? 0); if (weight < 0 || weight > config.PutThresholdMin) { recordRepository.Insert(new RecordModel { Device = deviceId, Entrance = dataPick.EntranceId, GrossWeight = weight + data.TareWeight, TareWeight = data.TareWeight, NetWeight = weight, Time = DateTime.Now, Team = currentTeam?.Id ?? 0 }); Task.Run(() => speech.SpeakAsync($" {dataPick.EntranceId}号料口加料{weight / 1000f}吨")); if (IsHandleCreated) { Invoke(new EventHandler(delegate { if (deviceId == 1) { series1.Points.Add(new SeriesPoint(DateTime.Now, (weight / 1000f).ToString("0.00"))); } BindTable(currentTeam?.Id ?? 0); if (bool.TryParse(startModbus, out bool isStartModbus) && isStartModbus) { Task.Run(() => RefreshModbusServerAsync()); } })); } } //清空开斗数据记录 weightData.Records = new List(); } } weightData.OpenState = data.OP; #endregion 重量计算 } else { if (data != null) { data.IsOnline = false; } } if (!isExist) viewDatas.Add(data); if (isThreadRun) { if (IsHandleCreated) { Invoke(new EventHandler(delegate { InitView(deviceId); })); } } } private void InitView(int deviceId) { if (!isBindChart) { BindChart(); } var viewData = viewDatas.FirstOrDefault(c => c.DeviceId == deviceId); if (viewData == null) { return; } if (deviceId == 1) { lbl_devcieName_1.Text = group_1.Text = viewData.DeviceName; var totalWeight = viewData.NetWeight + viewData.TareWeight; var axisY1 = ((XYDiagram)chartControl1.Diagram).AxisY; if (!axisY1.ConstantLines.Any(c => c.Value == viewData.RatedWeight / 1000 * 1.05f)) { axisY1.ConstantLines.Clear(); ConstantLine line = new ConstantLine { Color = Color.Red, AxisValue = viewData.RatedWeight / 1000f * 1.05f, Name = L.GetString("overload") }; line.LineStyle.DashStyle = DashStyle.Dash; axisY1.ConstantLines.Add(line); } if (viewData.BJ) { lbl_netWeight_1.ForeColor = Color.FromArgb(234, 21, 122); } else { lbl_netWeight_1.ForeColor = viewData.YJ ? Color.FromArgb(254, 184, 10) : Color.FromArgb(127, 209, 59); } lbl_netWeight_1.Text = (viewData.NetWeight / 1000F).ToString("0.00"); if (viewData.IsOnline) { lbl_isOnline_1.Text = L.GetString("normal"); pic_isOnline_1.Image = Properties.Resources.green; } else { lbl_isOnline_1.Text = L.GetString("abnormal"); pic_isOnline_1.Image = Properties.Resources.red; } pic_lw_1.Image = viewData.LW ? Properties.Resources.green : Properties.Resources.gray; pic_wd_1.Image = viewData.WD ? Properties.Resources.green : Properties.Resources.gray; if (viewData.BJ) { pic_yj_1.Image = Properties.Resources.red; lbl_yj_1.Text = L.GetString("overload"); } else { pic_yj_1.Image = viewData.YJ ? Properties.Resources.yellow : Properties.Resources.gray; lbl_yj_1.Text = L.GetString("warning"); } busTcpServer?.Write("1100", new int[] { viewData.NetWeight, viewData.TareWeight, viewData.RatedWeight }); //A车 if (viewData.E1) { if (!pic_entrance_1_1.Enabled) { pic_entrance_1_1.Enabled = true; pic_entrance_1_2.Enabled = false; lbl_entrance_1.Text = string.Format(L.GetString("enterEntrance"), entrances.Single(c => c.Id == 1).Name); } } else if (viewData.E2) { if (!pic_entrance_1_2.Enabled) { pic_entrance_1_1.Enabled = false; pic_entrance_1_2.Enabled = true; lbl_entrance_1.Text = string.Format(L.GetString("enterEntrance"), entrances.Single(c => c.Id == 2).Name); } } else { if (pic_entrance_1_1.Enabled || pic_entrance_1_2.Enabled ) { pic_entrance_1_1.Enabled = pic_entrance_1_2.Enabled = false; lbl_entrance_1.Text = string.Empty; } } } } private async Task RefreshModbusServerAsync() { var source = await recordRepository.TotalStatistics(); busTcpServer?.Write("1000", new int[] { source.Daily, source.Weekly, source.Monthly, source.AnnualTotal }); } public void BindTable(int? teamId) { if (teamId == null) { teamId = currentTeam?.Id ?? 0; } var source1 = Task.Run(() => recordRepository.DailyStatistics(teamId.Value, 1)).Result; if (source1.Any()) { var entrance1 = source1.First(c => c.Id == 1); lbl_1_entrance_1_name.Text = entrance1.Name; lbl_1_entrance_1_daily.Text = entrance1.DailyCount + " 斗, " + (entrance1.DailyTotal / 1000f).ToString("0.00") + "T"; lbl_1_entrance_1_team.Text = entrance1.TeamCount + " 斗, " + (entrance1.TeamTotal / 1000f).ToString("0.00") + "T"; var entrance2 = source1.First(c => c.Id == 2); lbl_1_entrance_2_name.Text = entrance2.Name; lbl_1_entrance_2_daily.Text = entrance2.DailyCount + " 斗, " + (entrance2.DailyTotal / 1000f).ToString("0.00") + "T"; lbl_1_entrance_2_team.Text = entrance2.TeamCount + " 斗, " + (entrance2.TeamTotal / 1000f).ToString("0.00") + "T"; //var entrance3 = source1.First(c => c.Id == 3); //lbl_1_entrance_3_name.Text = entrance3.Name; //lbl_1_entrance_3_daily.Text = entrance3.DailyCount + " 斗, " + (entrance3.DailyTotal / 1000f).ToString("0.00") + "T"; //lbl_1_entrance_3_team.Text = entrance3.TeamCount + " 斗, " + (entrance3.TeamTotal / 1000f).ToString("0.00") + "T"; lbl_1_entrance_all_daily.Text = source1.Sum(c => c.DailyCount) + " 斗, " + (source1.Sum(c => c.DailyTotal) / 1000f).ToString("0.00") + "T"; lbl_1_entrance_all_team.Text = source1.Sum(c => c.TeamCount) + " 斗, " + (source1.Sum(c => c.TeamTotal) / 1000f).ToString("0.00") + "T"; //lbl_total_1.Text = ((entrance1.TeamTotal + entrance2.TeamTotal + entrance3.TeamTotal) / 1000f).ToString("0.00") + "T"; lbl_total_1.Text = ((entrance1.TeamTotal + entrance2.TeamTotal) / 1000f).ToString("0.00") + "T"; } var source3 = Task.Run(() => recordRepository.DailyTotalStatistics(teamId.Value)).Result; if (source3.Any()) { var entrance1 = source3.First(c => c.Id == 1); lbl_all_entrance_1_name.Text = entrance1.Name; lbl_all_entrance_1_daily.Text = entrance1.DailyCount + " 斗, " + (entrance1.DailyTotal / 1000f).ToString("0.00") + "T"; lbl_all_entrance_1_team.Text = entrance1.TeamCount + " 斗, " + (entrance1.TeamTotal / 1000f).ToString("0.00") + "T"; var entrance2 = source3.First(c => c.Id == 2); lbl_all_entrance_2_name.Text = entrance2.Name; lbl_all_entrance_2_daily.Text = entrance2.DailyCount + " 斗, " + (entrance2.DailyTotal / 1000f).ToString("0.00") + "T"; lbl_all_entrance_2_team.Text = entrance2.TeamCount + " 斗, " + (entrance2.TeamTotal / 1000f).ToString("0.00") + "T"; //var entrance3 = source3.First(c => c.Id == 3); //lbl_all_entrance_3_name.Text = entrance3.Name; //lbl_all_entrance_3_daily.Text = entrance3.DailyCount + " 斗, " + (entrance3.DailyTotal / 1000f).ToString("0.00") + "T"; //lbl_all_entrance_3_team.Text = entrance3.TeamCount + " 斗, " + (entrance3.TeamTotal / 1000f).ToString("0.00") + "T"; lbl_all_entrance_all_daily.Text = source3.Sum(c => c.DailyCount) + " 斗, " + (source3.Sum(c => c.DailyTotal) / 1000f).ToString("0.00") + "T"; lbl_all_entrance_all_team.Text = source3.Sum(c => c.TeamCount) + " 斗, " + (source3.Sum(c => c.TeamTotal) / 1000f).ToString("0.00") + "T"; } } public void BindChart() { series1.Points.Clear(); var soruce1 = Task.Run(() => recordRepository.GetDailyRealTimeData(1, currentTeam.Id)).Result; foreach (var point in soruce1) { series1.Points.Add(new SeriesPoint(point.Time, point.Weight.ToString("0.00"))); } } private void RealTimeForm_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.MdiFormClosing)//判断点击的是父窗体还是子窗体 { isThreadRun = false; } else if (e.CloseReason == CloseReason.UserClosing) { e.Cancel = true; } } private void RealTimeForm_FormClosed(object sender, FormClosedEventArgs e) { isThreadRun = false; } private void panelControl10_Resize(object sender, EventArgs e) { lbl_devcieName_1.Location = new Point(Convert.ToInt32(panelControl10.Width - lbl_devcieName_1.Width) / 2, Convert.ToInt32(panelControl10.Height - lbl_devcieName_1.Height) / 4); } //private void panelControl12_Resize(object sender, EventArgs e) //{ // lbl_devcieName_2.Location = new Point(Convert.ToInt32(panelControl12.Width - lbl_devcieName_2.Width) / 2, Convert.ToInt32(panelControl12.Height - lbl_devcieName_2.Height) / 4); //} public void Measure(DataPickDto dataPick, WeightDataDto weightData) { //是否有称重数据 if (dataPick.Weights.Any()) { var lastDataTime = dataPick.Weights.Last().Time; var firstDataTime = dataPick.Weights.First().Time; dataPick.Weights.Reverse(); //截取有效值 即 松斗信号之前x毫秒数据内n条重量记录 var effectWeights = dataPick.Weights.Where(c => c.Time < lastDataTime.AddMilliseconds(-frontTimes)).Take(effectCount); //有效值数量是否满足 if (effectWeights.Count() == effectCount) { //获得准确重量 var weight = (int)effectWeights.OrderBy(c => c.Weight).Skip(1).Take(effectCount - 2).Average(c => c.Weight); var effectWeight = effectWeights.ToJsonString(); var recordWeight = dataPick.Weights.Take(40).ToJsonString(); //记录松斗记录(有可能一次投料 松斗合斗好几次 造成多次累积 故记录多次 离开或者归零时取首次) weightData.Records.Add(new WeightDataItem { Time = DateTime.Now, EffectWeight = effectWeight, RecordWeight = recordWeight, Weight = weight }); } dataPick.Weights = new List(); } } } }