diff --git a/Infrastructure/Helper/ModbusTcpClientHelper.cs b/Infrastructure/Helper/ModbusTcpClientHelper.cs
new file mode 100644
index 00000000..2649dc39
--- /dev/null
+++ b/Infrastructure/Helper/ModbusTcpClientHelper.cs
@@ -0,0 +1,376 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Infrastructure.Helper
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net.Sockets;
+ using System.Threading.Tasks;
+
+ ///
+ /// Modbus TCP 客户端帮助类(支持常用功能码) 客户端 = 主站
+ ///
+ public class ModbusTcpClientHelper : IDisposable
+ {
+ private TcpClient _tcpClient;
+ private NetworkStream _networkStream;
+ private readonly object _lockObj = new object(); // 线程安全锁
+
+ ///
+ /// 连接Modbus TCP服务器 服务端 = 从站
+ ///
+ /// 服务器IP
+ /// 端口(默认502)
+ /// 超时时间(毫秒,默认3000)
+ public void Connect(string ip, int port = 502, int timeoutMs = 3000)
+ {
+ if (_tcpClient != null && _tcpClient.Connected)
+ return;
+
+ lock (_lockObj)
+ {
+ try
+ {
+ _tcpClient = new TcpClient();
+ _tcpClient.SendTimeout = timeoutMs;
+ _tcpClient.ReceiveTimeout = timeoutMs;
+ _tcpClient.Connect(ip, port);
+ _networkStream = _tcpClient.GetStream();
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"连接Modbus TCP服务器失败:{ex.Message}", ex);
+ }
+ }
+ }
+
+ ///
+ /// 断开连接
+ ///
+ public void Disconnect()
+ {
+ lock (_lockObj)
+ {
+ _networkStream?.Close();
+ _tcpClient?.Close();
+ _networkStream = null;
+ _tcpClient = null;
+ }
+ }
+
+ ///
+ /// 读取保持寄存器(功能码0x03)
+ ///
+ /// 从站地址(单元ID)
+ /// 起始地址(0-based)
+ /// 寄存器数量
+ /// 寄存器值列表(每个寄存器2字节,高位在前)
+ public List ReadHoldingRegisters(byte unitId, ushort startAddress, ushort numberOfRegisters)
+ {
+ var request = BuildReadRequest(unitId, 0x03, startAddress, numberOfRegisters);
+ var response = SendAndReceive(request);
+ return ParseReadRegistersResponse(response, numberOfRegisters);
+ }
+
+ ///
+ /// 读取输入寄存器(功能码0x04)
+ ///
+ public List ReadInputRegisters(byte unitId, ushort startAddress, ushort numberOfRegisters)
+ {
+ var request = BuildReadRequest(unitId, 0x04, startAddress, numberOfRegisters);
+ var response = SendAndReceive(request);
+ return ParseReadRegistersResponse(response, numberOfRegisters);
+ }
+
+ ///
+ /// 写入单个保持寄存器(功能码0x06)
+ ///
+ /// 从站地址
+ /// 寄存器地址(0-based)
+ /// 要写入的值(16位)
+ public void WriteSingleRegister(byte unitId, ushort address, ushort value)
+ {
+ var request = BuildWriteSingleRequest(unitId, 0x06, address, value);
+ var response = SendAndReceive(request);
+ ValidateWriteResponse(response, 0x06, address, value);
+ }
+
+ ///
+ /// 写入多个保持寄存器(功能码0x10)
+ ///
+ /// 从站地址
+ /// 起始地址(0-based)
+ /// 要写入的值列表(每个值16位)
+ public void WriteMultipleRegisters(byte unitId, ushort startAddress, List values)
+ {
+ var request = BuildWriteMultipleRequest(unitId, 0x10, startAddress, values);
+ var response = SendAndReceive(request);
+ ValidateWriteResponse(response, 0x10, startAddress, (ushort)values.Count);
+ }
+
+ ///
+ /// 读取线圈状态(功能码0x01)
+ ///
+ /// 从站地址
+ /// 起始地址(0-based)
+ /// 线圈数量(1-2000)
+ /// 线圈状态列表(true=ON,false=OFF)
+ public List ReadCoils(byte unitId, ushort startAddress, ushort numberOfCoils)
+ {
+ var request = BuildReadRequest(unitId, 0x01, startAddress, numberOfCoils);
+ var response = SendAndReceive(request);
+ return ParseReadCoilsResponse(response, numberOfCoils);
+ }
+
+ ///
+ /// 写入单个线圈(功能码0x05)
+ ///
+ public void WriteSingleCoil(byte unitId, ushort address, bool value)
+ {
+ var request = BuildWriteSingleCoilRequest(unitId, 0x05, address, value);
+ var response = SendAndReceive(request);
+ ValidateWriteResponse(response, 0x05, address, value ? (ushort)0xFF00 : (ushort)0x0000);
+ }
+
+
+ #region 私有方法(协议构建与解析)
+
+ ///
+ /// 构建读请求报文(功能码0x01、0x02、0x03、0x04通用)
+ ///
+ private byte[] BuildReadRequest(byte unitId, byte functionCode, ushort startAddress, ushort quantity)
+ {
+ var request = new List
+ {
+ unitId, // 单元ID
+ functionCode // 功能码
+ };
+ request.AddRange(BitConverter.GetBytes(startAddress).Reverse()); // 起始地址(大端序)
+ request.AddRange(BitConverter.GetBytes(quantity).Reverse()); // 数量(大端序)
+ AddCrcOrLength(request); // 添加长度(Modbus TCP无CRC,用MBAP长度)
+ return request.ToArray();
+ }
+
+ ///
+ /// 构建写单个寄存器请求(功能码0x06)
+ ///
+ private byte[] BuildWriteSingleRequest(byte unitId, byte functionCode, ushort address, ushort value)
+ {
+ var request = new List
+ {
+ unitId,
+ functionCode
+ };
+ request.AddRange(BitConverter.GetBytes(address).Reverse());
+ request.AddRange(BitConverter.GetBytes(value).Reverse());
+ AddCrcOrLength(request);
+ return request.ToArray();
+ }
+
+ ///
+ /// 构建写多个寄存器请求(功能码0x10)
+ ///
+ private byte[] BuildWriteMultipleRequest(byte unitId, byte functionCode, ushort startAddress, List values)
+ {
+ var request = new List
+ {
+ unitId,
+ functionCode,
+ (byte)(startAddress >> 8), // 起始地址高字节
+ (byte)(startAddress & 0xFF),// 起始地址低字节
+ (byte)(values.Count >> 8), // 数量高字节
+ (byte)(values.Count & 0xFF),// 数量低字节
+ (byte)(values.Count * 2) // 字节数(每个寄存器2字节)
+ };
+ foreach (var value in values)
+ {
+ request.AddRange(BitConverter.GetBytes(value).Reverse()); // 寄存器值(大端序)
+ }
+ AddCrcOrLength(request);
+ return request.ToArray();
+ }
+
+ ///
+ /// 构建写单个线圈请求(功能码0x05)
+ ///
+ private byte[] BuildWriteSingleCoilRequest(byte unitId, byte functionCode, ushort address, bool value)
+ {
+ var request = new List
+ {
+ unitId,
+ functionCode
+ };
+ request.AddRange(BitConverter.GetBytes(address).Reverse());
+ request.AddRange(value ? new byte[] { 0xFF, 0x00 } : new byte[] { 0x00, 0x00 }); // ON=0xFF00,OFF=0x0000
+ AddCrcOrLength(request);
+ return request.ToArray();
+ }
+
+ ///
+ /// 添加MBAP头的长度字段(Modbus TCP无CRC,用长度标识后续字节数)
+ ///
+ private void AddCrcOrLength(List data)
+ {
+ // Modbus TCP格式:[事务ID(2)][协议ID(2)][长度(2)][单元ID(1)][PDU...]
+ // 此处简化:假设事务ID=0,协议ID=0,长度=单元ID+PDU长度(即data.Length)
+ var mbapHeader = new List
+ {
+ 0x00, 0x00, // 事务ID=0
+ 0x00, 0x00, // 协议ID=0(Modbus)
+ 0x00, (byte)(data.Count) // 长度=单元ID+PDU长度(data已包含单元ID+PDU)
+ };
+ mbapHeader.AddRange(data);
+ data.Clear();
+ data.AddRange(mbapHeader);
+ }
+
+ ///
+ /// 发送请求并接收响应
+ ///
+ private byte[] SendAndReceive(byte[] request)
+ {
+ if (_networkStream == null || !_tcpClient.Connected)
+ throw new InvalidOperationException("未连接到Modbus TCP服务器");
+
+ lock (_lockObj)
+ {
+ try
+ {
+ // 发送请求
+ _networkStream.Write(request, 0, request.Length);
+
+ // 接收响应(先读MBAP头的长度字段,再读剩余数据)
+ var headerBuffer = new byte[6]; // MBAP头前6字节(事务ID+协议ID+长度)
+ var bytesRead = _networkStream.Read(headerBuffer, 0, headerBuffer.Length);
+ if (bytesRead != 6)
+ throw new Exception("接收MBAP头失败");
+
+ // 解析长度字段(第5-6字节,大端序)
+ var length = (headerBuffer[4] << 8) | headerBuffer[5];
+ var responseBuffer = new byte[length + 6]; // 总长度=MBAP头(6)+长度字段指定的字节数
+ Array.Copy(headerBuffer, responseBuffer, 6);
+
+ // 读剩余数据
+ bytesRead = _networkStream.Read(responseBuffer, 6, length);
+ if (bytesRead != length)
+ throw new Exception("接收响应数据不完整");
+
+ return responseBuffer;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"通信失败:{ex.Message}", ex);
+ }
+ }
+ }
+
+ ///
+ /// 解析读寄存器响应(功能码0x03、0x04)
+ ///
+ private List ParseReadRegistersResponse(byte[] response, ushort expectedCount)
+ {
+ // 响应格式:[MBAP头(7)][单元ID(1)][功能码(1)][字节数(1)][数据(n)]
+ var dataStartIndex = 7; // MBAP头7字节(事务ID2+协议ID2+长度2+单元ID1)+ 功能码1?不,重新算:
+ // 实际响应结构:MBAP头(7字节) = [事务ID(2),协议ID(2),长度(2),单元ID(1)]?不,标准MBAP头是7字节:
+ // 正确的MBAP头:事务ID(2)、协议ID(2)、长度(2)、单元ID(1) → 共7字节。然后PDU是功能码(1)+数据。
+ // 所以response的结构:
+ // 0-1: 事务ID
+ // 2-3: 协议ID
+ // 4-5: 长度(=单元ID+PDU长度)
+ // 6: 单元ID
+ // 7: 功能码
+ // 8: 字节数(=n*2,n为寄存器数量)
+ // 9~: 数据(每个寄存器2字节,大端序)
+
+ if (response[7] != 0x03 && response[7] != 0x04) // 检查功能码(成功时无异常码)
+ throw new Exception($"Modbus异常:功能码={response[7]:X2}");
+
+ var byteCount = response[8];
+ if (byteCount != expectedCount * 2)
+ throw new Exception($"响应字节数与预期不符:实际={byteCount},预期={expectedCount * 2}");
+
+ var registers = new List();
+ for (int i = 0; i < expectedCount; i++)
+ {
+ var index = 9 + i * 2;
+ var highByte = response[index];
+ var lowByte = response[index + 1];
+ registers.Add((ushort)((highByte << 8) | lowByte));
+ }
+ return registers;
+ }
+
+ ///
+ /// 解析读线圈响应(功能码0x01)
+ ///
+ private List ParseReadCoilsResponse(byte[] response, ushort expectedCount)
+ {
+ if (response[7] != 0x01)
+ throw new Exception($"Modbus异常:功能码={response[7]:X2}");
+
+ var byteCount = response[8];
+ var expectedBytes = (expectedCount + 7) / 8; // 向上取整
+ if (byteCount != expectedBytes)
+ throw new Exception($"响应字节数与预期不符:实际={byteCount},预期={expectedBytes}");
+
+ var coils = new List();
+ for (int i = 0; i < expectedCount; i++)
+ {
+ var byteIndex = 9 + i / 8;
+ var bitIndex = i % 8;
+ var mask = (byte)(1 << bitIndex);
+ coils.Add((response[byteIndex] & mask) != 0);
+ }
+ return coils;
+ }
+
+ ///
+ /// 验证写操作响应(确保从站正确接收)
+ ///
+ private void ValidateWriteResponse(byte[] response, byte functionCode, ushort address, ushort value)
+ {
+ if (response[7] != functionCode) // 功能码应与原请求一致(无异常)
+ throw new Exception($"写操作失败:响应功能码={response[7]:X2}");
+
+ // 解析响应中的地址和值(应与请求一致)
+ var respAddress = (ushort)((response[8] << 8) | response[9]);
+ var respValue = (ushort)((response[10] << 8) | response[11]);
+ if (respAddress != address || respValue != value)
+ throw new Exception($"写操作响应不匹配:地址={respAddress:X4}(预期={address:X4}),值={respValue:X4}(预期={value:X4})");
+ }
+
+ #endregion
+
+
+ #region IDisposable实现
+ private bool _disposed = false;
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ Disconnect();
+ }
+ _disposed = true;
+ }
+ }
+
+ ~ModbusTcpClientHelper()
+ {
+ Dispose(false);
+ }
+ #endregion
+ }
+}
diff --git a/ZR.Admin.WebApi/Program.cs b/ZR.Admin.WebApi/Program.cs
index 37757eb5..93755909 100644
--- a/ZR.Admin.WebApi/Program.cs
+++ b/ZR.Admin.WebApi/Program.cs
@@ -1,4 +1,5 @@
using AspNetCoreRateLimit;
+using Infrastructure.Helper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
@@ -124,6 +125,15 @@ builder.Services.AddSingleton(provider =>
return server;
});
+builder.Services.AddSingleton(provider =>
+{
+ var modbus = new ModbusTcpClientHelper();
+
+ modbus.Connect("192.168.2.22", 9999); // 你可以按需修改 IP 和端口
+
+
+ return modbus;
+});
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 74b95681..a8c22a26 100644
--- a/ZR.Admin.WebApi/background/SocketBackgroundService.cs
+++ b/ZR.Admin.WebApi/background/SocketBackgroundService.cs
@@ -1,6 +1,7 @@
using DOAN.ServiceCore.MyMatchPush;
using Infrastructure;
+using Infrastructure.Helper;
using Microsoft.Extensions.Logging;
namespace ZR.Admin.WebApi.background
@@ -8,12 +9,14 @@ namespace ZR.Admin.WebApi.background
public class SocketBackgroundService : BackgroundService
{
private readonly SocketGatewayServer _socketGateway;
+ private readonly ModbusTcpClientHelper _modbusClient;
private readonly ILogger _logger;
- public SocketBackgroundService(SocketGatewayServer socketGateway, ILogger logger)
+ public SocketBackgroundService(SocketGatewayServer socketGateway, ILogger logger, ModbusTcpClientHelper modbusClient)
{
_socketGateway = socketGateway;
_logger = logger;
+ _modbusClient = modbusClient;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
@@ -22,15 +25,111 @@ namespace ZR.Admin.WebApi.background
{
// 等待服务完全启动
await Task.Delay(1000, stoppingToken);
-
+
// 测试Socket推送功能
- //var result = Watchup.StartPush("测试Socket推送功能", _socketGateway);
- //_logger.LogInformation($"Socket推送测试结果: {result}");
+ var result = Watchup.StartPush("测试Socket推送功能", _socketGateway);
+ _logger.LogInformation($"Socket推送测试结果: {result}");
+ TestLight();
}
catch (Exception ex)
{
_logger.LogError(ex, "Socket推送测试失败");
}
}
+
+ 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} 个寄存器...");
+ List registerValues = _modbusClient.ReadHoldingRegisters(UNIT_ID, startAddress, numberOfRegisters);
+
+ // 4. 解析警灯返回指令(即解析读取到的寄存器值)
+ if (registerValues.Count == numberOfRegisters)
+ {
+ Console.WriteLine("读取成功,解析数据:");
+
+ // 创建一个字典或列表来存储解析后的状态
+ var lightStatus = new Dictionary
+ {
+ { "红色", 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);
+ }
+ }
+ ///
+ /// 根据业务逻辑解读灯的状态值(这是一个示例,具体值需参考设备手册)
+ ///
+ static void InterpretLightStatus(Dictionary 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["电池电量"]}%"); // 假设寄存器值直接代表百分比
+ }
+
+
+
+ }
+
}
-}
diff --git a/ZR.Service/Utils/MyAlarmLigth/LightUp.cs b/ZR.Service/Utils/MyAlarmLigth/LightUp.cs
new file mode 100644
index 00000000..e13515b1
--- /dev/null
+++ b/ZR.Service/Utils/MyAlarmLigth/LightUp.cs
@@ -0,0 +1,95 @@
+using Infrastructure.Helper;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+
+namespace ZR.Service.Utils.MyAlarmLigth
+{
+ ///
+ /// 三色灯帮助类
+ ///
+ public class LightUp
+ {
+ ///
+ /// 读警灯设备站号
+ ///
+ /// 0 没有解析出来
+ /// 其他 解析出来设备站号
+
+ public static ushort ReadAlarmlightNumber(ModbusTcpClientHelper _modbusClient)
+ {
+
+ // 2. 定义要读取的寄存器信息(根据您的表格)
+ const byte UNIT_ID = 0x00; // 从站地址,根据您的指令示例是 01
+ ushort startAddress = 0x0fa1; // 起始地址,对应
+ ushort numberOfRegisters = 1; // 要读取的寄存器数量 (40001 到 40012)
+
+ // 3. PLC 下发读指令并获取原始寄存器值列表
+ Console.WriteLine($"正在读取从站{UNIT_ID}广播的寄存器 {startAddress} 开始的 {numberOfRegisters} 个寄存器...");
+ List registerValues = _modbusClient.ReadHoldingRegisters(UNIT_ID, startAddress, numberOfRegisters);
+
+ if (registerValues.Count == numberOfRegisters)
+ {
+ Console.WriteLine("读取成功,解析数据:");
+ return registerValues[0];
+
+ }
+ return 0;
+ }
+
+
+
+ ///
+ /// 向指定的警灯设备写入指令,控制警灯的状态为红色闪烁 且蜂鸣器响
+ ///
+ ///
+ /// 警灯站号
+ ///
+ ///
+ public static void WriteAlarmLightCommand_Red(ModbusTcpClientHelper _modbusClient, byte unitId )
+ {
+ ushort startAddress = 0x0000; // 起始地址,对应
+ ushort numberOfRegisters = 0x000B; // 要读取的寄存器数量 (40001 到 40012)
+ List commandValues= new List { 0x00001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,0x0000, 0x0000,0x000A }; // 红色闪烁 且蜂鸣器响
+ // 发送写指令到警灯设备
+ _modbusClient.WriteMultipleRegisters(unitId, startAddress, commandValues);
+ Console.WriteLine($"已向从站 {unitId} 的寄存器 {startAddress} 写入指令: {string.Join(", ", commandValues)}");
+ }
+ ///
+ /// 向指定的警灯设备写入指令,控制警灯的状态为黄色常亮 且蜂鸣器响
+ ///
+ ///
+ /// 警灯站号
+ ///
+ ///
+ public static void WriteAlarmLightCommand_Yellow(ModbusTcpClientHelper _modbusClient, byte unitId)
+ {
+ ushort startAddress = 0x0000; // 起始地址,对应
+ ushort numberOfRegisters = 0x000B; // 要读取的寄存器数量 (40001 到 40012)
+ List commandValues = new List { 0x0000, 0x0000, 0x0063, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x000A }; // 红色闪烁 且蜂鸣器响
+ // 发送写指令到警灯设备
+ _modbusClient.WriteMultipleRegisters(unitId, startAddress, commandValues);
+ Console.WriteLine($"已向从站 {unitId} 的寄存器 {startAddress} 写入指令: {string.Join(", ", commandValues)}");
+ }
+
+ ///
+ /// 向指定的警灯设备写入指令,控制警灯的状态为绿灯常亮 且蜂鸣器关闭
+ ///
+ ///
+ /// 警灯站号
+ ///
+ ///
+ public static void WriteAlarmLightCommand_Normal(ModbusTcpClientHelper _modbusClient, byte unitId)
+ {
+ ushort startAddress = 0x0000; // 起始地址,对应
+ ushort numberOfRegisters = 0x000B; // 要读取的寄存器数量 (40001 到 40012)
+ List commandValues = new List { 0x0000, 0x0063, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; // 红色闪烁 且蜂鸣器响
+ // 发送写指令到警灯设备
+ _modbusClient.WriteMultipleRegisters(unitId, startAddress, commandValues);
+ Console.WriteLine($"已向从站 {unitId} 的寄存器 {startAddress} 写入指令: {string.Join(", ", commandValues)}");
+ }
+ }
+}