diff --git a/viewshanghai-module-iot/viewshanghai-module-iot-gateway/src/main/java/com/viewshanghai/module/iot/gateway/codec/jt808/IotJt808DeviceMessageCodec.java b/viewshanghai-module-iot/viewshanghai-module-iot-gateway/src/main/java/com/viewshanghai/module/iot/gateway/codec/jt808/IotJt808DeviceMessageCodec.java index 01cc47e..2dc3438 100644 --- a/viewshanghai-module-iot/viewshanghai-module-iot-gateway/src/main/java/com/viewshanghai/module/iot/gateway/codec/jt808/IotJt808DeviceMessageCodec.java +++ b/viewshanghai-module-iot/viewshanghai-module-iot-gateway/src/main/java/com/viewshanghai/module/iot/gateway/codec/jt808/IotJt808DeviceMessageCodec.java @@ -68,8 +68,12 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec { case "jt808.platform.textDown", "textDown" -> encodeTextDown(message, phone, flowId); // === 上行消息方法(不应用于下行) === + // 注意:正常情况下不应该到达这里,因为: + // 1. 业务层已跳过 JT808 协议的回复消息生成 + // 2. 协议处理器会自动生成通用应答 + // 这里保留作为防御性检查 case "thing.property.post", "thing.property.report" -> { - log.warn("[encode][JT808 协议不支持下行属性上报方法: {},请使用 thing.property.set 进行属性设置]", method); + log.warn("[encode][JT808 协议不支持下行属性上报方法: {},请使用 thing.property.set 进行属性设置。如果这是回复消息,应使用 jt808.platform.commonResp 方法]", method); yield new byte[0]; } @@ -83,6 +87,16 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec { throw new RuntimeException("JT808 消息编码失败: " + e.getMessage(), e); } } + + /** + * 判断是否为上行消息方法 + */ + private boolean isUpstreamMethod(String method) { + return "thing.property.post".equals(method) + || "thing.property.report".equals(method) + || "thing.event.post".equals(method) + || "thing.state.update".equals(method); + } @Override public IotDeviceMessage decode(byte[] bytes) { @@ -259,38 +273,41 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec { /** * 解析按键事件为事件上报格式(thing.event.post) - * - * 物模型标准格式: + *
+ * 根据 JT808 协议: + * - 短按:keyId = 0x01-0x0A(对应1-10号键),keyState = 按键次数 + * - 长按:keyId = 0x0B-0x0E(对应长按1-4号键),keyState = 按键次数 + *
+ * 物模型标准格式(简化版,只保留 keyId 和 keyState): * { * "eventId": "button_event", * "eventTime": 1234567890, * "params": { - * "keyId": 1, - * "keyState": 1, - * "keyType": "short_press", - * "keyNumber": 1, - * "isLongPress": false + * "keyId": 1, // 0x01=短按1号键, 0x0B=长按1号键 + * "keyState": 1 // 按键次数(0x01=按键一次) * } * } + *
+ * 判断长按/短按:通过 keyId 判断
+ * - keyId < 0x0B:短按
+ * - keyId >= 0x0B:长按
*/
private Map
+ * 提取优先级:
+ * 1. 从 metadata.flowId 中提取(最可靠)
+ * 2. 从 requestId 中提取(格式:terminalPhone_flowId_timestamp)
+ */
+ @SuppressWarnings("unchecked")
+ private int extractFlowId(IotDeviceMessage message) {
+ // 优先从 metadata 中提取
+ if (message.getParams() instanceof Map) {
+ Map, ?> params = (Map, ?>) message.getParams();
+ if (params.get("_metadata") instanceof Map) {
+ Map, ?> metadata = (Map, ?>) params.get("_metadata");
+ Object flowId = metadata.get("flowId");
+ if (flowId instanceof Number) {
+ return ((Number) flowId).intValue();
+ }
+ }
+ }
+
+ // 如果 metadata 中没有,尝试从 requestId 中提取
+ String requestId = message.getRequestId();
+ if (requestId != null && requestId.contains("_")) {
+ try {
+ String[] parts = requestId.split("_");
+ if (parts.length >= 2) {
+ return Integer.parseInt(parts[1]);
+ }
+ } catch (Exception e) {
+ log.debug("[extractFlowId][从 requestId 提取流水号失败: {}]", requestId);
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * 从消息中提取 JT808 消息ID
+ * 从 metadata 中获取原始 JT808 消息ID(格式:0x%04X,如 "0x0200")
+ */
+ @SuppressWarnings("unchecked")
+ private int extractJt808MsgId(IotDeviceMessage message) {
+ Object params = message.getParams();
+ if (params instanceof Map) {
+ Map
- * 流水号存储在消息的 _metadata.flowId 字段中
- *
- * @param message 设备消息
- * @return 流水号,提取失败返回 1
- */
- @SuppressWarnings("unchecked")
- private int extractFlowId(IotDeviceMessage message) {
- if (message.getParams() instanceof Map) {
- Map, ?> params = (Map, ?>) message.getParams();
- if (params.get("_metadata") instanceof Map) {
- Map, ?> metadata = (Map, ?>) params.get("_metadata");
- Object flowId = metadata.get("flowId");
- if (flowId instanceof Number) {
- return ((Number) flowId).intValue();
- }
- }
- }
- return 1;
- }
/**
* 从消息中提取鉴权码