警灯通讯
This commit is contained in:
parent
a4a52320f4
commit
c38ac18a30
376
Infrastructure/Helper/ModbusTcpClientHelper.cs
Normal file
376
Infrastructure/Helper/ModbusTcpClientHelper.cs
Normal file
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Modbus TCP 客户端帮助类(支持常用功能码) 客户端 = 主站
|
||||
/// </summary>
|
||||
public class ModbusTcpClientHelper : IDisposable
|
||||
{
|
||||
private TcpClient _tcpClient;
|
||||
private NetworkStream _networkStream;
|
||||
private readonly object _lockObj = new object(); // 线程安全锁
|
||||
|
||||
/// <summary>
|
||||
/// 连接Modbus TCP服务器 服务端 = 从站
|
||||
/// </summary>
|
||||
/// <param name="ip">服务器IP</param>
|
||||
/// <param name="port">端口(默认502)</param>
|
||||
/// <param name="timeoutMs">超时时间(毫秒,默认3000)</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开连接
|
||||
/// </summary>
|
||||
public void Disconnect()
|
||||
{
|
||||
lock (_lockObj)
|
||||
{
|
||||
_networkStream?.Close();
|
||||
_tcpClient?.Close();
|
||||
_networkStream = null;
|
||||
_tcpClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取保持寄存器(功能码0x03)
|
||||
/// </summary>
|
||||
/// <param name="unitId">从站地址(单元ID)</param>
|
||||
/// <param name="startAddress">起始地址(0-based)</param>
|
||||
/// <param name="numberOfRegisters">寄存器数量</param>
|
||||
/// <returns>寄存器值列表(每个寄存器2字节,高位在前)</returns>
|
||||
public List<ushort> ReadHoldingRegisters(byte unitId, ushort startAddress, ushort numberOfRegisters)
|
||||
{
|
||||
var request = BuildReadRequest(unitId, 0x03, startAddress, numberOfRegisters);
|
||||
var response = SendAndReceive(request);
|
||||
return ParseReadRegistersResponse(response, numberOfRegisters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取输入寄存器(功能码0x04)
|
||||
/// </summary>
|
||||
public List<ushort> ReadInputRegisters(byte unitId, ushort startAddress, ushort numberOfRegisters)
|
||||
{
|
||||
var request = BuildReadRequest(unitId, 0x04, startAddress, numberOfRegisters);
|
||||
var response = SendAndReceive(request);
|
||||
return ParseReadRegistersResponse(response, numberOfRegisters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入单个保持寄存器(功能码0x06)
|
||||
/// </summary>
|
||||
/// <param name="unitId">从站地址</param>
|
||||
/// <param name="address">寄存器地址(0-based)</param>
|
||||
/// <param name="value">要写入的值(16位)</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入多个保持寄存器(功能码0x10)
|
||||
/// </summary>
|
||||
/// <param name="unitId">从站地址</param>
|
||||
/// <param name="startAddress">起始地址(0-based)</param>
|
||||
/// <param name="values">要写入的值列表(每个值16位)</param>
|
||||
public void WriteMultipleRegisters(byte unitId, ushort startAddress, List<ushort> values)
|
||||
{
|
||||
var request = BuildWriteMultipleRequest(unitId, 0x10, startAddress, values);
|
||||
var response = SendAndReceive(request);
|
||||
ValidateWriteResponse(response, 0x10, startAddress, (ushort)values.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取线圈状态(功能码0x01)
|
||||
/// </summary>
|
||||
/// <param name="unitId">从站地址</param>
|
||||
/// <param name="startAddress">起始地址(0-based)</param>
|
||||
/// <param name="numberOfCoils">线圈数量(1-2000)</param>
|
||||
/// <returns>线圈状态列表(true=ON,false=OFF)</returns>
|
||||
public List<bool> ReadCoils(byte unitId, ushort startAddress, ushort numberOfCoils)
|
||||
{
|
||||
var request = BuildReadRequest(unitId, 0x01, startAddress, numberOfCoils);
|
||||
var response = SendAndReceive(request);
|
||||
return ParseReadCoilsResponse(response, numberOfCoils);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入单个线圈(功能码0x05)
|
||||
/// </summary>
|
||||
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 私有方法(协议构建与解析)
|
||||
|
||||
/// <summary>
|
||||
/// 构建读请求报文(功能码0x01、0x02、0x03、0x04通用)
|
||||
/// </summary>
|
||||
private byte[] BuildReadRequest(byte unitId, byte functionCode, ushort startAddress, ushort quantity)
|
||||
{
|
||||
var request = new List<byte>
|
||||
{
|
||||
unitId, // 单元ID
|
||||
functionCode // 功能码
|
||||
};
|
||||
request.AddRange(BitConverter.GetBytes(startAddress).Reverse()); // 起始地址(大端序)
|
||||
request.AddRange(BitConverter.GetBytes(quantity).Reverse()); // 数量(大端序)
|
||||
AddCrcOrLength(request); // 添加长度(Modbus TCP无CRC,用MBAP长度)
|
||||
return request.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建写单个寄存器请求(功能码0x06)
|
||||
/// </summary>
|
||||
private byte[] BuildWriteSingleRequest(byte unitId, byte functionCode, ushort address, ushort value)
|
||||
{
|
||||
var request = new List<byte>
|
||||
{
|
||||
unitId,
|
||||
functionCode
|
||||
};
|
||||
request.AddRange(BitConverter.GetBytes(address).Reverse());
|
||||
request.AddRange(BitConverter.GetBytes(value).Reverse());
|
||||
AddCrcOrLength(request);
|
||||
return request.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建写多个寄存器请求(功能码0x10)
|
||||
/// </summary>
|
||||
private byte[] BuildWriteMultipleRequest(byte unitId, byte functionCode, ushort startAddress, List<ushort> values)
|
||||
{
|
||||
var request = new List<byte>
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建写单个线圈请求(功能码0x05)
|
||||
/// </summary>
|
||||
private byte[] BuildWriteSingleCoilRequest(byte unitId, byte functionCode, ushort address, bool value)
|
||||
{
|
||||
var request = new List<byte>
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加MBAP头的长度字段(Modbus TCP无CRC,用长度标识后续字节数)
|
||||
/// </summary>
|
||||
private void AddCrcOrLength(List<byte> data)
|
||||
{
|
||||
// Modbus TCP格式:[事务ID(2)][协议ID(2)][长度(2)][单元ID(1)][PDU...]
|
||||
// 此处简化:假设事务ID=0,协议ID=0,长度=单元ID+PDU长度(即data.Length)
|
||||
var mbapHeader = new List<byte>
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送请求并接收响应
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析读寄存器响应(功能码0x03、0x04)
|
||||
/// </summary>
|
||||
private List<ushort> 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<ushort>();
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析读线圈响应(功能码0x01)
|
||||
/// </summary>
|
||||
private List<bool> 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<bool>();
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证写操作响应(确保从站正确接收)
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -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<SocketGatewayServer>(provider =>
|
||||
|
||||
return server;
|
||||
});
|
||||
builder.Services.AddSingleton<ModbusTcpClientHelper>(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;
|
||||
|
||||
@ -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<SocketBackgroundService> _logger;
|
||||
|
||||
public SocketBackgroundService(SocketGatewayServer socketGateway, ILogger<SocketBackgroundService> logger)
|
||||
public SocketBackgroundService(SocketGatewayServer socketGateway, ILogger<SocketBackgroundService> 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<ushort> registerValues = _modbusClient.ReadHoldingRegisters(UNIT_ID, startAddress, numberOfRegisters);
|
||||
|
||||
// 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["电池电量"]}%"); // 假设寄存器值直接代表百分比
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
95
ZR.Service/Utils/MyAlarmLigth/LightUp.cs
Normal file
95
ZR.Service/Utils/MyAlarmLigth/LightUp.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 三色灯帮助类
|
||||
/// </summary>
|
||||
public class LightUp
|
||||
{
|
||||
/// <summary>
|
||||
/// 读警灯设备站号
|
||||
/// </summary>
|
||||
/// <returns>0 没有解析出来</returns>
|
||||
/// <returns>其他 解析出来设备站号</returns>
|
||||
|
||||
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<ushort> registerValues = _modbusClient.ReadHoldingRegisters(UNIT_ID, startAddress, numberOfRegisters);
|
||||
|
||||
if (registerValues.Count == numberOfRegisters)
|
||||
{
|
||||
Console.WriteLine("读取成功,解析数据:");
|
||||
return registerValues[0];
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 向指定的警灯设备写入指令,控制警灯的状态为红色闪烁 且蜂鸣器响
|
||||
/// </summary>
|
||||
/// <param name="_modbusClient"></param>
|
||||
/// <param name="unitId">警灯站号</param>
|
||||
/// <param name="startAddress"></param>
|
||||
/// <param name="commandValues"></param>
|
||||
public static void WriteAlarmLightCommand_Red(ModbusTcpClientHelper _modbusClient, byte unitId )
|
||||
{
|
||||
ushort startAddress = 0x0000; // 起始地址,对应
|
||||
ushort numberOfRegisters = 0x000B; // 要读取的寄存器数量 (40001 到 40012)
|
||||
List<ushort> commandValues= new List<ushort> { 0x00001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,0x0000, 0x0000,0x000A }; // 红色闪烁 且蜂鸣器响
|
||||
// 发送写指令到警灯设备
|
||||
_modbusClient.WriteMultipleRegisters(unitId, startAddress, commandValues);
|
||||
Console.WriteLine($"已向从站 {unitId} 的寄存器 {startAddress} 写入指令: {string.Join(", ", commandValues)}");
|
||||
}
|
||||
/// <summary>
|
||||
/// 向指定的警灯设备写入指令,控制警灯的状态为黄色常亮 且蜂鸣器响
|
||||
/// </summary>
|
||||
/// <param name="_modbusClient"></param>
|
||||
/// <param name="unitId">警灯站号</param>
|
||||
/// <param name="startAddress"></param>
|
||||
/// <param name="commandValues"></param>
|
||||
public static void WriteAlarmLightCommand_Yellow(ModbusTcpClientHelper _modbusClient, byte unitId)
|
||||
{
|
||||
ushort startAddress = 0x0000; // 起始地址,对应
|
||||
ushort numberOfRegisters = 0x000B; // 要读取的寄存器数量 (40001 到 40012)
|
||||
List<ushort> commandValues = new List<ushort> { 0x0000, 0x0000, 0x0063, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x000A }; // 红色闪烁 且蜂鸣器响
|
||||
// 发送写指令到警灯设备
|
||||
_modbusClient.WriteMultipleRegisters(unitId, startAddress, commandValues);
|
||||
Console.WriteLine($"已向从站 {unitId} 的寄存器 {startAddress} 写入指令: {string.Join(", ", commandValues)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向指定的警灯设备写入指令,控制警灯的状态为绿灯常亮 且蜂鸣器关闭
|
||||
/// </summary>
|
||||
/// <param name="_modbusClient"></param>
|
||||
/// <param name="unitId">警灯站号</param>
|
||||
/// <param name="startAddress"></param>
|
||||
/// <param name="commandValues"></param>
|
||||
public static void WriteAlarmLightCommand_Normal(ModbusTcpClientHelper _modbusClient, byte unitId)
|
||||
{
|
||||
ushort startAddress = 0x0000; // 起始地址,对应
|
||||
ushort numberOfRegisters = 0x000B; // 要读取的寄存器数量 (40001 到 40012)
|
||||
List<ushort> commandValues = new List<ushort> { 0x0000, 0x0063, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; // 红色闪烁 且蜂鸣器响
|
||||
// 发送写指令到警灯设备
|
||||
_modbusClient.WriteMultipleRegisters(unitId, startAddress, commandValues);
|
||||
Console.WriteLine($"已向从站 {unitId} 的寄存器 {startAddress} 写入指令: {string.Join(", ", commandValues)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user