2025-12-20 13:23:44 +08:00
|
|
|
|
|
|
|
|
|
|
using DOAN.ServiceCore.MyMatchPush;
|
|
|
|
|
|
using Infrastructure;
|
2025-12-23 09:17:36 +08:00
|
|
|
|
using Infrastructure.Helper;
|
2025-12-20 13:23:44 +08:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2026-01-06 08:49:12 +08:00
|
|
|
|
using System.Net.Sockets;
|
2025-12-20 13:23:44 +08:00
|
|
|
|
|
|
|
|
|
|
namespace ZR.Admin.WebApi.background
|
|
|
|
|
|
{
|
|
|
|
|
|
public class SocketBackgroundService : BackgroundService
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly SocketGatewayServer _socketGateway;
|
2026-01-06 08:49:12 +08:00
|
|
|
|
//private readonly ModbusTcpClientHelper _modbusClient;
|
2025-12-20 13:23:44 +08:00
|
|
|
|
private readonly ILogger<SocketBackgroundService> _logger;
|
2026-01-06 08:49:12 +08:00
|
|
|
|
// 直接注入包装类(无需IServiceProvider,无需命名)
|
|
|
|
|
|
private readonly ThreeColorLightModbus _threeColorLightModbus;
|
|
|
|
|
|
private readonly AlarmLightModbus _alarmLightModbus;
|
2025-12-20 13:23:44 +08:00
|
|
|
|
|
2026-01-06 08:49:12 +08:00
|
|
|
|
//public SocketBackgroundService(SocketGatewayServer socketGateway, ILogger<SocketBackgroundService> logger, ModbusTcpClientHelper modbusClient)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// _socketGateway = socketGateway;
|
|
|
|
|
|
// _logger = logger;
|
|
|
|
|
|
// _modbusClient = modbusClient;
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
public SocketBackgroundService( SocketGatewayServer socketGateway,ILogger<SocketBackgroundService> logger,
|
|
|
|
|
|
ThreeColorLightModbus threeColorLightModbus, // 三色灯实例
|
|
|
|
|
|
AlarmLightModbus alarmLightModbus) // 调漆房实例
|
2025-12-20 13:23:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
_socketGateway = socketGateway;
|
|
|
|
|
|
_logger = logger;
|
2026-01-06 08:49:12 +08:00
|
|
|
|
_threeColorLightModbus = threeColorLightModbus;
|
|
|
|
|
|
_alarmLightModbus = alarmLightModbus;
|
2025-12-20 13:23:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 等待服务完全启动
|
|
|
|
|
|
await Task.Delay(1000, stoppingToken);
|
2025-12-23 09:17:36 +08:00
|
|
|
|
|
2025-12-20 13:23:44 +08:00
|
|
|
|
// 测试Socket推送功能
|
2026-01-08 10:57:12 +08:00
|
|
|
|
//string strWatchAddress = "181-127-162-058";
|
|
|
|
|
|
//var result = Watchup.StartPush("测试Socket推送功能", _socketGateway, strWatchAddress);
|
|
|
|
|
|
//_logger.LogInformation($"Socket推送测试结果: {result}");
|
2025-12-24 14:26:46 +08:00
|
|
|
|
//TestLight();
|
2026-01-06 08:49:12 +08:00
|
|
|
|
TestTiaoQiIOModel();
|
2025-12-20 13:23:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError(ex, "Socket推送测试失败");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-23 09:17:36 +08:00
|
|
|
|
|
2026-01-06 08:49:12 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 仅测试与调漆房IO模块的通讯连通性)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
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<ushort> testValues = _modbusClient.ReadInputRegisters(MODBUS_SLAVE_ID, 0x0000, 1);
|
|
|
|
|
|
List<ushort> 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层面)");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-23 09:17:36 +08:00
|
|
|
|
private void TestLight()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 2. 定义要读取的寄存器信息(根据您的表格)
|
|
|
|
|
|
const byte UNIT_ID = 0x01; // 从站地址,根据您的指令示例是 01
|
|
|
|
|
|
ushort startAddress = 0x0000; // 起始地址,对应 40001
|
|
|
|
|
|
ushort numberOfRegisters = 12; // 要读取的寄存器数量 (40001 到 40012)
|
|
|
|
|
|
|
|
|
|
|
|
// 3. PLC 下发读指令并获取原始寄存器值列表
|
|
|
|
|
|
Console.WriteLine($"正在读取从站 {UNIT_ID} 的寄存器 {startAddress} 开始的 {numberOfRegisters} 个寄存器...");
|
2026-01-06 08:49:12 +08:00
|
|
|
|
//List<ushort> registerValues = _modbusClient.ReadHoldingRegisters(UNIT_ID, startAddress, numberOfRegisters);
|
|
|
|
|
|
List<ushort> registerValues = _alarmLightModbus.ReadHoldingRegisters(UNIT_ID, startAddress, numberOfRegisters);
|
2025-12-23 09:17:36 +08:00
|
|
|
|
|
|
|
|
|
|
// 4. 解析警灯返回指令(即解析读取到的寄存器值)
|
|
|
|
|
|
if (registerValues.Count == numberOfRegisters)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("读取成功,解析数据:");
|
|
|
|
|
|
|
|
|
|
|
|
// 创建一个字典或列表来存储解析后的状态
|
|
|
|
|
|
var lightStatus = new Dictionary<string, ushort>
|
|
|
|
|
|
{
|
|
|
|
|
|
{ "红色", registerValues[0] }, // 40001 -> index 0
|
|
|
|
|
|
{ "绿色", registerValues[1] }, // 40002 -> index 1
|
|
|
|
|
|
{ "黄色", registerValues[2] }, // 40003 -> index 2
|
|
|
|
|
|
{ "蓝色", registerValues[3] }, // 40004 -> index 3
|
|
|
|
|
|
{ "白色", registerValues[4] }, // 40005 -> index 4
|
|
|
|
|
|
{ "备用1", registerValues[5] }, // 40006 -> index 5
|
|
|
|
|
|
{ "备用2", registerValues[6] }, // 40007 -> index 6
|
|
|
|
|
|
{ "备用3", registerValues[7] }, // 40008 -> index 7
|
|
|
|
|
|
{ "备用4", registerValues[8] }, // 40009 -> index 8
|
|
|
|
|
|
{ "备用5", registerValues[9] }, // 40010 -> index 9
|
|
|
|
|
|
{ "蜂鸣器", registerValues[10] }, // 40011 -> index 10
|
|
|
|
|
|
{ "电池电量", registerValues[11] } // 40012 -> index 11
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 打印解析结果
|
|
|
|
|
|
foreach (var status in lightStatus)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"{status.Key}: {status.Value}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- 根据业务逻辑解读状态值 ---
|
|
|
|
|
|
// 示例:假设 0=灭/关, 1=闪烁, 2=常亮 (具体含义需查阅设备手册)
|
|
|
|
|
|
InterpretLightStatus(lightStatus);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 根据业务逻辑解读灯的状态值(这是一个示例,具体值需参考设备手册)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
static void InterpretLightStatus(Dictionary<string, ushort> status)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("\n--- 状态解读 (示例) ---");
|
|
|
|
|
|
|
|
|
|
|
|
// 红色
|
|
|
|
|
|
switch (status["红色"])
|
|
|
|
|
|
{
|
|
|
|
|
|
case 0: Console.WriteLine("红色: 灭"); break;
|
|
|
|
|
|
case 1: Console.WriteLine("红色: 0.1S 闪烁"); break; // 根据您之前的例子
|
|
|
|
|
|
default: Console.WriteLine($"红色: 未知状态 ({status["红色"]})"); break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 绿色
|
|
|
|
|
|
switch (status["绿色"])
|
|
|
|
|
|
{
|
|
|
|
|
|
case 0: Console.WriteLine("绿色: 灭"); break;
|
|
|
|
|
|
case 10: Console.WriteLine("绿色: 1S 闪烁"); break; // 根据您之前的例子 (10 * 0.1S = 1S)
|
|
|
|
|
|
default: Console.WriteLine($"绿色: 未知状态 ({status["绿色"]})"); break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 黄色
|
|
|
|
|
|
switch (status["黄色"])
|
|
|
|
|
|
{
|
|
|
|
|
|
case 0: Console.WriteLine("黄色: 灭"); break;
|
|
|
|
|
|
case 99: Console.WriteLine("黄色: 常亮"); break; // 根据您之前的例子
|
|
|
|
|
|
default: Console.WriteLine($"黄色: 未知状态 ({status["黄色"]})"); break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 蓝、白
|
|
|
|
|
|
Console.WriteLine($"蓝色: {(status["蓝色"] == 0 ? "灭" : $"未知状态({status["蓝色"]})")}");
|
|
|
|
|
|
Console.WriteLine($"白色: {(status["白色"] == 0 ? "灭" : $"未知状态({status["白色"]})")}");
|
|
|
|
|
|
|
|
|
|
|
|
// 蜂鸣器
|
|
|
|
|
|
switch (status["蜂鸣器"])
|
|
|
|
|
|
{
|
|
|
|
|
|
case 0: Console.WriteLine("蜂鸣器: 静音"); break;
|
|
|
|
|
|
case 10: Console.WriteLine("蜂鸣器: 1S 蜂鸣"); break; // 根据您之前的例子
|
|
|
|
|
|
default: Console.WriteLine($"蜂鸣器: 未知状态 ({status["蜂鸣器"]})"); break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 电池电量
|
|
|
|
|
|
Console.WriteLine($"电池电量: {status["电池电量"]}%"); // 假设寄存器值直接代表百分比
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-20 13:23:44 +08:00
|
|
|
|
}
|