package com.ruoyi.fuzhou.utils.electricitymodbus;
|
|
import com.alibaba.fastjson2.JSONObject;
|
import com.ruoyi.fuzhou.domain.ReceiveElectricityInfo;
|
import com.ruoyi.fuzhou.enums.DataTypeEnum;
|
import com.ruoyi.fuzhou.utils.oilmodbus.Crc16Utils;
|
import com.ruoyi.fuzhou.utils.watermodbus.FloatInverseWaterParser;
|
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.OutputStream;
|
import java.net.ServerSocket;
|
import java.net.Socket;
|
import java.nio.ByteBuffer;
|
import java.nio.ByteOrder;
|
import java.util.List;
|
|
|
/**
|
* 电表设备数据接入
|
*/
|
public class ModbusElectricityUtils {
|
public static void main(String[] args) {
|
|
//利和油设备
|
String value = getValue("0.0.0.0", 8334, (byte) 35, (byte) 0x03, 20, 1, 3);
|
// String value = getValue("0.0.0.0", 8247, (byte) 1, (byte) 0x03, 13, 2, 3);
|
System.out.println(value);
|
}
|
|
/**
|
* 查询多个设备项
|
*
|
* @param ip ip
|
* @param port 端口
|
* @param list 查询项列表
|
*/
|
public static JSONObject getValue(String ip, int port, List<ReceiveElectricityInfo> list) {
|
// 服务端配置
|
String SERVER_IP = ip; // 监听所有网络接口
|
int SERVER_PORT = port; // 端口号
|
ServerSocket serverSocket = null;
|
try {
|
serverSocket = new ServerSocket(SERVER_PORT);
|
System.out.println("🛡️ 服务端已启动,正在监听 " + SERVER_IP + ":" + SERVER_PORT + "...");
|
serverSocket.setSoTimeout(4000);
|
Socket clientSocket = serverSocket.accept();
|
System.out.println("🔌 客户端已连接: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
|
try (InputStream inputStream = clientSocket.getInputStream();
|
OutputStream outputStream = clientSocket.getOutputStream()) {
|
JSONObject jsonObject = new JSONObject();
|
for (ReceiveElectricityInfo info : list
|
) {
|
// 构造请求帧
|
ByteBuffer requestBuffer = ByteBuffer.allocate(8);
|
if (info.getDeviceAddress() != 0) {
|
requestBuffer.put(info.getDeviceAddress()); // 设备地址
|
}
|
if (info.getFunctionCode() != 0) {
|
requestBuffer.put(info.getFunctionCode()); // 功能码
|
}
|
if (info.getRegisterAdress() != 0) {
|
requestBuffer.putShort((short) info.getRegisterAdress().intValue()); // 寄存器地址
|
}
|
if (info.getRegisterCount() != 0) {
|
requestBuffer.putShort((short) info.getRegisterCount().intValue()); // 寄存器数量
|
}
|
// 计算CRC校验码
|
byte[] requestData = requestBuffer.array();
|
String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
|
int decimal = Integer.parseInt(hex, 16);
|
requestBuffer.putShort((short) decimal); // CRC校验码
|
// 发送请求帧
|
outputStream.write(requestBuffer.array());
|
System.out.println("📤 已发送 MODBUS 请求: " + bytesToHex(requestBuffer.array()));
|
// 接收设备响应
|
byte[] response = new byte[1024];
|
int bytesRead = inputStream.read(response);
|
if (bytesRead == -1) {
|
System.out.println("❌ 未收到设备响应");
|
continue;
|
}
|
// 打印响应数据
|
byte[] responseData = new byte[bytesRead];
|
System.arraycopy(response, 0, responseData, 0, bytesRead);
|
String resultData = bytesToHex(responseData);
|
System.out.println("📥 收到设备响应: " + resultData);
|
// 检查响应长度
|
if (responseData.length <= 5) {
|
System.out.println("❌ 无效的响应长度: " + responseData.length + " 字节");
|
continue;
|
}
|
//功能码
|
byte responseFunctionCode = responseData[1];
|
//数据字节数
|
byte byteCount = responseData[2];
|
byte[] data = new byte[byteCount];
|
System.arraycopy(responseData, 3, data, 0, byteCount);
|
byte[] crcReceived = new byte[2];
|
System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
|
// 检查是否为错误响应(功能码 + 0x80)
|
if ((responseFunctionCode & 0x80) != 0) {
|
byte errorCode = responseData[2]; // 错误码
|
System.out.println("❌ 设备返回错误响应,错误码: " + errorCode);
|
continue;
|
}
|
if (DataTypeEnum.ELECTRICITY.getCode().equals(info.getDataType())) {
|
if (byteCount == 2) {
|
//解析整形
|
long value = HexStringToInt.hexStringToIntelc(resultData.substring(6, 6 + byteCount * 2));
|
jsonObject.put(info.getParamCode(), String.valueOf(value/10.0));
|
System.out.println(info.getParam() + "的值为" + (value/10.0) + info.getUnit());
|
} else if (byteCount == 4) {
|
//解析浮点型
|
long floatValue = HexStringToInt.hexStringToIntelc(resultData.substring(6, 6 + byteCount * 2));
|
jsonObject.put(info.getParamCode(), String.valueOf(floatValue/100.0));
|
System.out.println(info.getParam() + "的值为" + floatValue/100.0 + info.getUnit());
|
} else {
|
continue;
|
}
|
}
|
}
|
serverSocket.close();
|
return jsonObject;
|
} catch (Exception e) {
|
System.out.println("⚠️ 客户端异常断开: " + e.getMessage());
|
} finally {
|
clientSocket.close();
|
}
|
|
} catch (Exception e) {
|
System.out.println("❌ 服务端启动失败: " + e.getMessage());
|
} finally {
|
if (serverSocket != null) {
|
try {
|
System.out.println("设备不在线");
|
serverSocket.close();
|
} catch (Exception ex) {
|
System.out.println("❌ 服务端关闭失败: " + ex.getMessage());
|
}
|
}
|
}
|
return null;
|
}
|
|
/**
|
* @param ip ip
|
* @param port 端口
|
* @param address 地址码
|
* @param functionCode 功能码
|
* @param registerAddress 寄存器地址
|
* @param registerCount 寄存器数量
|
*/
|
public static String getValue(String ip, int port, byte address, byte functionCode, int registerAddress, int registerCount, int dataType) {
|
// 服务端配置
|
String SERVER_IP = ip; // 监听所有网络接口
|
int SERVER_PORT = port; // 端口号
|
ServerSocket serverSocket = null;
|
try {
|
serverSocket = new ServerSocket(SERVER_PORT);
|
System.out.println("🛡️ 服务端已启动,正在监听 " + SERVER_IP + ":" + SERVER_PORT + "...");
|
serverSocket.setSoTimeout(8000);
|
Socket clientSocket = serverSocket.accept();
|
System.out.println("🔌 客户端已连接: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
|
try (InputStream inputStream = clientSocket.getInputStream();
|
OutputStream outputStream = clientSocket.getOutputStream()) {
|
// 构造请求帧
|
ByteBuffer requestBuffer = ByteBuffer.allocate(8);
|
if (address != 0) {
|
requestBuffer.put(address); // 设备地址
|
}
|
if (functionCode != 0) {
|
requestBuffer.put(functionCode); // 功能码
|
}
|
if (registerAddress != 0) {
|
requestBuffer.putShort((short) registerAddress); // 寄存器地址
|
}
|
if (registerCount != 0) {
|
requestBuffer.putShort((short) registerCount); // 寄存器数量
|
}
|
// 计算CRC校验码
|
byte[] requestData = requestBuffer.array();
|
String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
|
int decimal = Integer.parseInt(hex, 16);
|
requestBuffer.putShort((short) decimal); // CRC校验码
|
// 发送请求帧
|
outputStream.write(requestBuffer.array());
|
System.out.println("📤 已发送 MODBUS 请求: " + bytesToHex(requestBuffer.array()));
|
// 接收设备响应
|
byte[] response = new byte[1024];
|
int bytesRead = inputStream.read(response);
|
if (bytesRead == -1) {
|
System.out.println("❌ 未收到设备响应");
|
return null;
|
}
|
// 打印响应数据
|
byte[] responseData = new byte[bytesRead];
|
System.arraycopy(response, 0, responseData, 0, bytesRead);
|
String resultData = bytesToHex(responseData);
|
System.out.println("📥 收到设备响应: " + resultData);
|
// 检查响应长度
|
if (responseData.length <= 5) {
|
System.out.println("❌ 无效的响应长度: " + responseData.length + " 字节");
|
return null;
|
}
|
//功能码
|
byte responseFunctionCode = responseData[1];
|
//数据字节数
|
byte byteCount = responseData[2];
|
byte[] data = new byte[byteCount];
|
System.arraycopy(responseData, 3, data, 0, byteCount);
|
byte[] crcReceived = new byte[2];
|
System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
|
// 检查是否为错误响应(功能码 + 0x80)
|
if ((responseFunctionCode & 0x80) != 0) {
|
byte errorCode = responseData[2]; // 错误码
|
System.out.println("❌ 设备返回错误响应,错误码: " + errorCode);
|
return null;
|
}
|
if (DataTypeEnum.ELECTRICITY.getCode().equals(dataType)) {
|
if (byteCount == 2) {
|
//解析整形
|
long value = HexStringToInt.hexStringToIntelc(resultData.substring(6, 6 + byteCount * 2));
|
|
System.out.println("的值为" + (value/10.0) );
|
} else if (byteCount == 4) {
|
//解析浮点型
|
long floatValue = HexStringToInt.hexStringToIntelc(resultData.substring(6, 6 + byteCount * 2));
|
System.out.println( "的值为" + floatValue/100.0);
|
} else {
|
|
}
|
}
|
} catch (IOException e) {
|
System.out.println("⚠️ 客户端异常断开: " + e.getMessage());
|
} finally {
|
clientSocket.close();
|
}
|
} catch (IOException e) {
|
if (serverSocket != null) {
|
System.out.println("设备不在线" + e.getMessage());
|
} else {
|
System.out.println("❌ 服务端启动失败: " + e.getMessage());
|
}
|
} finally {
|
try {
|
serverSocket.close();
|
} catch (IOException ex) {
|
System.out.println("❌ 服务端关闭失败: " + ex.getMessage());
|
}
|
}
|
return null;
|
}
|
|
// 将字节数组转换为十六进制字符串
|
public static String bytesToHex(byte[] bytes) {
|
StringBuilder sb = new StringBuilder();
|
for (byte b : bytes) {
|
sb.append(String.format("%02X", b));
|
}
|
return sb.toString();
|
}
|
|
// CRC16 计算
|
public static int crc16(byte[] data) {
|
int crc = 0xFFFF;
|
for (byte b : data) {
|
crc ^= (b & 0xFF);
|
for (int i = 0; i < 8; i++) {
|
if ((crc & 0x0001) != 0) {
|
crc >>= 1;
|
crc ^= 0xA001;
|
} else {
|
crc >>= 1;
|
}
|
}
|
}
|
return crc;
|
}
|
}
|