feat(iot): 信标检测支持 iBeacon 三元组匹配(uuid+major+minor)
BeaconPresenceConfig 新增 beaconUuid/major/minor 字段; RssiSlidingWindowDetector.extractTargetRssi 优先 MAC 匹配, 降级为 iBeacon 三元组匹配,兼容两种设备上报格式。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,31 @@ public class BeaconPresenceConfig {
|
||||
private String beaconMac;
|
||||
|
||||
/**
|
||||
* <EFBFBD><EFBFBD>动窗口配置
|
||||
* iBeacon UUID
|
||||
* <p>
|
||||
* iBeacon 协议的 UUID 标识,用于区分不同的信标组
|
||||
* 例如:FDA50693-A4E2-4FB1-AFCF-C6EB07647825
|
||||
*/
|
||||
private String beaconUuid;
|
||||
|
||||
/**
|
||||
* iBeacon Major 值
|
||||
* <p>
|
||||
* 用于区分同一 UUID 下的不同区域或楼层
|
||||
* 范围:0-65535
|
||||
*/
|
||||
private Integer major;
|
||||
|
||||
/**
|
||||
* iBeacon Minor 值
|
||||
* <p>
|
||||
* 用于区分同一 Major 下的不同信标
|
||||
* 范围:0-65535
|
||||
*/
|
||||
private Integer minor;
|
||||
|
||||
/**
|
||||
* 滑动窗口配置
|
||||
*/
|
||||
private WindowConfig window;
|
||||
|
||||
|
||||
@@ -145,13 +145,16 @@ public class RssiSlidingWindowDetector {
|
||||
|
||||
/**
|
||||
* 从蓝牙设备列表中提取目标信标的 RSSI
|
||||
* <p>
|
||||
* 匹配策略:以设备上报数据为准,优先使用 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<java.util.Map<String, Object>> deviceList = (List<java.util.Map<String, Object>>) 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<String, Object> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断窗口是否有效
|
||||
* <p>
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user