燃气报警器解析\动火离人解析
parent
34ea26c4b6
commit
c696dc477d
@ -0,0 +1,44 @@
|
|||||||
|
package cc.iotkit.plugins.emqx.conf;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class GasDetectorParser {
|
||||||
|
|
||||||
|
// 探测器精度映射
|
||||||
|
private static final Map<Integer, String> PRECISION_MAP = Map.of(
|
||||||
|
0b000, "*1",
|
||||||
|
0b001, "*0.1",
|
||||||
|
0b010, "*0.01",
|
||||||
|
0b011, "*0.001",
|
||||||
|
0b100, "*0.0001"
|
||||||
|
);
|
||||||
|
|
||||||
|
// 浓度单位映射
|
||||||
|
private static final Map<Integer, String> UNIT_MAP = Map.of(
|
||||||
|
0b000, "%LEL",
|
||||||
|
0b001, "PPM",
|
||||||
|
0b010, "%VOL"
|
||||||
|
);
|
||||||
|
|
||||||
|
// 气体类型映射
|
||||||
|
private static final Map<Integer, String> GAS_TYPE_MAP = Map.of(
|
||||||
|
0b0000, "甲烷",
|
||||||
|
0b0001, "一氧化碳",
|
||||||
|
0b0010, "丙烷",
|
||||||
|
0b0011, "氢气",
|
||||||
|
0b0100, "苯",
|
||||||
|
0b0101, "氧气"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static String parse(int data) {
|
||||||
|
int precisionBits = (data >> 13) & 0b111; // 提取bit15-13
|
||||||
|
int unitBits = (data >> 10) & 0b111; // 提取bit12-10
|
||||||
|
int gasTypeBits = (data >> 6) & 0b1111; // 提取bit9-6
|
||||||
|
|
||||||
|
return String.format("探测器精度: %s, 浓度单位: %s, 测量气体: %s",
|
||||||
|
PRECISION_MAP.getOrDefault(precisionBits, "未知精度"),
|
||||||
|
UNIT_MAP.getOrDefault(unitBits, "未知单位"),
|
||||||
|
GAS_TYPE_MAP.getOrDefault(gasTypeBits, "未知气体")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
package cc.iotkit.plugins.emqx.conf;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.mqtt.messages.MqttMessage;
|
||||||
|
import io.vertx.mqtt.messages.MqttPublishMessage;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class MqttDataProcessor {
|
||||||
|
private static final byte HEADER = (byte) 0xAA;
|
||||||
|
private static final byte FOOTER = (byte) 0x55;
|
||||||
|
private static final int CRC_START_INDEX = 3; // 帧长度开始位置
|
||||||
|
private static final String HEX_FORMAT = "0x%02X";
|
||||||
|
public static String bytesToHex(byte[] bytes) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (byte b : bytes) {
|
||||||
|
sb.append(String.format("%02X", b));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
public static JsonObject parseFrame(byte[] frameData) {
|
||||||
|
|
||||||
|
// 基础校验
|
||||||
|
if (frameData[0] != HEADER || frameData[frameData.length - 1] != FOOTER) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取各字段
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(frameData);
|
||||||
|
byte type = buffer.get(1);
|
||||||
|
byte version = buffer.get(2);
|
||||||
|
int length = Short.toUnsignedInt(buffer.getShort(3));
|
||||||
|
byte mid = buffer.get(5);
|
||||||
|
byte cmd = buffer.get(6);
|
||||||
|
String hexCmd = String.format(HEX_FORMAT, cmd);
|
||||||
|
// 数据域提取
|
||||||
|
int dataLength = length - 10; // 总长减去固定字段长度
|
||||||
|
byte[] data = new byte[dataLength];
|
||||||
|
System.arraycopy(frameData, 7, data, 0, dataLength);
|
||||||
|
String data1 = parseToHexString(data);
|
||||||
|
// CRC校验
|
||||||
|
byte[] crcData = new byte[length - 6]; // 从LENGTH到DATA
|
||||||
|
System.arraycopy(frameData, 3, crcData, 0, crcData.length);
|
||||||
|
int receivedCrc = (frameData[length-2] & 0xFF) << 8 | (frameData[length-3] & 0xFF);
|
||||||
|
|
||||||
|
int calculatedCrc = calculateModbusCRC(crcData);
|
||||||
|
|
||||||
|
if (receivedCrc != calculatedCrc) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// 转换为16进制字符串
|
||||||
|
// 完整帧数据转16进制
|
||||||
|
StringBuilder frameHexBuilder = new StringBuilder();
|
||||||
|
for (byte b : frameData) {
|
||||||
|
frameHexBuilder.append(String.format("%02X", b));
|
||||||
|
}
|
||||||
|
String rawHex = frameHexBuilder.toString();
|
||||||
|
// 构建JSON
|
||||||
|
// ObjectMapper mapper = new ObjectMapper();
|
||||||
|
// ObjectNode json = mapper.createObjectNode();
|
||||||
|
JsonObject json = new JsonObject();
|
||||||
|
json.put("protocolType", type);
|
||||||
|
json.put("protocolVersion", version);
|
||||||
|
json.put("messageId", mid);
|
||||||
|
json.put("cmd", hexCmd);
|
||||||
|
json.put("data", data1);
|
||||||
|
json.put("rawHex", rawHex);
|
||||||
|
json.put("crcValid", true);
|
||||||
|
System.out.println("拿到的所有数据++++++++++" + json);
|
||||||
|
// JsonObject jsonObject = new JsonObject(json.toString());
|
||||||
|
return json;
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public static String parseToHexString(byte[] frameData) {
|
||||||
|
StringBuilder hexStr = new StringBuilder();
|
||||||
|
for (byte b : frameData) {
|
||||||
|
hexStr.append(String.format("%02X ", b));
|
||||||
|
}
|
||||||
|
return hexStr.toString().trim();
|
||||||
|
}
|
||||||
|
public static int calculateModbusCRC(byte[] data) {
|
||||||
|
int crc = 0xFFFF;
|
||||||
|
for (byte b : data) {
|
||||||
|
crc ^= (b & 0xFF);
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if ((crc & 1) == 1) {
|
||||||
|
crc = (crc >>> 1) ^ 0xA001;
|
||||||
|
} else {
|
||||||
|
crc >>>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package cc.iotkit.plugins.emqx.conf;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.DecoderException;
|
||||||
|
import org.apache.commons.codec.binary.Hex;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class MqttHexProcessor {
|
||||||
|
|
||||||
|
|
||||||
|
// 检测是否为HEX字符串格式
|
||||||
|
private static boolean isHexString(byte[] data) {
|
||||||
|
if (data.length % 2 != 0) return false;
|
||||||
|
for (byte b : data) {
|
||||||
|
char c = (char) b;
|
||||||
|
if (!(Character.isDigit(c) ||
|
||||||
|
(c >= 'A' && c <= 'F') ||
|
||||||
|
(c >= 'a' && c <= 'f') ||
|
||||||
|
Character.isWhitespace(c))) { // 新增空格检查
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HEX字符串转字节数组
|
||||||
|
/* private static byte[] parseHexString(String s) {
|
||||||
|
int len = s.length();
|
||||||
|
byte[] data = new byte[len / 2];
|
||||||
|
for (int i = 0; i < len; i += 2) {
|
||||||
|
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
||||||
|
+ Character.digit(s.charAt(i+1), 16));
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// 统一返回byte[]的入口方法
|
||||||
|
public static byte[] processToBytes(byte[] payload) {
|
||||||
|
try {
|
||||||
|
String payloadStr = new String(payload, StandardCharsets.UTF_8);
|
||||||
|
System.out.println("payloadStr:" + payloadStr);
|
||||||
|
System.out.println("payloadStr1:" + isHexString(payload));
|
||||||
|
return isHexString(payload) ?
|
||||||
|
Hex.decodeHex(payloadStr.replaceAll("\\s+", "")) :
|
||||||
|
payload; // 原始字节直接返回
|
||||||
|
} catch (Exception e) {
|
||||||
|
return payload; // 异常时返回原始数据
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*public static void main(String[] args) throws DecoderException {
|
||||||
|
String input = "AA 01 01 00 35001100013836323537313037393339313237393839383631313235323037303833363037383837000000000111b12255"; // 原始字符串
|
||||||
|
// byte[] result = convertHexStringToBytes(input);
|
||||||
|
byte[] bytes = Hex.decodeHex(input);
|
||||||
|
// 基础校验
|
||||||
|
|
||||||
|
|
||||||
|
// 提取各字段
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||||
|
byte type = buffer.get(1);
|
||||||
|
byte version = buffer.get(2);
|
||||||
|
System.out.println(String.format("%02X", bytes[0]));
|
||||||
|
System.out.println(type);
|
||||||
|
System.out.println(version);
|
||||||
|
|
||||||
|
}*/
|
||||||
|
}
|
Loading…
Reference in New Issue