224 lines
12 KiB
C#
224 lines
12 KiB
C#
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))
|
||
{
|
||
try
|
||
{
|
||
|
||
while (!stoppingToken.IsCancellationRequested && !_internalCts.Token.IsCancellationRequested)
|
||
{
|
||
if (!s7Helper.IsConnected)
|
||
{
|
||
var isConnected = await s7Helper.ConnectAsync();
|
||
if (!isConnected)
|
||
{
|
||
_logger.Error("Failed to connect to PLC.");
|
||
Task.Delay(1000, stoppingToken);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
#region 业务
|
||
|
||
bool? ReadHeartBeat = await s7Helper.ReadBoolAsync(_plcAddress.Read.ReadHeartBeat);//心跳
|
||
if (ReadHeartBeat != null && !ReadHeartBeat.Value)
|
||
{
|
||
Console.WriteLine("plc心跳 死亡");
|
||
// 使用内部取消源停止循环,而不是直接return
|
||
_internalCts.Cancel();
|
||
break; // 跳出循环,但会继续执行finally块和Dispose
|
||
}else if(ReadHeartBeat != null && ReadHeartBeat.Value)
|
||
{
|
||
await s7Helper.WriteBoolAsync(_plcAddress.Write.WriteHeartBeat, true);
|
||
}
|
||
|
||
//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 = "出站完毕",
|
||
EffectTime = DateTime.Now,
|
||
OutStationTime = DateTime.Now,
|
||
ResultCode = 1,
|
||
ResultDescription = "OK",
|
||
CreatedTime = DateTime.Now
|
||
|
||
};
|
||
|
||
// 出站完毕响应
|
||
await s7Helper.WriteBoolAsync(_plcAddress.Write.Resp, true);
|
||
|
||
}
|
||
#endregion
|
||
// Wait for a defined interval before the next poll
|
||
await Task.Delay(1000, stoppingToken);
|
||
}
|
||
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "Fatal error in PLC polling service");
|
||
throw;
|
||
}
|
||
finally
|
||
{
|
||
_logger.Info("PLC Polling Service stopped");
|
||
|
||
// 确保资源被正确释放
|
||
if (_internalCts != null)
|
||
{
|
||
_internalCts.Dispose();
|
||
_internalCts = null;
|
||
|
||
}
|
||
Console.WriteLine("后台任务关闭!!!!!");
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
}
|