diff --git a/Aucma.Core.SheetMetal/Business/SheetMetalPlanTaskHandle.cs b/Aucma.Core.SheetMetal/Business/SheetMetalPlanTaskHandle.cs new file mode 100644 index 00000000..8dfa5764 --- /dev/null +++ b/Aucma.Core.SheetMetal/Business/SheetMetalPlanTaskHandle.cs @@ -0,0 +1,226 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading; +using System.Windows; +using Admin.Core.Common; +using Admin.Core.IService; +using Admin.Core.Model; +using Aucma.Core.HwPLc; +using Microsoft.Extensions.DependencyInjection; + +namespace Aucma.Core.SheetMetal.Business; + +/// +/// 箱壳计划任务处理 +/// +public class SheetMetalPlanTaskHandle +{ + + /// + /// 刷新当前正在执行的计划 + /// + public delegate void RefreshCurrentPlanInfo(ExecutePlanInfo planInfo); + public event RefreshCurrentPlanInfo RefreshCurrentPlanInfoEvent; + + protected readonly IExecutePlanInfoServices? _executePlanInfoServices; + + public SheetMetalPlanTaskHandle() + { + _executePlanInfoServices = + App.ServiceProvider.GetService(); + } + + /// + /// 箱壳计划任务下发⾄设备PLC + /// + /// + public void SendPlanTaskToDevice() + { + + + Thread.Sleep(5000); + try + { + lock (string.Empty) + { + string stationCode = Appsettings.app("StoreInfo", "StationCode"); + //获取待执⾏的计划,根据计划序号进⾏排序依次下发 + var list = _executePlanInfoServices.Query(d => + d.ProductLineCode.Equals(stationCode) && d.ExecuteStatus == 1); + if (list != null) + { + + if (list.Count > 0) + { + ExecutePlanInfo task = list.OrderBy(x => x.ExecuteOrder).First(); + + var obj = PlcHelper.melsecList.FirstOrDefault(d => + d.EquipName.Equals("OldTypePlc1")); + if (obj != null) + { + //计划编号10个字:D6000-D6009、物料编号10个字:D6010-D6019、计划数量1个字:D6020、应答字1个字D6021 + obj.plc.WriteString("D6000", task.TaskCode); + string processNumber = GetProcessNumberBy(task.MaterialCode); + obj.plc.WriteString("D6010", "BCD/310NF"); + obj.plc.WriteInt32("D6020", task.PlanAmount); + obj.plc.WriteInt32("D6021", 1); + + Console.WriteLine($"{DateTime.Now.ToString("HH:m:s")}===>等待设备应答。。。。。。"); + //下发完成后读取PLC应答,应答后复位应答信号 + ReadPlcFeedBack(obj); + + //更新计划状态为2执行中 + task.ExecuteStatus = 2; + _executePlanInfoServices.UpdateExecutePlanInfo(task); + RefreshCurrentPlanInfoEvent?.Invoke(task); + + //读取设备进度,完成后再次下发新任务 + ReadDeviceComplate(obj); + } + } + else + { + Console.WriteLine($"{DateTime.Now.ToString("HH:m:s")}===>未获取到需要下发的生产计划!"); + } + } + } + } + catch (Exception ex) + { + MessageBox.Show($"箱壳⽣产计划下发异常:{ex.Message}", "提示", MessageBoxButton.OK, MessageBoxImage.Error, + MessageBoxResult.OK, MessageBoxOptions.DefaultDesktopOnly); + } + } + + /// + /// 读取PLC应答反馈,PLC反馈后复位应答地址 + /// + private void ReadPlcFeedBack(PlcModel obj) + { + + bool isFlag = true; + + if (obj != null) + { + do + { + + if (obj.plc.ReadInt32("D6021") == 2) + { + obj.plc.WriteInt32("D6021", 0); + Console.WriteLine($"{DateTime.Now.ToString("HH:m:s")}===>收到设备应答信号,复位应答地址"); + isFlag = false; + } + Thread.Sleep(2000); + } while (isFlag); + } + } + + /// + /// 读取设备完成数据 + /// + /// + public void ReadDeviceComplate(PlcModel obj) + { + bool isFlag = true; + + try + { + if (obj != null) + { + do + { + //计划编号:D6030-D6039,物料编号:D6040-D6049,计划完成数:D6050,计划下线数:D6051,设备状态:D6052-D6056,生产节拍:D6057-D6058 + + #region 单个地址读取 + + /* + string planCode = obj.plc.ReadString("D6030"); + string materialCode = obj.plc.ReadString("D6040"); + int complateAmount = obj.plc.ReadInt32("D6050"); + int offLineAmount = obj.plc.ReadInt32("D6051"); + int productionBeat = obj.plc.ReadInt32("D6057"); + */ + + #endregion + + byte[] info = obj.plc.Read("D6030", 59); + //计划编号 + string planCode = Encoding.ASCII.GetString(info.Skip(0).Take(20).ToArray()); + //物料编号 + string materialCode = Encoding.ASCII.GetString(info.Skip(20).Take(20).ToArray()); + //完成数量 + int complateAmount = short.Parse(bytesToHexStr(info.Skip(40).Take(1).ToArray(),1),System.Globalization.NumberStyles.HexNumber); + //下线数量 + int offLineAmount = short.Parse(bytesToHexStr(info.Skip(41).Take(2).ToArray(),2),System.Globalization.NumberStyles.HexNumber); + //设备状态 + int deviceStatus = short.Parse(bytesToHexStr(info.Skip(43).Take(2).ToArray(), 2),System.Globalization.NumberStyles.HexNumber); + //生产节拍 + int productionBeat = short.Parse(bytesToHexStr(info.Skip(51).Take(4).ToArray(),4),System.Globalization.NumberStyles.HexNumber); + + Console.WriteLine($"设备数据读取====>>>>当前计划:{planCode},物料编号:{materialCode},完成数量:{complateAmount},下线数量:{offLineAmount},设备状态:{deviceStatus},生产节拍:{productionBeat}"); + + //更新执行计划,差异值为0后任务结束再次下发新任务 + ExecutePlanInfo planInfo = _executePlanInfoServices.Query(x=>x.TaskCode.Equals(planCode.Substring(0,13)) && x.ExecuteStatus == 2).FirstOrDefault(); + + if (planInfo != null) + { + if (complateAmount > planInfo.CompleteAmount) + { + + if (planInfo.PlanAmount - complateAmount == 0) + { + Console.WriteLine($"计划:{planCode},执行完成!!!"); + planInfo.CompleteAmount = complateAmount; + planInfo.ExecuteStatus = 3; + _executePlanInfoServices.UpdateExecutePlanInfo(planInfo); + + isFlag = false; + } + else + { + Console.WriteLine( + $"设备当前计划:{planCode},计划数量:{planInfo.PlanAmount},实际完成:{complateAmount},差异:{planInfo.PlanAmount - complateAmount}"); + planInfo.CompleteAmount = complateAmount; + _executePlanInfoServices.UpdateExecutePlanInfo(planInfo); + } + + RefreshCurrentPlanInfoEvent?.Invoke(planInfo); + } + } + + Thread.Sleep(5000); + } while (isFlag); + } + } + catch (Exception e) + { + Console.WriteLine($"读取设备完成数据异常:{e.Message}"); + } + } + + /// + /// 通过物料编号获取工艺编号 + /// + /// + /// + private string GetProcessNumberBy(string materialCode) + { + return System.Guid.NewGuid().ToString("N").Substring(0,20); + } + + public static string bytesToHexStr(byte[] bytes, int iLen)//e.g. { 0x01, 0x01} ---> " 01 01" + { + string returnStr = ""; + if (bytes != null) + { + for (int i = 0; i < iLen; i++) + { + returnStr += bytes[i].ToString("X2"); + } + } + return returnStr; + } +} \ No newline at end of file diff --git a/Aucma.Core.SheetMetal/ViewModels/IndexPageViewModel.cs b/Aucma.Core.SheetMetal/ViewModels/IndexPageViewModel.cs index 352e36bf..d52e6e64 100644 --- a/Aucma.Core.SheetMetal/ViewModels/IndexPageViewModel.cs +++ b/Aucma.Core.SheetMetal/ViewModels/IndexPageViewModel.cs @@ -20,6 +20,9 @@ using System.Windows.Media; using log4net; using Admin.Core.Common; using LiveCharts.Defaults; +using Aucma.Core.SheetMetal.Business; +using static Aucma.Core.SheetMetal.Business.SheetMetalPlanTaskHandle; +using System.Threading; /* * 首页信息 * @@ -29,6 +32,7 @@ namespace Aucma.Core.SheetMetal.ViewModels public partial class IndexPageViewModel : ObservableObject { protected readonly IExecutePlanInfoServices? _taskExecutionPlanInfoServices; + private SheetMetalPlanTaskHandle _taskHandle = new SheetMetalPlanTaskHandle(); private AppConfigHelper appConfig = new AppConfigHelper(); List list = new List() { new SelectModel() @@ -46,6 +50,12 @@ namespace Aucma.Core.SheetMetal.ViewModels #region 构造函数 public IndexPageViewModel() { + _taskHandle.RefreshCurrentPlanInfoEvent += RefreshCurrentPlanInfo; + Task.Run(() => + { + Thread.Sleep(5000); + _taskHandle.SendPlanTaskToDevice(); + }); _taskExecutionPlanInfoServices = App.ServiceProvider.GetService(); StationName = Appsettings.app("StoreInfo", "StationName"); Job_SheetMetalTask_Quartz.SmEverDayDelegateEvent += InitEveryDayMethod; @@ -610,5 +620,18 @@ namespace Aucma.Core.SheetMetal.ViewModels return model; } #endregion + + /// + /// 刷新当前执行的计划进度 + /// + /// + private void RefreshCurrentPlanInfo(ExecutePlanInfo planInfo) + { + App.Current.Dispatcher.BeginInvoke((Action)(() => + { + PlanInfoDataGrid.Clear(); + LoadData(); + })); + } } } diff --git a/Aucma.Core.SheetMetal/appsettings.json b/Aucma.Core.SheetMetal/appsettings.json index 1c94b625..98ad211f 100644 --- a/Aucma.Core.SheetMetal/appsettings.json +++ b/Aucma.Core.SheetMetal/appsettings.json @@ -124,15 +124,19 @@ "PLCServer": [ { "Id": 1, - "EquipName": "FrontPlatePlc", + "EquipName": "OldTypePlc1", + "PlcType": "Melsec", + "Enabled": true, "IP": "10.10.91.1", - "Port": 6000 + "Port": 5552 }, { - "Id": 2, + "Id": 1, "EquipName": "RearPanelPLC", - "IP": "10.10.91.12", - "Port": 6000 + "PlcType": "Siemens", + "Enabled": true, + "IP": "10.10.93.41", + "Port": 102 } ] }