using MDM.Model.Plant; using MDM.Model.Process; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NLog; using NPOI.SS.Formula.Functions; 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.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace RIZO.Service.PLCBackground.Stations { /// /// OP07_01 出站 /// public class PlcOutStationService_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 PlcOutStationService_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 outStationAsk = await _plcService.ReadAsync("DB1001.DBW2002"); if (outStationAsk == 1) { // 处理进站请求 _logger.Info("Processing out 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 ASKoutStation = new ProductPassStationRecord { ProductSN = productSN, WorkstationCode = WorkstationCode, Routingcode = processOperations.First().FkRoutingCode, OperationCode = WorkstationCode, ProductionLifeStage = 1, // 1表示生产中 PasstationType = 2, // 0表示出站请求 PasstationDescription = "出站请求ASK", EffectTime = DateTime.Now, CreatedTime = DateTime.Now, }; await Context.Insertable(ASKoutStation).ExecuteCommandAsync(); //上传工艺参数 bool CheckOutstationResult = await UploadProcessParameters(productSN, processOperations.First().FkRoutingCode, WorkstationCode); //判断该产品是否允许进站 OutPermissionResult result = await checkOutPermission(productModel, productSN, WorkstationCode, processOperations, CheckOutstationResult); 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"); } /// /// 保存工艺参数上传 /// /// private async Task UploadProcessParameters(string productSN, string RoutingCode, string OperationCode) { bool result = true; List productProcessParameters = new List(); //实际产量 ProductProcessParameters ActualProductParameter = new ProductProcessParameters { ProductSN = productSN, RoutingCode = RoutingCode, OperationCode = OperationCode, ProductlinebodyCode = "line3", WorkstationCode = OperationCode, ParameterCode = "actual_product", ParameterName = "实际产量", PlcPoint = "DB1001.DBW1104", Description = OperationCode + "工序的" + "实际产量", DataType = "int", Unit = "个", ActualValue = (await _plcService.ReadAsync("DB1001.DBW1104")).ToString(), CreatedTime = DateTime.Now, }; productProcessParameters.Add(ActualProductParameter); //合格数量 ProductProcessParameters QualifiedProductParameter = new ProductProcessParameters { ProductSN = productSN, RoutingCode = RoutingCode, OperationCode = OperationCode, ProductlinebodyCode = "line3", WorkstationCode = OperationCode, ParameterCode = "actual_product", ParameterName = "合格数量", PlcPoint = "DB1001.DBW1108", Description = OperationCode + "工序的" + "合格数量", DataType = "int", Unit = "个", ActualValue = (await _plcService.ReadAsync("DB1001.DBW1108")).ToString(), CreatedTime = DateTime.Now, }; productProcessParameters.Add(QualifiedProductParameter); //失败数量 ProductProcessParameters FailureProductParameter = new ProductProcessParameters { ProductSN = productSN, RoutingCode = RoutingCode, OperationCode = OperationCode, ProductlinebodyCode = "line3", WorkstationCode = OperationCode, ParameterCode = "actual_product", ParameterName = "失败数量", PlcPoint = "DB1001.DBW1112", Description = OperationCode + "工序的" + "失败数量", DataType = "int", Unit = "个", ActualValue = (await _plcService.ReadAsync("DB1001.DBW1112")).ToString(), CreatedTime = DateTime.Now, }; productProcessParameters.Add(FailureProductParameter); //SN_1 ProductProcessParameters SN_1Parameter = new ProductProcessParameters { ProductSN = productSN, RoutingCode = RoutingCode, OperationCode = OperationCode, ProductlinebodyCode = "line3", WorkstationCode = OperationCode, ParameterCode = "SN_1", ParameterName = "SN_1", PlcPoint = "DB1001.DBW1112", Description = OperationCode + "工序的" + "SN_1", DataType = "string", Unit = "个", ActualValue = await _plcService.ReadStringAsync("DB1001.DBW1112"), CreatedTime = DateTime.Now, }; productProcessParameters.Add(SN_1Parameter); //SN_2 ProductProcessParameters SN_2Parameter = new ProductProcessParameters { ProductSN = productSN, RoutingCode = RoutingCode, OperationCode = OperationCode, ProductlinebodyCode = "line3", WorkstationCode = OperationCode, ParameterCode = "SN_1", ParameterName = "SN_1", PlcPoint = "DB1001.DBW2134", Description = OperationCode + "工序的" + "SN_2", DataType = "string", Unit = "个", ActualValue = await _plcService.ReadStringAsync("DB1001.DBW2134"), CreatedTime = DateTime.Now, }; productProcessParameters.Add(SN_2Parameter); //相机结果 int CameraResult = await _plcService.ReadAsync("DB1001.DBW2164"); if (CameraResult == 1) { result = true; } if (CameraResult == 2) { result = false; } ProductProcessParameters CameraParameter = new ProductProcessParameters { ProductSN = productSN, RoutingCode = RoutingCode, OperationCode = OperationCode, ProductlinebodyCode = "line3", WorkstationCode = OperationCode, ParameterCode = "CameraResult", ParameterName = "CameraResult", PlcPoint = "DB1001.DBW2164", Description = OperationCode + "工序的" + "相机结果 1 OK 2 NG", DataType = "int", Unit = "个", ActualValue = CameraResult.ToString(), ExpectValue = "1", Result = result ? 1 : 0, CreatedTime = DateTime.Now, }; productProcessParameters.Add(CameraParameter); //站位结果 int StationPosition = await _plcService.ReadAsync("DB1001.DBW2166"); if (StationPosition == 1) { result = true; } if (StationPosition == 2) { result = false; } ProductProcessParameters StationPositionParameter = new ProductProcessParameters { ProductSN = productSN, RoutingCode = RoutingCode, OperationCode = OperationCode, ProductlinebodyCode = "line3", WorkstationCode = OperationCode, ParameterCode = "StationPosition", ParameterName = "StationPosition", PlcPoint = "DB1001.DBW2166", Description = OperationCode + "工序的" + "站位结果 1 OK 2 NG", DataType = "int", Unit = "个", ActualValue = StationPosition.ToString(), ExpectValue = "1", Result = result ? 1 : 0, CreatedTime = DateTime.Now, }; productProcessParameters.Add(StationPositionParameter); //节拍时间 real类型 ProductProcessParameters BeatParameter = new ProductProcessParameters { ProductSN = productSN, RoutingCode = RoutingCode, OperationCode = OperationCode, ProductlinebodyCode = "line3", WorkstationCode = OperationCode, ParameterCode = "beat", ParameterName = "节拍时间", PlcPoint = "DB1001.DBD2168", Description = OperationCode + "工序的" + "节拍时间", DataType = "float", Unit = "s", ActualValue = (await _plcService.ReadAsync("DB1001.DBD2168")).ToString(), CreatedTime = DateTime.Now, }; productProcessParameters.Add(BeatParameter); await Context.Insertable(productProcessParameters).ExecuteCommandAsync(); return result; } /// /// 校验是否可以出站 /// /// 产品型号 /// 产品SN /// private async Task checkOutPermission(string productModel, string productSN, string workstationCode, List processOperations, bool CheckOutstationResult) { OutPermissionResult result = OutPermissionResult.UnkownException; if (!CheckOutstationResult) { result = OutPermissionResult.ProcessParameterNG; goto InsertPassrecord; } //OK 准许进站 result = OutPermissionResult.OK; goto InsertPassrecord; InsertPassrecord: //插入出站请求Resp 过站记录 ProductPassStationRecord RespintoStation = new ProductPassStationRecord { ProductSN = productSN, WorkstationCode = WorkstationCode, Routingcode = processOperations.First().FkRoutingCode, OperationCode = WorkstationCode, ProductionLifeStage = 1, // 1表示生产中 PasstationType = 3, // 出站完毕 PasstationDescription = "出站完毕Resp", EffectTime = DateTime.Now, OutStationTime = DateTime.Now, ResultCode = (int)result, ResultDescription = result.ToString(), CreatedTime = DateTime.Now, }; await Context.Insertable(RespintoStation).ExecuteCommandAsync(); return result; } } /// /// 出站校验结果 /// public enum OutPermissionResult { /// /// 1 OK - 成功 /// OK = 1, /// /// 2 产品时间属性增加失败 /// ProductTimeAttributeAddFailed = 2, /// /// 3 产品条码合并失败 /// ProductBarcodeMergeFailed = 3, /// /// 4 产品结果上传次数超出 /// ProductUploadCountExceeded = 4, /// /// 5 时间属性移除失败 /// TimeAttributeRemoveFailed = 5, /// /// 6 数据保存失败 /// DataSaveFailed = 6, /// /// 10 上传条码为空 /// UploadBarcodeEmpty = 10, /// /// 11 未知异常 /// UnkownException = 11, /// /// 工艺参数NG /// ProcessParameterNG = 12 } }