package com.ruoyi.fuzhou.utils.watermodbus; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.fuzhou.domain.ReceiveWaterInfo; import com.ruoyi.fuzhou.enums.DataTypeEnum; import com.ruoyi.fuzhou.utils.electricitymodbus.HexStringToInt; import com.ruoyi.fuzhou.utils.oilmodbus.Crc16Utils; 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 ModbusWaterUtils { public static void main(String[] args) { //利和油设备 //String value = getValue("10.3.10.201", 8137, (byte) 2, (byte) 0x03, 22, 2, 10,""); String value = getValue("0.0.0.0", 8136, (byte) 1, (byte) 0x04, 4120, 2, 2, "整数"); } /** * @param ip ip * @param port 端口 * @param list 查询项列表 */ public static JSONObject getValue(String ip, int port, List 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 (ReceiveWaterInfo info : list ) { if (!"createTime".equals(info.getParamCode())) { // 构造请求帧 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.WATER_FLOW.getCode().equals(info.getDataType())) { String src = resultData.substring(6, 6 + byteCount * 2); if (info.getParam().contains("整数")) { long value = HexStringToInt.hexStringToInt(src); jsonObject.put(info.getParamCode(), String.valueOf(value)); System.out.println(info.getParam() + "的值为" + value + info.getUnit()); } else if (src.length() == 8) { byte[] bytes = FloatInverseWaterParser.hexStringToByteArray(src); // 解析为浮点数(大端字节顺序) byte[] reversedBytes = FloatInverseWaterParser.reverseByteArray(bytes); float floatValue = FloatInverseWaterParser.parseAsFloat(reversedBytes, ByteOrder.LITTLE_ENDIAN); jsonObject.put(info.getParamCode(), String.valueOf(floatValue)); System.out.println(info.getParam() + "的值为" + floatValue + info.getUnit()); } else { long value = HexStringToInt.hexStringToInt(src); jsonObject.put(info.getParamCode(), String.valueOf(value)); System.out.println(info.getParam() + "的值为" + value + info.getUnit()); } } else if (DataTypeEnum.WATER_YA.getCode().equals(info.getDataType())) { byte[] bytes = FloatInverseWaterParser.hexStringToByteArray(resultData.substring(6, 14)); // 解析为浮点数(大端字节顺序) byte[] reversedBytes = FloatInverseWaterParser.reverseByteArray(bytes); float floatValue = FloatInverseWaterParser.parseAsFloat(reversedBytes, ByteOrder.LITTLE_ENDIAN); jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue))); } } } 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 ss) { // 服务端配置 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.WATER_FLOW.getCode().equals(dataType)) { String src = resultData.substring(6, 6 + byteCount * 2); if (ss.contains("整数")) { long value = HexStringToInt.hexStringToInt(src); System.out.println("2值为" + value); } else if (src.length() == 8) { byte[] bytes = FloatInverseWaterParser.hexStringToByteArray(src); // 解析为浮点数(大端字节顺序) byte[] reversedBytes = FloatInverseWaterParser.reverseByteArray(bytes); float floatValue = FloatInverseWaterParser.parseAsFloat(reversedBytes, ByteOrder.LITTLE_ENDIAN); System.out.println("1值为" + floatValue); } else { long value = HexStringToInt.hexStringToInt(src); System.out.println("3值为" + value); } } else if (DataTypeEnum.WATER_YA.getCode().equals(dataType)) { byte[] bytes = FloatInverseWaterParser.hexStringToByteArray(resultData.substring(6, 14)); // 解析为浮点数(大端字节顺序) byte[] reversedBytes = FloatInverseWaterParser.reverseByteArray(bytes); float floatValue = FloatInverseWaterParser.parseAsFloat(reversedBytes, ByteOrder.LITTLE_ENDIAN); System.out.println(floatValue); } } catch (IOException e) { System.out.println("⚠️ 客户端异常断开: " + e.getMessage()); } finally { clientSocket.close(); } } catch (IOException e) { if (serverSocket != null) { try { System.out.println("设备不在线" + e.getMessage()); serverSocket.close(); } catch (IOException ex) { System.out.println("❌ 服务端关闭失败: " + ex.getMessage()); } } else { System.out.println("❌ 服务端启动失败: " + e.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; } }