using Infrastructure.Attribute; using Infrastructure.Extensions; using Infrastructure.Model; using MDM.Model.Plant; using MDM.Model.Process; using Microsoft.AspNetCore.JsonPatch.Operations; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NLog; using RIZO.Model.Mes; using RIZO.Model.MES.product_trace; using RIZO.Repository; using RIZO.Service.MES.product.IService; using RIZO.Service.PLC; using S7.Net; using SqlSugar.IOC; using System; using System.Threading; using System.Threading.Tasks; namespace RIZO.Service.PLCBackground.Stations.Into { /// /// OP点散热胶GF1500 /// //[AppService(ServiceType = typeof(PlcIntoStationService_Common), ServiceLifetime = LifeTime.Singleton)] public class PlcIntoStationService_Common : BackgroundService { protected static Logger _logger = LogManager.GetCurrentClassLogger(); protected PlcConntectHepler _plcService; protected readonly TimeSpan _pollingInterval = TimeSpan.FromSeconds(5); // private readonly string _ipAddress = "192.168.10.222"; // private readonly CpuType _cpuType = CpuType.S71500; protected string WorkstationCode; protected readonly SqlSugarClient Context; protected readonly OptionsSetting _optionsSetting; protected PlcSettings plcSetting; public PlcIntoStationService_Common(IOptions options) { Context = DbScoped.SugarScope.CopyNew(); _optionsSetting= options.Value; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.Info("PLC Polling Service started"); // 使用工厂方法创建服务实例 Enum.TryParse(plcSetting.PlcType, out CpuType cpuType); // 获取当前的工序/工站 //WorkstationCode = await Context.Queryable().Where(it => it.PlcIP == plcSetting.IpAddress) // .Select(it => it.WorkstationCode).FirstAsync(); plcSetting = _optionsSetting.PlcSettings.Where(it => it.WorkStationCode == WorkstationCode).First(); using (_plcService = new PlcConntectHepler(plcSetting.IpAddress, cpuType)) { while (!stoppingToken.IsCancellationRequested) { try { //心跳检测 "DB1010.DBW0" await _plcService.WriteAsync(plcSetting.intoStation.Heartbeat, 1); // 轮询进站请求信号/工位开始查询请求 "DB1001.DBW2000" int intoStationAsk = await _plcService.ReadAsync(plcSetting.intoStation.IntoStationAsk); if (intoStationAsk == 1) { // 处理进站请求 _logger.Info("Processing into station request..."); //获取产品SN码 "DB1001.DBB1000" string productModel = await _plcService.ReadStringAsync(plcSetting.intoStation.ProductModel); //"DB1001.DBB1054" string productSN = await _plcService.ReadStringAsync(plcSetting.intoStation.ProductSN); // 获取工单 //获取工艺路线工序 List processOperations = await Context.Queryable().LeftJoin((r, o) => r.RoutingCode == o.FkRoutingCode) .Where((r, o) => r.FkProductMaterialCode == productModel && r.Status == 1) .Select((r, o) => o).ToListAsync(); //判断改产品是正常件还是返工件 //插入入站请求ASK过站记录 ProductPassStationRecord ASKintoStation = new ProductPassStationRecord { ProductSN = productSN, WorkstationCode = WorkstationCode, Routingcode = processOperations.First().FkRoutingCode, OperationCode = WorkstationCode, OperationName= plcSetting.WorkStationName, ProductionLifeStage = 1, // 1表示生产中 PasstationType = 0, // 0表示入站请求 PasstationDescription = "入站请求ASK", EffectTime = DateTime.Now, CreatedTime = DateTime.Now, }; await Context.Insertable(ASKintoStation).ExecuteCommandAsync(); //判断该产品是否允许进站 EntryPermissionResult result = await checkEntryPermission(productModel, productSN, WorkstationCode, processOperations); // "DB1010.DBW2000" await _plcService.WriteAsync(plcSetting.intoStation.IntoStationResp, (int)result); } await Task.Delay(_pollingInterval, stoppingToken); } catch (OperationCanceledException) { _logger.Info("PLC Polling Service is stopping"); break; } catch (Exception ex) { _logger.Error(ex, "PLC polling error"); await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken); } } } _logger.Info("PLC Polling Service stopped"); } /// /// 校验是否可以进站 /// /// 产品型号 /// 产品SN /// protected async Task checkEntryPermission(string productModel, string productSN, string workstationCode, List processOperations) { EntryPermissionResult result = EntryPermissionResult.UnkownException; //2上工位无记录 //ProcessOperation LastOperation = processOperations.Where(operation => operation.OperationSeq < processOperations.Where(it => it.OperationCode == workstationCode).Select(it => it.OperationSeq).First()).OrderByDescending(operation => operation.OperationSeq).First(); int LastOperationSeq = processOperations.Where(operation => operation.OperationCode == workstationCode).Select(operation => operation.LastOperationSeq ?? -1).First(); ProcessOperation LastOperation = processOperations.Where(it => it.OperationSeq == LastOperationSeq).First(); bool isExistLastOperationRecord = await DbScoped.SugarScope.CopyNew().Queryable() .Where(it => it.ProductSN == productSN) .Where(it => it.OperationCode == LastOperation.OperationCode) .AnyAsync(); if (!isExistLastOperationRecord) { return EntryPermissionResult.NoRecordAtPreviousStation; } // 3 上工位NG 入站或者出站结果 NG bool isExistLastOperationNG = await Context.Queryable() .Where(it => it.ProductSN == productSN) .Where(it => it.OperationCode == LastOperation.OperationCode) .Where(it => it.PasstationType == 2 || it.PasstationType == 4) .Where(it => it.ResultCode != 1) .AnyAsync(); if (!isExistLastOperationNG) { result = EntryPermissionResult.PreviousStationNG; goto InsertPassrecord; } // 4 扫码产品型号错误 bool isExistproductSN = await Context.Queryable() .Where(it => it.ProductSN == productSN).AnyAsync(); bool isExistproductSNProducting = await Context.Queryable() .Where(it => it.ProductSN == productSN && (it.ProductCurrentStatus != 1 && it.ProductCurrentStatus != 3)).AnyAsync(); if (!isExistproductSN || !isExistproductSNProducting) { result = EntryPermissionResult.ProductModelError; goto InsertPassrecord; } //6时间超出规定无法生产 //7固化时间未到规定时间 int LastOperationStandardTime = processOperations.Where(operation => operation.OperationCode == LastOperation.OperationCode) .Select(operation => operation.StandardTime??0).First(); if (LastOperationStandardTime > 0) { // 上一站的入站时间 和本站的请求时间差值 DateTime LastInStationTime= await Context.Queryable() .Where(it => it.ProductSN == productSN) .Where(it => it.OperationCode == LastOperation.OperationCode) .Where(it => it.PasstationType == 1) .MaxAsync(it => it.InStationTime??DateTime.MinValue); TimeSpan timeDiff = DateTime.Now - LastInStationTime; double totalSeconds = timeDiff.TotalSeconds; if(totalSeconds < LastOperationStandardTime) { result = EntryPermissionResult.CuringTimeNotReached; goto InsertPassrecord; } } //12 最大重复入站次数 int MaxRepeatEntries = processOperations.Where(operation => operation.OperationCode == workstationCode).Select(operation => operation.MaxStationCount??1).First(); if(MaxRepeatEntries>1) { int currentStationEntryCount = await Context.Queryable() .Where(it => it.ProductSN == productSN) .Where(it => it.OperationCode == workstationCode) .Where(it => it.PasstationType == 1) .CountAsync(); if(currentStationEntryCount >= MaxRepeatEntries) { result = EntryPermissionResult.MaximumRepeatedEntries; goto InsertPassrecord; } } //OK 准许进站 result = EntryPermissionResult.AllowIntoStation; goto InsertPassrecord; InsertPassrecord: //插入入站请求Resp过站记录 ProductPassStationRecord RespintoStation = new ProductPassStationRecord { ProductSN = productSN, WorkstationCode = WorkstationCode, Routingcode = processOperations.First().FkRoutingCode, OperationCode = WorkstationCode, OperationName = plcSetting.WorkStationName, ProductionLifeStage = 1, // 1表示生产中 PasstationType = 1, // 入站完毕 PasstationDescription = "入站完毕Resp", EffectTime = DateTime.Now, InStationTime = DateTime.Now, ResultCode = (int)result, ResultDescription = result.ToString(), CreatedTime = DateTime.Now, }; await Context.Insertable(RespintoStation).ExecuteCommandAsync(); return result; } } }