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 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) LinJiangAnalysisProductLine(data, plc);//输送线处理 -- 成品下线 //if (plc.deviceType == 3) LinJiangAnalysisProductLine(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 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 endArea = ""; string fullTaskType = ""; string emptyTaskType = ""; if (workInfo.S_UsingNow == "Y") { LogHelper.Info("即产即用工单"); //即产即用在起点为线边 var bcpInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯即产即用A" && a.enable == 1).FirstOrDefault(); if (bcpInfo != null) { startArea = bcpInfo.areaCode; } fullTaskType = "翻斗机即产满托上线(瓶坯)"; emptyTaskType = "翻斗机即产空托下线(瓶坯)"; } else { LogHelper.Info("非即产即用工单"); //非即产即用起点为库区 var bcpInfo = Settings.areaInfos.Where(a => a.areaName == "瓶坯非即产即用" && a.enable == 1).FirstOrDefault(); if (bcpInfo != null) { startArea = bcpInfo.areaCode; } fullTaskType = "翻斗机库存满托上线(瓶坯)"; emptyTaskType = "翻斗机库存空托下线(瓶坯)"; } endArea = Settings.areaInfos.Where(a => a.areaName == "瓶坯翻斗机空托" && a.enable == 1).FirstOrDefault().areaCode; if (data.Length == 6) { if (data.Substring(0, 2) == "11") { 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).ToList(); if (plcLoca.Count <= 0) { LogHelper.Info($"瓶坯翻斗机上无托盘,生成满托上线任务,瓶坯翻斗机点位:{plc.TN_Location[0]}"); //初始状态,无托盘,直接上满托(非即产即用需要校验 套袋完成,即产即用直接使用) if (workInfo.S_UsingNow == "Y") { LogHelper.Info($"瓶坯即产即用A库区查找"); startLoca = getFDSXArea(db, workInfo, startArea); if (startLoca == null) { LogHelper.Info($"瓶坯即产即用A库区未找到满托,去瓶坯即产即用B库区查找"); startLoca = TaskProcess.BCPInOrOut(db, true, "瓶坯即产即用B", workInfo.S_ItemCode); } } else { startLoca = getFDSXArea(db, workInfo, startArea); } if (startLoca != null) { //创建作业 WMSHelper.CreateOpTask(startLoca.S_CODE, locCode, "出库", fullTaskType, startLoca.LocCntrRel.S_CNTR_CODE); } } else { LogHelper.Info($"瓶坯翻斗机上有空托盘,生成空托下线任务,瓶坯翻斗机点位:{plc.TN_Location[0]}"); //创建作业 WMSHelper.CreateOpTask(locCode, "", "入库", emptyTaskType, plcLoca[0].S_CNTR_CODE); } } } 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 == "执行中") { LogHelper.Info($"查询到执行中的工单,工单类型:{workInfo.S_PLineNo}"); string startArea = ""; string endArea = ""; 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 = "翻斗机库存空托下线(瓶盖)"; endArea = Settings.areaInfos.Where(a => a.areaCode == "瓶盖空托" && a.enable == 1).FirstOrDefault().areaCode; if (data.Length == 6) { if (data.Substring(0, 2) == "11") { 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).ToList(); if (plcLoca.Count <= 0) { 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); } } else { LogHelper.Info($"瓶盖翻斗机上有空托盘,生成空托下线任务,瓶盖翻斗机点位:{plc.TN_Location[0]}"); //创建作业 WMSHelper.CreateOpTask(plc.TN_Location[0],"", "入库", emptyTaskType, startLoca.LocCntrRel.S_CNTR_CODE); } } } 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) { 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) { if(itemInfo.S_ITEM_CODE == workInfo.S_ItemCode) { result = a; break; } } } } } } return result; } /// /// 瓶坯机满托下线 /// /// /// /// private static void LinZhiAnalysisPreform(string data, Settings.deviceInfo plc) { 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 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 == 4) { if (data == "1122") LinZhialysisBottleCapAndPreformTwo(plc, db, workInfo, endArea, taskType, plc.TN_Location[0], "瓶坯机"); if (data == "1221") LinZhialysisBottleCapAndPreformTwo(plc, db, workInfo, endArea, taskType, plc.TN_Location[1], "瓶坯机"); } } 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) { 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); //创建作业 WMSHelper.CreateOpTask(startLoca.S_CODE, deviceBit, "出库", taskType, startLoca.LocCntrRel.S_CNTR_CODE); } else { LogHelper.Info($"{type}注塑机上未绑定托盘,自动绑定托盘"); string cntrCode = Guid.NewGuid().ToString("N"); var cntrInfo = db.Queryable().Where(a => a.S_LOC_CODE == deviceBit).First(); if(cntrInfo == null) { LocCntrRel cntr = new LocCntrRel { S_LOC_CODE = deviceBit, S_CNTR_CODE = cntrCode, }; if (db.Insertable(cntr).ExecuteCommand() > 0) { locInfo.N_CURRENT_NUM = locInfo.N_CURRENT_NUM + 1; db.Updateable(locInfo).UpdateColumns(a => a.N_CURRENT_NUM).ExecuteCommand(); LogHelper.Info($"起点成功绑定托盘,起点:{deviceBit},托盘号:{cntrCode}"); } } else { cntrCode = cntrInfo.S_CNTR_CODE; } //创建作业 WMSHelper.CreateOpTask(deviceBit, "", "入库", taskType, cntrCode); } } } } } /// /// 自动门 /// /// /// 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 == "112100" && DateTime.Now.Subtract(LineState[mst.S_START_LOC.Trim()].modify).TotalSeconds < 10) { NDCHelper.ChangeParam(mst.S_CODE.Trim(), 1101, 18); 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 (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); 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 == "112100" && DateTime.Now.Subtract(LineState[mst.S_END_LOC.Trim()].modify).TotalSeconds < 10) { NDCHelper.ChangeParam(mst.S_CODE.Trim(), 1103, 18); 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 (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); TaskProcess.sendSing(mst, 1103); } } } else LogHelper.Info($"字典中未包含终点的关键字,终点货位:{mst.S_END_LOC}"); } catch (Exception ex) { LogHelper.Info("Xieliao err :" + ex.Message); } } } }