using HH.WCS.Mobox3.NFLZ.device; using HH.WCS.Mobox3.NFLZ.dispatch; using HH.WCS.Mobox3.NFLZ.util; using HH.WCS.Mobox3.NFLZ.wms; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace HH.WCS.Mobox3.NFLZ.process { /// /// 设备信号处理,主要是tcp信号,我们做server被动接收信号来处理,根据项目定制的 /// internal class DeviceProcess { private static Dictionary LineState = new Dictionary(); public class statemodel { public string status { get; set; } public DateTime modify { 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.deviceInfos.Where(a => a.address == ip && a.enable == 1).FirstOrDefault(); if (plc != null) { LinZhiAnalysisDeviceChange(data, plc); } else { Console.WriteLine($"TCP信号处理:未查询到IP为{ip}的数据,请检查deviceInfo配置中心是否存在该IP的数据!"); } } } /// /// 农夫林芝不同项目设备特殊处理 /// /// /// /// private static void LinZhiAnalysisDeviceChange(string data, Settings.deviceInfo plc) { if (plc.deviceType == 1) AnalysisDoor(data, plc);//自动门处理 if (plc.deviceType == 2) LinZhiAnalysisProductLine(data, plc);//输送线处理 -- 成品下线 if (plc.deviceType == 3) LinZhiAnalysisProductLine(data, plc);//输送线处理 -- 空托上线 if (plc.deviceType == 4) LinZhiAnalysisPreform(data, plc);//瓶坯机 if (plc.deviceType == 5) LinZhiAnalysisPGDump(data, plc);//瓶盖翻斗机 if (plc.deviceType == 6) LinZhiAnalysisPPDump(data, plc);//瓶坯翻斗机 } private static void LinZhiAnalysisProductLine(string data, Settings.deviceInfo plc) { LogHelper.Info($"{plc.deviceName}-{plc.address}-{data}", "输送线"); if (LineState.Keys.Contains(plc.TN_Location[0])) { LineState[plc.TN_Location[0]].status = data; LineState[plc.TN_Location[0]].modify = DateTime.Now; } else { LineState.Add(plc.TN_Location[0], new statemodel { status = data, modify = DateTime.Now }); } //状态1 满托下线或空托上线,具体任务类型需要根据TCP消息位数判断 11-满托下线 21-空托上线 //满托下线:需要根据物料,品相,批次入库 空托上线:空托是否单独存在空托库区,待确定 //不同产线下线库区不同,部分产线下线库区相同,但有先后顺序 //下线库区先后顺序:入库区域顺序:3-6-2-5-4-1 //B1~B6 双托下线--可能存在尾托为单托的情况--尾托(单托)人工PDA下发(入零头库)----满托下线 //B1~B5 单托上线 B6 双托上线------------------------------------------------空托上线 if (data.Length == 4) { if (data.Substring(0, 4) == "1220") { //满托下线 ConveryInfoFull(plc, plc.TN_Location[0]); } if (data.Substring(0, 4) == "1021") { //空托上线 ConveryInfoEmpty(plc, plc.TN_Location[0]); } } } /// /// 输送线空托上线 /// /// /// private static void ConveryInfoEmpty(Settings.deviceInfo plc, string location) { //try //{ // if (location != "") // { // if (LocationHelper.CheckLocFree(location)) // { // var db = new SqlHelper().GetInstance(); // bool flag = true; // var cgInfo = db.Queryable().Where(a => a.Bit == location).First(); // if (cgInfo != null) // { // if (cgInfo.time.AddSeconds(5) > DateTime.Now) // { // flag = false; // } // // } // if (flag) // { // LogHelper.Info($"输送线:{plc.deviceName}, {location}补空信号 查询工单", "输送线"); // var workorder = WCSHelper.GetLinZhiWorkOrder(plc.deviceName); // if (workorder != null && workorder.S_WorkState.Trim() == "执行中") // { // LogHelper.Info($"输送线:{plc.deviceName}, {location}下线信号 找到工单", "输送线"); // ProductLineempty(plc, location, workorder); // } // else // { // LogHelper.Info($"输送线:{plc.deviceName} ,{location}下线信号 未找到工单", "输送线"); // } // } // } // else // { // LogHelper.Info($"输送线:{plc.deviceName} 当前位置{location}有任务,不可触发空托上线", "输送线"); // } // } //} //catch (Exception ex) //{ // Console.WriteLine($"输送线呼叫空托异常! 异常信息={ex.Message}"); //} } /// /// 输送线满托下线 /// /// /// private static bool ConveryInfoFull(Settings.deviceInfo plc, string location) { var result = false; try { if (location != "") { //取满,需要根据工单以及产线信息,判断当前产线应该下发到哪个库区,以及是什么托盘类型下线 if (LocationHelper.CheckLocFree(location)) { var db = new SqlHelper().GetInstance(); LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location} 查询工单", "输送线"); //1.查询当前产线工单信息 var workOrder = WCSHelper.GetLinZhiWorkOrder(plc.deviceName); if (workOrder != null) { //workOrder.S_BatchNo = DateTime.Now.ToString("yyyy-MM-dd"); //db.Updateable(workOrder).UpdateColumns(a => new { a.S_BatchNo }).ExecuteCommand(); // //workOrder = WCSHelper.GetLinJiangWorkOrder(plc.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) ? "" : workOrder.S_ItemLayer.Trim();//物料层数 string ItemTrayType = workOrder.S_TrayType;//货物大小板--大板、小板、集化板(托盘类型需要变动) string StartBit = plc.TN_Location[0]; string workNo = ""; //以下三个字段暂未使用 //string EndBit = ""; //string StartLayer = "1";//生产下线-起点层数默认为1 //string EndLayer = ""; //产线下线流程----正常流程下线 if (workOrder.S_ORDER_TYPE.Trim() != "无码入库") { bool full = true; //判断当前货位是否存在托盘,如果存在则 无需从托盘信息中间表获取 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(); trayInfo.ForEach(a => { TrayCode = TrayCode + a.S_CNTR_CODE + ","; workNo = a.S_SRC; }); } else { //2.获取设备第一次下线时间 bool IsTime = true; DeviceStartTime = ConveryInfoFullTwo(plc, DeviceStartTime); if (IsTime) { //3.处理 工单信息表数据--托规、批次号、物料层数 full = ConveryInfoFullThree(plc, location, workOrder, DeviceStartTime, ref TrayCode, ref BatchNo, ref ItemLayer, ref workNo); } else full = false; } if (full) { //5.正常产线下线 ProductLineFull(plc, location, workOrder, TrayCode, BatchNo, ItemLayer, ItemTrayType, StartBit, workNo); } else LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},托盘信息存在异常,请查询异常日志!", "输送线"); } //无码入库流程----人工创建工单时----工单类型 应选择 无码入库 else { //判断当前设备口是否存在托盘(任务未取货完成,托盘还是绑定在设备口的),有沿用,无生成新托盘 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 { TrayCode = ""; trayInfo.ForEach(a => { TrayCode = TrayCode + "," + a.S_CNTR_CODE.Trim(); }); } LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location} 无码入库!", "输送线"); Console.WriteLine($"输送线:{plc.deviceName} 下线信号:{location} 无码入库!"); ProductLineFull(plc, location, workOrder, TrayCode, BatchNo, ItemLayer, workOrder.S_TrayType, StartBit, workOrder.S_WorkNo); } } else LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location} 未找到工单", "输送线"); } else LogHelper.Info($"输送线:{plc.deviceName} 当前位置{location}有任务,不可触发满托下线", "输送线"); } } catch (Exception ex) { LogHelper.Info($"输送线处理异常:{ex.Message}", "输送线"); } return result; } private static void ProductLineFull(Settings.deviceInfo plc, string location, LinZhiWorkOrder workOrder, string TrayCode, string BatchNo, string ItemLayer, string ItemTrayType, string StartBit, string workNo = "", bool ProType = true) { //5.根据配置文件获取当前产线优先下发库区,再连同物料、大小板、批次,获取此库区 可用货位 // 遍历库区查询-判断排锁-表名: RowLock var creResult = false; LogHelper.Info($"输送线:{plc.deviceName} 查询入库终点货位", "输送线"); ////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 db = new SqlHelper().GetInstance(); LogHelper.Info($"itemtrayType:{ItemTrayType}"); var ipl = db.Queryable().Where(a => a.S_ITEM_CODE == workOrder.S_ItemCode.Trim() && a.S_TRAY_TYPE.Trim() == ItemTrayType.Trim()).OrderByDescending(a => a.S_PRIORITY).ToList(); if (ipl.Count() > 0) { if (ProType) { LogHelper.Info($"输送线:{plc.deviceName} 查询到表数据", "输送线"); ////Console.WriteLine($"输送线:{plc.deviceName} 查询到配置文件"); for (int i = 0; i < ipl.Count(); i++) { string areaCode = ipl[i].S_AREA_CODE; if (!creResult) creResult = TaskProcess.LinZhiPlcTask(StartBit, "成品下线", TrayCode, areaCode, workOrder.S_ItemCode.Trim(), BatchNo, ItemLayer, ItemTrayType, plc.deviceName, true, workNo); } } else { for (int i = 0; i < ipl.Count(); i++) { string areaCode = ipl[i].S_AREA_CODE; if (!creResult) creResult = TaskProcess.LinZhiPlcTask(StartBit, "零头下线", TrayCode, areaCode, workOrder.S_ItemCode.Trim(), BatchNo, ItemLayer, ItemTrayType, plc.deviceName, true, workOrder.S_WorkNo.Trim()); } } if (creResult) { LogHelper.Info("绑定托盘表和托盘物料表"); //任务创建成功 绑定起点托盘表,托盘物料表 TaskProcess.BindLocCntr(StartBit, TrayCode, workOrder.S_ItemCode.Trim(), BatchNo, workNo, ItemLayer); } } else LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location} 未获取到当前产线的优先下线库区 itemPrecedenceLine 数据。该物料不存在:{workOrder.S_ItemCode.Trim()}", "输送线"); } private static bool ConveryInfoFullThree(Settings.deviceInfo plc, string location, LinZhiWorkOrder workOrder, string DeviceStartTime, ref string TrayCode, ref string BatchNo, ref string ItemLayer, ref string workNo) { bool result = true; var db = new SqlHelper().GetInstance(); //3.从 富勒托盘信息中间表 获取 dateTime < DeviceStartTime 的数据 ChunAnTrayInfo // 有两条:进入第 3-1 步 // 小于两条:异常-连接 报警器 进行声光报警 //3-1.判断托盘信息中 托规、批次号、物料层数 是否有值---------根据 托规 判断当前托盘是否为零头 // 有值:判断当前值是否与 工单信息 相同,不同代表 当前产线切换了生产类型或首次下线,需同步更新 工单信息 // 无值:判断工单是否存在对应值,不存在 即 异常 if (!string.IsNullOrEmpty(DeviceStartTime)) { var trayTableInfo = WCSHelper.GetLinZhiTrayInfoList(DeviceStartTime, plc.deviceName); if (trayTableInfo != null) { if (trayTableInfo.Count == 2)// || trayTableInfo.Count == 1 { workNo = trayTableInfo[0].workNo; LogHelper.Info($"输送线:获取当前下线时间前的两个托盘数据,按时间升序。产线号:{plc.deviceName},下线时间:{DeviceStartTime}.", "输送线"); trayTableInfo = db.Queryable().Where(a => Convert.ToDateTime(a.dateTime.Trim()) < Convert.ToDateTime(DeviceStartTime) && a.deviceName == plc.deviceName).OrderBy(a => a.dateTime).Take(2).ToList(); LogHelper.Info($"输送线:获取当前下线时间前的两个托盘数据为:{JsonConvert.SerializeObject(trayTableInfo)}。{plc.deviceName},下线时间:{DeviceStartTime}.", "输送线"); string trayCode = ""; string batchNo = ""; string itemLayer = ""; //1-首先判断工单 托规、批次号、物料层数 三个参数是否有值 // 有值:判断和当前值是否相同,不同 即 更新 UpdateWorkInfo // 无值:更新工单对应信息 trayTableInfo.ForEach(a => { trayCode = trayCode + "," + a.trayCode; string TrayRule = ""; string UpdateWorkOn = "";//更新工单信息开关 默认为空 1-需要更新 托规、批次号、物料层数 信息 //生产下线:首托下线 必须 传输全部信息-托规、批次号、物料层数;否则 第一托就无法下线 // 之后如果缺少信息,可以从工单获取 //工单初始状态:托规、批次号、物料层数 必然有一个值为空;后续会一直有值 Console.WriteLine($"更改工单托盘数据:工单号:{workOrder.S_WorkNo},托规:{a.trayRule},批次号:{a.batchNo},物料层数:{a.itemLayer}"); if (string.IsNullOrEmpty(workOrder.S_TrayRules) || string.IsNullOrEmpty(workOrder.S_BatchNo) || string.IsNullOrEmpty(workOrder.S_ItemLayer)) { WCSHelper.UpdateWorkInfo(workOrder, a.trayRule, 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, TrayRule, 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}不符,标准托规信息异常!"); // SendErrorTcpMsg(plc, DeviceStartTime); //} }); var trayAll = WCSHelper.GetLinJiangTrayInfoAllList(plc.deviceName); if (trayTableInfo.Count != trayAll.Count && trayTableInfo.Count == 1) { result = false; LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},第一次下线时间之前只获得{trayTableInfo.Count}条托盘信息,记录托盘信息为{trayAll.Count}条,托盘信息异常!", "输送线"); //连接报警器 进行异常报警 Console.WriteLine($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},第一次下线时间之前只获得{trayTableInfo.Count}条托盘信息,记录托盘信息为{trayAll.Count}条,托盘信息异常!"); SendErrorTcpMsg(plc, DeviceStartTime); db.Deleteable().Where(a => a.DeviceName == plc.deviceName).ExecuteCommand(); } TrayCode = trayCode; BatchNo = batchNo; ItemLayer = itemLayer; } else { result = false; LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},第一次下线时间之前只获得{trayTableInfo.Count}条托盘信息,托盘信息异常!", "输送线"); //连接报警器 进行异常报警 Console.WriteLine($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},第一次下线时间之前只获得{trayTableInfo.Count}条托盘信息,托盘信息异常!"); SendErrorTcpMsg(plc, DeviceStartTime); db.Deleteable().Where(a => a.DeviceName == plc.deviceName).ExecuteCommand(); } } else { result = false; LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location},下线时间:{DeviceStartTime},第一次下线时间之前只获得{trayTableInfo.Count}条托盘信息,托盘信息异常!", "输送线"); SendErrorTcpMsg(plc, DeviceStartTime); db.Deleteable().Where(a => a.DeviceName == plc.deviceName).ExecuteCommand(); } } else LogHelper.Info($"输送线:{plc.deviceName} 下线信号:{location} ,DeviceStartTime 设备第一次下线时间为空,程序异常!", "输送线"); return result; } /// /// 输送线托盘信息异常-向输送线发送异常信号 /// 1、下线时间前的托盘数小于2 /// 2、托规不等于当前数量 /// /// public static void SendErrorTcpMsg(Settings.deviceInfo plc, string deviceStartTime) { if (DateTime.Now >= Convert.ToDateTime(deviceStartTime)) PlcHelper.SendHex(plc.address, "3F00600d0a"); } private static void ConveryInfoFullThreeS(Settings.deviceInfo plc, string location, LinZhiTrayInfo a, LinZhiWorkOrder 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; } } private static string ConveryInfoFullTwo(Settings.deviceInfo plc, string DeviceStartTime) { //2.获取当前产线 设备中间表 对应信息 LinJiangDeviceState //2-1.有数据,判断当前是否为第一次收到下线信号 // 第一次:更新 DeviceState = 1,DeviceStartTime = 当前时间 // 第N次:判断当前 DeviceState 是否为1,不为1,更新 DeviceState 以及 DeviceStartTime //2-2.无数据,插入 DeviceName ,DeviceState = 1,DeviceStartTime = 当前时间 数据 //任务创建成功会删除此表数据 var db = new SqlHelper().GetInstance(); var workInfo = db.Queryable().Where(a => a.S_PLineNo == plc.deviceName && a.S_ORDER_TYPE == "产线下线" && a.S_WorkState == "执行中").First(); if (workInfo != null) { var deviceTableInfo = WCSHelper.GetLinJiangDeviceState(plc.deviceName); if (deviceTableInfo != null) { if (deviceTableInfo.DeviceState.Trim() != "1") { WCSHelper.UpdateLinJiangDeviceState(deviceTableInfo, "1", DeviceStartTime); //isTime = false; } else { DeviceStartTime = deviceTableInfo.DeviceTime; } } else { DateTime dateTime = Convert.ToDateTime(DeviceStartTime).AddMinutes(1); DeviceStartTime = dateTime.ToString(); WCSHelper.LinJiangInsertDeviceState(new LinZhiDeviceState { DeviceName = plc.deviceName, DeviceTime = DeviceStartTime, DeviceState = "1" }); } } return DeviceStartTime; } /// /// 瓶坯翻斗机空托下线 /// /// /// /// private static void LinZhiAnalysisPPDump(string data, Settings.deviceInfo plc) { LogHelper.Info($"瓶坯翻斗机,查询任务终点:{plc.TN_Location[0]}"); if (LineState.Keys.Contains(plc.TN_Location[0])) { LogHelper.Info("瓶坯翻斗机包含该任务终点"); LineState[plc.TN_Location[0]].status = data; LineState[plc.TN_Location[0]].modify = DateTime.Now; } else { LogHelper.Info("瓶坯翻斗机未包含该任务终点"); LineState.Add(plc.TN_Location[0], new statemodel { status = data, modify = DateTime.Now }); } LogHelper.Info($"{plc.deviceName}-{plc.address}-{data}", "瓶坯翻斗机"); var db = new SqlHelper().GetInstance(); var workInfo = db.Queryable().Where(a => a.S_PLineNo == plc.deviceName).First(); if (workInfo != null && workInfo.S_WorkState == "执行中") { LogHelper.Info($"查询到执行中的工单,工单类型:{workInfo.S_PLineNo}"); string startArea = ""; string fullTaskType = ""; string emptyTaskType = ""; if (workInfo.S_UsingNow == "Y") { LogHelper.Info("即产即用工单"); //即产即用在起点为线边 var bcpInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯即产满框" && a.enable == 1).FirstOrDefault(); if (bcpInfo != null) { startArea = bcpInfo.areaCode; } fullTaskType = "翻斗机即产满托上线(瓶坯)"; emptyTaskType = "翻斗机即产空托下线(瓶坯)"; } else { LogHelper.Info("非即产即用工单"); //非即产即用起点为库区 string areaName = plc.deviceName.Split('-')[1].Substring(0, 1) + "号瓶坯翻斗机非即产满框"; var bcpInfo = Settings.areaInfos.Where(a => a.areaName == areaName && a.enable == 1).FirstOrDefault(); if (bcpInfo != null) { startArea = bcpInfo.areaCode; } fullTaskType = "翻斗机库存满托上线(瓶坯)"; emptyTaskType = "翻斗机库存空托下线(瓶坯)"; } if (data.Length == 6) { if (data.Substring(2, 2) == "22") { if (LocationHelper.CheckLocFree(plc.TN_Location[0])) { var bit = plc.TN_Location[0]; LogHelper.Info($"翻斗机点位:{bit}"); bool flag = true; var cgInfo = db.Queryable().Where(a => a.Bit == bit).First(); if (cgInfo != null) { LogHelper.Info($"查询到中间表数据CGTTable:{cgInfo.Bit},{cgInfo.time}"); LogHelper.Info($"当前时间:{DateTime.Now}"); if (cgInfo.time.AddSeconds(10) > DateTime.Now) { flag = false; } } else LogHelper.Info($"未查询到中间表数据CGTTable:{bit}"); if (flag) { //判断当前翻斗机是否有送过满托 S_NOTE 字段默认空字符串,满托卸货完成之后会标记为满托,空托取货完成复位为空字符串 Location startLoca = null; var locCode = plc.TN_Location[0]; var plcLoca = db.Queryable().Where(a => a.S_LOC_CODE == locCode).First(); if (plcLoca == null) { LogHelper.Info($"瓶坯翻斗机上无托盘,生成满托上线任务,瓶坯翻斗机点位:{plc.TN_Location[0]}"); //初始状态,无托盘,直接上满托(非即产即用需要校验 套袋完成,即产即用直接使用) if (workInfo.S_UsingNow == "Y") { LogHelper.Info($"瓶坯即产满框 查找"); startLoca = getFDSXArea(db, workInfo, startArea); } else { LogHelper.Info($"瓶坯翻斗机非即产满框 查找"); startLoca = getFDSXArea(db, workInfo, startArea); } if (startLoca != null) { //创建作业 WMSHelper.CreateOpTask(startLoca.S_CODE, locCode, "出库", fullTaskType, startLoca.LocCntrRel.S_CNTR_CODE, "", "", workInfo.S_WorkNo); } } else { LogHelper.Info($"瓶坯翻斗机上有空托盘,生成空托下线任务,瓶坯翻斗机点位:{plc.TN_Location[0]}"); //创建作业 WMSHelper.CreateOpTask(locCode, "", "入库", emptyTaskType, plcLoca.S_CNTR_CODE, "", "", workInfo.S_WorkNo); } } } else LogHelper.Info($"瓶坯翻斗机:{plc.deviceName} 当前位置{plc.TN_Location[0]}有任务,不可触发空托下线或满托上线任务", "瓶坯翻斗机"); } } } else LogHelper.Info($"瓶坯翻斗机:{plc.deviceName} 未开启工单,不可触发满托下线", "瓶坯翻斗机"); } /// /// 瓶盖翻斗机空托下线 瓶盖只有非即产即用 /// /// /// /// private static void LinZhiAnalysisPGDump(string data, Settings.deviceInfo plc) { LogHelper.Info($"{plc.deviceName}-{plc.address}-{data}", "瓶盖翻斗机"); //var doorPlc = Settings.GetDeviceInfoList().Where(a => a.address == plc.address && a.deviceType == 1 && a.enable == 1).FirstOrDefault(); //AnalysisDoor(data, doorPlc); LogHelper.Info($"瓶盖翻斗机,查询任务终点:{plc.TN_Location[0]}"); if (LineState.Keys.Contains(plc.TN_Location[0])) { LogHelper.Info("瓶盖翻斗机包含该任务终点"); LineState[plc.TN_Location[0]].status = data; LineState[plc.TN_Location[0]].modify = DateTime.Now; } else { LogHelper.Info("瓶盖翻斗机未包含该任务终点"); LineState.Add(plc.TN_Location[0], new statemodel { status = data, modify = DateTime.Now }); } var db = new SqlHelper().GetInstance(); var workInfo = db.Queryable().Where(a => a.S_PLineNo == plc.deviceName).First(); if (workInfo != null && workInfo.S_WorkState == "执行中") { if (workInfo.S_ItemName == "小包装盖") { return; } LogHelper.Info($"查询到执行中的工单,工单类型:{workInfo.S_PLineNo},物料编码:{workInfo.S_ItemCode},物料类型:{workInfo.S_ITEM_TYPE}"); string startArea = ""; string fullTaskType = ""; string emptyTaskType = ""; LogHelper.Info("非即产即用工单"); //非即产即用起点为库区 var bcpInfo = Settings.areaInfos.Where(a => a.areaName == "瓶盖非即产满框" && a.enable == 1).FirstOrDefault(); if (bcpInfo != null) { startArea = bcpInfo.areaCode; } fullTaskType = "翻斗机库存满托上线(瓶盖)"; emptyTaskType = "翻斗机库存空托下线(瓶盖)"; if (data.Length == 6) { if (data.Substring(2, 2) == "22") { if (LocationHelper.CheckLocFree(plc.TN_Location[0])) { var bit = plc.TN_Location[0]; bool flag = true; var cgInfo = db.Queryable().Where(a => a.Bit == bit).First(); if (cgInfo != null) { if (cgInfo.time.AddSeconds(10) > DateTime.Now) { flag = false; } } if (flag) { Location startLoca = null; var locCode = plc.TN_Location[0]; var plcLoca = db.Queryable().Where(a => a.S_LOC_CODE == locCode).First(); if (plcLoca == null) { LogHelper.Info($"瓶盖翻斗机上无托盘,生成满托上线任务,瓶盖翻斗机点位:{plc.TN_Location[0]}"); //初始状态,无托盘,直接上满托(非即产即用需要校验 套袋完成,即产即用直接使用) startLoca = getFDSXArea(db, workInfo, startArea); if (startLoca != null) { //创建作业 WMSHelper.CreateOpTask(startLoca.S_CODE, locCode, "出库", fullTaskType, startLoca.LocCntrRel.S_CNTR_CODE,"","",workInfo.S_WorkNo); } } else { LogHelper.Info($"瓶盖翻斗机上有空托盘,生成空托下线任务,瓶盖翻斗机点位:{locCode}"); //创建作业 WMSHelper.CreateOpTask(locCode, "", "入库", emptyTaskType, plcLoca.S_CNTR_CODE,"","",workInfo.S_WorkNo); } } } else LogHelper.Info($"瓶盖翻斗机:{plc.deviceName} 当前位置{plc.TN_Location[0]}有任务,不可触发空托下线或满托上线任务", "瓶盖翻斗机"); } } } else LogHelper.Info($"瓶盖翻斗机:{plc.deviceName} 未开启工单,不可触发满托下线", "瓶盖翻斗机"); } public static Location getFDSXArea(SqlSugar.SqlSugarClient db, LinZhiBCPWorkOrder workInfo, string startArea) { Location result = null; var locList = db.Queryable().Where(a => a.S_AREA_CODE == startArea && a.N_CURRENT_NUM > 0).Includes(a => a.LocCntrRel).ToList(); if(locList.Count > 0) { foreach(var a in locList) { LogHelper.Info($"getFDSXArea:查询到当前货位锁状态:{a.S_LOCK_STATE},货位编码:{a.S_CODE}"); if(a.S_LOCK_STATE == "无") { var cntrInfo = db.Queryable().Where(b => b.S_LOC_CODE == a.S_CODE).First(); if(cntrInfo != null) { var itemInfo = db.Queryable().Where(b => b.S_CNTR_CODE == cntrInfo.S_CNTR_CODE).First(); if(itemInfo != null) { LogHelper.Info($"getFDSXArea:查询到物料编码:{itemInfo.S_ITEM_CODE}"); LogHelper.Info($"getFDSXArea:查询到物料批次:{itemInfo.S_BATCH_NO}"); if (workInfo.S_PLineNo.Contains("瓶坯")) workInfo.S_ITEM_TYPE = ""; if (itemInfo.S_ITEM_CODE + itemInfo.S_BATCH_NO == workInfo.S_ItemCode + workInfo.S_ITEM_TYPE) { result = a; break; } } else { LogHelper.Info($"getFDSXArea:当前托盘未绑定物料,托盘编码:{cntrInfo.S_CNTR_CODE}"); } } else { LogHelper.Info($"getFDSXArea:当前货位未绑定托盘"); } } } } else { LogHelper.Info($"getFDSXArea:未查询到可用满托,库区编码:{startArea}"); } return result; } /// /// 瓶坯机满托下线 /// /// /// /// private static void LinZhiAnalysisPreform(string data, Settings.deviceInfo plc) { LogHelper.Info($"{plc.deviceName}-{plc.address}-{data}", "瓶坯机"); var db = new SqlHelper().GetInstance(); if (data.Length == 8) { string machinLoc = ""; if(data.Substring(4,2) == "00") { machinLoc = plc.TN_Location[0]; LogHelper.Info($"瓶坯机,查询任务终点:{machinLoc}"); if (LineState.Keys.Contains(machinLoc)) { LogHelper.Info("瓶坯机包含该任务终点"); LineState[machinLoc].status = data; LineState[machinLoc].modify = DateTime.Now; } else { LogHelper.Info("瓶坯机未包含该任务终点"); LineState.Add(machinLoc, new statemodel { status = data, modify = DateTime.Now }); } } if (data.Substring(6, 2) == "02") { machinLoc = plc.TN_Location[1]; LogHelper.Info($"瓶坯机,查询任务终点:{machinLoc}"); if (LineState.Keys.Contains(machinLoc)) { LogHelper.Info("瓶坯机包含该任务终点"); LineState[machinLoc].status = data; LineState[machinLoc].modify = DateTime.Now; } else { LogHelper.Info("瓶坯机未包含该任务终点"); LineState.Add(machinLoc, new statemodel { status = data, modify = DateTime.Now }); } } } var workInfo = db.Queryable().Where(a => a.S_PLineNo == plc.deviceName).First(); if (workInfo != null && workInfo.S_WorkState == "执行中") { LogHelper.Info($"查询到执行中的工单,工单类型:{workInfo.S_PLineNo}"); string endArea = ""; string taskType = ""; if (workInfo.S_UsingNow.ToString() == "Y") { LogHelper.Info("即产即用工单"); taskType = "注塑即产满托下线(瓶坯)"; } else { LogHelper.Info("非即产即用工单"); taskType = "注塑库存满托下线(瓶坯)"; } //endArea = Settings.GetLinJiangBCPAreaList().Where(a => a.AreaName == "瓶坯满托" && a.Enable == "1").FirstOrDefault().AreaNo; if (data.Length == 8) { if (data.Substring(0, 2) == "12") LinZhialysisBottleCapAndPreformTwo(plc, db, workInfo, endArea, taskType, plc.TN_Location[0], "瓶坯机", data); if (data.Substring(2, 2) == "22") LinZhialysisBottleCapAndPreformTwo(plc, db, workInfo, endArea, taskType, plc.TN_Location[1], "瓶坯机", data); } } else LogHelper.Info($"瓶坯机:{plc.deviceName} 未开启工单,不可触发满托下线", "瓶坯机"); } /// /// 注塑机下线流程 /// /// /// /// /// /// /// /// private static void LinZhialysisBottleCapAndPreformTwo(Settings.deviceInfo plc, SqlSugar.SqlSugarClient db, LinZhiBCPWorkOrder workInfo, string endArea, string taskType, string deviceBit, string type,string data) { LogHelper.Info($"{type}注塑机任务处理开始"); //再次判断信号 if (LocationHelper.CheckLocFree(deviceBit)) { bool flag = true; LogHelper.Info($"deviceBit:{deviceBit}"); var cgInfo = db.Queryable().Where(a => a.Bit == deviceBit).First(); if (cgInfo != null) { if (cgInfo.time.AddSeconds(10) > DateTime.Now) { flag = false; } } if (flag) { LogHelper.Info($"{type}{deviceBit}无任务,可触发下线任务"); var locInfo = db.Queryable().Where(a => a.S_CODE == deviceBit).First(); if(locInfo != null) { if(locInfo.N_CURRENT_NUM == 0) { LogHelper.Info($"{type}注塑机上未绑定托盘,生成空托上线任务"); string machine = type.Substring(0, type.Length - 1); if (workInfo.S_UsingNow == "Y") { taskType = $"注塑即产空托上线({machine})"; } else { taskType = $"注塑库存空托上线({machine})"; } Location startLoca = TaskProcess.getMStartLoc(db,workInfo.S_UsingNow); if (startLoca != null) { //创建作业 WMSHelper.CreateOpTask(startLoca.S_CODE, deviceBit, "出库", taskType, startLoca.LocCntrRel.S_CNTR_CODE, "", "", workInfo.S_WorkNo); } else { LogHelper.Info("未查询到可出空托"); } } else { string cntrCode = Guid.NewGuid().ToString("N"); var cntrInfo = db.Queryable().Where(a => a.S_LOC_CODE == deviceBit).First(); if(cntrInfo == null) { LogHelper.Info($"{type}注塑机上未绑定托盘,自动绑定托盘"); TaskProcess.BindLocCntr(deviceBit, cntrCode, workInfo.S_ItemCode, "","","",workInfo.S_ItemName); } else { cntrCode = cntrInfo.S_CNTR_CODE; TaskProcess.BindCntrItem(cntrCode, workInfo.S_ItemCode, "", "",workInfo.S_ItemName); } //创建作业 WMSHelper.CreateOpTask(deviceBit, "", "入库", taskType, cntrCode,"","",workInfo.S_WorkNo); } } } } } /// /// 自动门 /// /// /// internal static void AnalysisDoor(string data, Settings.deviceInfo plc) { LogHelper.Info($"自动门状态:{data},地址为:{plc.address}", "自动门"); if (data.Length / 2 == plc.deviceNo.Length * 2 || data.Length / 2 == plc.deviceNo.Length * 3)//2 2 { LogHelper.Info("自动门状态正确"); for (int i = 0; i < plc.deviceNo.Length; i++) { var state = data.Substring(3, 1); LogHelper.Info($"门{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 自动门--通用 private static Dictionary doorStatus = new Dictionary();//普通自动门字典 public class signalInfo { public string info { get; set; } public DateTime modify { get; set; } } #endregion internal static void Traffic(string forkliftNo, string lockNo, bool v) { } internal static void quliao(WCSTask mst) { LogHelper.Info($"安全交互开始 任务号={mst.S_CODE}", "安全交互"); //NDCHelper.ChangeParam(mst.S_TASK_NO.Trim(), 1101, 18); if (LineState.Keys.Contains(mst.S_START_LOC.Trim())) { LogHelper.Info($"任务类型:{mst.S_TYPE}"); if (mst.S_TYPE.Contains("翻斗机")) { 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) == "00" && DateTime.Now.Subtract(LineState[mst.S_START_LOC.Trim()].modify).TotalSeconds < 10) { //NDCHelper.ChangeParam(mst.S_CODE.Trim(), 1101, 18); NDCApi.ChangeOrderParam(mst.S_CODE.Trim(), 18, "1101"); TaskProcess.sendSing(mst, 1101); } } else { LogHelper.Info($"查询输送线允许取满信号 允许取满信号={LineState[mst.S_START_LOC.Trim()].status} 时间间隔={DateTime.Now.Subtract(LineState[mst.S_START_LOC.Trim()].modify).TotalSeconds}", "安全交互"); if (mst.S_TYPE.Contains("满托下线")) { if ((LineState[mst.S_START_LOC.Trim()].status.Substring(4,2) == "00" || LineState[mst.S_START_LOC.Trim()].status.Substring(4,2) == "02") && DateTime.Now.Subtract(LineState[mst.S_START_LOC.Trim()].modify).TotalSeconds < 10) { //NDCHelper.ChangeParam(mst.S_CODE.Trim(), 1101, 18); NDCApi.ChangeOrderParam(mst.S_CODE.Trim(), 18, "1101"); } } else { if (LineState[mst.S_START_LOC.Trim()].status == "1220" && DateTime.Now.Subtract(LineState[mst.S_START_LOC.Trim()].modify).TotalSeconds < 10) { //NDCHelper.ChangeParam(mst.S_CODE.Trim(), 1101, 18); NDCApi.ChangeOrderParam(mst.S_CODE.Trim(), 18, "1101"); TaskProcess.sendSing(mst, 1101); } } } } else LogHelper.Info($"字典中未找到该key的数据,key:{mst.S_START_LOC}"); } internal static void Xieliao(WCSTask mst) { try { LogHelper.Info($"安全交互开始 任务号={mst.S_CODE},任务终点:{mst.S_END_LOC}", "安全交互"); if (LineState.Keys.Contains(mst.S_END_LOC.Trim())) { LogHelper.Info($"查询到字典中包含终点的关键字,任务类型:{mst.S_TYPE}"); if (mst.S_TYPE.Contains("翻斗机")) { 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(4,2) == "00" && DateTime.Now.Subtract(LineState[mst.S_END_LOC.Trim()].modify).TotalSeconds < 10) { //NDCHelper.ChangeParam(mst.S_CODE.Trim(), 1103, 18); NDCApi.ChangeOrderParam(mst.S_CODE.Trim(), 18, "1103"); TaskProcess.sendSing(mst, 1103); } } else { LogHelper.Info($"查询输送线允许补空信号 允许补空信号={LineState[mst.S_END_LOC.Trim()].status} 时间间隔={DateTime.Now.Subtract(LineState[mst.S_END_LOC.Trim()].modify).TotalSeconds}", "安全交互"); if (mst.S_TYPE.Contains("空托上线")) { //if ((LineState[mst.S_END_LOC.Trim()].status.Substring(4,2) == "00" || LineState[mst.S_END_LOC.Trim()].status.Substring(6,2) == "02") && DateTime.Now.Subtract(LineState[mst.S_END_LOC.Trim()].modify).TotalSeconds < 10) if (DateTime.Now.Subtract(LineState[mst.S_END_LOC.Trim()].modify).TotalSeconds < 10) { //NDCHelper.ChangeParam(mst.S_CODE.Trim(), 1103, 18); NDCApi.ChangeOrderParam(mst.S_CODE.Trim(), 18, "1103"); TaskProcess.sendSing(mst, 1103); } } else { if (LineState[mst.S_END_LOC.Trim()].status == "1021" && DateTime.Now.Subtract(LineState[mst.S_END_LOC.Trim()].modify).TotalSeconds < 10) { //NDCHelper.ChangeParam(mst.S_CODE.Trim(), 1103, 18); NDCApi.ChangeOrderParam(mst.S_CODE.Trim(), 18, "1103"); TaskProcess.sendSing(mst, 1103); } } } } else LogHelper.Info($"字典中未包含终点的关键字,终点货位:{mst.S_END_LOC}"); } catch (Exception ex) { LogHelper.Info("Xieliao err :" + ex.Message); } } } }