diff --git a/src/main/java/com/iot/transport/jt808/common/Consts.java b/src/main/java/com/iot/transport/jt808/common/Consts.java index 4a3493e..01845b8 100644 --- a/src/main/java/com/iot/transport/jt808/common/Consts.java +++ b/src/main/java/com/iot/transport/jt808/common/Consts.java @@ -30,6 +30,8 @@ public class Consts { public static final Integer MSGID_TRANSMISSION_TYPE_PRESSURE = 0x0600; /** 查询终端参数应答 **/ public static final Integer MSGID_PARAM_QUERY_RESP = 0x0104; + /** 按键事件上报 **/ + public static final Integer MSGID_BUTTON_EVENT = 0x0006; /** 平台通用应答 **/ diff --git a/src/main/java/com/iot/transport/jt808/entity/request/ButtonEventPack.java b/src/main/java/com/iot/transport/jt808/entity/request/ButtonEventPack.java new file mode 100644 index 0000000..0e86c30 --- /dev/null +++ b/src/main/java/com/iot/transport/jt808/entity/request/ButtonEventPack.java @@ -0,0 +1,44 @@ +package com.iot.transport.jt808.entity.request; + +import com.iot.transport.jt808.entity.DataPack; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 按键事件上报消息 (0x0006) + * 4.10.1 短按按键 + * 4.10.2 长按按键 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ButtonEventPack extends DataPack { + /** + * 按键ID + * 0x01: 短按1号键 + * 0x0b: 长按1号键 + * 0x0c: 长按2号键 + * 0x0d: 长按3号键 + * 0x0e: 长按4号键 + */ + private int keyId; + + /** + * 按键状态/次数 + * 0x01: 按键一次 + */ + private int keyState; + + public ButtonEventPack() { + } + + public ButtonEventPack(DataPack packageData) { + this(); + this.channel = packageData.getChannel(); + this.checkSum = packageData.getCheckSum(); + this.bodyBytes = packageData.getBodyBytes(); + this.packHead = packageData.getPackHead(); + } +} + diff --git a/src/main/java/com/iot/transport/jt808/service/codec/DataDecoder.java b/src/main/java/com/iot/transport/jt808/service/codec/DataDecoder.java index 88ebb0c..2856f32 100644 --- a/src/main/java/com/iot/transport/jt808/service/codec/DataDecoder.java +++ b/src/main/java/com/iot/transport/jt808/service/codec/DataDecoder.java @@ -8,6 +8,7 @@ import com.iot.transport.jt808.entity.DataPack; import com.iot.transport.jt808.entity.DataPack.PackHead; import com.iot.transport.jt808.entity.request.LocationPack; import com.iot.transport.jt808.entity.request.RegisterPack; +import com.iot.transport.jt808.entity.request.ButtonEventPack; import com.iot.transport.jt808.entity.request.RegisterPack.TerminalRegInfo; import com.iot.transport.jt808.util.BCDUtil; import com.iot.transport.jt808.util.BitUtil; @@ -211,6 +212,23 @@ public class DataDecoder { return ret; } + public ButtonEventPack toButtonEventPack(DataPack packageData) { + ButtonEventPack ret = new ButtonEventPack(packageData); + byte[] data = ret.getBodyBytes(); + + // 1. byte[0] 按键ID + if (data.length > 0) { + ret.setKeyId(this.parseIntFromBytes(data, 0, 1)); + } + + // 2. byte[1] 按键状态/次数 + if (data.length > 1) { + ret.setKeyState(this.parseIntFromBytes(data, 1, 1)); + } + + return ret; + } + public LocationPack toLocationInfoUploadMsg(DataPack packageData) { LocationPack ret = new LocationPack(packageData); diff --git a/src/main/java/com/iot/transport/jt808/service/handler/MessageHandlerFactory.java b/src/main/java/com/iot/transport/jt808/service/handler/MessageHandlerFactory.java index 326bd1d..b89d0d8 100644 --- a/src/main/java/com/iot/transport/jt808/service/handler/MessageHandlerFactory.java +++ b/src/main/java/com/iot/transport/jt808/service/handler/MessageHandlerFactory.java @@ -8,11 +8,13 @@ import com.iot.transport.jt808.service.handler.terminal.HeartbeatHandler; import com.iot.transport.jt808.service.handler.terminal.LocationUploadHandler; import com.iot.transport.jt808.service.handler.terminal.LoginOutHandler; import com.iot.transport.jt808.service.handler.terminal.RegisterHandler; +import com.iot.transport.jt808.service.handler.terminal.ButtonEventHandler; public class MessageHandlerFactory { /** * 消息和处理类映射表 + * */ public static Map> handlerMap = new HashMap>(); static{ @@ -21,6 +23,7 @@ public class MessageHandlerFactory { handlerMap.put(Consts.MSGID_LOG_OUT, LoginOutHandler.class); // 终端注销 handlerMap.put(Consts.MSGID_AUTHENTICATION, AuthenticationHandler.class); // 终端鉴权 handlerMap.put(Consts.MSGID_LOCATION_UPLOAD, LocationUploadHandler.class); // 位置信息汇报 + handlerMap.put(Consts.MSGID_BUTTON_EVENT, ButtonEventHandler.class); // 按键事件上报 } diff --git a/src/main/java/com/iot/transport/jt808/service/handler/TCPServerHandler.java b/src/main/java/com/iot/transport/jt808/service/handler/TCPServerHandler.java index 77bf85e..404543b 100644 --- a/src/main/java/com/iot/transport/jt808/service/handler/TCPServerHandler.java +++ b/src/main/java/com/iot/transport/jt808/service/handler/TCPServerHandler.java @@ -24,6 +24,7 @@ import com.iot.transport.jt808.common.Consts; import com.iot.transport.jt808.entity.request.BatteryVersionInfo; import com.iot.transport.jt808.entity.request.BluetoothInfo; import com.iot.transport.jt808.entity.request.LocationPack; +import com.iot.transport.jt808.entity.request.ButtonEventPack; import java.util.List; public class TCPServerHandler extends ChannelInboundHandlerAdapter { // (1) @@ -114,6 +115,23 @@ public class TCPServerHandler extends ChannelInboundHandlerAdapter { // (1) locMap.put("lon", locPack.getLongitude()); logMap.put("location", locMap); + } catch (Exception e) { + logMap.put("details", packageData.toString() + " (Parse Error: " + e.getMessage() + ")"); + } + } else if (msgId == Consts.MSGID_BUTTON_EVENT || msgId == 0x0006) { + try { + ButtonEventPack btnPack = this.decoder.toButtonEventPack(packageData); + logMap.put("details", btnPack.toString()); + logMap.put("type", "badge"); // Keep it as badge type to update the device + logMap.put("id", header.getTerminalPhone()); + + // Add button event info + Map btnInfo = new HashMap<>(); + btnInfo.put("keyId", btnPack.getKeyId()); + btnInfo.put("keyState", btnPack.getKeyState()); + btnInfo.put("timestamp", System.currentTimeMillis()); + logMap.put("buttonEvent", btnInfo); + } catch (Exception e) { logMap.put("details", packageData.toString() + " (Parse Error: " + e.getMessage() + ")"); } diff --git a/src/main/java/com/iot/transport/jt808/service/handler/terminal/ButtonEventHandler.java b/src/main/java/com/iot/transport/jt808/service/handler/terminal/ButtonEventHandler.java new file mode 100644 index 0000000..0b3c32c --- /dev/null +++ b/src/main/java/com/iot/transport/jt808/service/handler/terminal/ButtonEventHandler.java @@ -0,0 +1,45 @@ +package com.iot.transport.jt808.service.handler.terminal; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.iot.transport.jt808.common.Consts; +import com.iot.transport.jt808.entity.DataPack; +import com.iot.transport.jt808.entity.DataPack.PackHead; +import com.iot.transport.jt808.entity.request.ButtonEventPack; +import com.iot.transport.jt808.entity.response.ServerBodyPack; +import com.iot.transport.jt808.service.handler.MessageHandler; + +/** + * 按键事件上报 (0x0006) ==> 平台通用应答 + */ +public class ButtonEventHandler extends MessageHandler { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + public ButtonEventHandler() { + super(); + } + + @Override + public void process(DataPack packageData) { + + PackHead header = packageData.getPackHead(); + logger.info("[按键上报],msgid={}, phone={},flowid={}", header.getId(), header.getTerminalPhone(), header.getFlowId()); + + try { + ButtonEventPack msg = this.decoder.toButtonEventPack(packageData); + log.info("按键事件: KeyID={}, State={}", msg.getKeyId(), msg.getKeyState()); + + // 回复通用应答 + int flowId = super.getFlowId(msg.getChannel()); + ServerBodyPack respMsgBody = new ServerBodyPack(header.getFlowId(), header.getId(), ServerBodyPack.success); + byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(msg, respMsgBody, flowId); + super.send2Client(msg.getChannel(), bs); + + } catch (Exception e) { + logger.error("[按键上报]错误, err={}", e.getMessage()); + } + } +} + diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index fc58a19..e12ccba 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -296,6 +296,13 @@ +{{ badge.bluetooth.length - 2 }} 更多... + + +
+ + {{ formatButtonEvent(badge.lastButtonEvent) }} + ({{ formatTime(badge.lastButtonEvent.timestamp) }}) +
@@ -444,10 +451,26 @@ // 1. 处理工牌数据 (识别 type=badge) if (data.type === 'badge' && data.id) { + // 合并旧数据,保留 lastButtonEvent 如果新数据没有覆盖它 + const oldData = this.badges[data.id] || {}; + const newButtonEvent = data.buttonEvent; + this.badges[data.id] = { + ...oldData, ...data, - lastUpdate: now + lastUpdate: now, + // 如果这次是按键事件,更新 lastButtonEvent;否则保留旧的(可以加个超时自动清除逻辑) + lastButtonEvent: newButtonEvent || oldData.lastButtonEvent }; + + // 简单的超时清除按键提示 (5秒后消失) + if (newButtonEvent) { + setTimeout(() => { + if (this.badges[data.id] && this.badges[data.id].lastButtonEvent === newButtonEvent) { + this.badges[data.id].lastButtonEvent = null; + } + }, 5000); + } } // 2. 处理计数器数据 (识别 type=counter) @@ -603,6 +626,20 @@ if (source === 'SYSTEM') return 'bg-info text-dark'; if (source === 'TCP') return 'bg-warning text-dark'; return 'bg-success'; + }, + formatButtonEvent(evt) { + if (!evt) return ''; + let action = '按键'; + // 0x01-0x0A: 短按 + if (evt.keyId >= 0x01 && evt.keyId <= 0x0A) { + action = `短按 ${evt.keyId}号键`; + } + // 0x0B-0x14: 长按 + else if (evt.keyId >= 0x0B && evt.keyId <= 0x14) { + const keyNum = evt.keyId - 0x0A; + action = `长按 ${keyNum}号键`; + } + return action; } } }).mount('#app')