package com.ruoyi.fuzhou.utils; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.fuzhou.domain.ReceiveOilInfo; import com.ruoyi.fuzhou.domain.ReceiveWeatherInfo; import com.ruoyi.fuzhou.enums.DataTypeEnum; import com.ruoyi.fuzhou.utils.oilmodbus.Crc16Utils; import com.ruoyi.fuzhou.utils.oilmodbus.ModbusFloatParserLittleUtil; import com.ruoyi.fuzhou.utils.oilmodbus.ModbusFloatParserUtil; 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 ModbusWeatherServerUtils { public static void main(String[] args) { // // //质量流量 String value = getValue("0.0.0.0", 8140, (byte) 0x05, (byte) 0x04, 167, 0x0002, 1); // //利和油设备 // String value = getValue("0.0.0.0", 8247, (byte) 1, (byte) 3, 13, 2, 12); System.out.println(value); } /** * @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(); ReceiveWeatherInfo info=list.get(0); // 构造请求帧 ByteBuffer requestBuffer = ByteBuffer.allocate(8); if (info.getDeviceAddress() != 0) { requestBuffer.put(info.getDeviceAddress()); // 设备地址 } if (info.getFunctionCode() != 0) { requestBuffer.put(info.getFunctionCode()); // 功能码 } requestBuffer.putShort((short) info.getRegisterAdress().intValue()); // 寄存器地址 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("❌ 未收到气象设备响应"); serverSocket.close(); return jsonObject; } // 打印响应数据 byte[] responseData = new byte[bytesRead]; System.arraycopy(response, 0, responseData, 0, bytesRead); String resultData = bytesToHex(responseData); System.out.println("📥 收到气象设备响应: " + resultData); // 检查响应长度 if (resultData.length()< 30) { System.out.println("❌ 无效的响应长度: " + resultData.length() + " 字节"); } //功能码 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); serverSocket.close(); return jsonObject; } //数据解析 String dataStr=resultData.substring(6,resultData.length()-1); //风速 float fengsu=Integer.parseInt(dataStr.substring(0,4),16); String fengsuStr= String.valueOf(String.format("%.2f",fengsu/100)); System.out.println("气象设备 风速解析为: " + fengsuStr); jsonObject.put("windSpeed", fengsuStr); //风向 int fengxiang=Integer.parseInt(dataStr.substring(4,8),16); String fengxiangStr=String.valueOf(fengxiang); System.out.println("气象设备 风速解析为: " + fengxiangStr); jsonObject.put("windDirection", fengxiangStr); //温度 float wendu=Integer.parseInt(dataStr.substring(8,12),16); String wenduStr=String.valueOf(String.format("%.1f",wendu/10)); System.out.println("气象设备 风速解析为: " + wenduStr); jsonObject.put("temp", wenduStr); //湿度 float shidu=Integer.parseInt(dataStr.substring(12,16),16); String shiduStr=String.valueOf(String.format("%.1f",shidu/10)); System.out.println("气象设备 风速解析为: " +shiduStr ); jsonObject.put("humidity", shiduStr); //大气压 float daqiya=Integer.parseInt(dataStr.substring(16,20),16); String daqiyaStr=String.valueOf(String.format("%.1f",daqiya/10)); System.out.println("气象设备 风速解析为: " + daqiyaStr); jsonObject.put("atmosphericPressure", daqiyaStr); serverSocket.close(); return jsonObject; } catch (Exception e) { System.out.println("⚠️ 气象客户端异常断开: " + e.getMessage()); } finally { clientSocket.close(); } } catch (Exception e) { if (serverSocket != null) { try { System.out.println("气象设备不在线" + e.getMessage()); serverSocket.close(); } catch (Exception ex) { System.out.println("❌ 气象服务端关闭失败: " + ex.getMessage()); } } else { System.out.println("❌ 气象服务端启动失败: " + e.getMessage()); } } return null; } public static JSONObject getValueTest(String ip, int port, List list) { JSONObject jsonObject = new JSONObject(); ReceiveWeatherInfo info=list.get(0); // 构造请求帧 ByteBuffer requestBuffer = ByteBuffer.allocate(8); if (info.getDeviceAddress() != 0) { requestBuffer.put(info.getDeviceAddress()); // 设备地址 } if (info.getFunctionCode() != 0) { requestBuffer.put(info.getFunctionCode()); // 功能码 } requestBuffer.putShort((short) info.getRegisterAdress().intValue()); // 寄存器地址 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校验码 // 发送请求帧 System.out.println("📤 已发送气象 MODBUS 请求: " + bytesToHex(requestBuffer.array())); // 接收设备响应 byte[] response = new byte[1024]; // int bytesRead = inputStream.read(response); // int bytesRead = Integer.parseInt(res, 16); // if (bytesRead == -1) { // System.out.println("❌ 未收到气象设备响应"); // // } //// 打印响应数据 // byte[] responseData = new byte[bytesRead]; // System.arraycopy(response, 0, responseData, 0, bytesRead); // String resultData = bytesToHex(responseData); String resultData="01030A014A00B60112033103F68534"; System.out.println("📥 收到气象设备响应: " + resultData); // 检查响应长度 if (resultData.length()< 30) { System.out.println("❌ 无效的响应长度: " + resultData.length() + " 字节"); } String data=resultData.substring(6,resultData.length()-1); //风速 int fengsu=Integer.parseInt(data.substring(0,4),16)/100; System.out.println("气象设备 风速解析为: " + fengsu); //风向 int fengxiang=Integer.parseInt(data.substring(4,8),16)/100; System.out.println("气象设备 风速解析为: " + fengsu); //温度 int wendu=Integer.parseInt(data.substring(8,12),16)/100; System.out.println("气象设备 风速解析为: " + fengsu); //湿度 int shidu=Integer.parseInt(data.substring(12,16),16)/100; System.out.println("气象设备 风速解析为: " + fengsu); //大气压 int daqiya=Integer.parseInt(data.substring(16,20),16)/100; System.out.println("气象设备 风速解析为: " + fengsu); //crc return jsonObject; } /** * @param ip ip * @param port 端口 * @param list 查询项列表 */ public static JSONObject getLijiuValue(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 (ReceiveOilInfo 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]; try { Thread.sleep(5000); } catch (Exception ex) { ex.printStackTrace(); } 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.OIL.getCode().equals(info.getDataType())) { byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2)); // 解析为浮点数(大端字节顺序) float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN); jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue))); } else if (DataTypeEnum.LIJIUOIL.getCode().equals(info.getDataType())) { byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2)); byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes); // 解析为浮点数(大端字节顺序) float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN); jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue))); } else if (DataTypeEnum.LIJIUJUN.getCode().equals(info.getDataType())) { //todo 未做处理 byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2)); byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes); // 解析为浮点数(大端字节顺序) float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN); jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue))); } else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(info.getDataType())) { //todo 未做处理 byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2)); byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes); // 解析为浮点数(大端字节顺序) float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN); jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue))); serverSocket.close(); } } return jsonObject; } catch (Exception e) { System.out.println("厦门利旧客户端异常断开: " + e.getMessage()); } finally { clientSocket.close(); } } catch (Exception e) { if (serverSocket != null) { try { System.out.println("厦门利旧油设备不在线" + e.getMessage()); serverSocket.close(); } catch (Exception ex) { System.out.println("厦门利旧油服务端关闭失败: " + ex.getMessage()); } } else { System.out.println("厦门利旧油服务端启动失败: " + e.getMessage()); } } return null; } /** * @param ip ip * @param port 端口 * @param address 地址码 * @param functionCode 功能码 * @param registerAddress 寄存器地址 * @param registerCount 寄存器数量 * @param dataType 结果数据类型 */ 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]; try { Thread.sleep(3000); } catch (Exception ex) { ex.printStackTrace(); } 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.OIL.getCode().equals(dataType)) { byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2)); // 解析为浮点数(大端字节顺序) float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN); return String.valueOf(floatValue); } else if (DataTypeEnum.LIJIUOIL.getCode().equals(dataType)) { byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2)); byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes); // 解析为浮点数(大端字节顺序) float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN); return String.valueOf(floatValue); } else if (DataTypeEnum.LIJIUJUN.getCode().equals(dataType)) { byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2)); // 解析为浮点数(大端字节顺序) float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN); return String.valueOf(floatValue); } else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(dataType)) { //todo 未做处理 byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2)); byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes); // 解析为浮点数(大端字节顺序) float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN); return String.valueOf(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; } }