using HH.WCS.NongFuChaYuan.DeviceService; using HH.WCS.NongFuChaYuan.DispatchService; using HH.WCS.NongFuChaYuan.OtherService; using HH.WCS.NongFuChaYuan.WmsService; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Timers; using static System.Runtime.CompilerServices.RuntimeHelpers; namespace HH.WCS.NongFuChaYuan.TaskController { /// /// 设备信号处理--特殊设备处理需增加项目名配置 /// internal class DeviceProcess { private static ModbusHelper modbusHelper = new ModbusHelper(); private static Dictionary LineState = new Dictionary(); public class statemodel { public string status { get; set; } public DateTime modify { get; set; } public int error { get; set; } } internal static void Analysis(string data, string ip) { if (data.Length >= 6) { //去掉消息头3F 00 data = data.Substring(4); ////Console.WriteLine($"{ip}-{data}"); var plc = Settings.GetDeviceInfoList().Where(a => a.address == ip && a.enable == 1).FirstOrDefault(); //if (data.Length == 6) //{ // if (data.Substring(4, 2) == "32") // { // //输送线第二个口 // plc = Settings.GetDeviceInfoList().Where(a => a.address == ip && a.location.Contains("") && a.enable == 1).FirstOrDefault(); // } // else if(data.Substring(0,2)=="12") // { // //输送线第一个口 // plc = Settings.GetDeviceInfoList().Where(a => a.address == ip && a.location.Contains("") && a.enable == 1).FirstOrDefault(); // } //} if (plc != null) { alysisDeviceChange(data, plc); } //else { }//Console.WriteLine($"TCP信号处理:未查询到IP为{ip}的数据,请检查deviceInfo配置中心是否存在该IP的数据!"); } } private static void alysisDeviceChange(string data, Settings.deviceInfo plc) { if (plc.deviceType == 1) AnalysisDoor(data, plc);//自动门处理 else if (plc.deviceType == 2) DaMingShanAnalysisBottleCapmolding(data, plc);//注塑机处理 else if (plc.deviceType == 3) DaMingShanAnalysisBottleCapTipper(data, plc);//瓶盖翻斗机处理 else if (plc.deviceType == 6) DaMingShanAnalysisBottleCapmoldTipper(data, plc);//瓶坯翻斗机处理 else if (plc.deviceType == 4) DaMingShanAnalysisBottleCap(data, plc);//瓶盖机处理 else if (plc.deviceType == 5) DaMingShanAnalysisProductLine(data, plc);//输送线处理 else if (plc.deviceType == 7) Roboticarm(data, plc);//机械臂处理 } private static void Roboticarm(string data, Settings.deviceInfo plc) { LogHelper.Info($"{plc.deviceName}--IP={plc.address}--msg={data}"); if (data.Length == 4) { if (data.Substring(0, 2) == "12") { //空框下线 RoboticarmEmpty(plc, plc.location[0]); } if (data.Substring(2, 2) == "21") { //满框上线 RoboticarmFull(plc, plc.location[0]); } } } private static void RoboticarmEmpty(Settings.deviceInfo plc, string location) { var result = false; try { var db = new SqlHelper().GetInstance(); if (location != "") { if (LocationHelper.CheckLocFree(location)) { //查询工单 var endinfo = Settings.GetDaMingShanPriProLineList().Where(a => a.deviceName == plc.deviceName && a.ItemTrayType == "空").FirstOrDefault(); if (endinfo != null) { var workorder = db.Queryable().Where(a => a.S_PLineNo == plc.deviceName && a.S_WorkState == "执行中").First(); if (workorder != null) { var trayNo = ""; var cntr = db.Queryable().Where(a => a.S_LOC_CODE == location).First(); if (cntr != null) { trayNo = cntr.S_CNTR_CODE; } else { trayNo = ContainerHelper.GenerateCntrNo(); } var endarea = endinfo.ProductArea[0]; var endbit = db.Queryable().Where(a => a.S_AREA_CODE == endarea && a.N_CURRENT_NUM == 0 && a.S_LOCK_STATE == "无").First(); if (endbit != null) { var endlocation = endbit.S_LOC_CODE.Trim(); result = IntensiveArea.DaMingShanCreateTransport(location, endlocation, "机械臂空框下线", trayNo, 1, 1, plc.deviceName, 1); if (result) { //绑定货位与托盘 LocCntrRel cn = new LocCntrRel { S_LOC_CODE = location, S_CNTR_CODE = trayNo }; db.Insertable(cn).ExecuteCommand(); } else LogHelper.Info($"机械臂下空任务 任务创建失败"); } else LogHelper.Info($"机械臂下空任务 查询不到可用货位"); } else LogHelper.Info($"机械臂下空任务 查询不到执行中的工单"); } else { LogHelper.Info($"机械臂下空任务 找不到终点配置"); } } else LogHelper.Info($"机械臂任务 当前点位{location} 有未完成的任务"); } } catch (Exception ex) { LogHelper.Error($"机械臂消息处理异常 异常信息={ex.Message}", ex); } } private static void RoboticarmFull(Settings.deviceInfo plc, string location) { try { var db = new SqlHelper().GetInstance(); if (location != "") { if (LocationHelper.CheckLocFree(location)) { //查询工单 var startinfo = Settings.GetDaMingShanPriProLineList().Where(a => a.deviceName == plc.deviceName && a.ItemTrayType == "满").FirstOrDefault(); if (startinfo != null) { var workorder = db.Queryable().Where(a => a.S_PLineNo == plc.deviceName && a.S_WorkState == "执行中").First(); if (workorder != null) { var startarea = startinfo.ProductArea[0]; var startbit = IntensiveArea.DaMingShanGetCacheLocationOut(startarea); if (startbit != null) { var startlocation = startbit.S_LOC_CODE.Trim(); if (startbit.LocCntrRel != null) { var trayNo = startbit.LocCntrRel.S_CNTR_CODE; IntensiveArea.DaMingShanCreateTransport(startlocation, location, "机械臂满框上线", trayNo, 1, 1, plc.deviceName, 1); } else { LogHelper.Info($"机械臂呼满任务 起点{startlocation} 没有绑定托盘信息"); } } else { LogHelper.Info($"机械臂呼满任务 查询不到可用货位"); } } else { LogHelper.Info($"机械臂呼满任务 查询不到执行中的工单"); } } else { LogHelper.Info($"机械臂下空任务 找不到终点配置"); } } else LogHelper.Info($"货位{location} 当前状态不能生成任务"); } else LogHelper.Info($"货位配置站点为空"); } catch (Exception ex) { LogHelper.Error($"机械臂消息处理异常 异常信息={ex.Message}", ex); } } private static void DaMingShanAnalysisBottleCapmoldTipper(string data, Settings.deviceInfo plc) { LogHelper.Info($"{plc.deviceName}--IP={plc.address}--msg={data}", "翻斗机"); //翻斗机下空筐 分配终点解绑起点物料 if (data.Substring(1, 1) == "1") { if (TipperEmpty2(plc, plc.location[0])) { } } var error = data.Substring(data.Length - 2); if (LineState.Keys.Contains(plc.location[0])) { LineState[plc.location[0]].status = data; LineState[plc.location[0]].modify = DateTime.Now; LineState[plc.location[0]].error = int.Parse(error); } else { LineState.Add(plc.location[0], new statemodel { status = data, modify = DateTime.Now, error = int.Parse(error) }); } data = data.Substring(2); LogHelper.Info($"自动门状态:{data},地址为:{plc.address}", "自动门"); //if (data.Length / 2 == plc.deviceNo.Length)//2 2 //{ for (int i = 0; i < plc.deviceNo.Length; i++) { var state = data.Substring(i * 2 + 1, 1); ////Console.WriteLine($"门{plc.deviceNo[i]}的状态{state}"); if (doorStatus.Keys.Contains(plc.deviceNo[i])) { doorStatus[plc.deviceNo[i]].info = state; doorStatus[plc.deviceNo[i]].modify = DateTime.Now; } else { doorStatus.Add(plc.deviceNo[i], new signalInfo { info = state, modify = DateTime.Now }); } } //} } #region 大明山信号处理流程 /// /// 注塑机、翻斗机二段任务 /// /// /// internal static void Secondstagetask(WMSTask mst, bool type) { LogHelper.Info($"大明山设备任务 二段处理"); var info = Settings.GetDeviceInfoList().Where(a => a.location.Contains(mst.S_START_LOC.Trim()) || a.location.Contains(mst.S_END_LOC.Trim())).FirstOrDefault(); if (info != null) { try { if (info.location.Contains(mst.S_START_LOC.Trim())) { if (type) { //取货完成 //注塑机二段任务 if (info.deviceType == 2) { //如果取满任务在A口 送空任务分配在B口 if (info.location[0] == mst.S_START_LOC.Trim()) { //A口 if (moldingEmpty(info, info.location[0])) { LogHelper.Info($"当前位置{info.location[1]} :创建注塑机送空筐任务成功", "注塑机"); } } else { //B口 if (moldingEmpty(info, info.location[1])) { LogHelper.Info($"当前位置{info.location[0]} :创建注塑机送空筐任务成功", "注塑机"); } } } else if (info.deviceType == 3) { //翻斗机二段任务 翻斗机只有一个口 取空送满 if (TipperFull2(info, info.location[0], false)) { //创建任务成功 LogHelper.Info($"当前位置{info.location[0]} :创建翻斗机补满筐任务成功", "翻斗机"); } } else if (info.deviceType == 6) { //翻斗机二段任务 翻斗机只有一个口 取空送满 if (TipperFull2(info, info.location[0], true)) { //创建任务成功 LogHelper.Info($"当前位置{info.location[0]} :创建翻斗机补满筐任务成功", "翻斗机"); } } else if (info.deviceType == 5) { if (mst.S_START_LOC.Trim() == info.location[0]) { //一号口 PlcHelper.SendHex(info.address, "3F00100D0A"); } else { //二号口 PlcHelper.SendHex(info.address, "3F00300D0A"); } } else if (info.deviceType == 4) { //如果取满任务在A口 送空任务分配在B口 if (info.location[0] == mst.S_START_LOC.Trim()) { //A口 if (moldingEmpty2(info, info.location[0])) { LogHelper.Info($"当前位置{info.location[0]} :创建瓶盖机送空筐任务成功", "瓶盖机"); } } else { //B口 if (moldingEmpty2(info, info.location[1])) { LogHelper.Info($"当前位置{info.location[1]} :创建瓶盖机送空筐任务成功", "瓶盖机"); } } } } } else { if (!type) { if (info.deviceType == 5) { PlcHelper.SendHex(info.address, "3F00200D0A"); } if (info.deviceType == 4 || info.deviceType == 2) { if (mst.S_END_LOC == info.location[0]) { PlcHelper.SendHex(info.address, "3F00100D0A"); LogHelper.Info($"当前位置{info.location[0]} :注塑机复位信号成功"); } if (mst.S_END_LOC == info.location[1]) { PlcHelper.SendHex(info.address, "3F00200D0A"); LogHelper.Info($"当前位置{info.location[1]} :注塑机复位信号成功"); } } if (info.deviceType == 3 || info.deviceType == 6) { LogHelper.Info($"翻斗机卸货完成 发送重置信号"); PlcHelper.SendHex(info.address, "3F00100D0A"); } } else { } } } catch (Exception ex) { LogHelper.Error("设备二段处理异常" + ex.Message, ex); } } } /// /// 瓶坯翻斗机上满筐 /// /// /// /// private static bool TipperFull2(Settings.deviceInfo plc, string location, bool v) { //通过站点编号查询工单 //通过工单获取物料编码、批号(前期富勒没上线批号自行编写) var result = false; var db = new SqlHelper().GetInstance(); if (location != "") { if (LocationHelper.CheckLocFree(location)) { LogHelper.Info($"翻斗机:{plc.deviceName} 下线信号:{location} 查询工单", "翻斗机"); var workOrder = WCSHelper.GetPGWorkOrder(plc.deviceName); if (workOrder != null) { LogHelper.Info($"查到了工单{workOrder.S_WorkNo} 工单状态为: {workOrder.S_WorkState }", "翻斗机"); if (workOrder.S_WorkState == "执行中") { var trayInfo = db.Queryable().Where(a => a.S_LOC_CODE == location).ToList(); if (trayInfo.Count() == 0) { if (v) { //瓶坯翻斗机叫料 result = IntensiveArea.DaMingShanPLCOut3(plc, location, true, workOrder); } else { //瓶盖翻斗机叫料 result = IntensiveArea.DaMingShanPLCOut3(plc, location, false, workOrder); } } else { LogHelper.Info($"当前位置{location} :托盘未解绑", "翻斗机"); } } } else { LogHelper.Info($"翻斗机:{plc.deviceName} 下线信号:{location} 未找到工单", "翻斗机"); } } else { LogHelper.Info($"翻斗机:{plc.deviceName} 当前位置{location}有任务,不可触发补满筐任务", "翻斗机"); } } return result; } private static void DaMingShanAnalysisBottleCap(string data, Settings.deviceInfo plc) { LogHelper.Info($"{plc.deviceName}--IP={plc.address}--msg={data}", "瓶盖机"); //下满筐信号生成下满筐任务 待取货完成解绑起点货位 生成送空任务 if (data.Substring(0, 2) == "11") { if (moldingFull2(plc, plc.location[0])) { LogHelper.Info($"{plc.deviceName}--IP={plc.address}--msg=瓶盖机A口生成取满任务", "注塑机"); } } if (data.Substring(2, 2) == "21") { if (moldingFull2(plc, plc.location[1])) { LogHelper.Info($"{plc.deviceName}--IP={plc.address}--msg=瓶盖机B口生成取满任务", "注塑机"); } } data = data.Substring(4); LogHelper.Info($"自动门状态:{data},地址为:{plc.address}", "自动门"); if (data.Length / 2 == plc.deviceNo.Length)//2 2 { for (int i = 0; i < plc.deviceNo.Length; i++) { var state = data.Substring(i * 2 + 1, 1); ////Console.WriteLine($"门{plc.deviceNo[i]}的状态{state}"); if (doorStatus.Keys.Contains(plc.deviceNo[i])) { doorStatus[plc.deviceNo[i]].info = state; doorStatus[plc.deviceNo[i]].modify = DateTime.Now; } else { doorStatus.Add(plc.deviceNo[i], new signalInfo { info = state, modify = DateTime.Now }); } } } } /// /// 接收PLC翻斗机信号 /// /// /// /// private static void DaMingShanAnalysisBottleCapTipper(string data, Settings.deviceInfo plc) { LogHelper.Info($"{plc.deviceName}--IP={plc.address}--msg={data}", "翻斗机"); //翻斗机下空筐 分配终点解绑起点物料 if (data.Substring(1, 1) == "1") { if (TipperEmpty(plc, plc.location[0])) { } } var error = data.Substring(data.Length - 2); if (LineState.Keys.Contains(plc.location[0])) { LineState[plc.location[0]].status = data; LineState[plc.location[0]].modify = DateTime.Now; LineState[plc.location[0]].error = int.Parse(error); } else { LineState.Add(plc.location[0], new statemodel { status = data, modify = DateTime.Now, error = int.Parse(error) }); } LogHelper.Info($"自动门状态:{data},地址为:{plc.address}", "自动门"); data = data.Substring(2); //if (data.Length / 2 == plc.deviceNo.Length)//2 2 //{ for (int i = 0; i < plc.deviceNo.Length; i++) { var state = data.Substring(i * 2 + 1, 1); ////Console.WriteLine($"门{plc.deviceNo[i]}的状态{state}"); if (doorStatus.Keys.Contains(plc.deviceNo[i])) { doorStatus[plc.deviceNo[i]].info = state; doorStatus[plc.deviceNo[i]].modify = DateTime.Now; } else { doorStatus.Add(plc.deviceNo[i], new signalInfo { info = state, modify = DateTime.Now }); } } //} } private static void DaMingShanAnalysisProductLine(string data, Settings.deviceInfo plc) { LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{data} 查询工单", "输送线"); if (data.Substring(0, 2) == "12") { var info = Settings.GetDeviceInfoList().Where(a => a.address == "" && a.location.Contains(plc.location[0]) && a.enable == 1).FirstOrDefault(); if (info != null) { var positionCode = ""; if (info.location.Length > 1) { positionCode = info.location[1]; } ProductLineFull(info, info.location[0], positionCode); } } //补空板||允许补空 if (data.Substring(2, 2) == "21") { var info = Settings.GetDeviceInfoList().Where(a => a.address == "" && a.location.Contains(plc.location[1]) && a.enable == 1).FirstOrDefault(); if (info != null) { ProductLineEmpty(info, info.location[0]); } } if (data.Length == 6) { if (data.Substring(4, 2) == "32") { var info = Settings.GetDeviceInfoList().Where(a => a.address == "" && a.location.Contains(plc.location[2]) && a.enable == 1).FirstOrDefault(); if (info != null) { var positionCode = ""; if (info.location.Length > 1) { positionCode = info.location[1]; } ProductLineFull(info, info.location[0], positionCode); } else { LogHelper.Info($"没有找到location {plc.location[2]} 的配置文件"); } } } if (LineState.Keys.Contains(plc.location[0])) { LineState[plc.location[0]].modify = DateTime.Now; LineState[plc.location[0]].status = data; } else { LineState.Add(plc.location[0], new statemodel { modify = DateTime.Now, status = data }); } if (LineState.Keys.Contains(plc.location[1])) { LineState[plc.location[1]].modify = DateTime.Now; LineState[plc.location[1]].status = data; } else { LineState.Add(plc.location[1], new statemodel { modify = DateTime.Now, status = data }); } if (plc.location.Length > 2) { if (LineState.Keys.Contains(plc.location[2])) { LineState[plc.location[2]].modify = DateTime.Now; LineState[plc.location[2]].status = data; } else { LineState.Add(plc.location[2], new statemodel { modify = DateTime.Now, status = data }); } } } /// /// 输送线补空托 /// /// /// private static void ProductLineEmpty(Settings.deviceInfo plc, string location) { try { if (location != "") { if (LocationHelper.CheckLocFree(location)) { LogHelper.Info($"输送线:{plc.deviceName} 补空信号:{location} 查询工单", "输送线"); var list = plc.deviceName.Split(',').ToList(); foreach (var item in list) { var workorder = WCSHelper.GetWorkOrder(item); if (workorder != null && workorder.S_WorkState.Trim() == "执行中") { LogHelper.Info($"输送线:{item} 下线信号:{location} 找到工单", "输送线"); ProductLineempty(plc, location, workorder, item); break; } else { LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location} 未找到工单", "输送线"); } } } else { LogHelper.Info($"输送线:{plc.deviceName} 当前位置{location}有任务,不可触发栈板上线", "输送线"); } } } catch (Exception ex) { //Console.WriteLine($"输送线呼叫空托异常! 异常信息={ex.Message}"); } } private static void ProductLineempty(Settings.deviceInfo plc, string location, WorkOrder workorder, string deviceName) { bool result = false; var db = new SqlHelper().GetInstance(); try { LogHelper.Info($"输送线:{deviceName} 下线信号:{location} 查询空托库区", "输送线"); var info = Settings.GetDaMingShanPriProLineList().Where(a => a.deviceName == deviceName && a.ItemTrayType == "空").FirstOrDefault(); if (info != null) { for (int i = 0; i < info.ProductArea.Length; i++) { string AreaCode = info.ProductArea[i]; var startLocation = IntensiveArea.GetEmptyOut(AreaCode, workorder.S_TrayType); if (startLocation != null) { var iteminfo = db.Queryable().Where(a => a.S_ITEM_CODE == workorder.S_ItemCode && a.S_ITEM_MODEL == workorder.S_ItemLayer).First(); if (iteminfo != null) { result = IntensiveArea.DaMingShanCreateTransport(startLocation.S_LOC_CODE, location, "栈板上线", startLocation.LocCntrRel.S_CNTR_CODE, 1, 1, deviceName, 1, 1, int.Parse(iteminfo.S_ITEM_LAYER), workorder.S_WorkNo, "", "", workorder.S_TrayType); if (result) { break; } } } } } else { LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location} 未找到空托库区配置文件", "输送线"); } } catch (Exception ex) { //Console.WriteLine($"查询补空库区配置文件异常,异常原因={ex.Message}"); } } internal static void QuLiao(WMSTask mst, bool v) { var info = Settings.GetDeviceInfoList().Where(a => a.location.Contains(mst.S_START_LOC) && a.address != "").FirstOrDefault(); if (info != null) { LogHelper.Info($"安全交互开始 任务号={mst.S_TASK_NO}", "安全交互"); if (info.location[0] == mst.S_START_LOC) { //一号口 if (v) { if (LineState.Keys.Contains(mst.S_START_LOC.Trim())) { LogHelper.Info($"查询输送线允许取满信号 允许取满信号={LineState[mst.S_START_LOC.Trim()].status} 时间间隔={DateTime.Now.Subtract(LineState[mst.S_START_LOC.Trim()].modify).TotalSeconds}", "安全交互"); if (LineState[mst.S_START_LOC.Trim()].status.Substring(0, 2) == "12" && DateTime.Now.Subtract(LineState[mst.S_START_LOC.Trim()].modify).TotalSeconds < 10) { NDCHelper.ChangeParam(mst.S_TASK_NO.Trim(), 1101, 18); PlcHelper.SendHex(info.address, "3F00110D0A"); } } } else { PlcHelper.SendHex(info.address, "3F00100D0A"); } } else { //二号口 if (v) { if (LineState.Keys.Contains(mst.S_START_LOC.Trim())) { LogHelper.Info($"查询输送线允许取满信号 允许取满信号={LineState[mst.S_START_LOC.Trim()].status} 时间间隔={DateTime.Now.Subtract(LineState[mst.S_START_LOC.Trim()].modify).TotalSeconds}", "安全交互"); if (LineState[mst.S_START_LOC.Trim()].status.Substring(4, 2) == "32" && DateTime.Now.Subtract(LineState[mst.S_START_LOC.Trim()].modify).TotalSeconds < 10) { NDCHelper.ChangeParam(mst.S_TASK_NO.Trim(), 1101, 18); PlcHelper.SendHex(info.address, "3F00310D0A"); } } } else { PlcHelper.SendHex(info.address, "3F00300D0A"); } } } else { LogHelper.Info($"任务号 {mst.S_TASK_NO} 找不到起点{mst.S_START_LOC} 对应的IP配置文件"); } } internal static void Xieliao(WMSTask mst, bool v = false) { var info = Settings.GetDeviceInfoList().Where(a => a.location.Contains(mst.S_END_LOC) && a.address != "").FirstOrDefault(); if (info != null) { LogHelper.Info($"安全交互开始 任务号={mst.S_TASK_NO}", "安全交互"); if (info.deviceType == 5) { if (v) { if (LineState.Keys.Contains(mst.S_END_LOC.Trim())) { LogHelper.Info($"查询输送线允许补空信号 允许补空信号={LineState[mst.S_END_LOC.Trim()].status} 时间间隔={DateTime.Now.Subtract(LineState[mst.S_END_LOC.Trim()].modify).TotalSeconds}", "安全交互"); if (LineState[mst.S_END_LOC.Trim()].status.Substring(2, 2) == "21" && DateTime.Now.Subtract(LineState[mst.S_END_LOC.Trim()].modify).TotalSeconds < 10) { NDCHelper.ChangeParam(mst.S_TASK_NO.Trim(), 1103, 18); PlcHelper.SendHex(info.address, "3F00210D0A"); } } } else { PlcHelper.SendHex(info.address, "3F00200D0A"); } } else if (info.deviceType == 3 || info.deviceType == 6) { if (v) { if (LineState.Keys.Contains(mst.S_END_LOC.Trim())) { LogHelper.Info($"查询翻斗机允许卸货信号 允许卸货信号={LineState[mst.S_END_LOC.Trim()].status} 时间间隔={DateTime.Now.Subtract(LineState[mst.S_END_LOC.Trim()].modify).TotalSeconds}", "安全交互"); if (LineState[mst.S_END_LOC.Trim()].error ==0 && DateTime.Now.Subtract(LineState[mst.S_END_LOC.Trim()].modify).TotalSeconds < 10) { NDCHelper.ChangeParam(mst.S_TASK_NO.Trim(), 1103, 18); } } } } } else { LogHelper.Info($"任务号 {mst.S_TASK_NO} 找不到终点{mst.S_END_LOC} 对应的IP配置文件"); } } private static bool ProductLineFull(Settings.deviceInfo plc, string location, string positionCode = "") { var result = false; try { if (location != "") { //取满,需要根据工单以及产线信息,判断当前产线应该下发到哪个库区,以及是什么托盘类型下线 if (LocationHelper.CheckLocFree(location)) { LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location} 查询工单", "输送线"); //1.查询当前产线工单信息 var list = plc.deviceName.Split(',').ToList(); foreach (var item in list) { var deviceName = item; //plc.deviceName = item; var workOrder = WCSHelper.GetWorkOrder(deviceName);//初始工单由富勒WMS传输,后续读取工单读取MOBOX工单表 if (workOrder != null && workOrder.S_WorkState.Trim() == "执行中") { LogHelper.Info($"输送线:{deviceName} 查询到执行中的工单 查询工单", "输送线"); string DeviceStartTime = DateTime.Now.ToString();//当前设备第一次收到下线信号时间 string TrayCode = "";//托盘编码--多个编码用 英文逗号隔开 string BatchNo = string.IsNullOrEmpty(workOrder.S_BatchNo) ? "" : workOrder.S_BatchNo.Trim();//批次号 string ItemLayer = string.IsNullOrEmpty(workOrder.S_ItemLayer) ? "10" : workOrder.S_ItemLayer.Trim();//物料层数 string ItemTrayType = string.IsNullOrEmpty(workOrder.S_TrayType) ? "" : workOrder.S_TrayType.Trim();//货物大小板--大板、小板 string StartBit = plc.location[0]; string EndBit = ""; string StartLayer = "1";//成品下线-起点层数默认为1 string EndLayer = ""; string plineNo = workOrder.S_PLineNo; //产线下线流程----正常流程下线 if (workOrder.S_ORDER_TYPE.Trim() != "无码入库") { bool full = true; //判断当前货位是否存在托盘,如果存在则 无需从托盘信息中间表获取 var db = new SqlHelper().GetInstance(); var trayInfo = db.Queryable().Where(a => a.S_LOC_CODE == StartBit).ToList(); if (trayInfo.Count() > 0) { BatchNo = workOrder.S_BatchNo.Trim(); ItemLayer = workOrder.S_ItemLayer.Trim(); string trayNo = ""; trayInfo.ForEach(a => { trayNo = a.S_CNTR_CODE; TrayCode = TrayCode + a.S_CNTR_CODE + ","; }); //获取工单号 var task = db.Queryable().Where(a => a.S_CNTRS.Contains(trayNo)).OrderByDescending(a => a.T_CREATE).First(); if (task != null) { LogHelper.Info($"获取任务{task.S_TASK_NO} 工单号{task.S_SRC_NO}"); workOrder.S_WorkNo = task.S_SRC_NO; } else { LogHelper.Info($"未获取到工单号"); full = false; } } else { //2.获取设备第一次下线时间 bool IsTime = true; DeviceStartTime = ConveryInfoFullTwo(plc, DeviceStartTime, deviceName); if (IsTime) { //3.处理 工单信息表数据--托规、批次号、物料层数 full = ConveryInfoFullThree(plc, location, workOrder, DeviceStartTime, positionCode, deviceName, ref TrayCode, ref BatchNo, ref ItemLayer); } else full = false; } if (full) { //5.正常产线下线 ProductLineFull(plc, location, workOrder, TrayCode, BatchNo, ItemLayer, ItemTrayType, StartBit, deviceName); } else LogHelper.Info($"输送线:{deviceName} 下线信号:{location},下线时间:{DeviceStartTime},托盘信息存在异常,请查询异常日志!", "输送线"); } //无码入库流程----人工创建工单时----工单类型 应选择 无码入库 else { var db = new SqlHelper().GetInstance(); var trayInfo = db.Queryable().Where(a => a.S_LOC_CODE == location).ToList(); if (trayInfo.Count() == 0) TrayCode = Guid.NewGuid().ToString("N") + "," + Guid.NewGuid().ToString("N"); else { trayInfo.ForEach(a => { TrayCode = TrayCode + "," + a.S_CNTR_CODE.Trim(); }); } LogHelper.Info($"输送线:{deviceName} 下线信号:{location} 无码入库!", "输送线"); //Console.WriteLine($"输送线:{plc.deviceName} 下线信号:{location} 无码入库!"); ProductLineFull(plc, location, workOrder, TrayCode, BatchNo, ItemLayer, ItemTrayType, StartBit, deviceName); } } else LogHelper.Info($"输送线:{deviceName} 下线信号:{location} 未找到工单", "输送线"); } } else LogHelper.Info($"输送线:{plc.deviceName} 当前位置{location}有任务,不可触发满托下线", "输送线"); } } catch (Exception ex) { //Console.WriteLine($"输送线处理异常:{ex.Message}"); LogHelper.Error($"输送线处理异常:{ex.Message}", ex); } return result; } public static void ProductLineFull(Settings.deviceInfo plc, string location, WorkOrder workOrder, string TrayCode, string BatchNo, string ItemLayer, string ItemTrayType, string StartBit, string deviceName, bool ProType = true) { //5.根据配置文件获取当前产线优先下发库区,再连同物料、大小板、批次,获取此库区 可用货位 // 遍历库区查询-判断排锁-表名: RowLock var creResult = false; LogHelper.Info($"输送线:{deviceName} 查询入库终点货位 批次号{BatchNo}", "输送线"); var db = new SqlHelper().GetInstance(); ////Console.WriteLine($"输送线:{plc.deviceName} 查询入库终点货位"); //string ItemNameLayer = workOrder.S_ItemCode.Trim() + workOrder.S_ItemLayer.Trim(); //var PriProLineInfo = Settings.GetDaMingShanPriProLineList().Where(a => a.deviceName == plc.deviceName && a.ItemTrayType == "满" && a.ItemName == workOrder.S_ItemCode.Trim()).FirstOrDefault(); var PriProLineInfo = db.Queryable().Where(a => a.S_ITEM_CODE == workOrder.S_ItemCode.Trim() && a.S_TRAY_TYPE == ItemTrayType).OrderByDescending(a => a.S_PRIORITY).ToList(); if (PriProLineInfo != null) { if (ProType) { LogHelper.Info($"输送线:{deviceName} 查询到配置文件", "输送线"); ////Console.WriteLine($"输送线:{plc.deviceName} 查询到配置文件"); for (int i = 0; i < PriProLineInfo.Count(); i++) { string areaCode = PriProLineInfo[i].S_AREA_CODE; if (!creResult) creResult = IntensiveArea.DaMingShanPlcTask(StartBit, "成品下线", TrayCode, areaCode, workOrder.S_ItemCode.Trim(), BatchNo, ItemLayer, ItemTrayType, deviceName, true, workOrder.S_WorkNo.Trim()); } } //else //{ // for (int i = 0; i < PriProLineInfo.Count(); i++) // { // string areaCode = PriProLineInfo[i].S_AREA_CODE; // if (!creResult) creResult = IntensiveArea.DaMingShanPlcTask(StartBit, "零头下线", TrayCode, areaCode, workOrder.S_ItemCode.Trim(), BatchNo, ItemLayer, ItemTrayType, plc.deviceName, true, workOrder.S_WorkNo.Trim()); // } //} if (creResult) { //任务创建成功 绑定起点托盘表,托盘物料表 LogHelper.Info("绑定货位容器"); IntensiveArea.BindLocCntr(StartBit, TrayCode, workOrder.S_ItemCode.Trim(), BatchNo, deviceName, ItemLayer, ItemTrayType); } } else LogHelper.Info($"输送线:{deviceName} 下线信号:{location} 未获取到当前产线的优先下线库区 DaMingShanPriProLine 配置项。该物料不存在:{workOrder.S_ItemCode.Trim()}", "输送线"); } /// /// 农夫大明山 处理翻斗机下空筐请求 /// /// 配置信息 /// 下件口 /// private static bool TipperEmpty(Settings.deviceInfo plc, string location) { //通过站点编号查询工单 //通过工单获取物料编码、批号(前期富勒没上线批号自行编写) var result = false; var db = new SqlHelper().GetInstance(); if (location != "") { if (LocationHelper.CheckLocFree(location)) { var taskFree = db.Queryable().Where(a => a.S_START_LOC == location && a.S_B_STATE != "取消" && a.S_B_STATE != "完成" && a.S_B_STATE != "失败").First(); if (taskFree == null) { LogHelper.Info($"翻斗机:{plc.deviceName} 下线信号:{location} 查询工单", "翻斗机"); var workOrder = WCSHelper.GetPGWorkOrder(plc.deviceName); if (workOrder != null) { LogHelper.Info($"查到了工单{workOrder.S_WorkNo} 工单状态为: {workOrder.S_WorkState} 即产即用={workOrder.S_UsingNow}", "翻斗机"); if (workOrder.S_WorkState == "执行中") { var trayInfo = db.Queryable().Where(a => a.S_LOC_CODE == location).ToList(); if (trayInfo.Count() > 0) { string TrayCode = ""; //string newbatchNo = DateTime.Now.Year.ToString() + "-" + DateTime.Now.Month.ToString() + "-" + DateTime.Now.Day.ToString() + "-" + SYSHelper.GenerateUniqueText(8); //string BatchNo = string.IsNullOrEmpty(workOrder.S_BatchNo) ? newbatchNo : workOrder.S_BatchNo; foreach (var b in trayInfo) { TrayCode = TrayCode + "," + b.S_CNTR_CODE.Trim(); } if (!string.IsNullOrEmpty(TrayCode)) { LogHelper.Info($"翻斗机 货位托盘号={TrayCode}"); if (workOrder.S_UsingNow == "Y") { result = IntensiveArea.DaMingShanPLCIn3(plc, location, TrayCode, "", true); } else { result = IntensiveArea.DaMingShanPLCIn3(plc, location, TrayCode, "", false); } } } else { //自动生成托盘码 string TrayCode = Guid.NewGuid().ToString().Replace("-", ""); if (!string.IsNullOrEmpty(TrayCode)) { LogHelper.Info($"翻斗机 货位托盘号={TrayCode}"); if (workOrder.S_UsingNow == "Y") { result = IntensiveArea.DaMingShanPLCIn3(plc, location, TrayCode, "", true); } else { result = IntensiveArea.DaMingShanPLCIn3(plc, location, TrayCode, "", false); } } } } } else { LogHelper.Info($"翻斗机:{plc.deviceName} 下线信号:{location} 未找到工单", "翻斗机"); } } else LogHelper.Info($"该点位有未完成的任务 不允许重复生成任务 任务号{taskFree.S_TASK_NO}"); } else { LogHelper.Info($"翻斗机:{plc.deviceName} 当前位置{location}有任务,不可触发空托下线", "翻斗机"); } } else { LogHelper.Info($"翻斗机:{plc.deviceName} 点位为空", "翻斗机"); } return result; } /// /// 农夫大明山 处理翻斗机下空筐请求 /// /// 配置信息 /// 下件口 /// private static bool TipperEmpty2(Settings.deviceInfo plc, string location) { //通过站点编号查询工单 //通过工单获取物料编码、批号(前期富勒没上线批号自行编写) var result = false; try { var db = new SqlHelper().GetInstance(); if (location != "") { if (LocationHelper.CheckLocFree(location)) { var taskFree = db.Queryable().Where(a => a.S_START_LOC == location && a.S_B_STATE != "取消" && a.S_B_STATE != "完成" && a.S_B_STATE != "失败").First(); if (taskFree == null) { LogHelper.Info($"翻斗机:{plc.deviceName} 下线信号:{location} 查询工单", "翻斗机"); var workOrder = WCSHelper.GetPGWorkOrder(plc.deviceName); if (workOrder != null) { LogHelper.Info($"查到了工单{workOrder.S_WorkNo} 工单状态为: {workOrder.S_WorkState} 即产即用={workOrder.S_UsingNow}", "翻斗机"); if (workOrder.S_WorkState == "执行中") { var trayInfo = db.Queryable().Where(a => a.S_LOC_CODE == location).ToList(); if (trayInfo.Count() > 0) { string TrayCode = ""; //string newbatchNo = DateTime.Now.Year.ToString() + "-" + DateTime.Now.Month.ToString() + "-" + DateTime.Now.Day.ToString() + "-" + SYSHelper.GenerateUniqueText(8); //string BatchNo = string.IsNullOrEmpty(workOrder.S_BatchNo) ? newbatchNo : workOrder.S_BatchNo; foreach (var b in trayInfo) { TrayCode = TrayCode + "," + b.S_CNTR_CODE.Trim(); } if (!string.IsNullOrEmpty(TrayCode)) { LogHelper.Info($"翻斗机 货位托盘号={TrayCode}"); if (workOrder.S_UsingNow == "Y") { result = IntensiveArea.DaMingShanPLCIn4(plc, location, TrayCode, workOrder, true); } else { result = IntensiveArea.DaMingShanPLCIn4(plc, location, TrayCode, workOrder, false); } } } else { //自动生成托盘码 string TrayCode = Guid.NewGuid().ToString().Replace("-", ""); if (!string.IsNullOrEmpty(TrayCode)) { LogHelper.Info($"翻斗机 货位托盘号={TrayCode}"); if (workOrder.S_UsingNow == "Y") { result = IntensiveArea.DaMingShanPLCIn4(plc, location, TrayCode, workOrder, true); } else { result = IntensiveArea.DaMingShanPLCIn4(plc, location, TrayCode, workOrder, false); } } } } } else { LogHelper.Info($"翻斗机:{plc.deviceName} 下线信号:{location} 未找到工单", "翻斗机"); } } else LogHelper.Info($"该点位有未完成的任务 不允许重复生成任务 任务号{taskFree.S_TASK_NO}"); } else { LogHelper.Info($"翻斗机:{plc.deviceName} 当前位置{location}有任务,不可触发空托下线", "翻斗机"); } } } catch (Exception ex) { LogHelper.Error($"瓶坯翻斗机异常 异常信息={ex.Message}", ex); } return result; } /// /// 接收PLC注塑机信号 /// /// /// private static void DaMingShanAnalysisBottleCapmolding(string data, Settings.deviceInfo plc) { LogHelper.Info($"{plc.deviceName}--IP={plc.address}--msg={data}", "注塑机"); //下满筐信号生成下满筐任务 待取货完成解绑起点货位 生成送空任务 if (data.Substring(0, 2) == "11") { if (moldingFull(plc, plc.location[0])) { LogHelper.Info($"{plc.deviceName}--IP={plc.address}--msg=注塑机A口生成取满任务", "注塑机"); } } if (data.Substring(2, 2) == "21") { if (moldingFull(plc, plc.location[1])) { LogHelper.Info($"{plc.deviceName}--IP={plc.address}--msg=注塑机B口生成取满任务", "注塑机"); } } LogHelper.Info($"自动门状态:{data},地址为:{plc.address}", "自动门"); data = data.Substring(4); if (data.Length / 2 == plc.deviceNo.Length)//2 2 { for (int i = 0; i < plc.deviceNo.Length; i++) { var state = data.Substring(i * 2 + 1, 1); ////Console.WriteLine($"门{plc.deviceNo[i]}的状态{state}"); if (doorStatus.Keys.Contains(plc.deviceNo[i])) { doorStatus[plc.deviceNo[i]].info = state; doorStatus[plc.deviceNo[i]].modify = DateTime.Now; } else { doorStatus.Add(plc.deviceNo[i], new signalInfo { info = state, modify = DateTime.Now }); } } } } /// /// 农夫大明山--处理注塑机满托请求 /// /// /// private static bool moldingFull(Settings.deviceInfo plc, string location) { //通过站点编号查询工单 //通过工单获取物料编码、批号(前期富勒没上线批号自行编写) var result = false; var db = new SqlHelper().GetInstance(); if (location != "") { if (LocationHelper.CheckLocFree(location)) { LogHelper.Info($"瓶盖机:{plc.deviceName} 下线信号:{location} 查询工单", "瓶盖机"); var workOrder = WCSHelper.GetPGWorkOrder(plc.deviceName); if (workOrder != null) { LogHelper.Info($"查到了工单{workOrder.S_WorkNo} 工单状态为: {workOrder.S_WorkState} 即产即用={workOrder.S_UsingNow} 连接区域={workOrder.S_LinkLineNo}", "瓶盖机"); if (workOrder.S_WorkState.Trim() == "执行中") { LogHelper.Info($"查询当前货位 托盘数量 货位编码={location}"); var trayInfo = db.Queryable().Where(a => a.S_LOC_CODE == location).ToList(); if (trayInfo.Count() > 0) { LogHelper.Info($"当前货位托盘数量大于0"); string TrayCode = trayInfo[0].S_CNTR_CODE; //string newbatchNo = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + SYSHelper.GenerateUniqueText(8); //string BatchNo = string.IsNullOrEmpty(workOrder.) ? newbatchNo : workOrder.S_BatchNo; if (!string.IsNullOrEmpty(TrayCode)) { if (workOrder.S_UsingNow == "Y") { result = IntensiveArea.DaMingShanPLCIn(plc, location, TrayCode, "", workOrder, true); } else { result = IntensiveArea.DaMingShanPLCIn(plc, location, TrayCode, "", workOrder, false); } } } else { LogHelper.Info($"瓶盖机:{plc.deviceName} 下线信号:{location} 该站点没有托盘无法取满", "瓶盖机"); } } } else { LogHelper.Info($"瓶盖机:{plc.deviceName} 下线信号:{location} 未找到工单", "瓶盖机"); } } else { LogHelper.Info($"瓶盖机:{plc.deviceName} 当前位置{location}有任务,不可触发满托下线", "瓶盖机"); } } return result; } /// /// 农夫大明山--处理瓶盖机满托请求 /// /// /// private static bool moldingFull2(Settings.deviceInfo plc, string location) { //通过站点编号查询工单 //通过工单获取物料编码、批号(前期富勒没上线批号自行编写) var result = false; var db = new SqlHelper().GetInstance(); if (location != "") { if (LocationHelper.CheckLocFree(location)) { LogHelper.Info($"瓶盖机:{plc.deviceName} 下线信号:{location} 查询工单", "瓶盖机"); var workOrder = WCSHelper.GetPGWorkOrder(plc.deviceName); if (workOrder != null) { LogHelper.Info($"查到了工单{workOrder.S_WorkNo} 工单状态为: {workOrder.S_WorkState} 即产即用={workOrder.S_UsingNow}", "瓶盖机"); if (workOrder.S_WorkState.Trim() == "执行中") { LogHelper.Info($"查询当前货位 托盘数量 货位编码={location}"); var trayInfo = db.Queryable().Where(a => a.S_LOC_CODE == location).ToList(); if (trayInfo.Count() > 0) { LogHelper.Info($"当前货位托盘数量大于0"); string TrayCode = trayInfo[0].S_CNTR_CODE; //string newbatchNo = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + SYSHelper.GenerateUniqueText(8); //string BatchNo = string.IsNullOrEmpty(workOrder.S_BatchNo) ? newbatchNo : workOrder.S_BatchNo; if (!string.IsNullOrEmpty(TrayCode)) { if (workOrder.S_UsingNow == "Y") { result = IntensiveArea.DaMingShanPLCIn2(plc, location, TrayCode, "", workOrder.S_ItemCode, true); } else { result = IntensiveArea.DaMingShanPLCIn2(plc, location, TrayCode, "", workOrder.S_ItemCode, false); } } } else { LogHelper.Info($"瓶盖机:{plc.deviceName} 下线信号:{location} 该站点没有托盘无法取满", "瓶盖机"); } } } else { LogHelper.Info($"瓶盖机:{plc.deviceName} 下线信号:{location} 未找到工单", "瓶盖机"); } } else { LogHelper.Info($"瓶盖机:{plc.deviceName} 当前位置{location}有任务,不可触发满托下线", "瓶盖机"); } } return result; } private static bool moldingEmpty(Settings.deviceInfo plc, string location) { //通过站点编号查询工单 //通过工单获取物料编码、批号(前期富勒没上线批号自行编写) var result = false; var db = new SqlHelper().GetInstance(); if (location != "") { if (LocationHelper.CheckLocFree(location)) { LogHelper.Info($"注塑机:{plc.deviceName} 下线信号:{location} 查询工单", "注塑机"); var workOrder = WCSHelper.GetPGWorkOrder(plc.deviceName); if (workOrder != null) { LogHelper.Info($"查到了工单{workOrder.S_WorkNo} 工单状态为: {workOrder.S_WorkState}", "注塑机"); if (workOrder.S_WorkState.Trim() == "执行中") { var trayInfo = db.Queryable().Where(a => a.S_LOC_CODE.Trim() == location).ToList(); if (trayInfo.Count() == 0) { result = IntensiveArea.DaMingShanPLCOut(plc, location, true, workOrder); } else { LogHelper.Info($"注塑机:{plc.deviceName} 下线信号:{location} 该站点有托盘无法送空", "注塑机"); } } } else { LogHelper.Info($"注塑机:{plc.deviceName} 下线信号:{location} 未找到工单", "注塑机"); } } else { LogHelper.Info($"注塑机:{plc.deviceName} 当前位置{location}有任务,不可触发栈板上线", "注塑机"); } } return result; } private static bool moldingEmpty2(Settings.deviceInfo plc, string location) { //通过站点编号查询工单 //通过工单获取物料编码、批号(前期富勒没上线批号自行编写) var result = false; var db = new SqlHelper().GetInstance(); if (location != "") { if (LocationHelper.CheckLocFree(location)) { LogHelper.Info($"瓶盖机:{plc.deviceName} 下线信号:{location} 查询工单", "瓶盖机"); var workOrder = WCSHelper.GetPGWorkOrder(plc.deviceName); if (workOrder != null) { LogHelper.Info($"查到了工单{workOrder.S_WorkNo} 工单状态为: {workOrder.S_WorkState}", "瓶盖机"); if (workOrder.S_WorkState.Trim() == "执行中") { var trayInfo = db.Queryable().Where(a => a.S_LOC_CODE.Trim() == location).ToList(); if (trayInfo.Count() == 0) { //if (workOrder.S_UsingNo == "Y") //{ result = IntensiveArea.DaMingShanPLCOut2(plc, location, true, workOrder); //} //else //{ // result = IntensiveArea.DaMingShanPLCOut2(plc, location, false); //} if (!result) { LogHelper.Info($"空筐缓存区无可用空筐"); } } else { LogHelper.Info($"瓶盖机:{plc.deviceName} 下线信号:{location} 该站点有托盘无法送空", "瓶盖机"); } } } else { LogHelper.Info($"瓶盖机:{plc.deviceName} 下线信号:{location} 未找到工单", "瓶盖机"); } } else { LogHelper.Info($"瓶盖机:{plc.deviceName} 当前位置{location}有任务,不可触发栈板上线", "瓶盖机"); } } return result; } #endregion #region 自动门--通用 private static Dictionary doorStatus = new Dictionary();//普通自动门字典 private static Dictionary doorRecord = new Dictionary(); private static Dictionary elevatorRecord = new Dictionary();//电梯安全门字典 public class signalInfo { public string info { get; set; } public DateTime modify { get; set; } public int error { get; set; } = 0; } /// /// 交管信号处理 /// /// /// /// internal static void SpecialTraffic(string agvNo, string lockNo, int state) { if (state == 1023 || state == 1025) { Traffic(agvNo, lockNo, state == 1023);//标准交管处理 1023 1025 } if (state == 1120) { tiqianopen(agvNo, lockNo); } } private static void tiqianopen(string agvNo, string lockNo) { LogHelper.Info($"安全门开门请求 车号={agvNo} 门号={lockNo}"); var plc = Settings.GetDeviceInfoList().Where(a => a.deviceNo.Contains(lockNo)).FirstOrDefault(); if (plc != null) { LogHelper.Info($"找到配置文件"); var index = 1; for (int i = 0; i < plc.deviceNo.Length; i++) { if (plc.deviceNo[i] == lockNo) { index = i + 1; break; } } index = index + plc.location.Length; LogHelper.Info($"安全门对接:门号:{lockNo},index:{index}", "自动门"); //开门请求 3F 00 11 20 0d 0a( 3F 00 10 21 0d 0a) var req = $"3f 00 {index}1 0d 0a"; PlcHelper.SendHex(plc.address, req); var msg = $"安全门开门请求,门号:{lockNo},index:{index},ip={plc.address}, data={req}"; LogHelper.Info(msg, "自动门"); } } /// /// 自动门 /// /// /// internal static void AnalysisDoor(string data, Settings.deviceInfo plc) { LogHelper.Info($"自动门状态:{data},地址为:{plc.address}", "自动门"); if (data.Length / 2 == plc.deviceNo.Length)//2 2 { for (int i = 0; i < plc.deviceNo.Length; i++) { var state = data.Substring(i * 2 + 1, 1); ////Console.WriteLine($"门{plc.deviceNo[i]}的状态{state}"); if (doorStatus.Keys.Contains(plc.deviceNo[i])) { doorStatus[plc.deviceNo[i]].info = state; doorStatus[plc.deviceNo[i]].modify = DateTime.Now; } else { doorStatus.Add(plc.deviceNo[i], new signalInfo { info = state, modify = DateTime.Now }); } } } } /// /// TcpServer-交管请求 /// /// /// /// internal static void Traffic(string agv, string zone, bool occupy) { LogHelper.Info($"安全门开门请求 车号={agv} 门号={zone} 开门请求={occupy}"); var plc = Settings.GetDeviceInfoList().Where(a => a.deviceNo.Contains(zone)).FirstOrDefault(); if (plc != null) { LogHelper.Info($"找到配置文件"); var index = 1; for (int i = 0; i < plc.deviceNo.Length; i++) { if (plc.deviceNo[i] == zone) { index = i + 1; break; } } index = index + plc.location.Length; LogHelper.Info($"安全门对接:门号:{zone},index:{index}", "自动门"); if (occupy) { //开门请求 3F 00 11 20 0d 0a( 3F 00 10 21 0d 0a) var req = $"3f 00 {index}1 0d 0a"; PlcHelper.SendHex(plc.address, req); var msg = $"安全门开门请求,门号:{zone},index:{index},ip={plc.address}, data={req}"; LogHelper.Info(msg, "自动门"); //车子请求一次就发一次开门请求 if (doorStatus.Keys.Contains(zone) && DateTime.Now.Subtract(doorStatus[zone].modify).TotalSeconds < 5) { if (doorStatus[zone].info == "1") { LogHelper.Info($"安全门已经打开:门号:{zone},index:{index}", "自动门"); NDCHelper.Traffic(zone); } } } else { //关门信号 3F 00 10 20 0d 0a var req = $"3f 00 {index}0 0d 0a"; PlcHelper.SendHex(plc.address, req); var msg = $"安全门关门请求,门号:{zone},index:{index},ip={plc.address}, data={req}"; LogHelper.Info(msg, "自动门"); } } } /// /// ModBusTcp-交管请求 /// /// /// /// internal static void ModBusTraffic(string agv, string zone, bool occupy) { LogHelper.Info($"安全门对接:收到信号:{occupy},备注:真为1023,假为1025,门号:{zone},车号:{agv}", "自动门"); var plc = Settings.GetModBusTcpPlc().Where(a => a.location == zone).FirstOrDefault(); if (plc != null) { if (occupy) { int[] result = modbusHelper.ReadHoldingRegisters(plc.readAddr + 2, 1, plc.ip, plc.port); if (result[0] == 1) { NDCHelper.Traffic(zone); } else { modbusHelper.WriteSingleRegister(plc.readAddr + 2, 1, plc.ip, plc.port); } } else { modbusHelper.WriteSingleRegister(plc.readAddr + 2, 2, plc.ip, plc.port); } } else { LogHelper.Info($"请检查配置文件:未在配置文件中查询到该门号的信息。当前门号:{zone}", "自动门"); } } /// /// 十字路口安全交互 /// /// /// /// internal static void Crossroads(string agv, string zone, bool occupy) { LogHelper.Info($"十字路口安全交互:收到信号:{occupy},备注:真为1101,假为1102,门号:{zone},车号:{agv}", "自动门"); var plc = Settings.GetModBusTcpPlc().Where(a => a.location == zone).FirstOrDefault(); if (plc != null) { if (occupy) { modbusHelper.WriteSingleRegister(plc.readAddr + 3, 1, plc.ip, plc.port); } else { modbusHelper.WriteSingleRegister(plc.readAddr + 3, 2, plc.ip, plc.port); } } else { LogHelper.Info($"请检查配置文件:未在配置文件中查询到该门号的信息。当前门号:{zone}", "自动门"); } } /* IO模块1 只用02功能码读取 1x0000 一楼开门到位信号 1x0001 二楼开门到位信号 IO模块2 只用05功能码写入 0x0000 一楼楼层按钮信号 0x0001 二楼楼层按钮信号 */ /// /// 电梯只需要开门,不需要关门 /// /// /// private static void TrafficElevator(string zone, bool occupy) { //判断是否时电梯门 var elevatorDoor = Settings.GetelEvatorDoorList().Where(a => a.door == zone).FirstOrDefault(); if (elevatorDoor != null) { //oitcp中转 modbus rtu 方式开电梯 //BitConverter.ToString(CRC16LH(Hex2Bytes("01 02 00 03 00 01"))).Replace("-", string.Empty).ToLower() LogHelper.Info($"收到agv开电梯门请求{zone}", "电梯"); if (occupy) { var readAddr = elevatorDoor.addr == 1 ? 0 : 1; var read = $"01 02 00 0{readAddr} 00 01 "; read += BitConverter.ToString(PlcHelper.CRC16LH(PlcHelper.Hex2Bytes(read))).Replace("-", " ").ToLower(); LogHelper.Info($"查询电梯门{zone}状态发送{read}", "电梯"); var res = OITcpHelper.HexTransit(new OITcpHelper.StrTransitData { host = Settings.ElevatorIP, data = read, port = 8899 }); if (res != null && res.errCode == 0 && res.result.Replace(" ", "").Substring(7, 1) == "1") { //判断门开了,通知agv走 LogHelper.Info($"电梯门{zone}开了,通知agv进去", "电梯"); NDCHelper.Traffic(zone); } else { if (!elevatorRecord.Keys.Contains(zone) || DateTime.Now.Subtract(elevatorRecord[zone]).TotalSeconds < 8) { //开门是一次吸合,一次断开 var write = $"01 05 00 0{elevatorDoor.addr} ff 00 "; write += BitConverter.ToString(PlcHelper.CRC16LH(PlcHelper.Hex2Bytes(write))).Replace("-", " ").ToLower(); LogHelper.Info($"发送电梯{zone}开门请求{write},吸合", "电梯"); res = OITcpHelper.HexTransit(new OITcpHelper.StrTransitData { host = Settings.ElevatorIP, data = write, port = 8899 }); if (res != null && res.errCode == 0) { //Console.WriteLine("准备发送断开信号"); Thread.Sleep(1000); write = $"01 05 00 0{elevatorDoor.addr} 00 00 "; write += BitConverter.ToString(PlcHelper.CRC16LH(PlcHelper.Hex2Bytes(write))).Replace("-", " ").ToLower(); LogHelper.Info($"发送电梯{zone}开门请求{write},断开", "电梯"); OITcpHelper.HexTransit(new OITcpHelper.StrTransitData { host = Settings.ElevatorIP, data = write, port = 8899 }); Thread.Sleep(1000); LogHelper.Info($"发送电梯{zone}开门请求{write},断开", "电梯"); OITcpHelper.HexTransit(new OITcpHelper.StrTransitData { host = Settings.ElevatorIP, data = write, port = 8899 }); Thread.Sleep(1000); LogHelper.Info($"发送电梯{zone}开门请求{write},断开", "电梯"); OITcpHelper.HexTransit(new OITcpHelper.StrTransitData { host = Settings.ElevatorIP, data = write, port = 8899 }); if (!elevatorRecord.Keys.Contains(zone)) { elevatorRecord.Add(zone, DateTime.Now); } else { elevatorRecord[zone] = DateTime.Now; } } else { //Console.WriteLine("发送吸合信号失败"); } } } } } } #endregion #region 瓶盖机 //记录当前瓶盖机是即产即用还是入库模式,后面空托开始卸货时,如果模式有变需要通知设备 private static Dictionary bottleCapState = new Dictionary(); /// /// 瓶盖机 3F 00 11(设备1) 22(设备2) 01(1塑料筐、2铁筐) 0d 0a /// /// /// internal static void JunZhouAnalysisBottleCap(string data, Settings.deviceInfo plc) { LogHelper.Info($"{plc.deviceName}-{plc.address}-{data}", "瓶盖机"); /* 状态1 满托产生,需要取满送空,从满托产生到满托取走一直维持状态1 状态2 送空完成之后为状态2 状态3 满托取走,送空之前为状态3,开机默认状态也为状态3 */ //信号出错 if (data.Substring(0, 1) != "1" || data.Substring(2, 1) != "2") { //判断哪边没有托盘 if (ContainerHelper.CheckEmpty(plc.location[0])) { PlcHelper.SendHex(plc.address, "3F00110d0a"); } if (ContainerHelper.CheckEmpty(plc.location[1])) { PlcHelper.SendHex(plc.address, "3F00210d0a"); } } } #endregion #region 输送线 /* 淳安大小版处理: 1.入库计算货位获取到空排,需判断另一个 版位所对应的排 是否存在货位,以及无锁定 ----------OVER 2.移库工单点击执行中时:需要拿出所有的 起点库位以及终点库位,判断后缀必须一致 ----------OVER 3.小板库区库位 需要 在大板的库区库位上加上后缀 -XB ----------OVER 4.进行库位锁定解锁回报时,需要去除后缀 -XB ----------OVER 5.大板的库区库位需要与富勒WMS同步 ----------OVER */ private static string ConveryInfoFullTwo(Settings.deviceInfo plc, string DeviceStartTime, string deviceName) { //2.获取当前产线 设备中间表 对应信息 ChunAnDeviceState //2-1.有数据,判断当前是否为第一次收到下线信号 // 第一次:更新 DeviceState = 1,DeviceStartTime = 当前时间 // 第N次:判断当前 DeviceState 是否为1,不为1,更新 DeviceState 以及 DeviceStartTime //2-2.无数据,插入 DeviceName ,DeviceState = 1,DeviceStartTime = 当前时间 数据 var deviceTableInfo = WCSHelper.GetDaMingShanDeviceState(deviceName); if (deviceTableInfo != null) { if (deviceTableInfo.DeviceState != "1") WCSHelper.UpdateDaMingShanDeviceState(deviceTableInfo, "1", DeviceStartTime); else DeviceStartTime = deviceTableInfo.DeviceTime; } else { WCSHelper.DaMingShangInsertDeviceState(new DaMingShanDeviceState { DeviceName = deviceName, DeviceTime = DeviceStartTime, DeviceState = "1" }); } return DeviceStartTime; } private static bool ConveryInfoFullThree(Settings.deviceInfo plc, string location, WorkOrder workOrder, string DeviceStartTime, string positionCode, string deviceName, ref string TrayCode, ref string BatchNo, ref string ItemLayer) { bool result = true; var db = new SqlHelper().GetInstance(); //3.从 富勒托盘信息中间表 获取 dateTime < DeviceStartTime 的数据 ChunAnTrayInfo // 有两条:进入第 3-1 步 // 小于两条:异常-连接 报警器 进行声光报警 //3-1.判断托盘信息中 托规、批次号、物料层数 是否有值---------根据 托规 判断当前托盘是否为零头 // 有值:判断当前值是否与 工单信息 相同,不同代表 当前产线切换了生产类型或首次下线,需同步更新 工单信息 // 无值:判断工单是否存在对应值,不存在 即 异常 if (!string.IsNullOrEmpty(DeviceStartTime)) { LogHelper.Info($"输送线:{deviceName} 获取托盘数据 位置代码{positionCode}"); var trayTableInfo = WCSHelper.GetDaMingShanTrayInfoList(positionCode, deviceName); if (trayTableInfo != null) { trayTableInfo = trayTableInfo.OrderBy(a => Convert.ToDateTime(a.dateTime)).ToList(); if (trayTableInfo.Count == 2) { string trayCode = ""; string batchNo = ""; string itemLayer = ""; //1-首先判断工单 托规、批次号、物料层数 三个参数是否有值 // 有值:判断和当前值是否相同,不同 即 更新 UpdateWorkInfo // 无值:更新工单对应信息 trayTableInfo.ForEach(a => { LogHelper.Info($"托盘号{a.trayCode} 批次号{a.batchNo} 物料层数{a.itemLayer}"); trayCode = trayCode + "," + a.trayCode; string TrayRule = ""; string UpdateWorkOn = "";//更新工单信息开关 默认为空 1-需要更新 托规、批次号、物料层数 信息 //成品下线:首托下线 必须 传输全部信息-托规、批次号、物料层数;否则 第一托就无法下线 // 之后如果缺少信息,可以从工单获取 //工单初始状态:托规、批次号、物料层数 必然有一个值为空;后续会一直有值 if (string.IsNullOrEmpty(workOrder.S_BatchNo) || string.IsNullOrEmpty(workOrder.S_ItemLayer)) { WCSHelper.UpdateWorkInfo(workOrder, a.batchNo, a.itemLayer); batchNo = a.batchNo; itemLayer = a.itemLayer; } //处理 当前托盘 托规、批次号、物料层数 信息 ConveryInfoFullThreeS(plc, location, a, workOrder, DeviceStartTime, ref batchNo, ref itemLayer, ref TrayRule, ref UpdateWorkOn); if (UpdateWorkOn == "1") WCSHelper.UpdateWorkInfo(workOrder, batchNo, itemLayer); //零头物料判断 //if (TrayRule != a.trayNum) //{ // result = false; // LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},成品下线-当前物料箱数:{a.itemLayer}与标准托规:{TrayRule}不符,标准托规信息异常!", "输送线"); // //正常下线-不是整托下线 连接报警器 报警 // //Console.WriteLine($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},成品下线-当前物料箱数:{a.itemLayer}与标准托规:{TrayRule}不符,标准托规信息异常!"); //} workOrder.S_WorkNo = a.workNo; }); var trayAll = WCSHelper.GetDaMingShanTrayInfoAllList(deviceName); if (trayTableInfo.Count != trayAll.Count && trayTableInfo.Count == 1) { result = false; LogHelper.Info($"输送线:{deviceName} 下线信号:{location},下线时间:{DeviceStartTime},第一次下线时间之前只获得{trayTableInfo.Count}条托盘信息,记录托盘信息为{trayAll.Count}条,托盘信息异常!", "输送线"); //连接报警器 进行异常报警 SendErrorTcpMsg(plc, DeviceStartTime); db.Deleteable().Where(a => a.DeviceName.Trim() == deviceName).ExecuteCommand(); //Console.WriteLine($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},第一次下线时间之前只获得{trayTableInfo.Count}条托盘信息,记录托盘信息为{trayAll.Count}条,托盘信息异常!"); } TrayCode = trayCode; BatchNo = batchNo; ItemLayer = itemLayer; } else { result = false; LogHelper.Info($"输送线:{deviceName} 下线信号:{location},下线时间:{DeviceStartTime},第一次下线时间之前只获得{trayTableInfo.Count}条托盘信息,托盘信息异常!", "输送线"); //连接报警器 进行异常报警 SendErrorTcpMsg(plc, DeviceStartTime); db.Deleteable().Where(a => a.DeviceName.Trim() == deviceName).ExecuteCommand(); //Console.WriteLine($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},第一次下线时间之前只获得{trayTableInfo.Count}条托盘信息,托盘信息异常!"); } } else { result = false; LogHelper.Info($"输送线:{deviceName} 下线信号:{location},下线时间:{DeviceStartTime},第一次下线时间之前只获得{trayTableInfo.Count}条托盘信息,托盘信息异常!", "输送线"); SendErrorTcpMsg(plc, DeviceStartTime); db.Deleteable().Where(a => a.DeviceName.Trim() == deviceName).ExecuteCommand(); } } else LogHelper.Info($"输送线:{deviceName} 下线信号:{location} ,DeviceStartTime 设备第一次下线时间为空,程序异常!", "输送线"); return result; } /// /// 输送线托盘信息异常-向输送线发送异常信号 /// 1、下线时间前的托盘数小于2 /// 2、托规不等于当前数量 /// /// public static void SendErrorTcpMsg(Settings.deviceInfo plc, string deviceStartTime) { if ((DateTime.Now - Convert.ToDateTime(deviceStartTime)).TotalSeconds > 60) PlcHelper.SendHex(plc.address, "3F00600d0a"); } private static void ConveryInfoFullThreeS(Settings.deviceInfo plc, string location, DaMingShanTrayInfo a, WorkOrder workOrder, string DeviceStartTime, ref string BatchNo, ref string ItemLayer, ref string TrayRule, ref string UpdateWorkOn) { //if (string.IsNullOrEmpty(a.trayRule)) //{ // //传输缺少 标准托规信息,需要从工单获取 // if (!string.IsNullOrEmpty(workOrder.S_TrayRules)) TrayRule = workOrder.S_TrayRules; // else LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},托盘信息表无标准托规信息且工单:{workOrder.S_WorkNo}也没有标准托规信息,标准托规信息异常!", "输送线"); //} //else //{ // //中途切换了 生产物料,需要更新 工单信息 // if (workOrder.S_TrayRules != a.trayRule) // { // TrayRule = a.trayRule; // UpdateWorkOn = "1"; // } // else TrayRule = a.trayRule; //} if (string.IsNullOrEmpty(a.batchNo)) { //传输缺少 批次号信息,需要从工单获取 if (!string.IsNullOrEmpty(workOrder.S_BatchNo)) BatchNo = workOrder.S_BatchNo; else LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},托盘信息表无批次号信息且工单:{workOrder.S_WorkNo}也没有批次号信息,批次号信息异常!", "输送线"); } else { //中途切换了 生产物料,需要更新 工单信息 if (workOrder.S_BatchNo != a.batchNo) { BatchNo = a.batchNo; UpdateWorkOn = "1"; } else BatchNo = a.batchNo; } if (string.IsNullOrEmpty(a.itemLayer)) { //传输缺少 批次号信息,需要从工单获取 if (!string.IsNullOrEmpty(workOrder.S_ItemLayer)) ItemLayer = workOrder.S_ItemLayer; else LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},托盘信息表无物料层数信息且工单:{workOrder.S_WorkNo}也没有物料层数信息,物料层数信息异常!", "输送线"); } else { //中途切换了 生产物料,需要更新 工单信息 if (workOrder.S_ItemLayer != a.itemLayer) { ItemLayer = a.itemLayer; UpdateWorkOn = "1"; } else ItemLayer = a.itemLayer; } } #endregion #region 其他设备 private static void AnalysisDevice() { } #endregion } }