diff --git a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/dal/dataobject/integration/clean/BeaconPresenceConfig.java b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/dal/dataobject/integration/clean/BeaconPresenceConfig.java index 94044d8..c2cd228 100644 --- a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/dal/dataobject/integration/clean/BeaconPresenceConfig.java +++ b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/dal/dataobject/integration/clean/BeaconPresenceConfig.java @@ -26,7 +26,31 @@ public class BeaconPresenceConfig { private String beaconMac; /** - * ��动窗口配置 + * iBeacon UUID + *

+ * iBeacon 协议的 UUID 标识,用于区分不同的信标组 + * 例如:FDA50693-A4E2-4FB1-AFCF-C6EB07647825 + */ + private String beaconUuid; + + /** + * iBeacon Major 值 + *

+ * 用于区分同一 UUID 下的不同区域或楼层 + * 范围:0-65535 + */ + private Integer major; + + /** + * iBeacon Minor 值 + *

+ * 用于区分同一 Major 下的不同信标 + * 范围:0-65535 + */ + private Integer minor; + + /** + * 滑动窗口配置 */ private WindowConfig window; diff --git a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/detector/RssiSlidingWindowDetector.java b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/detector/RssiSlidingWindowDetector.java index 5ee8673..fa31cf9 100644 --- a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/detector/RssiSlidingWindowDetector.java +++ b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/detector/RssiSlidingWindowDetector.java @@ -145,13 +145,16 @@ public class RssiSlidingWindowDetector { /** * 从蓝牙设备列表中提取目标信标的 RSSI + *

+ * 匹配策略:以设备上报数据为准,优先使用 MAC 地址匹配; + * 若 MAC 未配置,降级为 iBeacon 三元组(uuid+major+minor)匹配 * * @param bluetoothDevices 蓝牙设备列表 * 格式:[{"rssi":-52,"type":243,"mac":"F0:C8:60:1D:10:BB"},...] - * @param targetMac 目标信标 MAC 地址 + * @param beaconConfig 信标配置 * @return RSSI 值,如果未找到返回 -999(缺失值) */ - public Integer extractTargetRssi(Object bluetoothDevices, String targetMac) { + public Integer extractTargetRssi(Object bluetoothDevices, BeaconPresenceConfig beaconConfig) { if (bluetoothDevices == null) { return -999; } @@ -160,17 +163,59 @@ public class RssiSlidingWindowDetector { @SuppressWarnings("unchecked") List> deviceList = (List>) bluetoothDevices; - return deviceList.stream() - .filter(device -> targetMac.equals(device.get("mac"))) - .map(device -> (Integer) device.get("rssi")) - .findFirst() - .orElse(-999); + // 优先使用 MAC 地址匹配(工牌上报的是 MAC) + String targetMac = beaconConfig.getBeaconMac(); + if (targetMac != null) { + return deviceList.stream() + .filter(device -> targetMac.equalsIgnoreCase((String) device.get("mac"))) + .map(device -> toInt(device.get("rssi"))) + .findFirst() + .orElse(-999); + } + + // 降级为 iBeacon 三元组匹配(适配上报 uuid+major+minor 的设备) + if (beaconConfig.getBeaconUuid() != null && beaconConfig.getMajor() != null + && beaconConfig.getMinor() != null) { + return deviceList.stream() + .filter(device -> matchIBeacon(device, beaconConfig)) + .map(device -> toInt(device.get("rssi"))) + .findFirst() + .orElse(-999); + } + + log.warn("[RssiDetector] 信标配置缺少 beaconMac 和 iBeacon 三元组,无法匹配"); + return -999; } catch (Exception e) { - log.error("[RssiDetector] 解析蓝牙数据失败:targetMac={}", targetMac, e); + log.error("[RssiDetector] 解析蓝牙数据失败:beaconMac={}", beaconConfig.getBeaconMac(), e); return -999; } } + /** + * 匹配 iBeacon 三元组(uuid + major + minor) + */ + private boolean matchIBeacon(java.util.Map device, BeaconPresenceConfig config) { + String uuid = (String) device.get("uuid"); + Integer major = toInt(device.get("major")); + Integer minor = toInt(device.get("minor")); + return config.getBeaconUuid().equalsIgnoreCase(uuid) + && config.getMajor().equals(major) + && config.getMinor().equals(minor); + } + + /** + * 安全转换为 Integer + */ + private Integer toInt(Object value) { + if (value instanceof Integer) { + return (Integer) value; + } + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return null; + } + /** * 判断窗口是否有效 *

diff --git a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java index 04286bb..be3fcfb 100644 --- a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java +++ b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java @@ -120,7 +120,7 @@ public class BeaconDetectionRuleProcessor { } // 4. 解析蓝牙数据,提取目标信标的 RSSI - Integer targetRssi = detector.extractTargetRssi(propertyValue, beaconConfig.getBeaconMac()); + Integer targetRssi = detector.extractTargetRssi(propertyValue, beaconConfig); log.debug("[BeaconDetection] 提取RSSI:deviceId={}, areaId={}, beaconMac={}, rssi={}", deviceId, areaId, beaconConfig.getBeaconMac(), targetRssi);