package com.doumee.core.device; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.Socket; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; public class WaterElectricityUtil { private static double parseBcdToDouble(byte[] bcdBytes) { StringBuilder sb = new StringBuilder(); for (byte b : bcdBytes) { sb.append(String.format("%02X", b)); } try { return Double.parseDouble(sb.toString()); } catch (NumberFormatException e) { return 0.0; } } private static byte[] reverseAddress(String address) { byte[] result = new byte[6]; for (int i = 0; i < 6; i++) { if (i * 2 + 1 < address.length()) { String hex = address.substring(i * 2, Math.min((i + 1) * 2, address.length())); result[i] = (byte) Integer.parseInt(hex, 16); } } return result; } private static byte calculateChecksum(byte[] data, int offset, int length) { int sum = 0; for (int i = offset; i < offset + length; i++) { sum += data[i] & 0xFF; } return (byte) (sum & 0xFF); } private static byte[] hexStringToByteArray(String hex) { int len = hex.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); } return data; } public static byte calcCS(byte[] data) { int sum = 0; for (byte b : data) { sum += b & 0xFF; } return (byte) (sum & 0xFF); } public static byte[] getRequestParam(int feCount, byte[] address, byte control, byte[] data) throws IOException { ///FEFEFE 68 999999999999 68 01 02 65 F3C1 16 // byte b = (byte) 0xFE; // byte[] msg = {(byte) 0xFE,0x68}; ByteArrayOutputStream frame = new ByteArrayOutputStream(); for (int i = 0; i < feCount; i++) { frame.write(0xFE); } // 2. 帧起始符 frame.write(0x68); // 3. 地址域 frame.write(address); // 4. 再次帧起始符 frame.write(0x68); // 5. 控制码 frame.write(control); // 6. 数据长度 frame.write(data.length); // 7. 数据域 frame.write(data); // 8. 计算 CS(从第一个 68 开始) byte[] csData = frame.toByteArray(); int start = feCount; // 第一个 68 的位置 byte cs = calcCS(Arrays.copyOfRange(csData, start, csData.length)); frame.write(cs); // 9. 结束符 frame.write(0x16); return frame.toByteArray(); } private static byte[] readDeviceData(String ip, int port, byte[] data) { Socket socket = null; try { socket = new Socket(ip, port); socket.setSoTimeout(5000); java.io.OutputStream out = socket.getOutputStream(); java.io.InputStream in = socket.getInputStream(); out.write(data); out.flush(); // 读取响应 byte[] buffer = new byte[2048]; int bytesRead = in.read(buffer); byte[] response = Arrays.copyOf(buffer, bytesRead); // 解析响应数据 return response; } catch (Exception e) { // e.printStackTrace(); throw new RuntimeException("Failed to read from device", e); } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { } } } } private static String bytesToHex(byte[] bytes) { StringBuilder hexString = new StringBuilder(); for (byte b : bytes) { String hex = String.format("%02X", b & 0xFF); hexString.append(hex); } return hexString.toString(); } /** * 将12位十进制地址转换为6字节BCD小端序地址 * * @param decimalAddress 12位十进制地址字符串 * @return 6字节的BCD地址(小端序) */ private static byte[] convertToBCDAddress(String decimalAddress) { // 1. 验证输入 if (decimalAddress == null || decimalAddress.length() != 12) { throw new IllegalArgumentException("地址必须是12位十进制数"); } if (!decimalAddress.matches("\\d{12}")) { throw new IllegalArgumentException("地址必须全部是数字"); } // 2. 准备结果数组(6字节) byte[] result = new byte[6]; // 3. 从右向左每2位一组处理(小端序) for (int i = 0; i < 6; i++) { // 计算在字符串中的位置(从右向左) int strIndex = 10 - (i * 2); // 因为要取两位,所以是10,8,6,4,2,0 String twoDigits = decimalAddress.substring(strIndex, strIndex + 2); // 将两位十进制数转换为BCD字节 // 例如:"25" -> 0x25 result[i] = (byte) Integer.parseInt(twoDigits, 16); } // 注意:上面的循环顺序已经是小端序,result[0]存的是最低两位 return result; } private static String subByte(String value, byte sub) { byte b = (byte) Integer.parseInt(value, 16); int result = (b & 0xFF) - (sub & 0xFF); // 确保结果在0-255范围内(处理负数) if (result < 0) { result += 256; } String hexResult = String.format("%02X", result & 0xFF); return hexResult; } private static String addByte(String value, byte add) { byte b = (byte) Integer.parseInt(value, 16); int result = (b & 0xFF) + (add & 0xFF); // 确保结果在0-255范围内(处理负数) if (result < 0) { result += 256; } String hexResult = String.format("%02X", result & 0xFF); return hexResult; } private static String[] parseSub33Reverse(String msg, int n) { //33333333 3333 String[] nArr = new String[n]; byte _33 = 0x33; for (int i = 0; i < n; i++) { int index = i * 2; String twoDigits = msg.substring(index, index + 2); String hexResult = subByte(twoDigits, _33); // 反向存储:nArr[n - i - 1] 实现反转 nArr[n - i - 1] = hexResult; } return nArr; } public static Map water(String ip, int port, String address) throws IOException { byte[] address_buf = convertToBCDAddress(address); byte control = 0x01; byte[] data = {0x43, (byte) 0xC3}; byte[] bufReq = getRequestParam(3, address_buf, control, data); byte[] resp = readDeviceData(ip, port, bufReq); String hex = bytesToHex(resp); //FEFEFE6899254652010068810843C3333433333333E916 // System.out.println(hex); String msg = hex.substring(30, 30 + 8 + 4); String[] nArr = parseSub33Reverse(msg, 4); Double total = strArrNum(nArr); Map r = new HashMap<>(); r.put("total", total); msg = hex.substring(40, 40 + 2); byte sub = 0x33; String hexResult = subByte(msg, sub); String v = hexToBinary(hexResult); /** * Y0.B0 存储器状态 (1:故障,0:正常); * Y0.B1 阀门状态 (1:故障,0:正常); * Y0.B2 信号状态 (1:故障,0:正常); * Y0.B3 电池状态 (1:故障,0:正常); * Y0.B4 保留; * Y0.B5 保留; * Y0.B6 水表通讯状态( 1:故障,0:正常); * Y0.B7 阀门开关状态 (1: 合,0:开); * 注意:状态位无时为 0(正常) * 红色:无记忆直读表的状态 */ r.put("status", v); return r; } private static void electricityTotal(String ip, int port, byte[] addressBuf, Map map) throws IOException { byte control = 0x11; byte[] data = {0x33, 0x33, 0x33, 0x33}; byte[] bufReq = getRequestParam(4, addressBuf, control, data); byte[] respBuf = readDeviceData(ip, port, bufReq); String resp = bytesToHex(respBuf); String msg = resp.substring(28 + 8, 28 + 8 + 8); String[] nArr = parseSub33Reverse(msg, 4); Double total = strArrNum(nArr); map.put("total", total); } /** * 电表跳闸、合闸 * @param ip * @param port * @param addressBuf * @param type (0跳闸 1合闸) * @param date 有效截止时间 * @throws IOException */ private static boolean electricityControl(String ip, int port, byte[] addressBuf,int type, String date) { /** * N1为控制命令类型,N1=1AH代表跳闸4D,N1=1BH代表合闸4F允许N2保留 * 权限密码操作代码:PAP2P1P0C3C2C1C0(02/223203/111111H) * 4F * TCP/IP直接合闸指令[2026年03月09日 10:57:39] * Tx ->FEFEFEFE68615121010000681C1035366555776655444F33568843433659E016 * TCP/IP直接合闸指令[2026年03月09日 10:57:40] * Rx <-FEFEFEFE68615121010000689C004016 * 直接合闸执行成功! 9C */ try { byte control = 0x1C; byte n1 = 0x4D; if(type==1){ n1 = 0x4F; } // byte[] data0 = {0x02, 0x03, 0x32, 0x22,0x44,0x33,0x22,0x11}; byte[] data = {0x35, 0x36, 0x65, 0x55,0x77,0x66,0x55,0x44,n1,0x33,0,0,0,0,0,0}; byte[] data2 = getDateBytes(date); for (int i = 0; i < data2.length; i++) { data[10+i]=data2[i]; } byte[] bufReq = getRequestParam(4, addressBuf, control, data); String reqt = bytesToHex(bufReq); System.out.println(reqt); byte[] respBuf = readDeviceData(ip, port, bufReq); String resp = bytesToHex(respBuf); System.out.println(resp); //FEFEFEFE68379707010000689C004216 String msg = resp.substring(24, 26); return msg.equals("9C"); }catch (Exception e){ } return false; } private static byte[] getDateBytes(String dateStr) { // String dateStr = new SimpleDateFormat("yyyyMMddHHmmss").format(date); dateStr = dateStr.substring(2); // 1. 验证输入 if (dateStr == null || dateStr.length() != 12) { throw new IllegalArgumentException("时间必须是12位十进制数"); } if (!dateStr.matches("\\d{12}")) { throw new IllegalArgumentException("时间必须全部是数字"); } // 2. 准备结果数组(6字节) byte[] result = new byte[6]; // 3. 从右向左每2位一组处理(小端序) byte add = 0x33; for (int i = 0; i < 6; i++) { // 计算在字符串中的位置(从右向左) int strIndex = 10 - (i * 2); // 因为要取两位,所以是10,8,6,4,2,0 String twoDigits = dateStr.substring(strIndex, strIndex + 2); // 将两位十进制数转换为BCD字节 // 例如:"25" -> 0x25 int t = Integer.parseInt(twoDigits, 16); int t1 = ( t& 0xFF) + (add & 0xFF); System.out.println(t1+":"); result[i] =(byte) t1 ; } // 注意:上面的循环顺序已经是小端序,result[0]存的是最低两位 return result; } private static void electricityStatus(String ip, int port, byte[] addressBuf, Map map) throws IOException { byte control = 0x11; byte[] data = {0x36, 0x38, 0x33, 0x37}; byte[] bufReq = getRequestParam(4, addressBuf, control, data); byte[] respBuf = readDeviceData(ip, port, bufReq); String resp = bytesToHex(respBuf); String msg = resp.substring(36, 36 + 4); System.out.println(resp); String[] nArr = parseSub33Reverse(msg, 2); String status = hexToBinary1(nArr); // String resp = "FEFEFEFE 68 615121010000 68 91 06 36383337 3333 7916"; map.put("status", status); } private static void electricityTime(String ip, int port, byte[] addressBuf, Map map) throws IOException { byte control = 0x11; byte[] data = {0x3F, 0x34, 0x33, 0x37}; byte[] bufReq = getRequestParam(4, addressBuf, control, data); byte[] respBuf = readDeviceData(ip, port, bufReq); String resp = bytesToHex(respBuf); String msg = resp.substring(36, 36 + 14); // System.out.println(msg); String[] nArr = parseSub33Reverse(msg, 7); String ts = hexToBinary1(nArr); String time = "20"+ts.substring(0,6)+ts.substring(8); Date date = getDateByStr(time); System.out.println( formatData(date)); // String resp = "FEFEFEFE 68 615121010000 68 91 06 36383337 3333 7916"; map.put("time", date); // map.put("currentTime", formatData(date)); } public static Date getDateByStr(String date) { TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai"); if(date!=null ){ int i = date.indexOf("+"); if(i >0){ date = date.substring(0,i); } } DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); df.setTimeZone(tz); Date dates = null; try { dates = df.parse(date); } catch (Exception e) { e.printStackTrace(); } return dates; } public static String formatData(Date date) { DateFormat df = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒"); try { return df.format(date); } catch (Exception e) { } return null; } public static Map electricityData(String ip, int port, String address) throws IOException { Map r = new HashMap<>(); byte[] addressBuf = convertToBCDAddress(address); electricityTotal(ip, port, addressBuf, r); electricityStatus(ip, port, addressBuf, r); electricityTime(ip, port, addressBuf, r); return r; } public static boolean electricityAct(String ip, int port, String address,int type,String dateStr) { Map r = new HashMap<>(); byte[] addressBuf = convertToBCDAddress(address); return electricityControl(ip,port,addressBuf,type,dateStr); } private static String hexToBinary(String hex) { StringBuilder sb = new StringBuilder(); for (char c : hex.toCharArray()) { int val = Integer.parseInt(String.valueOf(c), 16); sb.append(String.format("%4s", Integer.toBinaryString(val)).replace(' ', '0')); } return sb.toString(); } private static String hexToBinary(String[] hexArr) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < hexArr.length; i++) { sb.append(hexToBinary(hexArr[i])); } return sb.toString(); } private static String hexToBinary1(String[] hexArr) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < hexArr.length; i++) { sb.append(hexArr[i]); } return sb.toString(); } private static String addHex(String hex1, String hex2) { int num1 = Integer.parseInt(hex1.replace("0x", ""), 16); int num2 = Integer.parseInt(hex2.replace("0x", ""), 16); int sum = num1 + num2; return "0x" + Integer.toHexString(sum).toUpperCase(); } private static void testWater() throws IOException { //"00000152462599"; 000152462599 //FEFEFE 68 999999999999 68 01(C) 02(L) 65(DI0) F3(DI1) C1(CS校验码) 16(结束符) //FEFEFE6899254652010068010243C33016 //FEFEFE6899254652010068810843C3333333333333E816 // FEFEFE6899254652010068810843C3333333333333E816 String ip = "192.168.1.78"; int port = 1030; // DeviceData d = readDeviceData(ip, port, "00000152462599"); // System.out.println(d); // String address = "000152462599"; String address = "000152462599"; //00000152462599 byte[] address_buf = convertToBCDAddress(address); // byte[] address_buf = hexStringToByteArray(address); // System.out.println(buf); /** * * FEFEFE 68 000152462599 68010243C33016 * FEFEFE 68 992546520100 68010243C33016 */ byte control = 0x01; byte[] data = {0x43, (byte) 0xC3}; byte[] datas = getRequestParam(3, address_buf, control, data); System.out.println(bytesToHex(datas)); System.out.println("FEFEFE6899254652010068010243C33016"); // datas = hexStringToByteArray("FEFEFE6899254652010068010243C33016"); byte[] resp = readDeviceData(ip, port, datas); String r = bytesToHex(resp); System.out.println(r); /** * * FEFEFE 68 992546520100 68 01 02 43C3 30 16 * FEFEFE 68 992546520100 68 81 08 43C3 33333333 3333 E8 16 */ // String r = "FEFEFE6899254652010068810843C3333333333333E816"; String msg = r.substring(30, 30 + 8 + 4); System.out.println(msg); String[] nArr = parseSub33Reverse(msg, 4); System.out.println(strArrNum(nArr)); // byte d10 = 0x10; // byte add = 0x33; // String hex = String.format("%02X", (d10 + add) & 0xFF); // System.out.println(hex); // r = addHex("0x10", "0x33"); // System.out.println(r); // // r = addHex("0x90", "0x33"); // System.out.println(r); msg = r.substring(40, 40 + 2); System.out.println(msg); byte sub = 0x33; String hexResult = subByte(msg, sub); String v = hexToBinary(hexResult); System.out.println(v); } /** * 最后一位是小数点 * * @param nArr * @return */ private static Double strArrNum(String[] nArr) { if (nArr == null || nArr.length == 0) { return 0.0; } // 将所有部分拼接起来 StringBuilder sb = new StringBuilder(); for (int i = 0; i < nArr.length; i++) { sb.append(nArr[i]); } // 在适当位置插入小数点 String combined = sb.toString(); int totalLength = combined.length(); int decimalLength = nArr[nArr.length - 1].length(); // 插入小数点 String numberStr = combined.substring(0, totalLength - decimalLength) + "." + combined.substring(totalLength - decimalLength); return Double.parseDouble(numberStr); } public static void electricityTest() throws IOException { //000001215161 // FEFEFEFE 68 615121010000 68 11 04 33333333 8516 // FEFEFEFE6861512101000068910833333333A93333334B16 // FEFEFEFE6861512101000068910833333333AC3333334E16 String ip = "192.168.1.78"; int port = 1030; String address = "000001215161"; byte[] addressBuf = convertToBCDAddress(address); // byte control = 0x11; // byte[] data = {0x33, 0x33, 0x33, 0x33}; //// // byte[] bufReq = getRequestParam(4, addressBuf, control, data); //// String req = bytesToHex(bufReq); ////// String param = "FEFEFE68615121010000681104333333338516"; //// System.out.println(req); ////// System.out.println(param); //// byte[] buf = hexStringToByteArray(param); // byte[] respBuf = readDeviceData(ip, port, bufReq); // String hex = bytesToHex(respBuf); //// System.out.println(hex); // String resp = "FEFEFEFE6861512101000068910833333333AC3333334E16"; //// FEFEFEFE68615121010000 68 91 08 33333333 A9 333333 4B16 // // String msg = resp.substring(28, 28 + 8); // System.out.println(msg); // // String[] nArr = parseSub33Reverse(msg, 4); // System.out.println(strArrNum(nArr)); // msg = resp.substring(28 + 8, 28 + 8 + 8); // System.out.println(msg); // // nArr = parseSub33Reverse(msg, 4); //// parseSub33Reverse // System.out.println(strArrNum(nArr)); // String msgStatus = "FEFEFEFE 68 379707010000 68 11 04 36383337 9316"; // String msgStatus = "FEFEFEFE68379707010000681104363833379316"; // byte control = 0x11; // byte[] data = {0x36, 0x38, 0x33, 0x37}; // byte[] bufReq = getRequestParam(4, addressBuf, control, data); // String req = bytesToHex(bufReq); // System.out.println(req); // System.out.println(msgStatus); // byte[] respBuf = readDeviceData(ip, port, bufReq); // String resp = bytesToHex(respBuf); // System.out.println(resp); // FEFEFEFE 68 615121010000 68 91 06 36383337 3333 79 16 // FEFEFEFE 68 615121010000 68 91 06 36383337 3333 79 16 String resp = "FEFEFEFE686151210100006891063638333733337916"; String msg = resp.substring(36, 36 + 4); System.out.println(msg); String[] nArr = parseSub33Reverse(msg, 2); // System.out.println(strArrNum(nArr)); String v = hexToBinary(nArr); v="0000000000010000"; System.out.println(v); System.out.println(v.charAt(11)); } public static void main(String[] args) throws IOException { // testWater(); // electricityTest(); // water("192.168.1.78",1030,"000152462599"); // Map map = electricityData("192.168.1.78", 1030, "000001215161"); // System.out.println(JSONObject.toJSONString(map)); electricityAct("192.168.1.78", 1030, "000001215161",0,"20260309162655"); // FEFEFE6899254652010068810 843C3333433333333 E9 16 // FEFEFE6899254652010068810 84 3C3333433333333E916 // Map map1 = water("192.168.1.78", 1030, "000152462599"); // System.out.println(JSONObject.toJSONString(map1)); } }