修复Log不显示的问题,重构了S7BackgroundService中的读取变量的方法
This commit is contained in:
11
App.xaml.cs
11
App.xaml.cs
@@ -28,8 +28,14 @@ public partial class App : Application
|
|||||||
public App()
|
public App()
|
||||||
{
|
{
|
||||||
Host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder()
|
Host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder()
|
||||||
.ConfigureServices((context, services) => { ConfigureServices(services); })
|
.ConfigureServices((context, services) =>
|
||||||
.ConfigureLogging(loggingBuilder => { ConfigureLogging(loggingBuilder); })
|
{
|
||||||
|
ConfigureServices(services);
|
||||||
|
})
|
||||||
|
.ConfigureLogging(loggingBuilder =>
|
||||||
|
{
|
||||||
|
ConfigureLogging(loggingBuilder);
|
||||||
|
})
|
||||||
.Build();
|
.Build();
|
||||||
Services = Host.Services;
|
Services = Host.Services;
|
||||||
}
|
}
|
||||||
@@ -85,6 +91,7 @@ public partial class App : Application
|
|||||||
|
|
||||||
private void ConfigureLogging(ILoggingBuilder loggingBuilder)
|
private void ConfigureLogging(ILoggingBuilder loggingBuilder)
|
||||||
{
|
{
|
||||||
|
LogManager.Setup().LoadConfigurationFromFile("Config/nlog.config");
|
||||||
loggingBuilder.ClearProviders();
|
loggingBuilder.ClearProviders();
|
||||||
loggingBuilder.SetMinimumLevel(LogLevel.Trace);
|
loggingBuilder.SetMinimumLevel(LogLevel.Trace);
|
||||||
loggingBuilder.AddNLog();
|
loggingBuilder.AddNLog();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -66,6 +67,51 @@ namespace PMSWPF.Services
|
|||||||
_logger.LogInformation("S7 Background Service has stopped.");
|
_logger.LogInformation("S7 Background Service has stopped.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化或重新连接PLC客户端
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">S7设备</param>
|
||||||
|
/// <returns>连接成功的Plc客户端实例,如果连接失败则返回null</returns>
|
||||||
|
private async Task<Plc?> InitializePlcClient(Device device)
|
||||||
|
{
|
||||||
|
// 检查字典中是否已存在该设备的PLC客户端
|
||||||
|
if (!_s7PlcClients.TryGetValue(device.Id, out var plcClient))
|
||||||
|
{
|
||||||
|
// 如果不存在,则创建新的Plc客户端
|
||||||
|
try
|
||||||
|
{
|
||||||
|
plcClient = new Plc(device.CpuType, device.Ip, (short)device.Prot, device.Rack, device.Slot);
|
||||||
|
await plcClient.OpenAsync(); // 尝试打开连接
|
||||||
|
_s7PlcClients[device.Id] = plcClient; // 将新创建的客户端添加到字典
|
||||||
|
_logger.LogInformation($"已连接到S7 PLC: {device.Name} ({device.Ip})");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"连接S7 PLC失败: {device.Name} ({device.Ip})");
|
||||||
|
return null; // 连接失败,返回null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!plcClient.IsConnected)
|
||||||
|
{
|
||||||
|
// 如果存在但未连接,则尝试重新连接
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await plcClient.OpenAsync(); // 尝试重新打开连接
|
||||||
|
_logger.LogInformation($"已重新连接到S7 PLC: {device.Name} ({device.Ip})");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"重新连接S7 PLC失败: {device.Name} ({device.Ip})");
|
||||||
|
return null; // 重新连接失败,返回null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return plcClient; // 返回连接成功的Plc客户端
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 轮询S7设备数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stoppingToken">取消令牌</param>
|
||||||
private async Task PollS7Devices(CancellationToken stoppingToken)
|
private async Task PollS7Devices(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
if (_s7Devices == null || !_s7Devices.Any())
|
if (_s7Devices == null || !_s7Devices.Any())
|
||||||
@@ -78,98 +124,72 @@ namespace PMSWPF.Services
|
|||||||
{
|
{
|
||||||
if (stoppingToken.IsCancellationRequested) return;
|
if (stoppingToken.IsCancellationRequested) return;
|
||||||
|
|
||||||
if (!_s7PlcClients.ContainsKey(device.Id))
|
// 尝试获取或初始化PLC客户端连接
|
||||||
|
var plcClient = await InitializePlcClient(device);
|
||||||
|
if (plcClient == null)
|
||||||
{
|
{
|
||||||
// Initialize Plc client for the device
|
continue; // 如果连接失败,则跳过当前设备
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 读取设备变量
|
||||||
|
await ReadDeviceVariables(plcClient, device, stoppingToken);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 读取设备的S7变量并更新其值。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="plcClient">已连接的Plc客户端实例。</param>
|
||||||
|
/// <param name="device">S7设备。</param>
|
||||||
|
/// <param name="stoppingToken">取消令牌。</param>
|
||||||
|
private async Task ReadDeviceVariables(Plc plcClient, Device device, CancellationToken stoppingToken)
|
||||||
|
{
|
||||||
|
// 过滤出当前设备和S7协议相关的变量
|
||||||
|
var s7Variables = device.VariableTables
|
||||||
|
.Where(vt => vt.ProtocolType == ProtocolType.S7 && vt.IsActive)
|
||||||
|
.SelectMany(vt => vt.DataVariables)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (!s7Variables.Any())
|
||||||
|
{
|
||||||
|
_logger.LogDebug($"设备 {device.Name} 没有找到活跃的S7变量。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
|
// 遍历并读取每个S7变量
|
||||||
|
foreach (var variable in s7Variables)
|
||||||
|
{
|
||||||
|
if (stoppingToken.IsCancellationRequested) return; // 如果取消令牌被请求,则停止读取
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var plc = new Plc(device.CpuType, device.Ip, (short)device.Prot, device.Rack, device.Slot);
|
// 从PLC读取变量值
|
||||||
await plc.OpenAsync();
|
var value = await plcClient.ReadAsync(variable.S7Address);
|
||||||
_s7PlcClients[device.Id] = plc;
|
if (value != null)
|
||||||
_logger.LogInformation($"Connected to S7 PLC: {device.Name} ({device.Ip})");
|
{
|
||||||
|
// 更新变量的原始数据值和显示值
|
||||||
|
variable.DataValue = value.ToString();
|
||||||
|
variable.DisplayValue = SiemensHelper.ConvertS7Value(value, variable.DataType, variable.Converstion);
|
||||||
|
// _logger.LogDebug($"已读取变量 {variable.Name}: {variable.DataValue}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, $"Failed to connect to S7 PLC: {device.Name} ({device.Ip})");
|
_logger.LogError(ex, $"从设备 {device.Name} 读取变量 {variable.Name} 失败。");
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var plcClient = _s7PlcClients[device.Id];
|
sw.Stop();
|
||||||
if (!plcClient.IsConnected)
|
_logger.LogInformation($"从: {device.Name} ({device.Ip})读取变量总耗时:{sw.ElapsedMilliseconds}ms");
|
||||||
{
|
}
|
||||||
try
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await plcClient.OpenAsync();
|
_logger.LogError(ex, $"设备 {device.Name} 批量读取过程中发生错误。");
|
||||||
_logger.LogInformation($"Reconnected to S7 PLC: {device.Name} ({device.Ip})");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, $"Failed to reconnect to S7 PLC: {device.Name} ({device.Ip})");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter variables for the current device and S7 protocol
|
|
||||||
var s7VariablesTemp = device
|
|
||||||
.VariableTables.Where(vd => vd.ProtocolType == ProtocolType.S7 && vd.IsActive)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var s7Variables = s7VariablesTemp.SelectMany(vt => vt.DataVariables)
|
|
||||||
.ToList();
|
|
||||||
// ?.SelectMany(vt => vt.DataVariables)
|
|
||||||
|
|
||||||
|
|
||||||
if (s7Variables == null || !s7Variables.Any())
|
|
||||||
{
|
|
||||||
_logger.LogDebug($"No active S7 variables found for device: {device.Name}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Batch read variables
|
|
||||||
var addressesToRead = s7Variables.Select(vd => vd.S7Address)
|
|
||||||
.ToList();
|
|
||||||
if (!addressesToRead.Any()) continue;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// S7.Net.Plus library supports ReadMultiple, but it's more complex for different data types.
|
|
||||||
// For simplicity, we'll read them one by one for now, or use a more advanced batch read if all are same type.
|
|
||||||
// A more robust solution would involve grouping by data block and type.
|
|
||||||
|
|
||||||
// Example of reading multiple items (assuming all are of type DWord for simplicity)
|
|
||||||
// This part needs to be refined based on actual variable types and addresses
|
|
||||||
// var dataItems = addressesToRead.Select(addr => new DataItem { DataType = DataType.DataBlock, VarType = VarType.DWord, StringLength = 1, DB = 1, StartByteAdr = 0 }).ToList();
|
|
||||||
// plcClient.ReadMultiple(dataItems);
|
|
||||||
|
|
||||||
foreach (var variable in s7Variables)
|
|
||||||
{
|
|
||||||
if (stoppingToken.IsCancellationRequested) return;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// This is a simplified read. In a real scenario, you'd parse S7Address
|
|
||||||
// to get DataType, DB, StartByteAdr, BitAdr, etc.
|
|
||||||
// For now, assuming S7Address is directly readable by Read method (e.g., "DB1.DBW0")
|
|
||||||
var value = await plcClient.ReadAsync(variable.S7Address);
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
// Update the variable's DataValue and DisplayValue
|
|
||||||
variable.DataValue = value.ToString();
|
|
||||||
variable.DisplayValue
|
|
||||||
= SiemensHelper.ConvertS7Value(value, variable.DataType, variable.Converstion);
|
|
||||||
_logger.LogDebug($"Read {variable.Name}: {variable.DataValue}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, $"Failed to read variable {variable.Name} from {device.Name}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, $"Error during batch read for device {device.Name}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user