Explorar o código

feat(gas): 更新数据解析逻辑以支持新协议格式

- 新增 calcSumOnly 方法用于仅累加字节数据并取低8位- 调整帧结构解析偏移量,适配新的数据格式
- 修改气体浓度和类型解析方式,支持多种气体类型识别
- 添加温度、湿度解析功能,并保留两位小数- 更新示例报文用于测试新协议格式
- 打印输出中增加温度、湿度及气体单位信息
林仔 hai 7 meses
pai
achega
e654e3510f

+ 14 - 0
flammable-gas-service/src/main/java/com/zksy/gas/utils/DataCheckUtil.java

@@ -94,4 +94,18 @@ public class DataCheckUtil {
         }
         return (0xFF - (sum & 0xFF)) & 0xFF;
     }
+    /**
+     * 仅对数据累加后取低8位
+     * @param data 待计算字节数组
+     * @param offset 起始索引
+     * @param length 计算长度
+     * @return 8位校验结果
+     */
+    static int calcSumOnly(byte[] data, int offset, int length) {
+        int sum = 0;
+        for (int i = offset; i < offset + length; i++) {
+            sum += (data[i] & 0xFF); // 累加每个字节的无符号值
+        }
+        return sum & 0xFF; // 仅取低8位,无FF-操作
+    }
 }

+ 77 - 45
flammable-gas-service/src/main/java/com/zksy/gas/utils/DataParser.java

@@ -1,8 +1,8 @@
 package com.zksy.gas.utils;
 
 import com.zksy.gas.domain.GasMonitorData;
-
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDateTime;
 
 public class DataParser {
@@ -10,72 +10,106 @@ public class DataParser {
     public static GasMonitorData parseMessage(byte[] frame) {
         GasMonitorData data = new GasMonitorData();
 
-        // 帧类型
-        data.setFrameType(frame[2] & 0xFF);
+        // 帧类型(直接输出)
+        data.setFrameType(Integer.valueOf(String.format("%02X", frame[3])));
 
-        // MAC 地址
+        // MAC 地址 (4~11)
         byte[] macBytes = new byte[8];
-        System.arraycopy(frame, 3, macBytes, 0, 8);
+        System.arraycopy(frame, 4, macBytes, 0, 8);
         data.setMacAddress(ProtocolUtils.bytesToHex(macBytes));
 
-        // 短地址
-        data.setShortAddress(String.format("%02X%02X", frame[11], frame[12]));
+        // 短地址 (12~13)
+        data.setShortAddress(String.format("%02X%02X", frame[12], frame[13]));
+
+        // 自动应答 (14)
+        data.setAutoReplyOption(Integer.valueOf(String.format("%02X", frame[14])));
 
-        // 自动应答
-        data.setAutoReplyOption(frame[13] & 0xFF);
+        // 跳过 AA 帧头(15) 和数据长度(16)
+        int offset = 17;
 
-        // 序号
-        data.setSequenceNo(frame[15] & 0xFF);
+        // 序号 (17)
+        data.setSequenceNo(frame[offset] & 0xFF);
+        offset++;
 
-        // 命令
-        data.setCommand(frame[16] & 0xFF);
+        // 命令 (18)
+        data.setCommand(frame[offset] & 0xFF);
+        offset++;
 
-        // 设备属性
-        data.setDeviceAttr(frame[17] & 0xFF);
+        // 设备属性 (19)
+        data.setDeviceAttr(frame[offset] & 0xFF);
+        offset++;
 
-        // 协议版本
-        data.setProtocolVersion(String.format("%02X", frame[18]));
+        // 协议版本 (20)
+        data.setProtocolVersion(String.format("%02X", frame[offset]));
+        offset++;
 
-        // 报警信息(小端序 00 04 -> 0x0400)
-        int alarmInfo = ((frame[20] & 0xFF) << 8) | (frame[19] & 0xFF);
+        // 报警信息 (21~22)
+        int alarmInfo = ((frame[offset + 1] & 0xFF) << 8) | (frame[offset] & 0xFF);
         data.setAlarmInfo(alarmInfo);
+        offset += 2;
 
-        // 时间戳(BCD)
-        LocalDateTime reportTime = ProtocolUtils.parseTimestamp(frame, 21);
+        // 时间戳 (23~28)
+        LocalDateTime reportTime = ProtocolUtils.parseTimestamp(frame, offset);
         data.setReportTime(reportTime);
+        offset += 6;
 
-        // 数据个数
-        int dataCount = frame[27] & 0xFF;
+        // 数据个数 (29)
+        int dataCount = frame[offset] & 0xFF;
+        offset++;
 
-        // ------- 数据段开始(例子里有 5 个数据) -------
-        int offset = 28;
+        // ------------------- 数据段 -------------------
 
-        // 1. 气体浓度 + 气体类型
-        // 格式:04 10 00 00 00 00 -> 1004 (浓度=100, 类型=CH4)
-        int gasValue = ((frame[offset + 1] & 0xFF) << 8) | (frame[offset] & 0xFF);
-        int gasTypeCode = ((frame[offset + 3] & 0xFF) << 8) | (frame[offset + 2] & 0xFF);
-        data.setGasConcentration(BigDecimal.valueOf(gasValue));
-        data.setGasType(gasTypeCode == 0x0004 ? "CH4" : "未知");
+        // 1. 气体浓度 + 类型 (6 字节)
+        int gasTypeCode = frame[offset] & 0xFF; // 第1字节:气体类型
+        int unitCode = frame[offset + 1] & 0xFF; // 第2字节:单位
+        offset += 2;
 
-        offset += 6;
+        long gasValueRaw = ((long)(frame[offset + 3] & 0xFF) << 24)
+                | ((long)(frame[offset + 2] & 0xFF) << 16)
+                | ((long)(frame[offset + 1] & 0xFF) << 8)
+                | ((long)(frame[offset] & 0xFF));
+        offset += 4;
+
+        String gasType;
+        switch (gasTypeCode) {
+            case 0x04: gasType = "CH4"; break;
+            case 0x05: gasType = "CO"; break;
+            case 0x06: gasType = "O2"; break;
+            default: gasType = "未知";
+        }
+
+        BigDecimal gasConcentration = BigDecimal.valueOf(gasValueRaw / 10.0);
+        data.setGasType(gasType);
+        data.setGasConcentration(gasConcentration);
+        data.setGasUnit(unitCode == 0x10 ? "%LEL" : "未知单位");
 
         // 2. 电池电量
-        float battery = ProtocolUtils.bytesToFloatLE(frame, offset + 2);
+        float battery = ProtocolUtils.readFloat6(frame, offset);
         data.setBattery(BigDecimal.valueOf(battery));
         offset += 6;
 
         // 3. 信号强度
-        float signal = ProtocolUtils.bytesToFloatLE(frame, offset + 2);
+        float signal = ProtocolUtils.readFloat6(frame, offset);
         data.setSignalStrength(signal);
         offset += 6;
 
-        // 4. 经度
-        float lon = ProtocolUtils.bytesToFloatLE(frame, offset + 2);
+        // 4. 温度(保留两位小数)
+        float temperature = ProtocolUtils.readFloat6(frame, offset);
+        data.setTemperature(new BigDecimal(temperature).setScale(2, RoundingMode.HALF_UP).floatValue());
+        offset += 6;
+
+        // 5. 湿度(保留两位小数)
+        float humidity = ProtocolUtils.readFloat6(frame, offset);
+        data.setHumidity(new BigDecimal(humidity).setScale(2, RoundingMode.HALF_UP).floatValue());
+        offset += 6;
+
+        // 6. 经度
+        float lon = ProtocolUtils.readFloat6(frame, offset);
         data.setLongitude(BigDecimal.valueOf(lon));
         offset += 6;
 
-        // 5. 纬度
-        float lat = ProtocolUtils.bytesToFloatLE(frame, offset + 2);
+        // 7. 纬度
+        float lat = ProtocolUtils.readFloat6(frame, offset);
         data.setLatitude(BigDecimal.valueOf(lat));
         offset += 6;
 
@@ -86,12 +120,8 @@ public class DataParser {
     }
 
     public static void main(String[] args) {
-        // 示例报文
-        String hex = "7E003A902509040070010000FFFE01AA2B00010813000425091908473305"
-                + "041000000000F96F00000000F76F0000F841FA6F00000000FB6F0000000007";
-
+        String hex = "7E0046902509250560010000FFFE01AA37FA350813180025101614432007041000000000F96F00004442F76F00000000FF6F102CE841FE6F96646642FA6FEEB3E142FB6FF368E141C08E";
         byte[] frame = ProtocolUtils.hexStringToBytes(hex);
-
         GasMonitorData parsed = parseMessage(frame);
 
         System.out.println("========== 解析结果 ==========");
@@ -105,12 +135,14 @@ public class DataParser {
         System.out.println("协议版本: " + parsed.getProtocolVersion());
         System.out.println("报警信息: " + parsed.getAlarmInfo());
         System.out.println("时间戳: " + parsed.getReportTime());
-        System.out.println("气体浓度: " + parsed.getGasConcentration() + " %LEL");
+        System.out.println("气体浓度: " + parsed.getGasConcentration() + " " + parsed.getGasUnit());
         System.out.println("气体类型: " + parsed.getGasType());
         System.out.println("电池电量: " + parsed.getBattery());
         System.out.println("信号强度: " + parsed.getSignalStrength());
+        System.out.println("温度: " + parsed.getTemperature() + " °C");
+        System.out.println("湿度: " + parsed.getHumidity() + " %");
         System.out.println("经度: " + parsed.getLongitude());
         System.out.println("纬度: " + parsed.getLatitude());
         System.out.println("入库时间: " + parsed.getCreateTime());
     }
-}
+}