diff --git a/RIZO.Admin.WebApi/PLC/Model/Dto/PlcProductionDataDto.cs b/RIZO.Admin.WebApi/PLC/Model/Dto/PlcProductionDataDto.cs
index b0355f4..5a9d454 100644
--- a/RIZO.Admin.WebApi/PLC/Model/Dto/PlcProductionDataDto.cs
+++ b/RIZO.Admin.WebApi/PLC/Model/Dto/PlcProductionDataDto.cs
@@ -27,18 +27,16 @@ namespace RIZO.Admin.WebApi.PLC.Model.Dto
public int Id { get; set; }
public string? LineCode { get; set; }
-
+ public string? WorkstationCode { get; set; }
public string? PlcIp { get; set; }
public string? ProductCode { get; set; }
public string? ProductName { get; set; }
- public string? PartCode { get; set; }
+ public string? ProductModel { get; set; }
- public string? PartName { get; set; }
-
- public string? ProcessName { get; set; }
+ public string? WorkstationName { get; set; }
public string? ParamName { get; set; }
@@ -53,9 +51,17 @@ namespace RIZO.Admin.WebApi.PLC.Model.Dto
public int? ProductionCycle { get; set; }
public int? AutoManual { get; set; }
public int? RunStatus { get; set; }
+ public string? TrayNo { get; set; }
+ public string? ProduceModel { get; set; }
+
+ public string? OnlineStatus { get; set; }
public string? Remark { get; set; }
+ public string? SN1 { get; set; }
+ public string? SN2 { get; set; }
+ public string? CameraResult { get; set; }
+
public string? CreatedBy { get; set; }
public DateTime? CreatedTime { get; set; }
diff --git a/RIZO.Admin.WebApi/PLC/Model/PlcConfig.cs b/RIZO.Admin.WebApi/PLC/Model/PlcConfig.cs
index a0281bb..c45e0a3 100644
--- a/RIZO.Admin.WebApi/PLC/Model/PlcConfig.cs
+++ b/RIZO.Admin.WebApi/PLC/Model/PlcConfig.cs
@@ -26,6 +26,16 @@
public string ReadMessage { get; set; }
public bool WriteSuccess { get; set; }
public string WriteMessage { get; set; }
+
+ //设备运行状态
+ public string RunStatus { get; set; }
+ //设备模式
+ public string MachineModel { get; set; }
+ //设备在线模式
+ public string OnLineStatus { get; set; }
+ //设备生产模式
+ public string ProduceModel { get; set; }
+
}
}
diff --git a/RIZO.Admin.WebApi/PLC/Model/PlcProductionData.cs b/RIZO.Admin.WebApi/PLC/Model/PlcProductionData.cs
index bbb5234..2dc8ee0 100644
--- a/RIZO.Admin.WebApi/PLC/Model/PlcProductionData.cs
+++ b/RIZO.Admin.WebApi/PLC/Model/PlcProductionData.cs
@@ -21,6 +21,18 @@ namespace RIZO.Admin.WebApi.PLC.Model
[SugarColumn(ColumnName = "line_code")]
public string LineCode { get; set; }
+ ///
+ /// 工站编码
+ ///
+ [SugarColumn(ColumnName = "workstationCode")]
+ public string WorkstationCode { get; set; }
+
+ ///
+ /// 工站名称
+ ///
+ [SugarColumn(ColumnName = "workstationName")]
+ public string WorkstationName { get; set; }
+
///
/// PLC IP地址
///
@@ -40,22 +52,10 @@ namespace RIZO.Admin.WebApi.PLC.Model
public string ProductName { get; set; }
///
- /// 零件编码
+ /// 产品型号
///
- [SugarColumn(ColumnName = "part_code")]
- public string PartCode { get; set; }
-
- ///
- /// 零件名称
- ///
- [SugarColumn(ColumnName = "part_name")]
- public string PartName { get; set; }
-
- ///
- /// 工序名称
- ///
- [SugarColumn(ColumnName = "process_name")]
- public string ProcessName { get; set; }
+ [SugarColumn(ColumnName = "product_model")]
+ public string ProductModel { get; set; }
///
/// 参数名称
@@ -100,11 +100,28 @@ namespace RIZO.Admin.WebApi.PLC.Model
public int? AutoManual { get; set; }
///
- /// 运行状态:1正常,2异常
+ /// 运行状态:1=空闲,2=运行中,3=故障;
///
[SugarColumn(ColumnName = "runstatus")]
public int? RunStatus { get; set; }
+ ///
+ /// 托盘号
+ ///
+ [SugarColumn(ColumnName = "trayNo")]
+ public string TrayNo { get; set; }
+
+ ///
+ /// 生产模式
+ ///
+ [SugarColumn(ColumnName = "produceModel")]
+ public string ProduceModel { get; set; }
+
+ ///
+ /// 设备在线状态1=离线,0=在线
+ ///
+ [SugarColumn(ColumnName = "onlineStatus")]
+ public string OnlineStatus { get; set; }
///
/// 备注
///
@@ -134,5 +151,23 @@ namespace RIZO.Admin.WebApi.PLC.Model
[SugarColumn(ColumnName = "uPDATED_TIME")]
public DateTime? UpdatedTime { get; set; }
+ ///
+ /// 条码查询
+ ///
+ [SugarColumn(ColumnName = "SN_1")]
+ public string SN1 { get; set; }
+
+ ///
+ /// 结果上传条码
+ ///
+ [SugarColumn(ColumnName = "SN_2")]
+ public string SN2 { get; set; }
+
+ ///
+ /// 相机结果1,OK,2,NG
+ ///
+ [SugarColumn(ColumnName = "cameraResult")]
+ public string CameraResult { get; set; }
+
}
}
\ No newline at end of file
diff --git a/RIZO.Admin.WebApi/PLC/Service/PlcProductionDataService.cs b/RIZO.Admin.WebApi/PLC/Service/PlcProductionDataService.cs
index 3026bf8..fe74401 100644
--- a/RIZO.Admin.WebApi/PLC/Service/PlcProductionDataService.cs
+++ b/RIZO.Admin.WebApi/PLC/Service/PlcProductionDataService.cs
@@ -33,14 +33,6 @@ namespace RIZO.Admin.WebApi.PLC.Service
{
predicate = predicate.And(x => x.ProductCode == parm.ProductCode);
}
- if (!string.IsNullOrEmpty(parm.PartName))
- {
- predicate = predicate.And(x => x.PartName == parm.PartName);
- }
- if (!string.IsNullOrEmpty(parm.PartCode))
- {
- predicate = predicate.And(x => x.PartCode == parm.PartCode);
- }
if (!string.IsNullOrEmpty(parm.ReworkFlag))
{
predicate = predicate.And(x => x.ReworkFlag == parm.ReworkFlag);
@@ -78,14 +70,6 @@ namespace RIZO.Admin.WebApi.PLC.Service
{
predicate = predicate.And(x => x.ProductCode == parm.ProductCode);
}
- if (!string.IsNullOrEmpty(parm.PartName))
- {
- predicate = predicate.And(x => x.PartName == parm.PartName);
- }
- if (!string.IsNullOrEmpty(parm.PartCode))
- {
- predicate = predicate.And(x => x.PartCode == parm.PartCode);
- }
if (!string.IsNullOrEmpty(parm.ReworkFlag))
{
predicate = predicate.And(x => x.ReworkFlag == parm.ReworkFlag);
diff --git a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs
index 590d373..8f3c2f9 100644
--- a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs
+++ b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs
@@ -1,6 +1,8 @@
// 统一引入所有必要命名空间
using MDM.Services.Plant;
using Microsoft.Extensions.Options;
+using NPOI.SS.Formula.Functions;
+using Quartz;
using RIZO.Admin.WebApi.PLC.Model;
using RIZO.Common;
using S7.Net;
@@ -62,28 +64,34 @@ namespace RIZO.Admin.WebApi.PLC.Service
#region PLC地址块儿映射
// OP070-1 专属地址映射
- private readonly Dictionary _op070_1IntMap = new Dictionary
+ private readonly Dictionary _op070_1StringMap = new()
{
- { "运行状态", "DB1001.DBW0" }, // 运行状态
- { "设备模式", "DB1001.DBW2" }, // 设备模式
- { "设备在线状态", "DB1001.DBW4" },// 设备在线状态
- { "ByPass", "DB1001.DBW6" }, // ByPass
- { "生产模式", "DB1001.DBW8" }, // 生产模式
- { "查询请求", "DB1001.DBW2000" }, // 查询请求
- { "保存请求", "DB1001.DBW2002" }, // 保存请求
- { "托盘号", "DB1001.DBW2004" }, // 托盘号
- { "相机结果", "DB1001.DBW2164" }, // 相机结果
- { "站位结果", "DB1001.DBW2166" } // 站位结果
+ { "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
+ { "产品型号_48", ("DB1001.DBB1000", 48) }, // String[48]
+ { "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
+ { "产品型号_28", ("DB1001.DBB2006", 28) }, // String[28]
+ { "SN_1", ("DB1001.DBB2100", 28) }, // String[28]
+ { "SN_2", ("DB1001.DBB2134", 28) } // String[28]
};
- private readonly Dictionary _op070_1StringMap = new Dictionary
+ private readonly Dictionary _op070_1IntMap = new()
{
- { "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
- { "产品名称", ("DB1001.DBB1054", 48) }, // String[48]
- { "产品型号", ("DB1001.DBB2006", 28) }, // String[28]
- { "SN_1", ("DB1001.DBB2100", 28) }, // 条码查询
- { "SN_2", ("DB1001.DBB2134", 28) } // 结果上传条码
+ { "运行状态", "DB1001.DBW0" }, // Int
+ { "设备模式", "DB1001.DBW2" }, // Int
+ { "设备在线状态", "DB1001.DBW4" }, // Int
+ { "ByPass", "DB1001.DBW6" }, // Int
+ { "生产模式", "DB1001.DBW8" }, // Int
+ { "实际产量", "DB1001.DBD1104" }, // DInt
+ { "合格数量", "DB1001.DBD1108" }, // DInt
+ { "失败数量", "DB1001.DBD1112" }, // DInt
+ { "查询请求", "DB1001.DBW2000" }, // Int
+ { "保存请求", "DB1001.DBW2002" }, // Int
+ { "托盘号", "DB1001.DBW2004" }, // Int
+ { "相机结果", "DB1001.DBW2164" }, // Int
+ { "站位结果", "DB1001.DBW2166" }, // Int
+ { "节拍时间", "DB1001.DBD2168" } // Real
};
+
#endregion
///
/// 构造函数(依赖注入获取PLC配置)
@@ -99,83 +107,6 @@ namespace RIZO.Admin.WebApi.PLC.Service
#endregion
#region 核心业务方法
- /////
- ///// 读取PLC生产数据(严格匹配业务地址和解析规则)
- /////
- ///// PLC IP地址
- ///// 机架号
- ///// 槽位号
- ///// PLC型号(默认S7-1500)
- ///// 读取结果(状态+数据+消息)
- //public async Task<(bool Success, PlcProductionData Data, string Message)> ReadProductionDataAsync(
- // string ip,
- // short rack,
- // short slot,
- // CpuType cpuType = CpuType.S71500)
- //{
- // // 参数校验
- // if (string.IsNullOrWhiteSpace(ip))
- // return (false, null, "PLC IP地址不能为空");
-
- // Plc plc = null;
- // try
- // {
- // // 初始化PLC连接
- // plc = CreatePlcClient(cpuType, ip, rack, slot);
- // await OpenPlcConnectionAsync(plc);
-
- // if (!plc.IsConnected)
- // return (false, null, "PLC连接失败");
-
- // // 构建生产数据实体
- // var prodData = new PlcProductionData
- // {
- // PlcIp = ip.Trim(),
- // OccurTime = DateTime.Now, // MES自配时间
-
- // // 字符串字段(按规则解析)
- // LineCode = await ReadPlcStringAsync(plc, _plcStringMap["LineCode"].Addr, _plcStringMap["LineCode"].Len),
- // ProductCode = await ReadPlcStringAsync(plc, _plcStringMap["ProductCode"].Addr, _plcStringMap["ProductCode"].Len),
- // ProductName = await ReadPlcStringAsync(plc, _plcStringMap["ProductName"].Addr, _plcStringMap["ProductName"].Len),
- // PartCode = await ReadPlcStringAsync(plc, _plcStringMap["PartCode"].Addr, _plcStringMap["PartCode"].Len),
- // PartName = await ReadPlcStringAsync(plc, _plcStringMap["PartName"].Addr, _plcStringMap["PartName"].Len),
- // ProcessName = await ReadPlcStringAsync(plc, _plcStringMap["ProcessName"].Addr, _plcStringMap["ProcessName"].Len),
- // ParamName = await ReadPlcStringAsync(plc, _plcStringMap["ParamName"].Addr, _plcStringMap["ParamName"].Len),
- // ParamValue = await ReadPlcStringAsync(plc, _plcStringMap["ParamValue"].Addr, _plcStringMap["ParamValue"].Len),
-
- // // 修复:改为异步读取整数,确保类型兼容
- // //合格标志(0默认,1合格,2不合格)
- // QualificationFlag = (await ReadPlcIntAsync(plc, _plcIntMap["QualificationFlag"])).ToString(),
- // //返工标志(0正常,1返工)
- // ReworkFlag = (await ReadPlcIntAsync(plc, _plcIntMap["ReworkFlag"])).ToString(),
- // //设备自动手动:0-自动,1-手动
- // AutoManual = (await ReadPlcIntAsync(plc, _plcIntMap["AutoManual"])),
- // //运行状态:1正常,2异常
- // RunStatus = (await ReadPlcIntAsync(plc, _plcIntMap["RunStatus"])),
- // //生产节拍秒
- // ProductionCycle = await ReadPlcIntAsync(plc, _plcIntMap["ProductionCycle"])
- // };
-
- // // 空值兜底(避免入库报错)
- // prodData.QualificationFlag ??= "0";
- // prodData.ReworkFlag ??= "0";
- // prodData.ProductionCycle ??= 0;
-
- // // 保存生产数据到MES数据库
- // _plcProductionDataService.AddPlcProductionData(prodData);
- // return (true, prodData, "生产数据读取成功");
- // }
- // catch (Exception ex)
- // {
- // return (false, null, $"生产数据读取失败:{ex.Message}");
- // }
- // finally
- // {
- // ReleasePlcConnection(plc);
- // }
- //}
-
-
///
/// 读取PLC生产数据(优化版:连接池+并发控制+批量读取+异常防护)
@@ -185,6 +116,173 @@ namespace RIZO.Admin.WebApi.PLC.Service
/// 槽位号
/// PLC型号(默认S7-1500)
/// 读取结果(状态+数据+消息)
+ //public async Task<(bool Success, PlcProductionData Data, string Message)> ReadProductionDataAsync(
+ // string ip,
+ // string plcName,
+ // short rack,
+ // short slot,
+ // CpuType cpuType = CpuType.S71500)
+ //{
+ // // 1. 强化参数校验(源头避免无效请求)
+ // if (string.IsNullOrWhiteSpace(ip))
+ // return (false, null, "PLC IP地址不能为空");
+ // if (rack < 0 || rack > 10) // 工业场景机架号常规范围
+ // return (false, null, $"PLC机架号{rack}无效(有效值0-10)");
+ // if (slot < 0 || slot > 4) // 工业场景槽位号常规范围
+ // return (false, null, $"PLC槽位号{slot}无效(有效值0-4)");
+
+ // Plc plc = null;
+ // bool isConnReused = false; // 标记是否复用连接
+ // var poolKey = $"{ip}_{rack}_{slot}_{cpuType}"; // 连接池唯一标识
+
+ // // 2. 并发控制(防止50台PLC同时访问导致端口/线程耗尽)
+ // await _concurrencySemaphore.WaitAsync();
+
+ // try
+ // {
+ // // 3. 连接池复用(核心优化:避免高频创建/销毁连接)
+ // if (_plcConnPool.TryGetValue(poolKey, out var poolItem) && poolItem.Client.IsConnected)
+ // {
+ // plc = poolItem.Client;
+ // _plcConnPool.TryUpdate(poolKey, (plc, DateTime.Now), poolItem); // 更新最后使用时间
+ // isConnReused = true;
+ // }
+ // else
+ // {
+ // // 初始化新连接(保留你的原始逻辑,增加重试)
+ // plc = CreatePlcClient(cpuType, ip, rack, slot);
+ // // 连接重试(应对临时网络波动)
+ // int retryCount = 2;
+ // bool isConnected = false;
+ // while (retryCount-- > 0 && !isConnected)
+ // {
+ // try
+ // {
+ // await OpenPlcConnectionAsync(plc);
+ // isConnected = plc.IsConnected;
+ // }
+ // catch
+ // {
+ // if (retryCount > 0) await Task.Delay(100); // 重试间隔
+ // }
+ // }
+
+ // if (!isConnected)
+ // return (false, null, "PLC连接失败(含2次重试)");
+
+ // // 新连接加入池
+ // _plcConnPool.TryAdd(poolKey, (plc, DateTime.Now));
+ // }
+
+ // //先读取查询请求标志,判断是否需要读取生产数据
+ // int iQueryRequest = await ReadPlcIntAsync(plc, _plcIntMap["QueryRequest"]);
+ // if (iQueryRequest != 1)
+ // {
+ // return (false, null, "PLC查询请求标志未设置,跳过生产数据读取");
+ // }
+ // if (plcName == "OP070-1")
+ // {
+
+
+ // }
+ // // 4. 批量并行读取(核心优化:替代串行await,提升效率30%+)
+ // // 4.1 字符串字段批量读取
+ // var stringTasks = new Dictionary>
+ // {
+ // { "LineCode", ReadPlcStringAsync(plc, _plcStringMap["LineCode"].Addr, _plcStringMap["LineCode"].Len) },
+ // { "ProductCode", ReadPlcStringAsync(plc, _plcStringMap["ProductCode"].Addr, _plcStringMap["ProductCode"].Len) },
+ // { "ProductName", ReadPlcStringAsync(plc, _plcStringMap["ProductName"].Addr, _plcStringMap["ProductName"].Len) },
+ // { "PartCode", ReadPlcStringAsync(plc, _plcStringMap["PartCode"].Addr, _plcStringMap["PartCode"].Len) },
+ // { "PartName", ReadPlcStringAsync(plc, _plcStringMap["PartName"].Addr, _plcStringMap["PartName"].Len) },
+ // { "ProcessName", ReadPlcStringAsync(plc, _plcStringMap["ProcessName"].Addr, _plcStringMap["ProcessName"].Len) },
+ // { "ParamName", ReadPlcStringAsync(plc, _plcStringMap["ParamName"].Addr, _plcStringMap["ParamName"].Len) },
+ // { "ParamValue", ReadPlcStringAsync(plc, _plcStringMap["ParamValue"].Addr, _plcStringMap["ParamValue"].Len) }
+ // };
+
+ // // 4.2 整数字段批量读取
+ // var intTasks = new Dictionary>
+ // {
+ // { "QualificationFlag", ReadPlcIntAsync(plc, _plcIntMap["QualificationFlag"]) },
+ // { "ReworkFlag", ReadPlcIntAsync(plc, _plcIntMap["ReworkFlag"]) },
+ // { "AutoManual", ReadPlcIntAsync(plc, _plcIntMap["AutoManual"]) },
+ // { "RunStatus", ReadPlcIntAsync(plc, _plcIntMap["RunStatus"]) },
+ // { "ProductionCycle", ReadPlcIntAsync(plc, _plcIntMap["ProductionCycle"]) }
+ // };
+
+ // // 等待所有读取完成(并行执行,减少等待时间)
+ // IEnumerable allTasks = stringTasks.Values.Cast()
+ // .Concat(intTasks.Values.Cast());
+ // await Task.WhenAll(allTasks);
+
+ // // 5. 构建数据实体(空值安全处理,单个字段失败不影响整体)
+ // var prodData = new PlcProductionData
+ // {
+ // PlcIp = ip.Trim(),
+ // OccurTime = DateTime.Now,
+
+ // // 字符串字段(空值兜底)
+ // LineCode = await stringTasks["LineCode"] ?? string.Empty,
+ // ProductCode = await stringTasks["ProductCode"] ?? string.Empty,
+ // ProductName = await stringTasks["ProductName"] ?? string.Empty,
+ // PartCode = await stringTasks["PartCode"] ?? string.Empty,
+ // PartName = await stringTasks["PartName"] ?? string.Empty,
+ // ProcessName = await stringTasks["ProcessName"] ?? string.Empty,
+ // ParamName = await stringTasks["ParamName"] ?? string.Empty,
+ // ParamValue = await stringTasks["ParamValue"] ?? string.Empty,
+
+ // // 整数字段(读取失败返回0,不中断流程)
+ // QualificationFlag = (await intTasks["QualificationFlag"]).ToString(),
+ // ReworkFlag = (await intTasks["ReworkFlag"]).ToString(),
+ // AutoManual = await intTasks["AutoManual"],
+ // RunStatus = await intTasks["RunStatus"],
+ // ProductionCycle = await intTasks["ProductionCycle"]
+ // };
+
+ // // 空值兜底(保留你的原始逻辑)
+ // prodData.QualificationFlag ??= "0";
+ // prodData.ReworkFlag ??= "0";
+ // prodData.ProductionCycle ??= 0;
+
+ // // 6. 异步保存数据(非阻塞,提升响应速度)
+ // _ = Task.Run(() => _plcProductionDataService.AddPlcProductionData(prodData))
+ // .ContinueWith(t =>
+ // {
+ // if (t.IsFaulted)
+ // {
+ // // 记录保存失败日志(建议替换为ILogger)
+ // Console.WriteLine($"PLC({ip})数据保存失败:{t.Exception?.InnerException?.Message}");
+ // }
+ // });
+
+ // var successMsg = isConnReused ? "生产数据读取成功(复用连接)" : "生产数据读取成功(新建连接)";
+ // return (true, prodData, successMsg);
+ // }
+ // catch (Exception ex)
+ // {
+ // // 精细化异常日志(便于定位具体PLC故障)
+ // Console.WriteLine($"PLC({ip})生产数据读取异常:{ex.Message}\n{ex.StackTrace}");
+ // return (false, null, $"生产数据读取失败:{ex.Message}");
+ // }
+ // finally
+ // {
+ // // 7. 资源安全释放(核心:复用连接不释放,仅新建连接释放;必须释放并发信号量)
+ // if (!isConnReused)
+ // {
+ // ReleasePlcConnection(plc);
+ // }
+ // _concurrencySemaphore.Release(); // 防止死锁的关键
+ // }
+ //}
+
+ ///
+ /// 读取PLC生产数据(优化版:连接池+并发控制+OP070-1/OP080专属适配)
+ ///
+ /// PLC IP地址
+ /// PLC名称(支持OP070-1/OP080)
+ /// 机架号
+ /// 槽位号
+ /// PLC型号(默认S7-1500)
+ /// 读取结果(状态+数据+消息)
public async Task<(bool Success, PlcProductionData Data, string Message)> ReadProductionDataAsync(
string ip,
string plcName,
@@ -192,157 +290,311 @@ namespace RIZO.Admin.WebApi.PLC.Service
short slot,
CpuType cpuType = CpuType.S71500)
{
- // 1. 强化参数校验(源头避免无效请求)
+ // 1. 强化参数校验(补充PLC名称校验+白名单控制)
if (string.IsNullOrWhiteSpace(ip))
return (false, null, "PLC IP地址不能为空");
- if (rack < 0 || rack > 10) // 工业场景机架号常规范围
+ if (string.IsNullOrWhiteSpace(plcName))
+ return (false, null, "PLC名称不能为空");
+ if (rack < 0 || rack > 10)
return (false, null, $"PLC机架号{rack}无效(有效值0-10)");
- if (slot < 0 || slot > 4) // 工业场景槽位号常规范围
+ if (slot < 0 || slot > 4)
return (false, null, $"PLC槽位号{slot}无效(有效值0-4)");
- Plc plc = null;
- bool isConnReused = false; // 标记是否复用连接
- var poolKey = $"{ip}_{rack}_{slot}_{cpuType}"; // 连接池唯一标识
+ // 仅放行指定工位,防止非法请求
+ var supportedPlcs = new HashSet { "OP070-1", "OP080" };
+ if (!supportedPlcs.Contains(plcName))
+ return (false, null, $"仅支持OP070-1/OP080,当前工位:{plcName}");
- // 2. 并发控制(防止50台PLC同时访问导致端口/线程耗尽)
+ Plc plc = null;
+ bool isConnReused = false;
+ var poolKey = $"{ip}_{rack}_{slot}_{cpuType}";
+ PlcProductionData prodData = null;
+
+ // 2. 并发控制(核心保留,防止端口/线程耗尽)
await _concurrencySemaphore.WaitAsync();
try
{
- // 3. 连接池复用(核心优化:避免高频创建/销毁连接)
+ // 3. 连接池复用+精简重试逻辑(提升可读性)
if (_plcConnPool.TryGetValue(poolKey, out var poolItem) && poolItem.Client.IsConnected)
{
plc = poolItem.Client;
- _plcConnPool.TryUpdate(poolKey, (plc, DateTime.Now), poolItem); // 更新最后使用时间
+ _plcConnPool.TryUpdate(poolKey, (plc, DateTime.Now), poolItem);
isConnReused = true;
}
else
{
- // 初始化新连接(保留你的原始逻辑,增加重试)
plc = CreatePlcClient(cpuType, ip, rack, slot);
- // 连接重试(应对临时网络波动)
- int retryCount = 2;
bool isConnected = false;
- while (retryCount-- > 0 && !isConnected)
+ // for循环替代while,逻辑更直观
+ for (int retry = 0; retry < 2; retry++)
{
try
{
await OpenPlcConnectionAsync(plc);
isConnected = plc.IsConnected;
+ if (isConnected) break;
}
catch
{
- if (retryCount > 0) await Task.Delay(100); // 重试间隔
+ if (retry < 1) await Task.Delay(100); // 仅第一次失败后重试
}
}
if (!isConnected)
- return (false, null, "PLC连接失败(含2次重试)");
+ return (false, null, $"{plcName}连接失败(含2次重试)");
- // 新连接加入池
_plcConnPool.TryAdd(poolKey, (plc, DateTime.Now));
}
- //先读取查询请求标志,判断是否需要读取生产数据
- int iQueryRequest = await ReadPlcIntAsync(plc, _plcIntMap["QueryRequest"]);
- if (iQueryRequest != 1)
+ // 4. 多工位查询请求标志适配(核心:区分不同工位的寄存器地址)
+ int iQueryRequest = 0;
+ int iSaveRequest = 0;
+ if (plcName == "OP070-1" || plcName == "OP070-2" || plcName == "OP070-3" || plcName == "OP075")
{
- return (false, null, "PLC查询请求标志未设置,跳过生产数据读取");
+ iQueryRequest = await ReadPlcIntAsync(plc, _op070_1IntMap["查询请求"]);
+ iSaveRequest = await ReadPlcIntAsync(plc, _op070_1IntMap["保存请求"]);
}
+ // 无效请求直接返回(避免无谓资源消耗)
+ if (iQueryRequest != 1 && iSaveRequest != 1)
+ {
+ return (false, null, $"");
+ }
+
+ if (iQueryRequest == 1)
+ {
+
+ }
+ // 5. 多工位专属数据读取(预留扩展,逻辑隔离)
if (plcName == "OP070-1")
- {
-
-
- }
- // 4. 批量并行读取(核心优化:替代串行await,提升效率30%+)
- // 4.1 字符串字段批量读取
- var stringTasks = new Dictionary>
{
- { "LineCode", ReadPlcStringAsync(plc, _plcStringMap["LineCode"].Addr, _plcStringMap["LineCode"].Len) },
- { "ProductCode", ReadPlcStringAsync(plc, _plcStringMap["ProductCode"].Addr, _plcStringMap["ProductCode"].Len) },
- { "ProductName", ReadPlcStringAsync(plc, _plcStringMap["ProductName"].Addr, _plcStringMap["ProductName"].Len) },
- { "PartCode", ReadPlcStringAsync(plc, _plcStringMap["PartCode"].Addr, _plcStringMap["PartCode"].Len) },
- { "PartName", ReadPlcStringAsync(plc, _plcStringMap["PartName"].Addr, _plcStringMap["PartName"].Len) },
- { "ProcessName", ReadPlcStringAsync(plc, _plcStringMap["ProcessName"].Addr, _plcStringMap["ProcessName"].Len) },
- { "ParamName", ReadPlcStringAsync(plc, _plcStringMap["ParamName"].Addr, _plcStringMap["ParamName"].Len) },
- { "ParamValue", ReadPlcStringAsync(plc, _plcStringMap["ParamValue"].Addr, _plcStringMap["ParamValue"].Len) }
- };
-
- // 4.2 整数字段批量读取
- var intTasks = new Dictionary>
- {
- { "QualificationFlag", ReadPlcIntAsync(plc, _plcIntMap["QualificationFlag"]) },
- { "ReworkFlag", ReadPlcIntAsync(plc, _plcIntMap["ReworkFlag"]) },
- { "AutoManual", ReadPlcIntAsync(plc, _plcIntMap["AutoManual"]) },
- { "RunStatus", ReadPlcIntAsync(plc, _plcIntMap["RunStatus"]) },
- { "ProductionCycle", ReadPlcIntAsync(plc, _plcIntMap["ProductionCycle"]) }
- };
-
- // 等待所有读取完成(并行执行,减少等待时间)
- IEnumerable allTasks = stringTasks.Values.Cast()
- .Concat(intTasks.Values.Cast());
- await Task.WhenAll(allTasks);
-
- // 5. 构建数据实体(空值安全处理,单个字段失败不影响整体)
- var prodData = new PlcProductionData
- {
- PlcIp = ip.Trim(),
- OccurTime = DateTime.Now,
-
- // 字符串字段(空值兜底)
- LineCode = await stringTasks["LineCode"] ?? string.Empty,
- ProductCode = await stringTasks["ProductCode"] ?? string.Empty,
- ProductName = await stringTasks["ProductName"] ?? string.Empty,
- PartCode = await stringTasks["PartCode"] ?? string.Empty,
- PartName = await stringTasks["PartName"] ?? string.Empty,
- ProcessName = await stringTasks["ProcessName"] ?? string.Empty,
- ParamName = await stringTasks["ParamName"] ?? string.Empty,
- ParamValue = await stringTasks["ParamValue"] ?? string.Empty,
-
- // 整数字段(读取失败返回0,不中断流程)
- QualificationFlag = (await intTasks["QualificationFlag"]).ToString(),
- ReworkFlag = (await intTasks["ReworkFlag"]).ToString(),
- AutoManual = await intTasks["AutoManual"],
- RunStatus = await intTasks["RunStatus"],
- ProductionCycle = await intTasks["ProductionCycle"]
- };
-
- // 空值兜底(保留你的原始逻辑)
- prodData.QualificationFlag ??= "0";
- prodData.ReworkFlag ??= "0";
- prodData.ProductionCycle ??= 0;
-
- // 6. 异步保存数据(非阻塞,提升响应速度)
- _ = Task.Run(() => _plcProductionDataService.AddPlcProductionData(prodData))
- .ContinueWith(t =>
+ if (iSaveRequest == 1)
{
- if (t.IsFaulted)
- {
- // 记录保存失败日志(建议替换为ILogger)
- Console.WriteLine($"PLC({ip})数据保存失败:{t.Exception?.InnerException?.Message}");
- }
- });
+ prodData = await ReadOP070_1DataAsync(plc, ip, plcName);
+ }
+ }
+ else if (plcName == "OP080")
+ {
+ //prodData = await ReadOP080DataAsync(plc, ip);
+ }
- var successMsg = isConnReused ? "生产数据读取成功(复用连接)" : "生产数据读取成功(新建连接)";
+ // 6. 统一空值兜底(避免空引用)
+ if (prodData != null)
+ {
+ prodData.QualificationFlag ??= "0";
+ prodData.ReworkFlag ??= "0";
+ prodData.ProductionCycle ??= 0;
+
+ // 7. 异步保存数据(日志补充PLC名称,便于定位)
+ _ = Task.Run(() => _plcProductionDataService.AddPlcProductionData(prodData))
+ .ContinueWith(t =>
+ {
+ if (t.IsFaulted)
+ {
+ Console.WriteLine($"{plcName}({ip})数据保存失败:{t.Exception?.InnerException?.Message}");
+ }
+ });
+ }
+
+ // 8. 个性化返回消息(区分工位和连接类型)
+ var successMsg = isConnReused
+ ? $"{plcName}生产数据读取成功(复用连接)"
+ : $"{plcName}生产数据读取成功(新建连接)";
return (true, prodData, successMsg);
}
catch (Exception ex)
{
- // 精细化异常日志(便于定位具体PLC故障)
- Console.WriteLine($"PLC({ip})生产数据读取异常:{ex.Message}\n{ex.StackTrace}");
- return (false, null, $"生产数据读取失败:{ex.Message}");
+ // 精细化异常日志(包含PLC名称,快速定位故障)
+ Console.WriteLine($"{plcName}({ip})生产数据读取异常:{ex.Message}\n{ex.StackTrace}");
+ return (false, null, $"{plcName}生产数据读取失败:{ex.Message}");
}
finally
{
- // 7. 资源安全释放(核心:复用连接不释放,仅新建连接释放;必须释放并发信号量)
+ // 资源安全释放(核心:防止死锁/连接泄漏)
if (!isConnReused)
{
ReleasePlcConnection(plc);
}
- _concurrencySemaphore.Release(); // 防止死锁的关键
+ _concurrencySemaphore.Release();
}
}
+ #region 工位专属读取方法(扩展友好,逻辑隔离)
+ ///
+ /// OP070-1专属数据读取(精简版:高效+易读)
+ ///
+ //private async Task ReadOP070_1DataAsync(Plc plc, string ip)
+ //{
+ // // 1. 批量并行读取字符串字段
+ // // 合并并行读取
+ // var (strFields, intFields) = await Task.Run(async () => (
+ // // 字符串字段
+ // (
+ // await ReadPlcStringAsync(plc, _op070_1StringMap["报警信息"].Addr, _op070_1StringMap["报警信息"].Len),
+ // await ReadPlcStringAsync(plc, _op070_1StringMap["产品名称"].Addr, _op070_1StringMap["产品名称"].Len),
+ // await ReadPlcStringAsync(plc, _op070_1StringMap["产品型号"].Addr, _op070_1StringMap["产品型号"].Len),
+ // await ReadPlcStringAsync(plc, _op070_1StringMap["SN_1"].Addr, _op070_1StringMap["SN_1"].Len),
+ // await ReadPlcStringAsync(plc, _op070_1StringMap["SN_2"].Addr, _op070_1StringMap["SN_2"].Len)
+ // ),
+ // // 整数字段
+ // (
+ // await ReadPlcIntAsync(plc, _op070_1IntMap["运行状态"]),
+ // await ReadPlcIntAsync(plc, _op070_1IntMap["设备模式"]),
+ // await ReadPlcIntAsync(plc, _op070_1IntMap["设备在线状态"]),
+ // await ReadPlcIntAsync(plc, _op070_1IntMap["ByPass"]),
+ // await ReadPlcIntAsync(plc, _op070_1IntMap["生产模式"]),
+ // await ReadPlcIntAsync(plc, _op070_1IntMap["托盘号"]),
+ // await ReadPlcIntAsync(plc, _op070_1IntMap["站位结果"])
+ // )
+ // ));
+
+ // // 2.解构字段(保持原有逻辑)
+ // var (alarmMsg, productName, product_model, sn1, product_code) = strFields;
+ // var (runStatus, machineModel, onlineStatus, byPass, produceModel, trayNo, stationResult) = intFields;
+
+ // // 3. 写入保存请求(极简异常防护,不影响主流程)
+ // try { WritePlcValue(plc, _op070_1IntMap["保存请求"], "1"); }
+ // catch (Exception ex) { Console.WriteLine($"OP070-1({ip})写保存请求失败:{ex.Message}"); }
+
+ // // 4. 极简条件计算(一行搞定,易读高效)
+ // var reworkFlag = produceModel == 4 ? "1" : "0"; // 返工标志
+ // string produceModelDesc = produceModel switch // 生产模式映射
+ // {
+ // 1 => "正常模式",
+ // 2 => "清线模式",
+ // 4 => "返工模式",
+ // 8 => "换型模式",
+ // 16 => "预热模式",
+ // _ => $"未知({produceModel})"
+ // };
+
+ // // 5. 构建数据实体(极简空值兜底,逻辑清晰)
+ // return new PlcProductionData
+ // {
+ // //加一个产品型号
+ // PlcIp = ip.Trim(),
+ // OccurTime = DateTime.Now,
+ // LineCode = "line2",
+ // WorkstationCode = "OP070-1",
+ // ProductModel = product_model ?? "",
+ // ProductName = productName ?? "",
+ // ProductCode = product_code,
+ // QualificationFlag = stationResult.ToString(),
+ // ReworkFlag = reworkFlag,
+ // AutoManual = machineModel,
+ // RunStatus = runStatus,
+ // OnlineStatus = onlineStatus.ToString(),
+ // TrayNo = trayNo.ToString(),
+ // ProduceModel = produceModelDesc,
+ // CreatedBy = "PLC",
+ // CreatedTime = DateTime.Now
+ // };
+ //}
+
+ ///
+ /// 优化版OP070-1数据读取(集成增强型PLC读写方法)
+ ///
+ private async Task ReadOP070_1DataAsync(Plc plc, string ip,string workstationCode)
+ {
+ // 1. 批量并行读取所有字段(沿用原有结构+增强型读取方法)
+ var (strFields, intFields, dintFields, realFields) = await Task.Run(async () => (
+ // 字符串字段(增强空值和异常处理)
+ (
+ await ReadPlcStringAsync(plc, _op070_1StringMap["报警信息"].Addr, _op070_1StringMap["报警信息"].Len),
+ await ReadPlcStringAsync(plc, _op070_1StringMap["产品名称"].Addr, _op070_1StringMap["产品名称"].Len),
+ await ReadPlcStringAsync(plc, _op070_1StringMap["产品型号_48"].Addr, _op070_1StringMap["产品型号_48"].Len),
+ await ReadPlcStringAsync(plc, _op070_1StringMap["产品型号_28"].Addr, _op070_1StringMap["产品型号_28"].Len),
+ await ReadPlcStringAsync(plc, _op070_1StringMap["SN_1"].Addr, _op070_1StringMap["SN_1"].Len),
+ await ReadPlcStringAsync(plc, _op070_1StringMap["SN_2"].Addr, _op070_1StringMap["SN_2"].Len)
+ ),
+ // Int字段(使用增强版ReadPlcIntAsync)
+ (
+ await ReadPlcIntAsync(plc, _op070_1IntMap["运行状态"]),
+ await ReadPlcIntAsync(plc, _op070_1IntMap["设备模式"]),
+ await ReadPlcIntAsync(plc, _op070_1IntMap["设备在线状态"]),
+ await ReadPlcIntAsync(plc, _op070_1IntMap["ByPass"]),
+ await ReadPlcIntAsync(plc, _op070_1IntMap["生产模式"]),
+ await ReadPlcIntAsync(plc, _op070_1IntMap["查询请求"]),
+ await ReadPlcIntAsync(plc, _op070_1IntMap["保存请求"]),
+ await ReadPlcIntAsync(plc, _op070_1IntMap["托盘号"]),
+ await ReadPlcIntAsync(plc, _op070_1IntMap["相机结果"]),
+ await ReadPlcIntAsync(plc, _op070_1IntMap["站位结果"])
+ ),
+ // DInt字段(增强版读取方法)
+ (
+ await ReadPlcDIntAsync(plc, _op070_1IntMap["实际产量"]),
+ await ReadPlcDIntAsync(plc, _op070_1IntMap["合格数量"]),
+ await ReadPlcDIntAsync(plc, _op070_1IntMap["失败数量"])
+ ),
+ // Real字段(增强版读取方法)
+ (
+ await ReadPlcRealAsync(plc, _op070_1IntMap["节拍时间"])
+ )
+ ));
+
+ // 2. 解构字段(保持原有逻辑,空值兜底)
+ var (alarmMsg, productName, productModel48, productModel28, sn1, sn2) = strFields;
+ var (runStatus, machineModel, onlineStatus, byPass, produceModel, queryReq, saveReq, trayNo, cameraResult, stationResult) = intFields;
+ var (actualOutput, qualifiedQty, failedQty) = dintFields;
+ float cycleTime = realFields;
+
+ // 3. 写入保存请求(异步+增强异常日志)
+ try { WritePlcValue(plc, _op070_1IntMap["保存请求"], "1"); }
+ catch (Exception ex) { Console.WriteLine($"OP070-1({ip})写保存请求失败:{ex.Message}"); }
+
+ // 4. 极简条件计算(增强类型安全)
+ var reworkFlag = produceModel == 4 ? "1" : "0";
+ string produceModelDesc = produceModel switch
+ {
+ 1 => "正常模式",
+ 2 => "清线模式",
+ 4 => "返工模式",
+ 8 => "换型模式",
+ 16 => "预热模式",
+ _ => $"未知({produceModel})"
+ };
+ string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" };
+ string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线";
+ //string byPassDesc = byPass == 1 ? "旁路模式" : "正常模式";
+ string qualificationFlag = stationResult switch { 1 => "1", 2 => "0", _ => stationResult.ToString() };
+ string cameraResultDesc = cameraResult switch { 1 => "OK", 2 => "NG", _ => $"未知({cameraResult})" };
+
+ // 调试日志:输出关键读取结果
+ Console.WriteLine($"OP070-1({ip})读取结果:产品型号={productModel28 ?? productModel48},运行状态={runStatusDesc},产量={actualOutput}");
+
+ // 5. 构建数据实体(增强空值处理)
+ return new PlcProductionData
+ {
+ PlcIp = ip.Trim(),
+ OccurTime = DateTime.Now,
+ LineCode = "line2",
+ WorkstationCode = workstationCode,
+ ProductModel = productModel28 ?? productModel48 ?? string.Empty,
+ ProductName = productName ?? string.Empty,
+ ProductCode = sn2 ?? string.Empty,
+ SN1 = sn1 ?? string.Empty,
+ SN2 = sn2 ?? string.Empty,
+ QualificationFlag = qualificationFlag,
+ ReworkFlag = reworkFlag,
+ AutoManual = machineModel,
+ RunStatus = runStatus,
+ OnlineStatus = onlineStatusDesc,
+ //ByPass = byPassDesc,
+ ProduceModel = produceModelDesc,
+ TrayNo = trayNo.ToString(),
+ CameraResult = cameraResultDesc,
+ //ActualOutput = actualOutput,
+ //QualifiedQuantity = qualifiedQty,
+ //FailedQuantity = failedQty,
+ ProductionCycle = (int?)cycleTime,
+ //AlarmMsg = alarmMsg ?? string.Empty,
+ CreatedBy = "PLC",
+ CreatedTime = DateTime.Now
+ };
+ }
+
+ #endregion
+
// 可选:添加连接池清理方法(防止长期运行导致连接泄露)
private void CleanupExpiredConnections()
{
@@ -394,25 +646,21 @@ namespace RIZO.Admin.WebApi.PLC.Service
/// 测试结果
public async Task TestSinglePlcAsync(PlcConfig config, CancellationToken cancellationToken = default)
{
- // 参数校验
+ // 1. 极简参数校验(提前返回,减少嵌套)
if (config == null)
throw new ArgumentNullException(nameof(config), "PLC测试配置不能为空");
if (string.IsNullOrWhiteSpace(config.Ip))
return new PlcTestResult { PlcName = config.PlcName, Ip = config.Ip, ConnectSuccess = false, ConnectMessage = "IP地址为空" };
- var result = new PlcTestResult
- {
- PlcName = config.PlcName,
- Ip = config.Ip
- };
-
+ var result = new PlcTestResult { PlcName = config.PlcName, Ip = config.Ip };
Plc plc = null;
+
try
{
- // 初始化PLC客户端
+ // 2. 初始化PLC客户端
plc = CreatePlcClient(CpuType.S71500, config.Ip, config.Rack, config.Slot);
- // 带超时的连接测试
+ // 3. 带超时的连接测试(精简逻辑)
var connectTask = OpenPlcConnectionAsync(plc);
if (await Task.WhenAny(connectTask, Task.Delay(_globalConfig.ReadWriteTimeout, cancellationToken)) != connectTask)
{
@@ -422,41 +670,34 @@ namespace RIZO.Admin.WebApi.PLC.Service
}
await connectTask;
- // 检查连接状态
- if (plc.IsConnected)
- {
- result.ConnectSuccess = true;
- result.ConnectMessage = "连接成功";
- }
- else
+ // 4. 连接状态校验(精简分支)
+ if (!plc.IsConnected)
{
result.ConnectSuccess = false;
result.ConnectMessage = "连接失败(PLC未返回连接状态)";
return result;
}
+ result.ConnectSuccess = true;
+ result.ConnectMessage = "连接成功";
- string TestAddress = "DB1010.DBB238"; // 测试地址
-
- // 读取测试
+ const string TestAddress = "DB1010.DBB238";
if (!string.IsNullOrWhiteSpace(TestAddress))
{
+ // 读取测试
try
{
var readValue = await Task.Run(() => plc.Read(TestAddress), cancellationToken);
result.ReadSuccess = true;
result.ReadValue = FormatPlcValue(readValue);
- result.ReadMessage = "读取成功";
+ result.ReadMessage = "通用地址读取成功";
}
catch (Exception ex)
{
result.ReadSuccess = false;
- result.ReadMessage = $"读取失败:{ex.Message}";
+ result.ReadMessage = $"通用地址读取失败:{ex.Message}";
}
- }
- // 写入测试
- if (!string.IsNullOrWhiteSpace(TestAddress) && !string.IsNullOrWhiteSpace(TestAddress))
- {
+ // 写入测试
try
{
bool writeOk = await Task.Run(() => WritePlcValue(plc, TestAddress, "1"), cancellationToken);
@@ -469,6 +710,30 @@ namespace RIZO.Admin.WebApi.PLC.Service
result.WriteMessage = $"写入失败:{ex.Message}";
}
}
+
+ // 6. OP070-1专属状态读取(删除双层判断+内联转换逻辑)
+ if (config.PlcName == "OP070-1")
+ {
+ try
+ {
+ int runStatus = await ReadPlcIntAsync(plc, _op070_1IntMap["运行状态"]);
+ int machineModel = await ReadPlcIntAsync(plc, _op070_1IntMap["设备模式"]);
+ int onlineStatus = await ReadPlcIntAsync(plc, _op070_1IntMap["设备在线状态"]);
+ int produceModel = await ReadPlcIntAsync(plc, _op070_1IntMap["生产模式"]);
+
+ result.RunStatus = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" };
+ result.MachineModel = machineModel switch { 1 => "空模式", 2 => "手动", 4 => "初始化", 8 => "自动", 16 => "CycleStop", _ => $"未知({machineModel})" };
+ result.OnLineStatus = onlineStatus == 1 ? "离线" : (onlineStatus == 0 ? "在线" : $"未知({onlineStatus})");
+ result.ProduceModel = produceModel switch { 1 => "正常模式", 2 => "清线模式", 4 => "返工模式", 8 => "换型模式", 16 => "预热模式", _ => $"未知({produceModel})" };
+
+ result.ReadMessage = $"{result.ReadMessage}; OP070-1状态读取成功";
+ }
+ catch (Exception ex)
+ {
+ result.RunStatus = result.MachineModel = result.OnLineStatus = result.ProduceModel = "读取失败";
+ result.ReadMessage = $"{result.ReadMessage}; OP070-1状态读取失败:{ex.Message}";
+ }
+ }
}
catch (OperationCanceledException)
{
@@ -617,10 +882,25 @@ namespace RIZO.Admin.WebApi.PLC.Service
///
/// 异步打开PLC连接(封装同步方法为异步)
///
- private async Task OpenPlcConnectionAsync(Plc plc)
+ // 优化后的OpenPlcConnectionAsync
+ private async Task OpenPlcConnectionAsync(Plc plc)
{
- if (plc == null) return;
- await Task.Run(() => plc.Open());
+ if (plc == null) return false;
+ try
+ {
+ // 带超时的连接操作
+ var openTask = Task.Run(() => plc.Open());
+ if (await Task.WhenAny(openTask, Task.Delay(_globalConfig.ReadWriteTimeout)) != openTask)
+ {
+ return false;
+ }
+ await openTask;
+ return plc.IsConnected;
+ }
+ catch
+ {
+ return false;
+ }
}
///
@@ -736,7 +1016,58 @@ namespace RIZO.Admin.WebApi.PLC.Service
return 0;
}
}
+ private async Task ReadPlcDIntAsync(Plc plc, string addr)
+ {
+ if (plc == null || string.IsNullOrWhiteSpace(addr))
+ {
+ Console.WriteLine($"DInt读取失败:参数无效(地址:{addr})");
+ return 0;
+ }
+ try
+ {
+ var val = await Task.Run(() => plc.Read(addr));
+ Console.WriteLine($"DInt地址[{addr}] 原始值:{val},类型:{val?.GetType().Name}");
+ return val switch
+ {
+ int i => i,
+ long l => (int)l,
+ uint ui => (int)ui,
+ ulong ul => (int)ul,
+ _ => 0
+ };
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"DInt读取失败(地址:{addr}):{ex.Message}");
+ return 0;
+ }
+ }
+ private async Task ReadPlcRealAsync(Plc plc, string addr)
+ {
+ if (plc == null || string.IsNullOrWhiteSpace(addr))
+ {
+ Console.WriteLine($"Real读取失败:参数无效(地址:{addr})");
+ return 0.0f;
+ }
+ try
+ {
+ var val = await Task.Run(() => plc.Read(addr));
+ Console.WriteLine($"Real地址[{addr}] 原始值:{val},类型:{val?.GetType().Name}");
+ return val switch
+ {
+ float f => f,
+ double d => (float)d,
+ int i => i,
+ _ => 0.0f
+ };
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Real读取失败(地址:{addr}):{ex.Message}");
+ return 0.0f;
+ }
+ }
///
/// 格式化PLC读取的值,转为友好的字符串
///
diff --git a/RIZO.Service/MES/alarm/AlarmInfoService.cs b/RIZO.Service/MES/alarm/AlarmInfoService.cs
index 61f0450..ce93c72 100644
--- a/RIZO.Service/MES/alarm/AlarmInfoService.cs
+++ b/RIZO.Service/MES/alarm/AlarmInfoService.cs
@@ -50,6 +50,7 @@ namespace RIZO.Service.MES.alarm
///
///
public AlarmInfo AddAlarmInfo(AlarmInfo model)
+
{
return Insertable(model).ExecuteReturnEntity();
}