|
@@ -44,9 +44,10 @@ public class DataParser {
|
|
|
data.setProtocolVersion(String.valueOf(frame[offset] & 0xFF));
|
|
data.setProtocolVersion(String.valueOf(frame[offset] & 0xFF));
|
|
|
offset++;
|
|
offset++;
|
|
|
|
|
|
|
|
- // 报警信息 (21~22)
|
|
|
|
|
- int alarmInfo = (frame[offset] & 0xFF ) | ((frame[offset + 1] & 0xFF) << 8);
|
|
|
|
|
|
|
+ // 报警信息 (21~22):2 字节低字节在前(18 00 → 0x0018),与文档“01 00 低报警、04 00 超量程”一致
|
|
|
|
|
+ int alarmInfo = (frame[offset] & 0xFF) | ((frame[offset + 1] & 0xFF) << 8);
|
|
|
data.setAlarmInfo(alarmInfo);
|
|
data.setAlarmInfo(alarmInfo);
|
|
|
|
|
+ data.setAlarmNames(alarmNames(alarmInfo));
|
|
|
offset += 2;
|
|
offset += 2;
|
|
|
|
|
|
|
|
// 时间戳 (23~28)
|
|
// 时间戳 (23~28)
|
|
@@ -59,60 +60,49 @@ public class DataParser {
|
|
|
offset++;
|
|
offset++;
|
|
|
|
|
|
|
|
// ------------------- 数据段 -------------------
|
|
// ------------------- 数据段 -------------------
|
|
|
-
|
|
|
|
|
- // 1. 气体浓度 + 类型 (6 字节)
|
|
|
|
|
- int gasTypeCode = frame[offset] & 0xFF; // 第1字节:气体类型
|
|
|
|
|
- int unitCode = frame[offset + 1] & 0xFF; // 第2字节:单位
|
|
|
|
|
- offset += 2;
|
|
|
|
|
-
|
|
|
|
|
- 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 = "未知";
|
|
|
|
|
|
|
+ // 数据项总数由 dataCount 决定,数量随设备上报项变化(5 项无经纬度、7 项有经纬度),
|
|
|
|
|
+ // 不能按固定 6 项读取,否则短帧会越界。
|
|
|
|
|
+
|
|
|
|
|
+ // 第 1 项固定为气体浓度:气体类型 1 字节 + 单位 1 字节 + 值 4 字节
|
|
|
|
|
+ if (offset + 6 <= frame.length - 2) {
|
|
|
|
|
+ int gasTypeCode = frame[offset] & 0xFF;
|
|
|
|
|
+ int unitCode = frame[offset + 1] & 0xFF;
|
|
|
|
|
+ offset += 2;
|
|
|
|
|
+
|
|
|
|
|
+ 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 = "未知";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ data.setGasType(gasType);
|
|
|
|
|
+ data.setGasConcentration(BigDecimal.valueOf(gasValueRaw / 10.0));
|
|
|
|
|
+ data.setGasUnit(unitCode == 0x10 ? "%LEL" : "未知单位");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- BigDecimal gasConcentration = BigDecimal.valueOf(gasValueRaw / 10.0);
|
|
|
|
|
- data.setGasType(gasType);
|
|
|
|
|
- data.setGasConcentration(gasConcentration);
|
|
|
|
|
- data.setGasUnit(unitCode == 0x10 ? "%LEL" : "未知单位");
|
|
|
|
|
-
|
|
|
|
|
- // 2. 电池电量
|
|
|
|
|
- float battery = ProtocolUtils.readFloat6(frame, offset);
|
|
|
|
|
- data.setBattery(BigDecimal.valueOf(battery));
|
|
|
|
|
- offset += 6;
|
|
|
|
|
-
|
|
|
|
|
- // 3. 信号强度
|
|
|
|
|
- float signal = ProtocolUtils.readFloat6(frame, offset);
|
|
|
|
|
- data.setSignalStrength(signal);
|
|
|
|
|
- offset += 6;
|
|
|
|
|
-
|
|
|
|
|
- // 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;
|
|
|
|
|
-
|
|
|
|
|
- // 7. 纬度
|
|
|
|
|
- float lat = ProtocolUtils.readFloat6(frame, offset);
|
|
|
|
|
- data.setLatitude(BigDecimal.valueOf(lat));
|
|
|
|
|
- offset += 6;
|
|
|
|
|
|
|
+ // 其余项:[2 字节数据标识][4 字节小端浮点],按标识分派,与上报顺序无关
|
|
|
|
|
+ for (int i = 1; i < dataCount && offset + 6 <= frame.length - 2; i++) {
|
|
|
|
|
+ int tag = ((frame[offset] & 0xFF) << 8) | (frame[offset + 1] & 0xFF);
|
|
|
|
|
+ float value = ProtocolUtils.readFloat6(frame, offset);
|
|
|
|
|
+ switch (tag) {
|
|
|
|
|
+ case 0xF96F: data.setBattery(BigDecimal.valueOf(value)); break;
|
|
|
|
|
+ case 0xF76F: data.setSignalStrength(value); break;
|
|
|
|
|
+ case 0xFF6F: data.setTemperature(round2(value)); break;
|
|
|
|
|
+ case 0xFE6F: data.setHumidity(round2(value)); break;
|
|
|
|
|
+ case 0xFA6F: data.setLongitude(BigDecimal.valueOf(value)); break;
|
|
|
|
|
+ case 0xFB6F: data.setLatitude(BigDecimal.valueOf(value)); break;
|
|
|
|
|
+ default: break; // 未知标识按 6 字节长度跳过
|
|
|
|
|
+ }
|
|
|
|
|
+ offset += 6;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 入库时间
|
|
// 入库时间
|
|
|
data.setCreateTime(LocalDateTime.now());
|
|
data.setCreateTime(LocalDateTime.now());
|
|
@@ -120,6 +110,28 @@ public class DataParser {
|
|
|
return data;
|
|
return data;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private static float round2(float value) {
|
|
|
|
|
+ return new BigDecimal(value).setScale(2, RoundingMode.HALF_UP).floatValue();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 报警位名称,下标即位号,顺序与厂商协议一致 */
|
|
|
|
|
+ private static final String[] ALARM_NAMES = {
|
|
|
|
|
+ "低报警", "高报警", "超量程", "标定周期", "超寿命", "跌倒报警", "欠压报警", "区间报警",
|
|
|
|
|
+ "按键报警", "震动报警", "水位报警", "断电报警", "传感器故障", "超湿报警", "超温报警", "系统故障"
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ /** 报警位转可读描述,无报警返回 null */
|
|
|
|
|
+ private static String alarmNames(int alarmInfo) {
|
|
|
|
|
+ StringBuilder names = new StringBuilder();
|
|
|
|
|
+ for (int i = 0; i < ALARM_NAMES.length; i++) {
|
|
|
|
|
+ if ((alarmInfo & (1 << i)) != 0) {
|
|
|
|
|
+ if (names.length() > 0) names.append(',');
|
|
|
|
|
+ names.append(ALARM_NAMES[i]);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return names.length() == 0 ? null : names.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
public static void main(String[] args) {
|
|
public static void main(String[] args) {
|
|
|
String hex = "7E0046902509250560010000FFFE01AA37FA350813180025101614432007041000000000F96F00004442F76F00000000FF6F102CE841FE6F96646642FA6FEEB3E142FB6FF368E141C08E";
|
|
String hex = "7E0046902509250560010000FFFE01AA37FA350813180025101614432007041000000000F96F00004442F76F00000000FF6F102CE841FE6F96646642FA6FEEB3E142FB6FF368E141C08E";
|
|
|
byte[] frame = ProtocolUtils.hexStringToBytes(hex);
|
|
byte[] frame = ProtocolUtils.hexStringToBytes(hex);
|