using Autofac.Core; using HslCommunication; using Microsoft.AspNetCore.Components.Routing; using Microsoft.AspNetCore.Hosting; using Newtonsoft.Json; using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; using Quartz; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Eventing.Reader; using System.DirectoryServices.Protocols; using System.IO.Ports; using System.Linq; using System.Net; using System.Reflection.Metadata; using System.Security.Cryptography.Xml; using System.Text; using System.Threading.Tasks; using System.Transactions; using WIDESEA_Comm.Http; using WIDESEA_Common.Log; using WIDESEAWCS_Common.TaskEnum; using WIDESEAWCS_Core; using WIDESEAWCS_Core.Enums; using WIDESEAWCS_DTO.TaskInfo; using WIDESEAWCS_ISystemServices; using WIDESEAWCS_ITaskInfoRepository; using WIDESEAWCS_ITaskInfoService; using WIDESEAWCS_Model.Models; using WIDESEAWCS_Model.Models.System; using WIDESEAWCS_QuartzJob; using WIDESEAWCS_QuartzJob.DeviceBase; using WIDESEAWCS_QuartzJob.DTO; using WIDESEAWCS_QuartzJob.Models; using WIDESEAWCS_QuartzJob.Service; using WIDESEAWCS_QuartzJob.StackerCrane.Enum; using WIDESEAWCS_TaskInfoService; using WIDESEAWCS_Tasks.StackerCraneJob; using static WIDESEAWCS_Model.Models.System.JobError; namespace WIDESEAWCS_Tasks { [DisallowConcurrentExecution] public class CommonStackerCraneJob : IJob { private readonly ITaskService _taskService; private readonly ITaskExecuteDetailService _taskExecuteDetailService; private readonly ITaskRepository _taskRepository; private readonly IRouterService _routerService; private readonly IDt_PlatformStationService _DtPlatformStationService; public CommonStackerCraneJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, ITaskRepository taskRepository, IRouterService routerService, IDt_PlatformStationService dt_PlatformStationService) { _taskService = taskService; _taskExecuteDetailService = taskExecuteDetailService; _taskRepository = taskRepository; _routerService = routerService; _DtPlatformStationService = dt_PlatformStationService; } private static readonly Dictionary _deviceLastStatus = new Dictionary(); public string urlWMSdeverror = WIDESEAWCS_Core.Helper.AppSettings.Configuration["urlWMSdeverror"]; private static readonly Dictionary _stackerFaultMap = new Dictionary { { "DB107.26.0", "载货台货物超宽" },{ "DB107.26.1", "载货台货物超长" },{ "DB107.26.2", "载货台货物超高" }, { "DB107.26.3", "载货台货物检测传感器异常" },{ "DB107.26.4", "货叉编码器值错误" },{ "DB107.26.5", "货叉动作超时" }, { "DB107.26.6", "货叉编码器值与中位信号不一致" },{ "DB107.26.7", "无效的任务类型" },{ "DB107.27.0", "无效的作业地址" }, { "DB107.27.1", "重入库" },{ "DB107.27.2", "空出库" },{ "DB107.27.3", "货物高度与货位不匹配" }, { "DB107.27.4", "取货通道堵塞" },{ "DB107.27.5", "放货通道堵塞" },{ "DB107.27.6", "放货完成后载货台仍然有货" }, { "DB107.27.7", "任务未完成超时报警" },{ "DB107.28.0", "就地柜急停触发" },{ "DB107.28.1", "机载柜急停触发" }, { "DB107.28.2", "远程急停触发" },{ "DB107.28.3", "安全门被打开" },{ "DB107.28.4", "安全继电器断开" }, { "DB107.28.5", "松绳检测" },{ "DB107.28.6", "超速保护" },{ "DB107.28.7", "行走变频器故障" }, { "DB107.29.0", "升降变频器故障" },{ "DB107.29.1", "货叉1变频器故障" },{ "DB107.29.2", "货叉2变频器故障" }, { "DB107.29.3", "升降行走定位超时" },{ "DB107.29.4", "货叉1编码器值与中位信号不一致" },{ "DB107.29.5", "货叉2编码器值与中位信号不一致" }, { "DB107.29.6", "行走激光值错误" },{ "DB107.29.7", "升降激光值错误" },{ "DB107.30.0", "前进极限行程" }, { "DB107.30.1", "后退极限行程" },{ "DB107.30.2", "上升极限行程" },{ "DB107.30.3", "下降极限行程" }, { "DB107.30.4", "货叉1左极限行程" },{ "DB107.30.5", "货叉1右极限行程" },{ "DB107.30.6", "货叉2左极限行程" }, { "DB107.30.7", "货叉2右极限行程" },{ "DB107.31.0", "前进激光极限保护" },{ "DB107.31.1", "后退激光极限保护" }, { "DB107.31.2", "上升激光极限保护" },{ "DB107.31.3", "下降激光极限保护" },{ "DB107.31.4", "货叉1左软极限" }, { "DB107.31.5", "货叉1右软极限" },{ "DB107.31.6", "货叉2左软极限" },{ "DB107.31.7", "货叉2右软极限" }, { "DB107.32.0", "与地面站网络断开" },{ "DB107.32.1", "与输送线网络断开" },{ "DB107.32.2", "与WCS网络断开" }, { "DB107.32.3", "无效命令:堆垛机有货" },{ "DB107.32.4", "无效命令:堆垛机无货" },{ "DB107.32.5", "消防误报" }, { "DB107.32.6", "前进雷达报警" },{ "DB107.32.7", "后退雷达报警" },{ "DB107.33.0", "左防火门超时" }, { "DB107.33.1", "右防火门超时" },{ "DB107.33.2", "替罪羊检测报警" },{ "DB107.33.3", "近叉运行异常" }, { "DB107.33.4", "远叉运行异常" },{ "DB107.33.5", "水平运行异常" },{ "DB107.33.6", "升降运行异常" }, { "DB107.34.0", "升降刹车异常" },{ "DB107.34.1", "行走刹车异常" },{ "DB107.34.2", "近叉刹车异常" }, { "DB107.34.3", "远叉刹车异常" },{ "DB107.34.4", "左侧过载" },{ "DB107.34.5", "右侧过载" } }; public Task Execute(IJobExecutionContext context) { try { CommonStackerCrane commonStackerCrane = (CommonStackerCrane)context.JobDetail.JobDataMap.Get("JobParams"); if (commonStackerCrane != null) { WriteLog.Write_Log("堆垛机当前状态信息", $"{commonStackerCrane.DeviceCode}库堆垛机当前状态", $"堆垛机设备状态地址:【DB105.2.0】,读取的数据:【{commonStackerCrane.StackerCraneAutoStatusDes}】\n" + $"堆垛机工作模式地址:【DB105.3.0】,读取的数据:【{commonStackerCrane.StackerCraneStatusDes}】\n" + $"堆垛机作业状态地址:【DB105.22.0】,读取的数据:【{commonStackerCrane.StackerCraneWorkStatusDes}】\n" + $"堆垛机当前任务执行中地址:【DB105.18.0】,读取的数据:【{commonStackerCrane.CurrentTaskNum}】\n"); // 获取当前状态 bool isFaultNow = commonStackerCrane.StackerCraneStatusDes.Equals("故障"); string deviceCode = commonStackerCrane.DeviceCode; if (!_deviceLastStatus.ContainsKey(deviceCode)) { _deviceLastStatus[deviceCode] = isFaultNow; if (isFaultNow) { SendDevError(commonStackerCrane, "66", "start", ReadStackerFaults(commonStackerCrane)); } } else { bool lastStatus = _deviceLastStatus[deviceCode]; if (!lastStatus && isFaultNow) { SendDevError(commonStackerCrane, "66", "start", ReadStackerFaults(commonStackerCrane)); _deviceLastStatus[deviceCode] = true; } else if (lastStatus && !isFaultNow) { SendDevError(commonStackerCrane, "99", "stop", "堆垛机恢复正常"); _deviceLastStatus[deviceCode] = false; } } UpdateHandShake(commonStackerCrane.CurrentTaskNum, commonStackerCrane.StackerCraneWorkStatusDes); //任务完成StackerCraneWorkStatus if (commonStackerCrane.StackerCraneWorkStatusValue == StackerCraneWorkStatus.WorkCompleted) { //判断当前任务是否是盘点 Dt_Task? currtask = _taskService.CurrtaskInfo(commonStackerCrane.CurrentTaskNum); if(currtask != null) { string PalletCode = ""; //判断任务类型 if (currtask.TaskType== (int)TaskTypeEnum.Inventorybound) { //读取条码,进行配对 DeviceProDTO? deviceProDTO = commonStackerCrane.DeviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == "SCBarcode"); byte[] bytes = commonStackerCrane.Communicator.Read(deviceProDTO.DeviceProAddress, 64); //读取的托盘条码 PalletCode = Encoding.ASCII.GetString(bytes).Replace(" ", ""); } WebResponseContent webResponse = _taskService.StackCraneTaskCompleted(commonStackerCrane.CurrentTaskNum, PalletCode); if (webResponse.Status) { WriteLog.Write_Log("堆垛机任务上报完成信息", "堆垛机任务上报完成信息", $"【{commonStackerCrane.DeviceCode}】库堆垛机上报任务号:【{commonStackerCrane.CurrentTaskNum}】完成信号!"); bool ddjfk = commonStackerCrane.SetValue(StackerCraneDBName.WorkType, 5); } } } if (commonStackerCrane.StackerCraneAutoStatusValue == StackerCraneAutoStatus.Automatic && commonStackerCrane.StackerCraneStatusValue == StackerCraneStatus.Normal) { if (commonStackerCrane.StackerCraneWorkStatusValue == StackerCraneWorkStatus.Standby) { Dt_Task? task = GetTask(commonStackerCrane); if (task != null) { StackerCraneTaskCommand? stackerCraneTaskCommand = ConvertToStackerCraneTaskCommand(task); if (stackerCraneTaskCommand != null) { bool sendFlag = commonStackerCrane.SendCommand(stackerCraneTaskCommand); if (sendFlag) { commonStackerCrane.Communicator.Write("DB105.52", 1); WebResponseContent webResponseContent=_taskService.UpdateTaskStatusToNext(task.TaskNum); } } } } } } } catch (Exception ex) { Console.WriteLine(nameof(CommonStackerCraneJob) + ":" + ex.ToString()); WriteLog.Write_Log("堆垛机报错信息", "堆垛机报错信息", $"堆垛机报错信息:【{ex.ToString()}】"); } return Task.CompletedTask; } /// /// 故障上报(改为await调用,修复异步BUG) /// private async Task SendDevError(CommonStackerCrane crane, string errorcode, string dealType, string errorInfo = "") { CommandResult commandResult = new CommandResult(); try { DeviceErrorRequest deviceErrorRequest = new DeviceErrorRequest { devErrorJsons = new List { new DeviceErrorInfo { devuuid = crane.DeviceCode, id = "", errorcode = errorcode, errorinfo = errorInfo, erroraddress = "DB107", warehouse = crane.DeviceCode == "B" ? "ZR17":(crane.DeviceCode == "G"?"ZR18":"ZR16"), remark = dealType == "start" ? "设备异常" : "设备恢复", devname = $"{crane.DeviceCode}库堆垛机", } }, dealType = dealType, psd = "akjfapjfpadaoif", }; // 同步HTTP改为异步(推荐),保持你原有代码也可以 commandResult = await Task.Run(() => HttpHelper.Post(urlWMSdeverror, deviceErrorRequest, "设备故障回调")); WriteLog.Write_Log("同步给上游设备故障信息", "设备故障信息", $"设备id:【{crane.DeviceCode}】,成功", $"设备回调状态:【{dealType}】,异常信息:【{errorInfo}】\n" + $"调用上游返回结果信息:【{commandResult?.ToJsonString() ?? "返回结果为null"}】"); } catch (Exception ex) { WriteLog.Write_Log("故障上报失败", "错误", ex.ToString()); } } /// /// 获取任务 /// /// 堆垛机对象 /// private Dt_Task? GetTask(CommonStackerCrane commonStackerCrane) { try { //判断当前堆垛机是否有在执行的任务 if (_taskService.CutStackerCraneTask(commonStackerCrane.DeviceCode) != null) return null; List task = _taskService.QueryStackerCraneTask(commonStackerCrane.DeviceCode); if (task.Count > 0) { foreach (Dt_Task taskItem in task) { if (taskItem.TaskType == (int)TaskTypeEnum.Outbound) { if (OutTaskStationIsOccupied(taskItem.NextAddress,taskItem.Roadway)) { return taskItem; } } else if (taskItem.TaskType == (int)TaskTypeEnum.Inbound || taskItem.TaskType == (int)TaskTypeEnum.Inventorybound) { InTaskStationIsOccupied(taskItem.SourceAddress, taskItem.Roadway); return taskItem; } } } return null; } catch (Exception ex) { WriteLog.Write_Log("任务查找", "任务查错误", "错误原因", new { 信息 = ex.Message }); return null; } } /// /// 出库任务判断出库站台是否被占用 /// /// 任务实体 /// 如果未被占用,返回传入的任务信息,否则,返回null private bool OutTaskStationIsOccupied(string NextAddress,string Roadway) { try { CommonConveyorLine? conveyorLine = null; lock (Storage.Devices) { string deviceCode = Roadway == "C" ? "1004" : "1003"; conveyorLine = Storage.Devices.FirstOrDefault(x => x.DeviceCode == deviceCode) as CommonConveyorLine; } if (conveyorLine == null) return false; DeviceProDTO? deviceProDTO = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceChildCode == NextAddress && x.DeviceProParamName == "StationNum"); DeviceProDTO? HandShakeprodto = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceChildCode == NextAddress && x.DeviceProParamName == "HandShake"); if (deviceProDTO == null || HandShakeprodto == null) return false; int StationNum = conveyorLine.Communicator.Read(deviceProDTO.DeviceProAddress); int HandShake = conveyorLine.Communicator.Read(HandShakeprodto.DeviceProAddress); Task.Run(() => WriteLog.Write_Log("出库库口状态信息", "出库库口状态信息", $"库口是【{NextAddress}】,申请状态地址:【{HandShakeprodto.DeviceProAddress}】,读取的数据:【{HandShake}】\n库口是否有货状态地址:【{deviceProDTO.DeviceProAddress}】,读取的数据【{StationNum}】")); if (Roadway == "C") return StationNum == 0 && HandShake == 0; return (StationNum == 1 && HandShake == 0 && Roadway == "B") || (StationNum == 0 && HandShake == 0); } catch (Exception ex) { Task.Run(() => Console.WriteLine("读取站台信息错误:" + ex.Message)); return false; } } /// /// 入库任务库口有货无货状态 /// private void InTaskStationIsOccupied(string SourceAddress, string Roadway) { try { CommonConveyorLine? conveyorLine = null; lock (Storage.Devices) { string deviceCode = Roadway == "C" ? "1004" : "1003"; conveyorLine = Storage.Devices.FirstOrDefault(x => x.DeviceCode == deviceCode) as CommonConveyorLine; } if (conveyorLine == null) return; DeviceProDTO? deviceProDTO = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceChildCode == SourceAddress && x.DeviceProParamName == "StationNum"); DeviceProDTO? HandShakeprodto = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceChildCode == SourceAddress && x.DeviceProParamName == "HandShake"); if (deviceProDTO == null || HandShakeprodto == null) return; int StationNum = conveyorLine.Communicator.Read(deviceProDTO.DeviceProAddress); int HandShake = conveyorLine.Communicator.Read(HandShakeprodto.DeviceProAddress); Task.Run(() => WriteLog.Write_Log("入库库口状态信息", "入库库口状态信息", $"库口是【{SourceAddress}】,申请状态地址:【{HandShakeprodto.DeviceProAddress}】,读取的数据:【{HandShake}】\n库口是否有货状态地址:【{deviceProDTO.DeviceProAddress}】,读取的数据【{StationNum}】")); } catch (Exception ex) { Task.Run(() => Console.WriteLine("读取站台信息错误:" + ex.Message)); } } /// /// 任务实体转换成命令Model /// /// 任务实体 /// /// public StackerCraneTaskCommand? ConvertToStackerCraneTaskCommand([NotNull] Dt_Task task) { StackerCraneTaskCommand stackerCraneTaskCommand = new StackerCraneTaskCommand(); stackerCraneTaskCommand.TaskNum = task.TaskNum; stackerCraneTaskCommand.WorkType = 1; stackerCraneTaskCommand.TrayType = 0; if (task.Roadway == "B" || task.Roadway == "C") { //判断 task.PalletCode 是不是一个有效的 GUID stackerCraneTaskCommand.Barcode = stackerCraneTaskCommand.Barcode = Guid.TryParse(task.PalletCode, out var guid) ? guid.ToString("N")[0..6] : task.PalletCode; } else if (task.Roadway == "G" ) { if (Guid.TryParse(task.PalletCode, out var palletGuid)) { stackerCraneTaskCommand.Barcode = palletGuid.ToString("N")[0..6]; // 标准GUID就是36位,所以直接判断长度即可 stackerCraneTaskCommand.TrayType = (short)(task.PalletCode.Length == 36 ? 1 : 2); } else { stackerCraneTaskCommand.Barcode = task.PalletCode; stackerCraneTaskCommand.TrayType = 2; } } if (task.TaskType == (int)TaskTypeEnum.Inbound)//判断是否是入库任务 { //获取站台编号 Dt_PlatformStation dt_Platform = _DtPlatformStationService.getStatiomInfo(task.SourceAddress); string[] targetCodest = dt_Platform.Station_storey.Split("-"); if (targetCodest.Length == 3) { string StartRow = targetCodest[0].Substring(1); stackerCraneTaskCommand.StartRow = Convert.ToInt16(StartRow); stackerCraneTaskCommand.StartColumn = Convert.ToInt16(targetCodest[1]); stackerCraneTaskCommand.StartLayer = Convert.ToInt16(targetCodest[2]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"入库起点错误,起点:【{task.SourceAddress}】"); return null; } string[] EndCodest = task.NextAddress.Split("-"); if (EndCodest.Length == 3) { string EndRow = EndCodest[0].Substring(1); string SCEndRow = LaneModification(task.Roadway, int.Parse(EndRow)); stackerCraneTaskCommand.EndRow = Convert.ToInt16(SCEndRow); stackerCraneTaskCommand.EndColumn = Convert.ToInt16(EndCodest[1]); stackerCraneTaskCommand.EndLayer = Convert.ToInt16(EndCodest[2]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"入库任务终点错误,起点:【{task.NextAddress}】"); return null; } } else if (task.TaskType == (int)TaskTypeEnum.Outbound) { string[] sourceCodes = task.CurrentAddress.Split("-"); if (sourceCodes.Length == 3) { string StartRow = sourceCodes[0].Substring(1); string SCStartRow = LaneModification(task.Roadway, int.Parse(StartRow)); stackerCraneTaskCommand.StartRow = Convert.ToInt16(SCStartRow); stackerCraneTaskCommand.StartColumn = Convert.ToInt16(sourceCodes[1]); stackerCraneTaskCommand.StartLayer = Convert.ToInt16(sourceCodes[2]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"出库任务起点错误,起点:【{task.CurrentAddress}】"); return null; } //获取站台编号 Dt_PlatformStation dt_Platform = _DtPlatformStationService.getStatiomInfo(task.NextAddress); string[] EndCodest = dt_Platform.Station_storey.Split("-"); if (EndCodest.Length == 3) { string EndRow = EndCodest[0].Substring(1); stackerCraneTaskCommand.EndRow = Convert.ToInt16(EndRow); stackerCraneTaskCommand.EndColumn = Convert.ToInt16(EndCodest[1]); stackerCraneTaskCommand.EndLayer = Convert.ToInt16(EndCodest[2]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"出库任务终点错误,起点:【{task.TargetAddress}】"); return null; } } else if (task.TaskType == (int)TaskTypeEnum.Inventorybound) { stackerCraneTaskCommand.WorkType = 6; stackerCraneTaskCommand.StartRow = Convert.ToInt16(0); stackerCraneTaskCommand.StartColumn = Convert.ToInt16(0); stackerCraneTaskCommand.StartLayer = Convert.ToInt16(0); string[] EndCodest = task.NextAddress.Split("-"); if (EndCodest.Length == 3) { string EndRow = EndCodest[0].Substring(1); string SCEnRow = LaneModification(task.Roadway, int.Parse(EndRow)); stackerCraneTaskCommand.EndRow = Convert.ToInt16(SCEnRow); stackerCraneTaskCommand.EndColumn = (short)(Convert.ToInt16(EndCodest[1]) + 1); stackerCraneTaskCommand.EndLayer = Convert.ToInt16(EndCodest[2]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"盘点任务起点错误,起点:【{task.CurrentAddress}】"); return null; } } return stackerCraneTaskCommand; } public string LaneModification(string Roadway,int SCRow) { if (Roadway == "G") { return SCRow == 1 ? "3" : "4"; }else if(Roadway == "C") { return SCRow == 1 ? "5" : "6"; } else { return SCRow.ToString(); } } /// /// 监测G库、C库出库放货时屏蔽光栅 /// /// /// public void UpdateHandShake(int taskNum, string stackerCraneWorkStatusDes) { try { var dtTask = _taskRepository.QueryFirst(x => x.TaskNum == taskNum); if (dtTask == null) return; string[] targets = { "G02", "G03", "G04", "C02", "C01" }; if (dtTask.TaskType != 100 || !targets.Contains(dtTask.TargetAddress)) return; short writeValue = stackerCraneWorkStatusDes switch { "放货中" => 1, "任务完成" => 0, _ => -1 }; if (writeValue == -1) return; CommonConveyorLine? conveyorLine = null; lock (Storage.Devices) { string deviceCode = dtTask.CurrentAddress.StartsWith("C") ? "1004" : "1003"; conveyorLine = Storage.Devices.FirstOrDefault(x => x.DeviceCode == deviceCode) as CommonConveyorLine; } if (conveyorLine == null) return; var handShake = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceChildCode == dtTask.TargetAddress && x.DeviceProParamName == "HandShake"); if (handShake == null) return; conveyorLine.Communicator.Write(handShake.DeviceProAddress, writeValue); } catch { } } /// /// 读取故障(优化GC) /// public string ReadStackerFaults(CommonStackerCrane crane) { string activeFaults = ""; try { foreach (var fault in _stackerFaultMap) { try { bool isFault = crane.Communicator.Read(fault.Key); if (isFault) { activeFaults = fault.Value; break; } } catch { } } } catch (Exception ex) { WriteLog.Write_Log("DB107故障读取异常", "错误", ex.ToString()); } return activeFaults; } } }