using Furion.Logging; using IoTClient; using Microsoft.AspNetCore.SignalR; using System.Data; namespace WCS.Application; public static class PLCService { private static readonly ISqlSugarClient _db = SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId); private static readonly IHubContext _taskLogHubContext; static PLCService() { _taskLogHubContext = App.GetService>(); } public static void OnChangeEvent(object sender, EventArgs e) { try { var mod = sender as WcsDeviceDto; Console.WriteLine("PLC值为" + mod.Value); switch (mod.Type) { case PLCTypeEnum.StackingMachine: StackingMachine(mod); break; case PLCTypeEnum.ConveyorLine: ConveyorLine(mod); break; case PLCTypeEnum.AGV: AGV(mod); break; case PLCTypeEnum.PalletMachine: PalletMachine(mod); break; default: break; } } catch (Exception ex) { Log.Error(ex.Message, ex); } } /// /// 跺机业务处理 /// /// private static void StackingMachine(WcsDeviceDto modDevice) { var plcConn = modDevice.PLCUtil; switch (modDevice.ToString()) { case "820": { var modTask = _db.Queryable().First(s => s.Status == TaskStatusEnum.Wait && s.TaskType == TaskTypeEnum.Out && s.StartRoadway == modDevice.StationNum); if (modTask == null) { break; } var modTaskMonitor = new WcsTaskMonitor() { TaskNo = modTask.TaskNo, StartLocat = modTask.StartLocate, EndLocat = modTask.EndLocate, PalletNo = modTask.PalletNo, }; // 根据跺机号确认放货工位 string outStationNum = "0"; string endRow = "", endColumn = "", endStorey = ""; switch (modDevice.StationNum) { case "R01": outStationNum = "11"; endRow = "1"; endColumn = "100"; endStorey = "1"; break; case "R02": outStationNum = "7"; endRow = "1"; endColumn = "100"; endStorey = "1"; break; default: break; } var modD = modDevice.listDevice.FirstOrDefault(); if (modD == null) { Log.Error($"IP{modDevice.PlcId}.设备id:{modDevice.Id}缺少工位级别设备信息"); break; } var (result, value) = plcConn.GetPlcDBValue(modD.PosType, modD.DbNumber, modD.PlcPos); if (result.IsSucceed) { if (value == 120)// 放货工位空闲 可放货 { if (int.Parse(outStationNum) > 0) { var row = int.Parse(modTaskMonitor.StartLocat.Substring(0, 2)).ToString(); var column = int.Parse(modTaskMonitor.StartLocat.Substring(2, 2)).ToString(); var layer = int.Parse(modTaskMonitor.StartLocat.Substring(4, 2)).ToString(); var deep = int.Parse(modTaskMonitor.StartLocat.Substring(6, 2)).ToString(); if (int.Parse(row) > 2) //大于4 { row = (int.Parse(row) - 2).ToString(); } else { // 起始储位地址为空,跳过 写入任务明细表 modTaskMonitor.StartLocat = ""; modTaskMonitor.InteractiveMsg = "起始储位为空!"; _db.Insertable(modTaskMonitor).ExecuteCommand(); //下发任务日志 _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt()); break; } //给PLC写入任务数据 var listResult = new List(); //任务号 var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo"); listResult.Add(plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, modTaskMonitor.TaskNo)); //托盘号 var modPosPalletNo = modDevice.listStation.FirstOrDefault(s => s.Text == "PalletNo"); listResult.Add(plcConn.SetPlcDBValue(modPosPalletNo.PosType, modDevice.DbNumber, modPosPalletNo.PlcPos, modTaskMonitor.PalletNo)); //起始排 var modPosRow = modDevice.listStation.FirstOrDefault(s => s.Text == "StartRow"); listResult.Add(plcConn.SetPlcDBValue(modPosRow.PosType, modDevice.DbNumber, modPosRow.PlcPos, row)); // 起始列 var modPosColumn = modDevice.listStation.FirstOrDefault(s => s.Text == "StartColumn"); listResult.Add(plcConn.SetPlcDBValue(modPosColumn.PosType, modDevice.DbNumber, modPosColumn.PlcPos, column)); // 起始层 var modPosStorey = modDevice.listStation.FirstOrDefault(s => s.Text == "StartLayer"); listResult.Add(plcConn.SetPlcDBValue(modPosStorey.PosType, modDevice.DbNumber, modPosStorey.PlcPos, layer)); // 目标放货工位 var modPosEndRow = modDevice.listStation.FirstOrDefault(s => s.Text == "EndRow"); listResult.Add(plcConn.SetPlcDBValue(modPosEndRow.PosType, modDevice.DbNumber, modPosEndRow.PlcPos, endRow)); var modPosEndColumn = modDevice.listStation.FirstOrDefault(s => s.Text == "EndColumn"); listResult.Add(plcConn.SetPlcDBValue(modPosEndColumn.PosType, modDevice.DbNumber, modPosEndColumn.PlcPos, endColumn)); var modPosEndStorey = modDevice.listStation.FirstOrDefault(s => s.Text == "EndLayer"); listResult.Add(plcConn.SetPlcDBValue(modPosEndStorey.PosType, modDevice.DbNumber, modPosEndStorey.PlcPos, endColumn)); //全部写入成功 if (listResult.All(s => s.IsSucceed)) { // 写入跺机任务下发完成 plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "10"); // 将出库任务待执行改为正在执行 _db.Updateable() .SetColumns(s => s.FinishDate == DateTime.Now) .SetColumns(s => s.Status == TaskStatusEnum.Doing) .SetColumns(s => s.Levels == 2) .Where(s => s.Id == modTask.Id) .ExecuteCommand(); var modInsertTaskMonitor = new WcsTaskMonitor() { TaskNo = modTask.TaskNo, PlcId = modDevice.Id, PlcName = modDevice.Text, InteractiveMsg = $"写入指令:{modTask.StartLocate}储位====》{outStationNum}工位", PalletNo = modTask.PalletNo, Status = TaskStatusEnum.Complete, StartLocat = modTask.StartLocate, EndLocat = outStationNum, }; _db.Insertable(modInsertTaskMonitor).ExecuteCommand(); //下发任务日志 _taskLogHubContext.Clients.All.PublicTaskMonitor(modInsertTaskMonitor.Adapt()); //修改led屏信息 //LedDisplay(modDevice.LedIP, "工位:" + modTask.EndLocate, "出库中 " + $"储位地址:{modTask.StartLocate}", "托盘号:" + modTask.PalletNo); } } } } else { Log.Error(string.Join(',', result.ErrList)); } } break; case "20": { var modPosPlcTask = modDevice.listStation.FirstOrDefault(s => s.Text == "PlcTaskNo"); var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo"); var (result, TaskNo) = plcConn.GetPlcDBValue(modPosPlcTask.PosType, modDevice.DbNumber, modPosPlcTask.PlcPos); if (!result.IsSucceed) break; string taskNo = Convert.ToString(TaskNo); var modTask = _db.Queryable().First(s => s.TaskNo == taskNo && s.Status == TaskStatusEnum.Doing); if (modTask == null) { Log.Error("【跺机】当前托盘号不存在对应的任务"); break; } if (modTask.TaskType.Value == TaskTypeEnum.In) { //入库任务 var res = plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, taskNo); if (!res.IsSucceed) break; // 根据跺机号确认取货工位 string outStationNum = "0"; switch (modDevice.StationNum) { case "R01": outStationNum = "10"; break; case "R02": outStationNum = "6"; break; default: break; } var modDevice2 = modDevice.listDevice.Where(s => s.StationNum == outStationNum).FirstOrDefault(); var modStation = _db.Queryable().First(s => s.DeviceId == modDevice2.Id && s.Text == "TaskNo"); // 向取货工位写入任务号 res = plcConn.SetPlcDBValue(modStation.PosType, modDevice2.DbNumber, modStation.PlcPos, taskNo); if (!res.IsSucceed) break; // 向取货工位写入流程控制字 res = plcConn.SetPlcDBValue(modDevice2.PosType, modDevice2.DbNumber, modDevice2.WcsPos, "100"); if (!res.IsSucceed) break; var modTaskMonitor = new WcsTaskMonitor() { TaskNo = modTask.TaskNo, PlcId = modDevice2.PlcId, PlcName = modDevice2.Text, InteractiveMsg = "跺机取货完成", StartLocat = outStationNum, EndLocat = modTask.EndLocate, PalletNo = modTask.PalletNo, Status = TaskStatusEnum.Complete }; _db.Insertable(modTaskMonitor).ExecuteCommand(); //下发任务日志 _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt()); } else if (modTask.TaskType.Value == TaskTypeEnum.Out) { //入库任务 var res = plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, taskNo); if (!res.IsSucceed) break; res = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "20"); if (!res.IsSucceed) break; // 根据跺机号确认取货工位 string outStationNum = "0"; switch (modDevice.StationNum) { case "R01": outStationNum = "11"; break; case "R02": outStationNum = "7"; break; default: break; } var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo"); var modTaskMonitor = new WcsTaskMonitor() { TaskNo = modTask.TaskNo, PlcId = modDevice.PlcId, PlcName = modDevice.Text, InteractiveMsg = "跺机取货完成", StartLocat = outStationNum, EndLocat = modTask.EndLocate, PalletNo = modTask.PalletNo, Status = TaskStatusEnum.Complete }; _db.Insertable(modTaskMonitor).ExecuteCommand(); //下发任务日志 _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt()); } } break; case "30": { //操作完成(放货完成) var modPosPlcTask = modDevice.listStation.FirstOrDefault(s => s.Text == "PlcTaskNo"); var (result, TaskNo) = plcConn.GetPlcDBValue(modPosPlcTask.PosType, modDevice.DbNumber, modPosPlcTask.PlcPos); if (!result.IsSucceed) break; string taskNo = Convert.ToString(TaskNo); var modTask = _db.Queryable().First(s => s.TaskNo == taskNo && s.Status == TaskStatusEnum.Doing); if (modTask == null) { Log.Error("【跺机】当前托盘号不存在对应的任务"); break; } switch (modTask.TaskType) { case TaskTypeEnum.In: case TaskTypeEnum.PLC: { //入库任务 var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo"); // 写入plc任务号 var res = plcConn.SetPlcDBValue(modStation.PosType, modDevice.DbNumber, modStation.PlcPos, taskNo); if (!res.IsSucceed) break; res = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "30"); if (!res.IsSucceed) break; //修改任务状态 modTask.Status = TaskStatusEnum.Complete; _db.Updateable() .SetColumns(s => s.Status == TaskStatusEnum.Complete) .Where(s => s.Id == modTask.Id) .ExecuteCommand(); //反馈给WMS var modTaskRequest = modTask.Adapt(); HttpService httpService = new HttpService(); var modResponseTask = httpService.RequestTask(modTaskRequest).Result; if (modResponseTask.StatusCode == "0") { //请求成功 modTask.IsSuccess = TaskSuccessEnum.Success; _db.Updateable(modTask).UpdateColumns(s => s.IsSuccess).ExecuteCommand(); //todo:修改储位信息 任务类型 执行状态 起始位置 目标位置 // //记录任务明细 var modTaskMonitor = new WcsTaskMonitor() { TaskNo = modTask.TaskNo, PlcId = modDevice.PlcId, PlcName = modDevice.Text, InteractiveMsg = "任务完成,返回给WMS任务完成", StartLocat = modTask.StartLocate, EndLocat = modTask.EndLocate, PalletNo = modTask.PalletNo, Status = TaskStatusEnum.Complete }; _db.Insertable(modTaskMonitor).ExecuteCommand(); //下发任务日志 _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt()); } else { //请求失败 modTask.IsSuccess = TaskSuccessEnum.Fail; modTask.Information = modResponseTask.Message; _db.Updateable(modTask).UpdateColumns(s => new { s.IsSuccess, s.Information }).ExecuteCommand(); } //todo:垛机入库不空跑 //todo:LED } break; case TaskTypeEnum.Out://出库 { // 从出库任务获取巷道号 string num = ""; // 放货工位号 if (modTask.StartRoadway == "R01") { num = "11"; //交互工位 } else if (modTask.StartRoadway == "R02") { num = "7"; //交互工位 } var modDevice2 = modDevice.listDevice.FirstOrDefault(s => s.StationNum == num); if (modDevice2 == null) { Log.Error($"【跺机】找不到工位{num}设备信息"); break; } // 根据目标口获取目标工位 string outCode = modTask.EndLocate.IsNullOrEmpty() ? "-1" : modTask.EndLocate; var listStation = _db.Queryable().Where(s => s.DeviceId == modDevice2.Id).ToList(); //给PLC写入任务数据 var listResult = new List(); //任务号 var modPosTask = listStation.FirstOrDefault(s => s.Text == "TaskNo"); listResult.Add(plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, modTask.TaskNo)); //托盘号 var modPosPalletNo = listStation.FirstOrDefault(s => s.Text == "PalletNo"); listResult.Add(plcConn.SetPlcDBValue(modPosPalletNo.PosType, modDevice.DbNumber, modPosPalletNo.PlcPos, modTask.PalletNo)); //起始工位 var modPosLocatNo = listStation.FirstOrDefault(s => s.Text == "StartLocatNo"); listResult.Add(plcConn.SetPlcDBValue(modPosLocatNo.PosType, modDevice.DbNumber, modPosLocatNo.PlcPos, num)); // 目标工位 var modPosEndLocatNo = listStation.FirstOrDefault(s => s.Text == "EndLocatNo"); listResult.Add(plcConn.SetPlcDBValue(modPosEndLocatNo.PosType, modDevice.DbNumber, modPosEndLocatNo.PlcPos, outCode)); //全部写入成功 if (listResult.All(s => s.IsSucceed)) { // 写入工位wcs控制字 var res = plcConn.SetPlcDBValue(modDevice2.PosType, modDevice2.DbNumber, modDevice2.WcsPos, "120"); if (!res.IsSucceed) break; //写入plc任务号 var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo"); res = plcConn.SetPlcDBValue(modStation.PosType, modDevice.DbNumber, modStation.PlcPos, modTask.TaskNo); if (!res.IsSucceed) break; //写入跺机wcs控制字流程30 返回垛机执行完成 res = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "30"); if (!res.IsSucceed) break; //记录任务明细 var modTaskMonitor = new WcsTaskMonitor() { TaskNo = modTask.TaskNo, PlcId = modDevice2.PlcId, PlcName = modDevice2.Text, InteractiveMsg = $"写入指令:收到跺机放货完成;放货{num}工位===》{outCode}出库口", PalletNo = modTask.PalletNo, Status = TaskStatusEnum.Complete, StartLocat = num, //起始位置 EndLocat = outCode, //目标工位 }; _db.Insertable(modTaskMonitor).ExecuteCommand(); //下发任务日志 _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt()); //todo:垛机出库不空跑 } } break; case TaskTypeEnum.Move: { //移库任务 var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo"); // 写入plc任务号 var res = plcConn.SetPlcDBValue(modStation.PosType, modDevice.DbNumber, modStation.PlcPos, taskNo); if (!res.IsSucceed) break; //写入plc控制字 res = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "30"); if (!res.IsSucceed) break; modTask.Status = TaskStatusEnum.Complete; _db.Updateable(modTask).UpdateColumns(s => s.Status).ExecuteCommand(); var modTaskRequest = modTask.Adapt(); HttpService httpService = new HttpService(); var modResponseTask = httpService.RequestTask(modTaskRequest).Result; if (modResponseTask.StatusCode == "0") { //请求成功 modTask.IsSuccess = TaskSuccessEnum.Success; _db.Updateable(modTask).UpdateColumns(s => s.IsSuccess).ExecuteCommand(); //todo:修改储位信息 任务类型 执行状态 起始位置 目标位置 // //记录任务明细 var modTaskMonitor = new WcsTaskMonitor() { TaskNo = modTask.TaskNo, PlcId = modDevice.PlcId, PlcName = modDevice.Text, InteractiveMsg = "任务完成,返回给WMS任务完成", StartLocat = modTask.StartLocate, EndLocat = modTask.EndLocate, PalletNo = modTask.PalletNo, Status = TaskStatusEnum.Complete }; _db.Insertable(modTaskMonitor).ExecuteCommand(); //下发任务日志 _taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt()); } else { //请求失败 modTask.IsSuccess = TaskSuccessEnum.Fail; modTask.Information = modResponseTask.Message; _db.Updateable(modTask).UpdateColumns(s => new { s.IsSuccess, s.Information }).ExecuteCommand(); } //todo:LED屏 } break; default: break; } } break; case "100": { //空取货异常 var modPosPlcTask = modDevice.listStation.FirstOrDefault(s => s.Text == "PlcTaskNo"); var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo"); var (result, TaskNo) = plcConn.GetPlcDBValue(modPosPlcTask.PosType, modDevice.DbNumber, modPosPlcTask.PlcPos); if (!result.IsSucceed) break; string taskNo = Convert.ToString(TaskNo); var modTask = _db.Queryable().First(s => s.TaskNo == taskNo && s.Status == TaskStatusEnum.Doing); if (modTask == null) { Log.Error($"【跺机】当前任务号不存在对应的任务,任务号:{modTask.TaskNo}"); break; } var res = plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, taskNo); if (!res.IsSucceed) break; res = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "100"); if (!res.IsSucceed) break; modTask.Status = TaskStatusEnum.Exception; _db.Updateable(modTask).UpdateColumns(s => s.Status).ExecuteCommand(); Log.Information($"【跺机】wcs任务变更空取异常,任务号:{modTask.TaskNo}"); var modTaskRequest = modTask.Adapt(); HttpService httpService = new HttpService(); var modResponseTask = httpService.RequestEmptyException(modTaskRequest).Result; if (modResponseTask.StatusCode == "0") { //请求成功 modTask.IsSuccess = TaskSuccessEnum.Success; _db.Updateable(modTask).UpdateColumns(s => s.IsSuccess).ExecuteCommand(); //下发任务日志 _taskLogHubContext.Clients.All.PublicTask(modTask.Adapt()); } else { //请求失败 modTask.IsSuccess = TaskSuccessEnum.Fail; modTask.Information = modResponseTask.Message; _db.Updateable(modTask).UpdateColumns(s => new { s.IsSuccess, s.Information }).ExecuteCommand(); } //todo:LED屏 } break; case "101": { //满放货异常 var modPosPlcTask = modDevice.listStation.FirstOrDefault(s => s.Text == "PlcTaskNo"); var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo"); var modPosPalletNo = modDevice.listStation.FirstOrDefault(s => s.Text == "PalletNo"); var (result, TaskNo) = plcConn.GetPlcDBValue(modPosPlcTask.PosType, modDevice.DbNumber, modPosPlcTask.PlcPos); if (!result.IsSucceed) break; string taskNo = Convert.ToString(TaskNo); var modTask = _db.Queryable().First(s => s.TaskNo == taskNo && s.Status == TaskStatusEnum.Doing); if (modTask == null) { Log.Error($"【跺机】当前任务号不存在对应的任务,任务号:{modTask.TaskNo}"); break; } modTask.Status = TaskStatusEnum.Exception; _db.Updateable(modTask).UpdateColumns(s => s.Status).ExecuteCommand(); Log.Information($"【跺机】wcs任务变更满取异常,任务号:{modTask.TaskNo}"); var modTaskRequest = modTask.Adapt(); HttpService httpService = new HttpService(); var modResponseTask = httpService.RequestEmptyException(modTaskRequest).Result; if (modResponseTask.StatusCode == "0") { //请求成功 modTask.IsSuccess = TaskSuccessEnum.Success; _db.Updateable(modTask).UpdateColumns(s => s.IsSuccess).ExecuteCommand(); var modInsertTask = modResponseTask.TaskList; modInsertTask.TaskType = TaskTypeEnum.In; modInsertTask.Origin = "WMS"; modInsertTask.StartLocate = modTask.StartLocate; modInsertTask.Levels = 1; _db.Insertable(modInsertTask); //下发任务日志 _taskLogHubContext.Clients.All.PublicTask(modInsertTask.Adapt()); } else { //请求失败 modTask.IsSuccess = TaskSuccessEnum.Fail; modTask.Information = modResponseTask.Message; _db.Updateable(modTask).UpdateColumns(s => new { s.IsSuccess, s.Information }).ExecuteCommand(); } //todo:LED屏 } break; default: break; } } /// /// 输送线业务处理 /// /// private static void ConveyorLine(WcsDeviceDto modDevice) { } /// /// AGV业务处理 /// /// private static void AGV(WcsDeviceDto modDevice) { } /// /// 叠托机业务处理 /// /// private static void PalletMachine(WcsDeviceDto modDevice) { } private static void Test(WcsDeviceDto modDevice) { //写死测试读string var (res, val) = modDevice.PLCUtil.GetPlcDBValue(PLCDataTypeEnum.String, "DB100", "64"); Console.WriteLine("DB100.64----" + val); //测试批量读取 Dictionary listaddress = new Dictionary(); foreach (var modStation in modDevice.listStation) { listaddress.Add(modStation.PlcPos, modStation.PosType); } var result = modDevice.PLCUtil.GetPlcBatchDBValue(listaddress); if (result.Value.Count > 0) { foreach (var value in result.Value) { Console.WriteLine("地址" + value.Key + "----值" + value, value); } } if (!result.IsSucceed) { foreach (var err in result.ErrList) { Console.WriteLine(err); } if (result.Value.Count > 0)//有错误的也有成功的 { } } if (modDevice.Value == 820) { //测试写入830 //var result = mod.PLCUtil.SetPlcDBValue(mod.PosType.Value, mod.DbNumber, mod.PlcPos, "830"); ////写入是否成功 //if (result.IsSucceed) //{ //} } else if (modDevice.Value == 840) { } else if (modDevice.Value == 860) { } } }