From a513d58aab97aa54ae59d4587da1d897f5b0eab9 Mon Sep 17 00:00:00 2001 From: quowingwang Date: Tue, 6 Jan 2026 08:49:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Helper/ModbusTcpClientHelper.cs | 4 + ZR.Admin.WebApi/Program.cs | 33 +++- .../background/SocketBackgroundService.cs | 73 +++++++- ZR.Service/Utils/MyAlarmLigth/LightUp.cs | 10 +- .../Utils/MyAlarmLigth/TiaoQiFangLight.cs | 168 ++++++++++++++++++ ZR.Service/ZR.Service.csproj | 1 + .../mes/andon/AndonAlarmRecordService.cs | 49 +++-- .../mes/andon/ScheduledBackgroundService.cs | 16 +- 8 files changed, 316 insertions(+), 38 deletions(-) create mode 100644 ZR.Service/Utils/MyAlarmLigth/TiaoQiFangLight.cs diff --git a/Infrastructure/Helper/ModbusTcpClientHelper.cs b/Infrastructure/Helper/ModbusTcpClientHelper.cs index 73d1f87e..0610361d 100644 --- a/Infrastructure/Helper/ModbusTcpClientHelper.cs +++ b/Infrastructure/Helper/ModbusTcpClientHelper.cs @@ -451,4 +451,8 @@ namespace Infrastructure.Helper } #endregion } + + // ===== 新增这两行 ===== + public class ThreeColorLightModbus : ModbusTcpClientHelper { } + public class AlarmLightModbus : ModbusTcpClientHelper { } } diff --git a/ZR.Admin.WebApi/Program.cs b/ZR.Admin.WebApi/Program.cs index 668d5a83..c3a8a2d6 100644 --- a/ZR.Admin.WebApi/Program.cs +++ b/ZR.Admin.WebApi/Program.cs @@ -3,6 +3,7 @@ using Infrastructure.Helper; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; using System.Text.Json.Serialization; using ZR.Admin.WebApi.AutoMapperProfile; @@ -16,11 +17,12 @@ using ZR.Common.Cache; using ZR.Common.MqttHelper; using ZR.Service.mes.andon; using ZR.Service.mqtt; +using ZR.Service.Utils.MyAlarmLigth; var builder = WebApplication.CreateBuilder(args); //后台定时任务 -//builder.Services.AddHostedService(); -//builder.Services.AddHostedService(); +builder.Services.AddHostedService(); +builder.Services.AddHostedService(); // Add services to the container. @@ -127,15 +129,36 @@ builder.Services.AddSingleton(provider => return server; }); //三色灯网关IP配置 -builder.Services.AddSingleton(provider => +builder.Services.AddSingleton(provider => { - var modbus = new ModbusTcpClientHelper(); + var modbus = new ThreeColorLightModbus(); - modbus.Connect("192.168.1.200", 9999); // 你可以按需修改 IP 和端口 + modbus.Connect("192.168.60.200", 9999); // 你可以按需修改 IP 和端口 return modbus; }); +//调漆房报警灯开关IP配置 +builder.Services.AddSingleton(provider => +{ + var modbus = new AlarmLightModbus(); + + modbus.Connect("192.168.60.105", 10001); // 你可以按需修改 IP 和端口 + + + return modbus; +}); +// 2. 注册调漆房灯控监听类 +builder.Services.AddSingleton(provider => +{ + var modbusClient = provider.GetRequiredService(); + var logger = provider.GetRequiredService>(); + var lightListener = new TiaoQiFangLight(modbusClient, logger); + + // 程序启动时自动启动监听 + lightListener.StartListen(); + return lightListener; +}); var app = builder.Build(); InternalApp.ServiceProvider = app.Services; InternalApp.Configuration = builder.Configuration; diff --git a/ZR.Admin.WebApi/background/SocketBackgroundService.cs b/ZR.Admin.WebApi/background/SocketBackgroundService.cs index c4dab804..1732a968 100644 --- a/ZR.Admin.WebApi/background/SocketBackgroundService.cs +++ b/ZR.Admin.WebApi/background/SocketBackgroundService.cs @@ -3,20 +3,34 @@ using DOAN.ServiceCore.MyMatchPush; using Infrastructure; using Infrastructure.Helper; using Microsoft.Extensions.Logging; +using System.Net.Sockets; namespace ZR.Admin.WebApi.background { public class SocketBackgroundService : BackgroundService { private readonly SocketGatewayServer _socketGateway; - private readonly ModbusTcpClientHelper _modbusClient; + //private readonly ModbusTcpClientHelper _modbusClient; private readonly ILogger _logger; + // 直接注入包装类(无需IServiceProvider,无需命名) + private readonly ThreeColorLightModbus _threeColorLightModbus; + private readonly AlarmLightModbus _alarmLightModbus; - public SocketBackgroundService(SocketGatewayServer socketGateway, ILogger logger, ModbusTcpClientHelper modbusClient) + //public SocketBackgroundService(SocketGatewayServer socketGateway, ILogger logger, ModbusTcpClientHelper modbusClient) + //{ + // _socketGateway = socketGateway; + // _logger = logger; + // _modbusClient = modbusClient; + //} + + public SocketBackgroundService( SocketGatewayServer socketGateway,ILogger logger, + ThreeColorLightModbus threeColorLightModbus, // 三色灯实例 + AlarmLightModbus alarmLightModbus) // 调漆房实例 { _socketGateway = socketGateway; _logger = logger; - _modbusClient = modbusClient; + _threeColorLightModbus = threeColorLightModbus; + _alarmLightModbus = alarmLightModbus; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) @@ -31,6 +45,7 @@ namespace ZR.Admin.WebApi.background var result = Watchup.StartPush("测试Socket推送功能", _socketGateway, strWatchAddress); _logger.LogInformation($"Socket推送测试结果: {result}"); //TestLight(); + TestTiaoQiIOModel(); } catch (Exception ex) { @@ -38,6 +53,55 @@ namespace ZR.Admin.WebApi.background } } + /// + /// 仅测试与调漆房IO模块的通讯连通性) + /// + private void TestTiaoQiIOModel() + { + // 仅保留通用配置,IP/端口不再硬编码(复用注入的_modbusClient的配置) + const byte MODBUS_SLAVE_ID = 0x01; // 从站地址(模块默认1) + const int TIMEOUT_LOG_THRESHOLD = 2000; // 超时阈值:2秒 + + try + { + var startTime = DateTime.Now; + bool isCommSuccess = false; + + // 尝试读取1个离散输入寄存器(DI,功能码02)- 最简指令,不易出错 + try + { + //List testValues = _modbusClient.ReadInputRegisters(MODBUS_SLAVE_ID, 0x0000, 1); + List testValues = _alarmLightModbus.ReadInputRegisters(MODBUS_SLAVE_ID, 0x0000, 1); + + var costTime = (DateTime.Now - startTime).TotalMilliseconds; + + // 指令返回非空即代表协议层通讯成功 + if (testValues != null && testValues.Count == 1) + { + isCommSuccess = true; + _logger.LogInformation($"✅ IO模块通讯通讯测试成功!"); + } + else + { + _logger.LogError($"❌ 通讯测试失败:MODBUS指令返回空/数量不匹配"); + } + } + catch (Exception cmdEx) + { + _logger.LogError(cmdEx, $"❌ 通讯测试失败:MODBUS指令执行异常"); + } + } + catch (SocketException ex) + { + _logger.LogError(ex, $"❌ TCP连接失败:IP/端口错误/模块离线/网段不一致"); + } + catch (Exception ex) + { + _logger.LogError(ex, $"❌ IO模块通讯测试异常(非TCP层面)"); + } + } + + private void TestLight() { // 2. 定义要读取的寄存器信息(根据您的表格) @@ -47,7 +111,8 @@ namespace ZR.Admin.WebApi.background // 3. PLC 下发读指令并获取原始寄存器值列表 Console.WriteLine($"正在读取从站 {UNIT_ID} 的寄存器 {startAddress} 开始的 {numberOfRegisters} 个寄存器..."); - List registerValues = _modbusClient.ReadHoldingRegisters(UNIT_ID, startAddress, numberOfRegisters); + //List registerValues = _modbusClient.ReadHoldingRegisters(UNIT_ID, startAddress, numberOfRegisters); + List registerValues = _alarmLightModbus.ReadHoldingRegisters(UNIT_ID, startAddress, numberOfRegisters); // 4. 解析警灯返回指令(即解析读取到的寄存器值) if (registerValues.Count == numberOfRegisters) diff --git a/ZR.Service/Utils/MyAlarmLigth/LightUp.cs b/ZR.Service/Utils/MyAlarmLigth/LightUp.cs index f09ec2ce..aadc8593 100644 --- a/ZR.Service/Utils/MyAlarmLigth/LightUp.cs +++ b/ZR.Service/Utils/MyAlarmLigth/LightUp.cs @@ -19,7 +19,7 @@ namespace ZR.Service.Utils.MyAlarmLigth /// 0 没有解析出来 /// 其他 解析出来设备站号 - public static ushort ReadAlarmlightNumber(ModbusTcpClientHelper _modbusClient) + public static ushort ReadAlarmlightNumber(ThreeColorLightModbus _modbusClient) { // 2. 定义要读取的寄存器信息(根据您的表格) @@ -49,7 +49,7 @@ namespace ZR.Service.Utils.MyAlarmLigth /// 警灯站号 /// /// - public static void WriteAlarmLightCommand_Red(ModbusTcpClientHelper _modbusClient, byte unitId ) + public static void WriteAlarmLightCommand_Red(ThreeColorLightModbus _modbusClient, byte unitId ) { ushort startAddress = 0x0000; // 起始地址,对应 ushort numberOfRegisters = 0x000B; // 要读取的寄存器数量 (40001 到 40012) @@ -66,7 +66,7 @@ namespace ZR.Service.Utils.MyAlarmLigth /// 警灯站号 /// /// - public static void WriteAlarmLightCommand_Yellow(ModbusTcpClientHelper _modbusClient, byte unitId) + public static void WriteAlarmLightCommand_Yellow(ThreeColorLightModbus _modbusClient, byte unitId) { ushort startAddress = 0x0000; // 起始地址,对应 ushort numberOfRegisters = 0x000B; // 要读取的寄存器数量 (40001 到 40012) @@ -84,7 +84,7 @@ namespace ZR.Service.Utils.MyAlarmLigth /// 警灯站号 /// /// - public static void WriteAlarmLightCommand_Normal(ModbusTcpClientHelper _modbusClient, byte unitId) + public static void WriteAlarmLightCommand_Normal(ThreeColorLightModbus _modbusClient, byte unitId) { ushort startAddress = 0x0000; // 起始地址,对应 ushort numberOfRegisters = 0x000B; // 要读取的寄存器数量 (40001 到 40012) @@ -99,7 +99,7 @@ namespace ZR.Service.Utils.MyAlarmLigth /// /// Modbus客户端 /// 警灯站号(不传则自动读取) - public static void CheckLightOnStatusAndTurnOn(ModbusTcpClientHelper _modbusClient, byte unitId) + public static void CheckLightOnStatusAndTurnOn(ThreeColorLightModbus _modbusClient, byte unitId) { ushort startAddress = 0x0000; // 起始地址,对应 ushort numberOfRegisters = 0x000B; // 要读取的寄存器数量 (40001 到 40012) diff --git a/ZR.Service/Utils/MyAlarmLigth/TiaoQiFangLight.cs b/ZR.Service/Utils/MyAlarmLigth/TiaoQiFangLight.cs new file mode 100644 index 00000000..c3da8c9e --- /dev/null +++ b/ZR.Service/Utils/MyAlarmLigth/TiaoQiFangLight.cs @@ -0,0 +1,168 @@ +using Infrastructure.Helper; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace ZR.Service.Utils.MyAlarmLigth +{ + /// + /// 调漆房IO端口监听+灯控类(X1-X8监听 → 触发对应灯控方法) + /// + public class TiaoQiFangLight : IDisposable + { + // 核心配置(仅保留必要参数,对齐测试代码风格) + private const byte MODBUS_SLAVE_ID = 0x01; + private const ushort DI_START_ADDR = 0x0000; + private const int POLLING_INTERVAL_MS = 200; + private const int DI_COUNT = 8; + + // 依赖注入(仅保留核心依赖) + private readonly ModbusTcpClientHelper _modbusClient; + private readonly ILogger _logger; + + // 状态缓存+监听控制(精简命名) + private readonly bool[] _lastDiState = new bool[DI_COUNT]; + private CancellationTokenSource _cts; + private Task _listenTask; + + /// + /// 构造函数(精简参数,日志可选) + /// + public TiaoQiFangLight(ModbusTcpClientHelper modbusClient, ILogger logger = null) + { + _modbusClient = modbusClient; + _logger = logger; + Array.Fill(_lastDiState, false); // 初始化未按下 + } + + /// + /// 启动监听(精简逻辑,无冗余判断) + /// + public void StartListen() + { + if (_listenTask?.IsCompleted == false) + { + _logger?.LogWarning("调漆房IO监听已启动,无需重复执行"); + return; + } + + _cts = new CancellationTokenSource(); + _listenTask = Task.Run(() => ListenDiLoop(_cts.Token), _cts.Token); + _logger?.LogInformation($"✅ 启动X1-X8监听(轮询间隔:{POLLING_INTERVAL_MS}ms)"); + } + + /// + /// 停止监听(精简释放逻辑) + /// + public void StopListen() + { + if (_cts == null) return; + + _cts.Cancel(); + _listenTask?.Wait(1000); + _logger?.LogInformation("❌ 停止X1-X8监听"); + } + + /// + /// 核心:轮询监听DI状态(精简循环逻辑,对齐测试代码异常处理) + /// + private async Task ListenDiLoop(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + try + { + // 1. 读取X1-X8状态(对齐测试代码的ReadInputRegisters写法) + List diValues = _modbusClient.ReadInputRegisters(MODBUS_SLAVE_ID, DI_START_ADDR, DI_COUNT); + + // 2. 结果校验(精简判断逻辑) + if (diValues == null || diValues.Count != DI_COUNT) + { + _logger?.LogError($"❌ 读取X1-X8失败:返回值数量异常(预期{DI_COUNT}个,实际{diValues?.Count ?? 0}个)"); + await Task.Delay(POLLING_INTERVAL_MS, cancellationToken); + continue; + } + + // 3. 检测状态变化(精简遍历逻辑) + for (int i = 0; i < DI_COUNT; i++) + { + bool isPressed = diValues[i] == 1; + string portName = $"X{i + 1}"; + + // 仅“从未按下→按下”时触发(精简条件判断) + if (isPressed && !_lastDiState[i]) + { + _logger?.LogInformation($"📌 检测到{portName}按下,触发灯控方法"); + TriggerLightMethod(i + 1); // X1=1,直接传端口号 + } + + _lastDiState[i] = isPressed; // 更新缓存 + } + } + // 分类捕获异常(对齐测试代码的异常分类) + catch (Exception cmdEx) + { + _logger?.LogError(cmdEx, $"❌ 读取DI状态异常"); + } + + await Task.Delay(POLLING_INTERVAL_MS, cancellationToken); + } + } + + /// + /// 触发灯控方法(精简逻辑,仅保留核心映射) + /// + private void TriggerLightMethod(int portNumber) + { + byte lightUnitId = 0x01; // 警灯站号(可按需替换为ReadAlarmlightNumber) + try + { + switch (portNumber) + { + // X1-X4 → 红灯 + case 1: + _logger?.LogInformation($"✅ X{portNumber}触发:红灯闪烁"); + break; + case 2: + _logger?.LogInformation($"✅ X{portNumber}触发:红灯闪烁"); + break; + case 3: + _logger?.LogInformation($"✅ X{portNumber}触发:红灯闪烁"); + break; + case 4: + _logger?.LogInformation($"✅ X{portNumber}触发:红灯闪烁"); + break; + // X5 → 绿灯 + case 5: + _logger?.LogInformation($"✅ X{portNumber}触发:绿灯常亮"); + break; + // X6-X8 → 黄灯(精简默认逻辑) + case 6: + _logger?.LogInformation($"✅ X{portNumber}触发:黄灯常亮"); + break; + case 7: + _logger?.LogInformation($"✅ X{portNumber}触发:黄灯常亮"); + break; + case 8: + _logger?.LogInformation($"✅ X{portNumber}触发:黄灯常亮"); + break; + } + } + catch (Exception ex) + { + _logger?.LogError(ex, $"❌ X{portNumber}触发灯控方法失败"); + } + } + + /// + /// 释放资源(精简Dispose) + /// + public void Dispose() + { + StopListen(); + _cts?.Dispose(); + } + } +} \ No newline at end of file diff --git a/ZR.Service/ZR.Service.csproj b/ZR.Service/ZR.Service.csproj index 04f88932..79aa4f83 100644 --- a/ZR.Service/ZR.Service.csproj +++ b/ZR.Service/ZR.Service.csproj @@ -4,6 +4,7 @@ net7.0 + diff --git a/ZR.Service/mes/andon/AndonAlarmRecordService.cs b/ZR.Service/mes/andon/AndonAlarmRecordService.cs index 29477d87..563f926d 100644 --- a/ZR.Service/mes/andon/AndonAlarmRecordService.cs +++ b/ZR.Service/mes/andon/AndonAlarmRecordService.cs @@ -29,11 +29,18 @@ namespace ZR.Service.mes.andon private AndonAlarmRecordProcessService andonAlarmRecordProcessService = new AndonAlarmRecordProcessService(); private AndonAlarmTypeDictService andonAlarmTypeDictService = new AndonAlarmTypeDictService(); private SocketGatewayServer _socketGateway = null; - private readonly ModbusTcpClientHelper _modbusClient; + //private readonly ModbusTcpClientHelper _modbusClient; + private readonly ThreeColorLightModbus _modbusClient; private AndonAlarmAreaLightDicService andonAlarmAreaLightDicService = new AndonAlarmAreaLightDicService(); private AndonAlarmReceiverWatchDicService andonAlarmReceiverWatchDicService = new AndonAlarmReceiverWatchDicService(); - public AndonAlarmRecordService(SocketGatewayServer socketGateway, ModbusTcpClientHelper modbusClient) + //public AndonAlarmRecordService(SocketGatewayServer socketGateway, ModbusTcpClientHelper modbusClient) + //{ + // _socketGateway = socketGateway; + // _modbusClient = modbusClient; + //} + + public AndonAlarmRecordService(SocketGatewayServer socketGateway, ThreeColorLightModbus modbusClient) { _socketGateway = socketGateway; _modbusClient = modbusClient; @@ -637,22 +644,28 @@ namespace ZR.Service.mes.andon } public ApiResult InitAlarmLightStates() - { - var lights = andonAlarmAreaLightDicService.GetList(); - if (lights.Any()) - { - foreach (var item in lights) - { - if (!string.IsNullOrEmpty(item.Lightip)) - { - byte bLightIp = Convert.ToByte(item.Lightip); - if (bLightIp != 0) - { - LightUp.CheckLightOnStatusAndTurnOn(_modbusClient, bLightIp); - } - } - } - } + { + //var lights = andonAlarmAreaLightDicService.GetList(); + //if (lights.Any()) + //{ + // foreach (var item in lights) + // { + // if (!string.IsNullOrEmpty(item.Lightip)) + // { + // byte bLightIp = Convert.ToByte(item.Lightip); + // if (bLightIp != 0) + // { + // LightUp.CheckLightOnStatusAndTurnOn(_modbusClient, bLightIp); + // } + // } + // } + //} + LightUp.CheckLightOnStatusAndTurnOn(_modbusClient, Convert.ToByte(14)); + LightUp.CheckLightOnStatusAndTurnOn(_modbusClient, Convert.ToByte(08)); + LightUp.CheckLightOnStatusAndTurnOn(_modbusClient, Convert.ToByte(07)); + LightUp.CheckLightOnStatusAndTurnOn(_modbusClient, Convert.ToByte(13)); + LightUp.CheckLightOnStatusAndTurnOn(_modbusClient, Convert.ToByte(04)); + LightUp.CheckLightOnStatusAndTurnOn(_modbusClient, Convert.ToByte(15)); return ApiResult.Success("处理成功"); } } diff --git a/ZR.Service/mes/andon/ScheduledBackgroundService.cs b/ZR.Service/mes/andon/ScheduledBackgroundService.cs index 67619066..9923508d 100644 --- a/ZR.Service/mes/andon/ScheduledBackgroundService.cs +++ b/ZR.Service/mes/andon/ScheduledBackgroundService.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Aliyun.OSS; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System; @@ -46,11 +47,14 @@ namespace ZR.Service.mes.andon // 执行报警信息自动超时上报逻辑 var result = alarmService.AlarmReportAuto(); // - if (lightAutoCount < 4) - { - var result2 = alarmService.InitAlarmLightStates(); - lightAutoCount++; - } + //if (lightAutoCount < 4) + //if(true) + //{ + // var result2 = alarmService.InitAlarmLightStates(); + // lightAutoCount++; + //} + + var result2 = alarmService.InitAlarmLightStates(); _logger.LogInformation($"定时任务执行完成,结果:{result.Msg}"); } _logger.LogInformation($"定时任务完成");