2026-02-01 18:15:03 +08:00
|
|
|
|
using Infrastructure.Model;
|
|
|
|
|
|
using JinianNet.JNTemplate;
|
|
|
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
|
|
using Microsoft.Extensions.Options;
|
|
|
|
|
|
using NLog;
|
|
|
|
|
|
using RIZO.Infrastructure.Helper;
|
|
|
|
|
|
|
|
|
|
|
|
using RIZO.Model.Mes;
|
|
|
|
|
|
using RIZO.Model.MES.product_trace;
|
|
|
|
|
|
using S7.Net;
|
|
|
|
|
|
using SqlSugar.IOC;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
|
|
namespace RIZO.Service.PLCbackTask
|
|
|
|
|
|
{
|
|
|
|
|
|
public class MES_PLC_InterationTask : BackgroundService
|
|
|
|
|
|
{
|
|
|
|
|
|
private static Logger _logger = LogManager.GetCurrentClassLogger();
|
|
|
|
|
|
|
|
|
|
|
|
private SiemensS7Helper s7Helper;
|
|
|
|
|
|
|
|
|
|
|
|
private readonly SqlSugarClient Context;
|
|
|
|
|
|
private readonly PlcAddress _plcAddress;
|
|
|
|
|
|
// 添加一个取消源来控制循环
|
|
|
|
|
|
private CancellationTokenSource _internalCts;
|
|
|
|
|
|
public MES_PLC_InterationTask(IOptions<OptionsSetting> options)
|
|
|
|
|
|
{
|
|
|
|
|
|
Context = DbScoped.SugarScope.CopyNew();
|
|
|
|
|
|
_plcAddress = options.Value.plcAddress;
|
|
|
|
|
|
}
|
|
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.Info("PLC Polling Service started");
|
|
|
|
|
|
// 创建内部取消源,用于手动触发停止
|
|
|
|
|
|
_internalCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
|
|
|
|
|
|
using (s7Helper = new SiemensS7Helper(_plcAddress.IP))
|
|
|
|
|
|
{
|
2026-02-01 19:19:49 +08:00
|
|
|
|
try
|
2026-02-01 18:15:03 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
2026-02-01 19:19:49 +08:00
|
|
|
|
while (!stoppingToken.IsCancellationRequested && !_internalCts.Token.IsCancellationRequested)
|
|
|
|
|
|
{
|
2026-02-01 18:15:03 +08:00
|
|
|
|
if (!s7Helper.IsConnected)
|
|
|
|
|
|
{
|
|
|
|
|
|
var isConnected = await s7Helper.ConnectAsync();
|
|
|
|
|
|
if (!isConnected)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.Error("Failed to connect to PLC.");
|
2026-02-01 19:19:49 +08:00
|
|
|
|
break;
|
2026-02-01 18:15:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region 业务
|
|
|
|
|
|
|
|
|
|
|
|
bool? ReadHeartBeat = await s7Helper.ReadBoolAsync(_plcAddress.Read.ReadHeartBeat);//心跳
|
|
|
|
|
|
if (ReadHeartBeat != null && !ReadHeartBeat.Value)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("plc心跳 死亡");
|
|
|
|
|
|
// 使用内部取消源停止循环,而不是直接return
|
|
|
|
|
|
_internalCts.Cancel();
|
|
|
|
|
|
break; // 跳出循环,但会继续执行finally块和Dispose
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//TODO :1. 轮询出站请求
|
|
|
|
|
|
bool? OutStationAsk = await s7Helper.ReadBoolAsync(_plcAddress.Read.OutStationAsk);
|
|
|
|
|
|
if (OutStationAsk != null && OutStationAsk.Value)
|
|
|
|
|
|
{
|
|
|
|
|
|
//TODO : 2.读取业务数据
|
|
|
|
|
|
int WorkStationId = await s7Helper.ReadIntAsync(_plcAddress.Read.WorkStation) ?? 0;//工站
|
|
|
|
|
|
int ProductModelID = await s7Helper.ReadIntAsync(_plcAddress.Read.ProductModelId) ?? 0;//产品型号ID
|
|
|
|
|
|
float temperature = await s7Helper.ReadFloatAsync(_plcAddress.Read.ProductModelId) ?? 0.0f;//温度
|
|
|
|
|
|
float waterPressure = await s7Helper.ReadFloatAsync(_plcAddress.Read.WaterPressure) ?? 0.0f; // 水压,默认0.0
|
|
|
|
|
|
float airPressure = await s7Helper.ReadFloatAsync(_plcAddress.Read.AirPressure) ?? 0.0f; // 气压,默认0.0
|
|
|
|
|
|
int workTime = await s7Helper.ReadIntAsync(_plcAddress.Read.WorkTime) ?? 0; // 工作时间,默认0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 同时记录到日志
|
|
|
|
|
|
_logger.Info($"业务数据读取完成 - 工站:{WorkStationId}, 产品型号:{ProductModelID}, 温度:{temperature}°C, 水压:{waterPressure}bar, 气压:{airPressure}bar, 工作时间:{workTime}秒");
|
|
|
|
|
|
List<ProductTraceProcessParameters> paramss = new();
|
|
|
|
|
|
// 存入工艺参数表
|
|
|
|
|
|
ProductTraceProcessParameters temperatureParam = new ProductTraceProcessParameters()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 基础信息
|
|
|
|
|
|
ProductSn = WorkStationId.ToString(), // 产品序列号
|
|
|
|
|
|
RoutingCode = "ROUTING_PCB_ASSEMBLY", // 工艺路线代码
|
|
|
|
|
|
OperationCode = WorkStationId.ToString(), // 工序代码
|
|
|
|
|
|
FlowCode = "", // 流程代码
|
|
|
|
|
|
ProductlinebodyCode = "LINE_SMT_01", // 生产线体代码
|
|
|
|
|
|
WorkstationCode = WorkStationId.ToString(), // 工位代码
|
|
|
|
|
|
// 参数信息
|
|
|
|
|
|
ParameterCode = "temperature", // 参数代码
|
|
|
|
|
|
ParameterName = "温度", // 参数名称
|
|
|
|
|
|
PlcPoint = _plcAddress.Read.ProductModelId, // PLC点位
|
|
|
|
|
|
Description = "温度", // 描述
|
|
|
|
|
|
DataType = "float", // 数据类型
|
|
|
|
|
|
Unit = "°C",
|
|
|
|
|
|
ActualValue = (decimal)temperature,
|
|
|
|
|
|
CreatedTime = DateTime.Now, // 创建时间
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
paramss.Add(temperatureParam);
|
|
|
|
|
|
ProductTraceProcessParameters airPressureParm = new ProductTraceProcessParameters()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 基础信息
|
|
|
|
|
|
ProductSn = WorkStationId.ToString(), // 产品序列号
|
|
|
|
|
|
RoutingCode = "ROUTING_PCB_ASSEMBLY", // 工艺路线代码
|
|
|
|
|
|
OperationCode = WorkStationId.ToString(), // 工序代码
|
|
|
|
|
|
FlowCode = "", // 流程代码
|
|
|
|
|
|
ProductlinebodyCode = "LINE_SMT_01", // 生产线体代码
|
|
|
|
|
|
WorkstationCode = WorkStationId.ToString(), // 工位代码
|
|
|
|
|
|
// 参数信息
|
|
|
|
|
|
ParameterCode = "waterPressure", // 参数代码
|
|
|
|
|
|
ParameterName = "气压", // 参数名称
|
|
|
|
|
|
PlcPoint = _plcAddress.Read.WaterPressure, // PLC点位
|
|
|
|
|
|
Description = "气压", // 描述
|
|
|
|
|
|
DataType = "float", // 数据类型
|
|
|
|
|
|
Unit = "N",
|
|
|
|
|
|
ActualValue = (decimal)airPressure,
|
|
|
|
|
|
CreatedTime = DateTime.Now, // 创建时间
|
|
|
|
|
|
};
|
|
|
|
|
|
paramss.Add(airPressureParm);
|
|
|
|
|
|
ProductTraceProcessParameters waterPressureParam = new ProductTraceProcessParameters()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 基础信息
|
|
|
|
|
|
ProductSn = WorkStationId.ToString(), // 产品序列号
|
|
|
|
|
|
RoutingCode = "ROUTING_PCB_ASSEMBLY", // 工艺路线代码
|
|
|
|
|
|
OperationCode = WorkStationId.ToString(), // 工序代码
|
|
|
|
|
|
FlowCode = "", // 流程代码
|
|
|
|
|
|
ProductlinebodyCode = "LINE_SMT_01", // 生产线体代码
|
|
|
|
|
|
WorkstationCode = WorkStationId.ToString(), // 工位代码
|
|
|
|
|
|
// 参数信息
|
|
|
|
|
|
ParameterCode = "waterPressure", // 参数代码
|
|
|
|
|
|
ParameterName = "水压", // 参数名称
|
|
|
|
|
|
PlcPoint = _plcAddress.Read.WaterPressure, // PLC点位
|
|
|
|
|
|
Description = "水压", // 描述
|
|
|
|
|
|
DataType = "float", // 数据类型
|
|
|
|
|
|
Unit = "N",
|
|
|
|
|
|
ActualValue = (decimal)waterPressure,
|
|
|
|
|
|
CreatedTime = DateTime.Now, // 创建时间
|
|
|
|
|
|
};
|
|
|
|
|
|
paramss.Add(waterPressureParam);
|
|
|
|
|
|
|
|
|
|
|
|
ProductTraceProcessParameters workTimeParam = new ProductTraceProcessParameters()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 基础信息
|
|
|
|
|
|
ProductSn = WorkStationId.ToString(), // 产品序列号
|
|
|
|
|
|
RoutingCode = "ROUTING_PCB_ASSEMBLY", // 工艺路线代码
|
|
|
|
|
|
OperationCode = WorkStationId.ToString(), // 工序代码
|
|
|
|
|
|
FlowCode = "", // 流程代码
|
|
|
|
|
|
ProductlinebodyCode = "LINE_SMT_01", // 生产线体代码
|
|
|
|
|
|
WorkstationCode = WorkStationId.ToString(), // 工位代码
|
|
|
|
|
|
// 参数信息
|
|
|
|
|
|
ParameterCode = "waterPressure", // 参数代码
|
|
|
|
|
|
ParameterName = "工作时间", // 参数名称
|
|
|
|
|
|
PlcPoint = _plcAddress.Read.WaterPressure, // PLC点位
|
|
|
|
|
|
Description = "工作时间", // 描述
|
|
|
|
|
|
DataType = "int", // 数据类型
|
|
|
|
|
|
Unit = "秒",
|
|
|
|
|
|
ActualValue = (decimal)workTime,
|
|
|
|
|
|
CreatedTime = DateTime.Now, // 创建时间
|
|
|
|
|
|
};
|
|
|
|
|
|
paramss.Add(workTimeParam);
|
|
|
|
|
|
await Context.Insertable(paramss).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//存入过站记录表
|
|
|
|
|
|
ProductPassStationRecord record = new ProductPassStationRecord()
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
ProductionLifeStage = 1,
|
|
|
|
|
|
PasstationType = 3,
|
|
|
|
|
|
PasstationDescription = "出站完毕",
|
2026-02-01 19:19:49 +08:00
|
|
|
|
EffectTime = DateTime.Now,
|
|
|
|
|
|
OutStationTime = DateTime.Now,
|
|
|
|
|
|
ResultCode = 1,
|
|
|
|
|
|
ResultDescription = "OK",
|
|
|
|
|
|
CreatedTime = DateTime.Now
|
2026-02-01 18:15:03 +08:00
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 出站完毕响应
|
|
|
|
|
|
await s7Helper.WriteBoolAsync(_plcAddress.Write.Resp, true);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
// Wait for a defined interval before the next poll
|
|
|
|
|
|
await Task.Delay(1000, stoppingToken);
|
|
|
|
|
|
}
|
2026-02-01 19:19:49 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.Error(ex, "Fatal error in PLC polling service");
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.Info("PLC Polling Service stopped");
|
|
|
|
|
|
|
|
|
|
|
|
// 确保资源被正确释放
|
|
|
|
|
|
if (_internalCts != null)
|
2026-02-01 18:15:03 +08:00
|
|
|
|
{
|
2026-02-01 19:19:49 +08:00
|
|
|
|
_internalCts.Dispose();
|
|
|
|
|
|
_internalCts = null;
|
2026-02-01 18:15:03 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
2026-02-01 19:19:49 +08:00
|
|
|
|
Console.WriteLine("后台任务关闭!!!!!");
|
2026-02-01 18:15:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|