From febc6291b89cfb707f94fccd7114b5e6fdf4fd59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=B1=BC=E5=B9=B2?= <1810377322@163.com> Date: Tue, 19 Aug 2025 18:11:04 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=94=E5=8A=A8=E6=8E=A7=E5=88=B6=E7=AE=B1?= =?UTF-8?q?=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugins/emqx/conf/EventTypeMapper.java | 11 +- .../plugins/emqx/conf/GasAlarmDataParser.java | 46 +++- .../plugins/emqx/conf/IoTConfigProtocol.java | 3 + .../emqx/conf/LinkageControlDataParser.java | 248 ++++++++++++++++++ .../plugins/emqx/conf/ProtocolTest.java | 75 +++++- .../plugins/emqx/service/EmqxPlugin.java | 49 +++- .../plugins/emqx/service/MqttDevice.java | 14 +- .../src/main/resources/application.yml | 6 +- 8 files changed, 420 insertions(+), 32 deletions(-) create mode 100644 emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/LinkageControlDataParser.java diff --git a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/EventTypeMapper.java b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/EventTypeMapper.java index 397c573..113dd07 100644 --- a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/EventTypeMapper.java +++ b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/EventTypeMapper.java @@ -2,9 +2,10 @@ package cc.iotkit.plugins.emqx.conf; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class EventTypeMapper { - private static final Map EVENT_TYPE_MAP = new HashMap<>(); + private static final Map EVENT_TYPE_MAP = new ConcurrentHashMap<>(); static { // 节点相关事件 @@ -23,7 +24,11 @@ public class EventTypeMapper { EVENT_TYPE_MAP.put(13, "模块联动"); EVENT_TYPE_MAP.put(14, "阀门动作"); EVENT_TYPE_MAP.put(15, "浓度变化上报"); - + EVENT_TYPE_MAP.put(16, "预热"); + EVENT_TYPE_MAP.put(17, "预热完成上报"); + EVENT_TYPE_MAP.put(18, "寿命到期上报"); + EVENT_TYPE_MAP.put(19, "新节点连接"); + EVENT_TYPE_MAP.put(20, "节点联动恢复"); // 控制器相关事件 EVENT_TYPE_MAP.put(30, "自检"); EVENT_TYPE_MAP.put(31, "备电故障"); @@ -47,6 +52,8 @@ public class EventTypeMapper { // 正常上报事件 EVENT_TYPE_MAP.put(128, "燃气报警器正常数据上报"); EVENT_TYPE_MAP.put(129, "动火离人正常数据上报"); + EVENT_TYPE_MAP.put(130, "联动控制箱正常数据上报"); + EVENT_TYPE_MAP.put(151, "上报输出反馈状态变化"); } public static String getEventTypeName(int eventType) { diff --git a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/GasAlarmDataParser.java b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/GasAlarmDataParser.java index d0b9210..2fe4d8c 100644 --- a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/GasAlarmDataParser.java +++ b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/GasAlarmDataParser.java @@ -1,5 +1,7 @@ package cc.iotkit.plugins.emqx.conf; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; import java.time.LocalDateTime; @@ -121,8 +123,9 @@ public class GasAlarmDataParser { Map eventMap = new LinkedHashMap<>(); eventMap.put("dataType", "CONTROLLER_EVENT"); - eventMap.put("eventType", buffer.getShort() & 0xFFFF); - eventMap.put("eventTypeValue", EventTypeMapper.getEventTypeName(Integer.parseInt(eventMap.get("eventType").toString()))); + int eventType = buffer.getShort() & 0xFFFF; + eventMap.put("eventType", eventType); + eventMap.put("eventTypeValue", EventTypeMapper.getEventTypeName(eventType)); eventMap.put("timestamp", parseBcdTime(buffer)); // eventList.add(eventMap); @@ -135,19 +138,30 @@ public class GasAlarmDataParser { Map eventMap = new LinkedHashMap<>(); eventMap.put("dataType", "NODE_EVENT"); - eventMap.put("eventType", buffer.getShort() & 0xFFFF); + int eventType = buffer.getShort() & 0xFFFF; + eventMap.put("eventType", eventType); if (!Objects.equals(eventMap.get("eventType"), 15)) { - eventMap.put("eventTypeValue", EventTypeMapper.getEventTypeName(Integer.parseInt(eventMap.get("eventType").toString()))); + eventMap.put("eventTypeValue", EventTypeMapper.getEventTypeName(eventType)); eventMap.put("timestamp", parseBcdTime(buffer)); eventMap.put("nodeId", buffer.getShort() & 0xFFFF); - eventMap.put("dataValue", buffer.getShort() & 0xFFFF); + // BigDecimal decimalValue = new BigDecimal(buffer.getShort() & 0xFFFF) + // .divide(new BigDecimal(1), 4, RoundingMode.HALF_UP).stripTrailingZeros(); + eventMap.put("dataValues", buffer.getShort() & 0xFFFF); + // eventMap.put("dataDetectorValue" , eventMap.get("dataValues")); } else { - eventMap.put("eventTypeValue", EventTypeMapper.getEventTypeName(Integer.parseInt(eventMap.get("eventType").toString()))); + eventMap.put("eventTypeValue", EventTypeMapper.getEventTypeName(eventType)); eventMap.put("timestamp", parseBcdTime(buffer)); - eventMap.put("totalNodes", buffer.getShort() & 0xFF); + eventMap.put("totalNodes", buffer.get() & 0xFF); eventMap.put("nodeId", buffer.getShort() & 0xFFFF); + System.out.println("浓度变化的剩余长度"+buffer.remaining()); + // int nodeCounter = 0; while (buffer.remaining() >= 2) { - eventMap.put("dataValue", buffer.getShort() & 0xFFFF); + // String suffix = String.valueOf(nodeCounter++); + // BigDecimal decimalValue = new BigDecimal(buffer.getShort() & 0xFFFF) + // .divide(new BigDecimal(1), 4, RoundingMode.HALF_UP).stripTrailingZeros(); + eventMap.put("dataValues", buffer.getShort() & 0xFFFF); + // 0:节点为探测器 + eventMap.put("dataDetectorValue" , eventMap.get("dataValues")); } } @@ -164,8 +178,9 @@ public class GasAlarmDataParser { // 基础信息 Map baseInfo = new LinkedHashMap<>(); baseInfo.put("dataType", "NORMAL_DATA"); - baseInfo.put("eventType", buffer.getShort() & 0xFFFF); - baseInfo.put("eventTypeValue", EventTypeMapper.getEventTypeName(Integer.parseInt(baseInfo.get("eventType").toString()))); + int eventType = buffer.getShort() & 0xFFFF; + baseInfo.put("eventType", eventType); + baseInfo.put("eventTypeValue", EventTypeMapper.getEventTypeName(eventType)); baseInfo.put("timestamp", parseBcdTime(buffer)); baseInfo.put("totalNodes", buffer.getShort() & 0xFFFF); baseInfo.put("reportedNodes", buffer.get() & 0xFF); @@ -182,13 +197,18 @@ public class GasAlarmDataParser { // nodeMap.put("unit", buffer.get() & 0xFF); // 节点节点参数 // nodeMap.put("precision", buffer.get() & 0xFF); baseInfo.put("gasType" + suffix, GasDetectorParser.parse(buffer.getShort() & 0xFFFF)); - baseInfo.put("dataValue" + suffix, buffer.getShort() & 0xFFFF); + Integer dataValue = buffer.getShort() & 0xFFFF; if (Objects.equals(baseInfo.get("nodeType" + suffix), 0)) { + // BigDecimal decimalValue = new BigDecimal(dataValue) + // .divide(new BigDecimal(1), 4, RoundingMode.HALF_UP).stripTrailingZeros(); + baseInfo.put("dataValues" + suffix, dataValue); // 0:节点为探测器 - baseInfo.put("dataTypeValue" + suffix, baseInfo.get("dataValue" + suffix)); + baseInfo.put("dataDetectorValue" + suffix, baseInfo.get("dataValues" + suffix)); } else if (Objects.equals(baseInfo.get("nodeType" + suffix), 1)) { + + baseInfo.put("dataValues" + suffix, dataValue); //1:节点为输出模块 - baseInfo.put("dataTypeValue" + suffix, baseInfo.get("dataValue" + suffix).equals("0") ? "未动作" : "已动作"); + baseInfo.put("dataSinksValue" + suffix, baseInfo.get("dataValues" + suffix).equals("0") ? "未动作" : "已动作"); } // dataList.add(nodeMap); } diff --git a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/IoTConfigProtocol.java b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/IoTConfigProtocol.java index 507d86b..fefc393 100644 --- a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/IoTConfigProtocol.java +++ b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/IoTConfigProtocol.java @@ -25,6 +25,7 @@ public class IoTConfigProtocol { public static final int SIGNAL = 0x0024; public static final int TIME_SYNC = 0x0025; public static final int VERSION = 0x0026; + public static final int REPORT_RATE_LinkConstraint = 0x0100; // 生成读取指令 // 反向映射Map private static final Map CONFIG_ID_TO_KEY = new HashMap<>(); @@ -47,6 +48,8 @@ public class IoTConfigProtocol { CONFIG_ID_TO_KEY.put(SIGNAL, "signal"); CONFIG_ID_TO_KEY.put(TIME_SYNC, "timeSyncInternal"); CONFIG_ID_TO_KEY.put(VERSION, "version"); + CONFIG_ID_TO_KEY.put(REPORT_RATE_LinkConstraint, "controlOutput"); + } public static String getKeyByConfigId(int configId) { diff --git a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/LinkageControlDataParser.java b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/LinkageControlDataParser.java new file mode 100644 index 0000000..51146a6 --- /dev/null +++ b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/LinkageControlDataParser.java @@ -0,0 +1,248 @@ +package cc.iotkit.plugins.emqx.conf; + +import java.nio.ByteBuffer; +import java.text.SimpleDateFormat; +import java.util.*; + +public class LinkageControlDataParser { + + private static void testEventGroup(String groupName, String[] testCases) { + System.out.println("\n=== " + groupName + "测试 ==="); + for (String hexData : testCases) { + try { + Map result = LinkageControlDataParser.parseHexDataToList(hexData); + System.out.println("原始数据: " + hexData); + System.out.println("解析结果: " + result.get("eventType") + + " - " + result.get("dataType")); + System.out.println("rrr解析结果: " + result.get(0)); + + + } catch (Exception e) { + System.out.println("解析异常: " + e.getMessage()); + } + } + } + + public static Map parseHexDataToList(String hexData) { + System.out.println("parseHexDataToList: " + hexData); + byte[] data = hexStringToByteArray(hexData); + return parseDataToList(data); + } + + public static Map parseDataToList(byte[] data) { + Map resultList = new HashMap<>(); + if (data == null || data.length < 1) { + return resultList; + } + + int eventType = Byte.toUnsignedInt(data[0]) + Byte.toUnsignedInt(data[1]); + System.out.println("eventType: " + eventType); + if (eventType == 130) { + // // 正常数据上报 (NORMAL_DATA) + return parseNormalDataToList(data); + } /*else if (isControllerEvent(eventType)) { + + // 控制器事件 (CONTROLLER_EVENT) + return parseControllerEventToList(data); + }*/ + + // 节点事件 (NODE_EVENT) + return LinkageControlEventToList(data); + } + + private static Map LinkageControlEventToList(byte[] data) { + // List> eventList = new ArrayList<>(); + ByteBuffer buffer = ByteBuffer.wrap(data); + Map eventMap = new LinkedHashMap<>(); + + eventMap.put("dataType", "LINKAGE_CONTROL_EVENT"); + int eventType = buffer.getShort() & 0xFFFF; + eventMap.put("eventType", eventType); + eventMap.put("eventTypeValue", EventTypeMapper.getEventTypeName(eventType)); + eventMap.put("timestamp", parseBcdTime(buffer)); + eventMap.put("nodeId", buffer.getShort() & 0xFFFF); + Integer dataValue = buffer.getShort() & 0xFFFF; + eventMap.put("dataValues", dataValue); + String status = (dataValue == 0) ? "不支持反馈" : + (dataValue == 1) ? "反馈未动作" : + (dataValue == 2) ? "反馈动作" : "未知状态"; + eventMap.put("dataDetectorValue" , status); + return eventMap; + } + + private static Map parseNodeEventToList(byte[] data) { + // Map eventList = new HashMap<>(); + ByteBuffer buffer = ByteBuffer.wrap(data); + Map eventMap = new LinkedHashMap<>(); + + eventMap.put("dataType", "NODE_EVENT"); + int eventType = buffer.getShort() & 0xFFFF; + eventMap.put("eventType", eventType); + if (!Objects.equals(eventMap.get("eventType"), 15)) { + eventMap.put("eventTypeValue", EventTypeMapper.getEventTypeName(eventType)); + eventMap.put("timestamp", parseBcdTime(buffer)); + eventMap.put("nodeId", buffer.getShort() & 0xFFFF); + // BigDecimal decimalValue = new BigDecimal(buffer.getShort() & 0xFFFF) + // .divide(new BigDecimal(1), 4, RoundingMode.HALF_UP).stripTrailingZeros(); + eventMap.put("dataValues", buffer.getShort() & 0xFFFF); + // eventMap.put("dataDetectorValue" , eventMap.get("dataValues")); + } else { + eventMap.put("eventTypeValue", EventTypeMapper.getEventTypeName(eventType)); + eventMap.put("timestamp", parseBcdTime(buffer)); + eventMap.put("totalNodes", buffer.get() & 0xFF); + eventMap.put("nodeId", buffer.getShort() & 0xFFFF); + System.out.println("浓度变化的剩余长度"+buffer.remaining()); + // int nodeCounter = 0; + while (buffer.remaining() >= 2) { + // String suffix = String.valueOf(nodeCounter++); + // BigDecimal decimalValue = new BigDecimal(buffer.getShort() & 0xFFFF) + // .divide(new BigDecimal(1), 4, RoundingMode.HALF_UP).stripTrailingZeros(); + eventMap.put("dataValues", buffer.getShort() & 0xFFFF); + // 0:节点为探测器 + eventMap.put("dataDetectorValue" , eventMap.get("dataValues")); + } + + } + System.out.println("eventMap+++++++++++: " + eventMap); + //eventList.add(eventMap); + + return eventMap; + } + + private static Map parseNormalDataToList(byte[] data) { + // List> dataList = new ArrayList<>(); + ByteBuffer buffer = ByteBuffer.wrap(data); + + // 基础信息 + Map baseInfo = new LinkedHashMap<>(); + baseInfo.put("dataType", "Linkage_DATA"); + int eventType = buffer.getShort() & 0xFFFF; + baseInfo.put("eventType", eventType); + baseInfo.put("eventTypeValue", EventTypeMapper.getEventTypeName(eventType)); + baseInfo.put("timestamp", parseBcdTime(buffer)); + // baseInfo.put("totalNodes", buffer.getShort() & 0xFFFF); + baseInfo.put("reportedNodes", buffer.get() & 0xFF); + // dataList.add(baseInfo); + System.out.println(buffer.remaining()); + // 节点数据 + // 节点数据(动态添加数字后缀) + int nodeCounter = 0; + while (buffer.remaining() >= 7) { + String suffix = String.valueOf(nodeCounter++); + // Map nodeMap = new LinkedHashMap<>(); + baseInfo.put("nodeId" + suffix, buffer.getShort() & 0xFFFF); + // baseInfo.put("nodeType" + suffix, buffer.get() & 0xFF); + // nodeMap.put("unit", buffer.get() & 0xFF); // 节点节点参数 + // nodeMap.put("precision", buffer.get() & 0xFF); + // baseInfo.put("gasType" + suffix, GasDetectorParser.parse(buffer.getShort() & 0xFFFF)); + Integer dataValue = buffer.getShort() & 0xFFFF; + // if (Objects.equals(baseInfo.get("nodeType" + suffix), 0)) { + // BigDecimal decimalValue = new BigDecimal(dataValue) + // .divide(new BigDecimal(1), 4, RoundingMode.HALF_UP).stripTrailingZeros(); + baseInfo.put("dataValues" + suffix, dataValue); + // 0:节点为探测器 + // if (Objects.equals(baseInfo.get("nodeType" + suffix), 0)) { + String status = (dataValue == 0) ? "不支持反馈" : + (dataValue == 1) ? "反馈未动作" : + (dataValue == 2) ? "反馈动作" : "未知状态"; + baseInfo.put("dataDetectorValue" + suffix, status); + // } else if (Objects.equals(baseInfo.get("nodeType" + suffix), 1)) { + + // baseInfo.put("dataValues" + suffix, dataValue); + //1:节点为输出模块 + // baseInfo.put("dataSinksValue" + suffix, baseInfo.get("dataValues" + suffix).equals("0") ? "未动作" : "已动作"); + // } + // dataList.add(nodeMap); + } + + return baseInfo; + } + // 辅助方法:字节数组转十六进制字符串 + + private static String bytesToHex(byte[] bytes) { + + StringBuilder hexSb = new StringBuilder(); + for (byte b : bytes) { + hexSb.append(String.format("%02X", b)); + } + return hexSb.toString(); + + } + // 保留原有辅助方法 + /*public static String parseBcdTime(ByteBuffer buffer) { + // 打印ByteBuffer的十六进制表示 + System.out.println("ByteBuffer内容(十六进制): " + bytesToHex(buffer.array())); + + byte[] bcdTime = new byte[6]; + + buffer.get(bcdTime); + + StringBuilder sb = new StringBuilder(); + + for (byte b : bcdTime) { + + // 提取高四位和低四位,并转换为十进制数字 + + int high = (b >> 4) & 0x0F; + + int low = b & 0x0F; + + // 组合成两位十进制字符串 + + sb.append(String.format("%1d%1d", high, low)); + + } + + String bcdStr = sb.toString(); + + try { + + SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss"); + + sdf.set2DigitYearStart(new Date(946684800000L)); // 2000-01-01 + + Date date = sdf.parse(bcdStr); + + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); + + } catch (Exception e) { + + return bcdStr; // 返回原始BCD字符串(可能包含越界值) + + } + }*/ + + public static String parseBcdTime(ByteBuffer buffer) { + // 打印ByteBuffer的十六进制表示 + System.out.println("ByteBuffer内容(十六进制): " + bytesToHex(buffer.array())); + + byte[] bcdTime = new byte[6]; + buffer.get(bcdTime); + StringBuilder sb = new StringBuilder(); + for (byte b : bcdTime) { + sb.append(String.format("%02X", b)); + } + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss"); + sdf.set2DigitYearStart(new SimpleDateFormat("yyyy").parse("2000")); // 设置世纪转折点 + Date date = sdf.parse(sb.toString()); + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); + } catch (Exception e) { + return sb.toString(); + } + } + + public static byte[] hexStringToByteArray(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; + } + + private static boolean isControllerEvent(int eventType) { + return eventType >= 30 && eventType <= 38; + } +} diff --git a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/ProtocolTest.java b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/ProtocolTest.java index 7340762..ab8a212 100644 --- a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/ProtocolTest.java +++ b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/conf/ProtocolTest.java @@ -3,13 +3,16 @@ package cc.iotkit.plugins.emqx.conf; import io.vertx.core.buffer.Buffer; import io.vertx.core.json.JsonObject; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.net.URI; import java.net.URISyntaxException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static cc.iotkit.plugins.emqx.conf.CRC16ModbusUtil.buildFrame; import static cc.iotkit.plugins.emqx.conf.IoTConfigProtocol.*; @@ -70,9 +73,75 @@ public class ProtocolTest { return ByteBuffer.wrap(bytes); } + public static String formatHexByte(String input) { + // 移除0x前缀并保留纯十六进制字符 + String hex = input.replaceAll("(?i)^0x", "").replaceAll("[^0-9a-fA-F]", ""); + // 标准化为2位十六进制(不足补零,超长截断) + return hex.isEmpty() ? "00" + : hex.length() == 1 ? "0" + hex + : hex.substring(hex.length() - 2); + } + public static void extractDetectorData(Map baseInfo) { + for (Map.Entry entry : baseInfo.entrySet()) { + if (entry.getKey().startsWith("dataDetectorValue")) { + String suffix = entry.getKey().substring(17); // 去掉前缀"dataDetectorValue" + Integer value = (Integer) entry.getValue(); + + // 获取对应节点信息 + String nodeIdKey = "nodeId" + suffix; + String gasTypeKey = "gasType" + suffix; + + System.out.println("NodeID: " + baseInfo.get(nodeIdKey) + + ", GasType: " + baseInfo.get(gasTypeKey) + + ", DetectorValue: " + value); + } + } + } + public static String generateWriteCommand(int configId, byte[] data) { + + ByteBuffer buf = ByteBuffer.allocate(3 + data.length); + //buf.putShort((short) (5 + data.length)); // 数据长度 + // buf.putShort((short) terminalType); + buf.putShort((short) configId); + buf.put((byte) data.length); // 数据长度字节 + buf.put(data); // 实际数据 + + return bytesToHex(buf.array()); + } + private static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02X", b)); + } + return sb.toString(); + } public static void main(String[] args) { + String dsada=null; + System.out.println(dsada.startsWith("https")); + System.out.println(generateWriteCommand(0x0100,ByteBuffer.allocate(4) + .order(ByteOrder.BIG_ENDIAN) + .putInt(Integer.parseUnsignedInt("00010001", 16)).array())); + System.out.println(ByteBuffer.allocate(2).putShort(Short.parseShort("1")).array()); + System.out.println(EventTypeMapper.getEventTypeName(Integer.parseInt("20"))); + BigDecimal decimalValue = new BigDecimal("1123.391111111111111") + .divide(new BigDecimal(1), 4, RoundingMode.HALF_UP).stripTrailingZeros(); + + System.out.println(decimalValue); + Map baseInfo = new HashMap<>(); + baseInfo.put("nodeId", 12345); + baseInfo.put("nodeType", 0); // 探测器 + baseInfo.put("dataDetectorValue", 0); + baseInfo.put("gasType", "ddddddddddddddddd"); + baseInfo.put("dataValue", "ddddddddddaaaa"); // 探测器值 + baseInfo.put("nodeId0111", 67890); + baseInfo.put("nodeType0111", 1); // 输出模块 + baseInfo.put("dataDetectorValue0111", 0); + baseInfo.put("gasType0111", "dasa12321"); + baseInfo.put("dataValue0111", "Ddsa"); + extractDetectorData(baseInfo); + System.out.println(formatHexByte("0x014")); // GasAlarmDataParser.parseBcdTime(createBcdTimeBuffer("250707131758")); System.out.println(GasAlarmDataParser.parseBcdTime(createBcdTimeBuffer("250703103146"))); //String url = "https://minio.dddd.com/feijialuo/20250702/lQLPKHYULtpjo8HM_Mz8sCPMoZZYPmEbCD1keBQpVgA_252_2521751416904105.png"; diff --git a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/service/EmqxPlugin.java b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/service/EmqxPlugin.java index e4d0e28..f71bdd2 100644 --- a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/service/EmqxPlugin.java +++ b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/service/EmqxPlugin.java @@ -99,8 +99,8 @@ public class EmqxPlugin implements PluginCloseListener, IPlugin, Runnable { String serverPassword = IdUtil.fastSimpleUUID(); MqttClientOptions options = new MqttClientOptions() - .setClientId("server11223") - .setUsername("server11223") + .setClientId("server112233") + .setUsername("server112233") .setPassword(serverPassword) .setCleanSession(true) .setMaxInflightQueue(100) @@ -244,19 +244,23 @@ public class EmqxPlugin implements PluginCloseListener, IPlugin, Runnable { switch(result.get("deviceType").toString()) { case "0": device.setProductKey("CEMpmANABN7Tt6Jh"); - + //家用报警器 break; case "1": device.setProductKey("XmXYxjzihseT76As"); - + //独立式报警器 break; case "2": device.setProductKey("bAASX8tBjYQjBGFP"); - + //工商业控制器 break; case "3": + //动火离人设备 device.setProductKey("WfpZZFkMxxbGfRca"); - + case "4": + //联动控制箱设备 + System.out.println("联动控制箱设备注册++++++++++++++++++++++++++++++++++++++++++"); + device.setProductKey("MQFejp7cyDMH3enG"); break; } //注册 @@ -282,6 +286,11 @@ public class EmqxPlugin implements PluginCloseListener, IPlugin, Runnable { FireSafetyDataReceiver.handleHexData(data).forEach( (key, value) -> result.merge(key, value, (v1, v2) -> v2)); payload.put("params",result); + }else if(cmd.equals("0x15")){ + //联动控制箱设备状态及参数数据上报 + LinkageControlDataParser.parseHexDataToList(data).forEach( + (key, value) -> result.merge(key, value, (v1, v2) -> v2)); + payload.put("params",result); } else if(cmd.equals("0x23")){ flag=false; @@ -460,8 +469,8 @@ public class EmqxPlugin implements PluginCloseListener, IPlugin, Runnable { private String replyToInstructions(JsonObject payload) { String mid = payload.getString("messageId"); String cmd = payload.getString("cmd"); - payload.getString("cmd"); - System.out.println("mid1" + mid); + //payload.getString("cmd"); + /* System.out.println("mid1" + mid); System.out.println("cmd1" + cmd); if (mid.toLowerCase().startsWith("0x")) { mid = mid.substring(2); @@ -471,12 +480,22 @@ public class EmqxPlugin implements PluginCloseListener, IPlugin, Runnable { } cmd = cmd.replaceAll("\\D", ""); mid = mid.replaceAll("\\D", ""); + if (cmd.length() == 0) { + cmd = "00"; // 空值默认补零 + } else if (cmd.length() == 1) { + cmd = "0" + cmd; // 单字符左侧补零 + } else if (cmd.length() > 2) { + cmd = cmd.slice(-2); // 超长取最后两位 + } + if (mid.length() % 2 != 0) { mid = "0" + mid; // 左侧补零 } if (cmd.length() % 2 != 0) { cmd = "0" + cmd; // 左侧补零 - } + }*/ + cmd = formatHexByte(cmd); + mid = formatHexByte(mid); System.out.println("mid" + mid); System.out.println("cmd" + cmd); // System.out.println(mid + "re++++++++++++++++++++++++++++++++++++++++++++++++++" + cmd); @@ -485,7 +504,17 @@ public class EmqxPlugin implements PluginCloseListener, IPlugin, Runnable { mid, cmd, "00" + formatBCDToHex(generateBCDTime())); return replyMessage; } - /** + public static String formatHexByte(String input) { + // 移除0x前缀并保留纯十六进制字符 + String hex = input.replaceAll("(?i)^0x", "").replaceAll("[^0-9a-fA-F]", ""); + + // 标准化为2位十六进制(不足补零,超长截断) + return hex.isEmpty() ? "00" + : hex.length() == 1 ? "0" + hex + : hex.substring(hex.length() - 2); + } + + /** * 回复设备 */ private void reply1(String replyMessage,String deviceName, JsonObject payload) { diff --git a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/service/MqttDevice.java b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/service/MqttDevice.java index 76fca71..9d6bf32 100644 --- a/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/service/MqttDevice.java +++ b/emqx-plugin/src/main/java/cc/iotkit/plugins/emqx/service/MqttDevice.java @@ -19,6 +19,7 @@ import lombok.Setter; import org.springframework.stereotype.Service; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; @@ -94,6 +95,14 @@ public class MqttDevice implements IDevice { configId = REPORT_RATE_LOWER; tlvData = ByteBuffer.allocate(2).putShort(Short.parseShort(value)).array(); break; + + case "controlOutput": + configId = REPORT_RATE_LinkConstraint; + tlvData = ByteBuffer.allocate(4) + .order(ByteOrder.BIG_ENDIAN) + .putInt(Integer.parseUnsignedInt(value, 16)).array(); + break; + case "card": case "signal": case "version": @@ -180,6 +189,9 @@ public class MqttDevice implements IDevice { case "version": configId = VERSION; break; + case "controlOutput": + configId = REPORT_RATE_LinkConstraint; + break; default: System.out.println("Unsupported config: " + key); continue; @@ -228,10 +240,10 @@ public class MqttDevice implements IDevice { for (int i = 0; i < list.size(); i++) { String replyMessage = buildFrame("01","01", "00", "24", list.get(i).get("data").toString()); - //循环发送配置指令 /* String replyMessage = buildFrame("01", "01", "01", "24", "01" + list.get(i).get("data"));*/ + System.out.println("配置指令" + replyMessage); send( topic,replyMessage ); diff --git a/emqx-plugin/src/main/resources/application.yml b/emqx-plugin/src/main/resources/application.yml index f313a37..ca8141e 100644 --- a/emqx-plugin/src/main/resources/application.yml +++ b/emqx-plugin/src/main/resources/application.yml @@ -1,9 +1,9 @@ plugin: - runMode: dev + runMode: prod mainPackage: cc.iotkit.plugin emqx: - host: 127.0.0.1 + host: 123.57.78.108 port: 1883 - topics: /sys/# + topics: FIGARO/# authPort: 8104