using Masuit.Tools; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Newtonsoft.Json; using SlnMesnac.Config; using SlnMesnac.Extensions; using SlnMesnac.Model.domain; using SlnMesnac.Model.dto.taskType; using SlnMesnac.Model.dto.webapi; using SlnMesnac.Plc; using SlnMesnac.Rfid; using SlnMesnac.Serilog; using SlnMesnac.WCS.Global; using SlnMesnac.WCS.Library; using SlnMesnac.WCS.WCS; using SqlSugar; using System.Timers; namespace SlnMesnac.WCS { public class MainCentralControl { private IHost host; //删除日志定时器 private System.Timers.Timer deleteLogTimer; //plc心跳交互定时器 private System.Timers.Timer plcHeartTimer; // 新增一个标志位,用于表示方法是否正在执行 private bool isExecuting = false; private readonly SerilogHelper _logger; private IServiceProvider serviceProvider; private ISqlSugarClient SqlSugarClient; #region 变量定义 public List plcList; //容器里面的读写器集合 public List rfidList; #endregion 变量定义 /// /// 构造函数 /// /// public MainCentralControl(IHost _host) { host = _host; SqlSugarClient = host.Services.GetRequiredService(); _logger = host.Services.GetRequiredService(); plcList = host.Services.GetRequiredService>(); rfidList = host.Services.GetRequiredService>(); InitCacheData(); } /// /// 加载缓存数据 /// private void InitCacheData() { //加载plc地址信息 StaticData.BaseConfigList = SqlSugarClient.Queryable().ToList(); StaticData.WmsMachineInfos = SqlSugarClient.Queryable().ToList(); StaticData.WcsAgvCodeMaps = SqlSugarClient.Queryable().ToList(); #region 定时删除日志 //DeleteLogsLogic(); //deleteLogTimer = new System.Timers.Timer(24 * 60 * 60 * 1000); //deleteLogTimer.Elapsed += OnTimedEvent; //deleteLogTimer.AutoReset = true; //deleteLogTimer.Enabled = true; #endregion 定时删除日志 #region 定时写入心跳 plcHeartTimer = new System.Timers.Timer(1000); plcHeartTimer.Elapsed += OnTimedPlcHeartEvent; plcHeartTimer.AutoReset = true; plcHeartTimer.Enabled = true; #endregion 定时写入心跳 } /// /// 启动程序 /// public void Start() { StartCheckStatus(); DeleteTaskLogic(); //根据条件创建任务 CreateTaskByRecord createTaskByRecord = new CreateTaskByRecord(host.Services); createTaskByRecord.StartPoint(); _logger.Agv("WCS调度程序启动成功!"); //背负式agv执行任务 BearAgv bearAgv = new BearAgv(host.Services); bearAgv.StartPoint(); } #region /// /// 检查设备状态自动重连 /// private void StartCheckStatus() { //数据库里面的读写器集合,仅用来更新状态 List rfidDbList = SqlSugarClient.Queryable().ToList(); List agvEquipList = SqlSugarClient.Queryable().Where(it => it.EquipType == 1).ToList(); Task.Run(async () => { while (true) { try { #region PLC状态 foreach (var plc in plcList) { PlcConfig? plcConfig = host.Services.GetService().plcConfig.FirstOrDefault(x => x.plcKey == plc.ConfigKey); if (plc != null && plc.IsConnected) { plc.IsConnected = plc.readHeartByAddress("M100"); //DB100.DBX0.0 if (!plc.IsConnected) { plc.IsConnected = await plc.ConnectAsync(plcConfig.plcIp, plcConfig.plcPort); } } else { if (plcConfig != null) { bool result = await plc.ConnectAsync(plcConfig.plcIp, plcConfig.plcPort); plc.IsConnected = result; } } } #endregion PLC状态 #region RFID状态 foreach (var rfid in rfidList) { if (rfid.ConfigKey == "2#Transplant") { } bool status = rfid.GetOnlineStatus(); if (!status) { status = await rfid.ConnectAsync(rfid.ip, rfid.port); } //状态同步数据库 BaseRfidInfo? rfidDb = rfidDbList.FirstOrDefault(x => x.EquipIp == rfid.ip); if (rfidDb != null) { rfidDb.IsOnline = status ? 1 : 0; } } SqlSugarClient.Updateable(rfidDbList).ExecuteCommand(); #endregion RFID状态 //实时获取agv状态 暂不开启,生产时打开 MessageSynchronousLogic(agvEquipList); ListeningTonerLocation(); } catch (Exception ex) { _logger.Error($"监听设备状态异常:{ex.Message}"); } await Task.Delay(1000 * 10); } }); } #endregion /// /// 监听色粉库位是否色粉未从料想取出,有的话通知plc声光报警 /// private void ListeningTonerLocation() { try { PlcAbsractFactory? workShop3Plc = plcList.FirstOrDefault(x => x.ConfigKey == "workShop3Plc"); // 构建查询并执行 Any 方法 bool hasRecords = SqlSugarClient.Queryable() .InnerJoin((wbe, wpi) => wbe.ContainerCode == wpi.PalletInfoCode && !string.IsNullOrEmpty(wbe.ContainerCode) && wpi.TonerFlag == 1 && wbe.EquipType == 7).Any(); if (workShop3Plc != null && workShop3Plc.IsConnected) { if (hasRecords) { workShop3Plc.writeBoolByAddress(StaticData.GetPlcAddress("3#异常色粉未处理提示"), true); } else { workShop3Plc.writeBoolByAddress(StaticData.GetPlcAddress("3#异常色粉未处理提示"), false); } } } catch (Exception ex) { _logger.Error($"监听色粉库位异常:{ex.Message}"); } } /// /// agv状态实时刷新 /// private void MessageSynchronousLogic(List agvEquipList) { try { List agvList = SqlSugarClient.Queryable().ToList(); var data = new { reqCode = StaticData.SnowId.NextId(), mapCode = "AA", }; string result = HttpHelper.SendPostMessage(agvEquipList.First().ServerIp, agvEquipList.First().ServerPort, "rcms-dps/rest/queryAgvStatus", data.ToJsonString()); var reponse = JsonConvert.DeserializeObject(result); if (reponse != null && reponse.code == "0") { foreach (var agv in agvList) { CardStatus? agvCard = reponse.data.FirstOrDefault(x => x.robotCode == agv.RobotCode); if (agvCard != null) { agv.Battery = agvCard.battery; agv.ExclType = agvCard.exclType; agv.Online = agvCard.online; agv.PosX = agvCard.posX; agv.PosY = agvCard.posY; agv.RobotDir = agvCard.robotDir; agv.Speed = agvCard.speed; agv.Status = agvCard.status; WcsAgvCodeMap? wcsAgvCodeMap = StaticData.WcsAgvCodeMaps.FirstOrDefault(x => x.AgvCode == long.Parse(agv.Status)); if (wcsAgvCodeMap != null) { agv.StatusDetail = wcsAgvCodeMap.agv_display_content; } agv.Stop = agvCard.stop; agv.Timestamp = DateTime.Now; } } SqlSugarClient.Updateable(agvList).ExecuteCommand(); } } catch (Exception ex) { _logger.Error($"同步agv状态信息异常:{ex.Message},{ex.StackTrace.ToJsonString()}"); } } #region 删除任务 -- 已经下发的任务,需要通知agv取消 /// /// 定时监测是否有待删除任务,完成删除 /// private void DeleteTaskLogic() { Task.Run(() => { List agvEquipList = SqlSugarClient.Queryable().Where(it => it.EquipType == 1).ToList(); while (true) { try { List wcsTasks = SqlSugarClient.Queryable().Where(t => t.IsDelete == 1 || t.IsDelete == 2).ToList(); foreach (var item in wcsTasks) { WcsBaseEquip agvEquip = agvEquipList.First(); if (!string.IsNullOrEmpty(item.TaskCode)) { var cancelTask = new { reqCode = StaticData.SnowId.NextId().ToString(), taskCode = item.TaskCode }; string reponse = HttpHelper.SendPostMessage(agvEquip.ServerIp, agvEquip.ServerPort, "rcms/services/rest/hikRpcService/cancelTask", cancelTask.ToJsonString()); var result = JsonConvert.DeserializeObject(reponse); if (result != null && result.code == "0") { #region 解锁起点库位与终点库位 //根据任务类型,如果是大料箱,解锁wmsbaseLocation List bigType = new List() { 1, 3, 8, 10 }; if (bigType.Contains(item.TaskType)) { List? wmsBaseLocations = SqlSugarClient.Queryable().Where(x => x.LocationCode == item.CurrPointNo || x.LocationCode == item.EndPointNo).ToList(); if (wmsBaseLocations != null && wmsBaseLocations.Count > 0) { wmsBaseLocations.ForEach(x => x.LocationStatus = 0); SqlSugarClient.Updateable(wmsBaseLocations).ExecuteCommand(); } } else //如果是小料箱,解锁wcsbaseEquip { List equips = SqlSugarClient.Queryable().Where(x => x.AgvPositionCode == item.CurrPointNo || x.AgvPositionCode == item.EndPointNo).ToList(); if (equips != null && equips.Count > 0) { equips.ForEach(x => x.EquipStatus = 0); SqlSugarClient.Updateable(equips).ExecuteCommand(); } } #endregion SqlSugarClient.Deleteable(item).ExecuteCommand(); _logger.Agv($"任务id:{item.Id},任务名:{item.TaskName}已删除"); // if (!string.IsNullOrEmpty(item.NextPointNo) && item.TaskStatus >= 2 && item.IsDelete == 2) //有执行任务的agv编号,并且需要去异常库位 { WmsBaseLocation? endLocation = SqlSugarClient.Queryable().First(x => x.LocationCode == "3066" && x.LocationStatus == 0 && string.IsNullOrEmpty(x.ContainerCode)); if (endLocation != null) { WcsTask task = new WcsTask(); task.TaskType = StaticTaskType.ExceptionTask; task.CurrPointNo = "ExceptionStart"; task.NextPointNo = item.NextPointNo; //指定agv task.EndPointNo = endLocation.AgvPositionCode; task.TaskStatus = 0; task.CreatedTime = DateTime.Now; task.CreatedBy = "wcs"; task.TaskName = "前往异常库位移库任务"; task.PalletInfoCode = item.PalletInfoCode; SqlSugarClient.AsTenant().BeginTran(); try { int id = SqlSugarClient.Insertable(task).ExecuteReturnIdentity(); WcsTaskLog wcsTaskLog = CoreMapper.Map(task); wcsTaskLog.Id = id; //锁定库位 endLocation.LocationStatus = 1; SqlSugarClient.Updateable(endLocation).ExecuteCommand(); SqlSugarClient.Insertable(wcsTaskLog).ExecuteCommand(); SqlSugarClient.AsTenant().CommitTran(); _logger.Agv($"生成{task.TaskName},起点:{task.CurrPointNo},终点:{task.EndPointNo}"); } catch (Exception ex) { _logger.Error($"生成移库任务提交事务异常:{ex.Message}"); SqlSugarClient.AsTenant().RollbackTran(); } } else { _logger.Error("想要创建异常库位任务,但是异常库位不可用或已经有托盘"); } } } else { _logger.Error($"任务id:{item.Id},任务名:{item.TaskName}删除失败,agv接口回复:{result.message}"); } } else { SqlSugarClient.Deleteable(item).ExecuteCommand(); _logger.Agv($"任务id:{item.Id},任务名:{item.TaskName}已删除"); } } } catch (Exception ex) { _logger.Error($"任务删除异常:{ex.Message}"); } Thread.Sleep(2000); } }); } #endregion 删除任务 -- 已经下发的任务,需要通知agv #region 定时删除日志处理 /// /// 定时器触发的事件处理方法 /// /// /// private void OnTimedEvent(Object source, ElapsedEventArgs e) { DeleteLogsLogic(); } /// /// 清除日志文件 /// private void DeleteLogsLogic() { try { // 获取当前程序运行目录下的 Log 文件夹 string logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); // 检查 Log 文件夹是否存在 if (!Directory.Exists(logPath)) { // 如果 Log 文件夹不存在,可以选择记录日志或者直接返回 Console.WriteLine($"Log 文件夹 {logPath} 不存在。"); return; } // 获取 Log 文件夹下的所有子文件夹 string[] logDirectories = Directory.GetDirectories(logPath); foreach (string directoryPath in logDirectories) { string directoryName = Path.GetFileName(directoryPath); if (!string.IsNullOrEmpty(directoryName) && DateTime.TryParse(directoryName, out DateTime directoryDate)) { // 检查文件夹日期是否早于当前日期三天之前 if (directoryDate < DateTime.Now.AddDays(-3)) { try { // 删除符合条件的文件夹 Directory.Delete(directoryPath, true); Console.WriteLine($"已删除文件夹: {directoryPath}"); } catch (Exception ex) { // 记录删除文件夹时的异常信息 Console.WriteLine($"删除文件夹 {directoryPath} 时出错: {ex.Message}"); } } } } } catch (Exception ex) { // 记录整体操作的异常信息 Console.WriteLine($"执行删除日志逻辑时出错: {ex.Message}"); } } #endregion #region 定时plc发送心跳脉冲 private bool heartFlag = true; /// /// 定时器触发的事件处理方法 /// /// /// private void OnTimedPlcHeartEvent(Object source, ElapsedEventArgs e) { // 检查方法是否正在执行 if (isExecuting) { return; } try { // 设置标志位为 true,表示方法正在执行 isExecuting = true; PlcAbsractFactory? plc3 = plcList.FirstOrDefault(x => x.ConfigKey == "workShop3Plc"); PlcAbsractFactory? plc2 = plcList.FirstOrDefault(x => x.ConfigKey == "workShop2Plc"); if (plc3 != null && plc3.IsConnected) { plc3.writeBoolByAddress("DB100.DBX84.0", heartFlag); heartFlag = !heartFlag; } if (plc2 != null && plc2.IsConnected) { plc2.writeBoolByAddress("DB100.DBX24.0", heartFlag); heartFlag = !heartFlag; } } finally { isExecuting = false; } } #endregion } }