using MDM.Model.Plant; using MDM.Model.Process; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NLog; using RIZO.Model.Mes; using RIZO.Model.MES.product_trace; using RIZO.Repository; using RIZO.Service.PLC; using S7.Net; using SqlSugar.IOC; using System; using System.Threading; using System.Threading.Tasks; namespace RIZO.Service.PLCBackground.Stations { public class PlcIntoStationService_OP07_01 : BackgroundService { private static Logger _logger = LogManager.GetCurrentClassLogger(); private PlcConntectHepler _plcService; private readonly TimeSpan _pollingInterval = TimeSpan.FromSeconds(5); private readonly string _ipAddress = "192.168.10.222"; private readonly CpuType _cpuType = CpuType.S71500; private string WorkstationCode; private readonly SqlSugarClient Context; public PlcIntoStationService_OP07_01() { Context = DbScoped.SugarScope.CopyNew(); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.Info("PLC Polling Service started"); // 使用工厂方法创建服务实例 using (_plcService = new PlcConntectHepler(_ipAddress, _cpuType)) { // 获取当前的工序/工站 WorkstationCode = await Context.Queryable().Where(it => it.PlcIP == _ipAddress) .Select(it => it.WorkstationCode).FirstAsync(); while (!stoppingToken.IsCancellationRequested) { try { //心跳检测 await _plcService.WriteAsync("DB1010.DBW0", 1); // 轮询进站请求信号/工位开始查询请求 int intoStationAsk = await _plcService.ReadAsync("DB1001.DBW2000"); if (intoStationAsk == 1) { // 处理进站请求 _logger.Info("Processing into station request..."); //获取产品SN码 string productModel = await _plcService.ReadStringAsync("DB1001.DBB1000"); string productSN = await _plcService.ReadStringAsync("DB1001.DBB1054"); // 获取工单 //获取工艺路线工序 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, 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); await _plcService.WriteAsync("DB1010.DBW2000", (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 /// private 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时间超出规定无法生产 //OK 准许进站 result = EntryPermissionResult.AllowIntoStation; goto InsertPassrecord; InsertPassrecord: //插入入站请求Resp过站记录 ProductPassStationRecord RespintoStation = new ProductPassStationRecord { ProductSN = productSN, WorkstationCode = WorkstationCode, Routingcode = processOperations.First().FkRoutingCode, OperationCode = WorkstationCode, 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; } } /// /// 入站校验结果 /// enum EntryPermissionResult { //1之前工位数据正常 AllowIntoStation = 1, // 2上工位无记录 NoRecordAtPreviousStation = 2, // 3上工位NG PreviousStationNG = 3, // 4扫码产品型号错误 ProductModelError = 4, //5本工位NG CurrentStationNG = 5, //6时间超出规定无法生产 TimeExceeded = 6, //7固化时间未到规定时间 CuringTimeNotReached = 7, // 8未找到时间属性 TimeAttributeNotFound = 8, // 10条码为空 BarcodeEmpty = 10, //0之前工位数据异常 PreviousStationDataAbnormal = 0, //11 未知异常 UnkownException = 11 } }