Android:iBeacon - 阅读它的广告(例如 txPower)
Android: iBeacon - read its advertisement (e.g txPower)
我现在遇到问题,因为我正在尝试从我的 Onyx iBeacon 读取 tx-Power。我已经阅读了很多建议并在互联网上尝试了很多代码,但我仍然无法弄清楚。
我正在使用 android 棒棒糖并尝试了 https://github.com/devunwired/accessory-samples/tree/master/BluetoothGatt 中的 iBeacon 教程
对于提取 BLUETOOTH_THERM_SERVICE
.
的蓝牙应用程序
我从广告中找到了 tx-Power 的两个值:
Bluetooth LE TX Power reading
0x1804
及其特征 0x2A07
,所以我调整了 Parcel UUID 以使用 0x1804
:
过滤我的 ScanResults
public static final ParcelUuid THERM_SERVICE = ParcelUuid.fromString("00001809-0000-1000-8000-00805f9b34fb");
public static final ParcelUuid TX_POWER_SERVICE = ParcelUuid.fromString("00001804-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid ONYX_STANDARD_SERVICE = ParcelUuid.fromString("0000180a-0000-1000-8000-00805f9b34fb");
如教程中所述:
byte[] data = record.getServiceData(TX_POWER_SERVICE);
应该存储一个字节数组,但它总是 returns 空!唯一存储字节数组,但我认为它存储整个记录的是:
byte[] data = record.getServiceData(ONYX_STANDARD_SERVICE);
尝试继续使用我可以通过 ONYX_STANDARD_SERVICE
获得的数据我可以看到一个扫描结果:
onScanResult() - ScanResult{mDevice=78:A5:04:07:AE:96, mScanRecord=ScanRecord [mAdvertiseFlags=6, mServiceUuids=null, mManufacturerSpecificData={76=[2, 21, 32, -54, -24, -96, -87, -49, 17, -29, -91, -30, 8, 0, 32, 12, -102, 102, 0, 7, -82, -106, -78]}, mServiceData={0000180a-0000-1000-8000-00805f9b34fb=[120, -91, 4, 7, -82, -106, -78, 32, -54, -24, -96, 0, 7, -82, -106]}, mTxPowerLevel=-2147483648, mDeviceName=OnyxBeacon], mRssi=-63, mTimestampNanos=174691272168825}
我认为我记录的重要部分是:
mServiceData={0000180a-0000-1000-8000-00805f9b34fb=[120, -91, 4, 7, -82, -106, -78, 32, -54, -24, -96, 0, 7, -82, -106]}
如何从该 ServiceData 中提取我的 txPower 值?我检查了几个应用程序,我的 tx-power 是 -78。
通过用 ONYX_STANDARD_SERVICE 检查结果,我可以用 scanResult[6] = -78
得到这个值。
这是正确的方法吗?如果是,为什么?
我还在这个问题上发现了一些有趣的例子,其中提到了要从记录中读取的另一个值:
如果您查看此处,您会找到代码:
private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
哪一个(0x1804
、0x2A07
、0x0A
)是正确的?
有人可以向我解释获取 THERM_SERVICE
的示例代码是如何工作的也很好,但不是必需的:
private float parseTemp(byte[] serviceData) {
/*
* Temperature data is two bytes, and precision is 0.5degC.
* LSB contains temperature whole number
* MSB contains a bit flag noting if fractional part exists
*/
float temp = (serviceData[0] & 0xFF);
if ((serviceData[1] & 0x80) != 0) {
temp += 0.5f;
}
return temp;
}
请帮我读取广告数据和提取tx-Power。
1。如何从此 ServiceData 中提取我的 txPower 值?我检查了几个应用程序,我的 tx-power 是 -78
好吧,从实用的角度来看,iBeacon 配置文件中有两种类型的广告数据。
首先是制造商数据。由于这些类型,您可以读取信标的 Proximity UUID、Major、Minor 或传输功率值。这种类型可以从任何 iBeacon 的广告数据包中读取,与 ibeacon 设备制造商无关。可以看到how the layout of the data looks like and parse it in order to extract the proximity-specific values (you can as well find information about it here at page no 3).
第二个是服务数据。与第一种类型相反,这种类型可以自定义,例如 kontakt.io iBeacon 提供其唯一 ID,由 4 个 ASCII 符号固件版本和传输功率级别(从 0 到 7)组成。
2。通过用 ONYX_STANDARD_SERVICE 检查结果,我可以用 scanResult[6] = -78 得到这个值
这是正确的方法吗?如果是,为什么?
我还没有看到 Onyx Beacon 规范,但如果服务数据中包含 tx Power,那么我建议找出 byte/bytes 描述 Tx Power is/are 的位置。您的 iBeacon 提供商应该知道。
3。如何从此 ServiceData 中提取我的 txPower 值?我检查了几个应用程序,我的 tx-power 是 -78
如前所述,您可以默认从制造商数据中读取计算的传输功率。但是,如果 Onyx 信标在服务数据中提供了有关 tx 功率的任何其他信息,那么您应该从 Onyx spec-or-sth-like-that 文件中获取信息。
4.通过用 ONYX_STANDARD_SERVICE 检查结果,我可以用 scanResult[6] = -78 得到这个值
这是正确的方法吗?如果是,为什么?
URI Beacon specification 清楚地说明了包括txPower在内的每条信息在哪个位置。我认为 Onyx Beacon 与 Uri Beacon 没有太多共同点。
5.有人可以向我解释获取 THERM_SERVICE 的示例代码是如何工作的也很好,但不是必须的:
这里没有什么难的。根据代码片段,我假设在位置 0 的服务数据中有一个描述温度的值(范围从 0 到 255)。下一个字节指定小数点位置。
顺便说一下,这是你问的吗?
6.请帮助我阅读广告数据并提取 txPower :)
为了解析任何与 iBeacon 相关的数据,这里有一个返回 SparseArray 的简单代码,其中键表示数据类型和与类型绑定的字节帧。该代码在您解析从远程 IBeacon 设备读取的整个字节帧的假设下工作。
private static SparseArray<byte[]> extractMetaData(final byte[] scanRecord) {
int index = 0;
final SparseArray<byte[]> map = new SparseArray<byte[]>();
final int scanRecordLength = scanRecord.length;
while (index < scanRecordLength) {
final int length = scanRecord[index++];
if (length == 0) {
break;
}
final int type = Converter.asInt(scanRecord[index]);
if (type == 0) {
break;
}
final byte[] data = Arrays.copyOfRange(scanRecord, index + 1, index + length);
map.put(type, data);
index += length;
}
return map;
}
我建议深入 Bluetooth-LE--Android project。我学会了
通过检查代码获取有价值的信息。别忘了为 ofc 加注星标。
希望我至少澄清了你的问题。
OnyxBeacon 的传输 (TX) 功率,以及与 iBeacon 兼容的任何其他 BLE 设备,都可以从广告数据包中获取。这不需要连接到设备。此外,TX 功率值将根据功率级别而变化,因为 TX 功率值针对设备的每个功率级别进行了校准。 TX 功率是广告有效载荷的最后一个字节。有关 iBeacon 数据包结构的更多信息,请参见此处:http://www.havlena.net/en/location-technologies/ibeacons-how-do-they-technically-work/
下面是如何解析iBeacon数据包并获取TX power的示例:
BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice bluetoothDevice, final int rssi, final byte[] scanData) {
if (scanData[7] == 0x02 && scanData[8] == 0x15) { // iBeacon indicator
System.out.println("iBeacon Packet: %s", bytesToHexString(scanData));
UUID uuid = getGuidFromByteArray(Arrays.copyOfRange(scanData, 9, 25));
int major = (scanData[25] & 0xff) * 0x100 + (scanData[26] & 0xff);
int minor = (scanData[27] & 0xff) * 0x100 + (scanData[28] & 0xff);
byte txpw = scanData[29];
System.out.println("iBeacon Major = " + major + " | Minor = " + minor + " TxPw " + (int)txpw + " | UUID = " + uuid.toString());
}
}
};
public static String bytesToHexString(byte[] bytes) {
StringBuilder buffer = new StringBuilder();
for(int i=0; i<bytes.length; i++) {
buffer.append(String.format("%02x", bytes[i]);
}
return buffer.toString();
}
public static UUID getGuidFromByteArray(byte[] bytes)
{
ByteBuffer bb = ByteBuffer.wrap(bytes);
UUID uuid = new UUID(bb.getLong(), bb.getLong());
return uuid;
}
我现在遇到问题,因为我正在尝试从我的 Onyx iBeacon 读取 tx-Power。我已经阅读了很多建议并在互联网上尝试了很多代码,但我仍然无法弄清楚。
我正在使用 android 棒棒糖并尝试了 https://github.com/devunwired/accessory-samples/tree/master/BluetoothGatt 中的 iBeacon 教程
对于提取 BLUETOOTH_THERM_SERVICE
.
我从广告中找到了 tx-Power 的两个值: Bluetooth LE TX Power reading
0x1804
及其特征 0x2A07
,所以我调整了 Parcel UUID 以使用 0x1804
:
public static final ParcelUuid THERM_SERVICE = ParcelUuid.fromString("00001809-0000-1000-8000-00805f9b34fb");
public static final ParcelUuid TX_POWER_SERVICE = ParcelUuid.fromString("00001804-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid ONYX_STANDARD_SERVICE = ParcelUuid.fromString("0000180a-0000-1000-8000-00805f9b34fb");
如教程中所述:
byte[] data = record.getServiceData(TX_POWER_SERVICE);
应该存储一个字节数组,但它总是 returns 空!唯一存储字节数组,但我认为它存储整个记录的是:
byte[] data = record.getServiceData(ONYX_STANDARD_SERVICE);
尝试继续使用我可以通过 ONYX_STANDARD_SERVICE
获得的数据我可以看到一个扫描结果:
onScanResult() - ScanResult{mDevice=78:A5:04:07:AE:96, mScanRecord=ScanRecord [mAdvertiseFlags=6, mServiceUuids=null, mManufacturerSpecificData={76=[2, 21, 32, -54, -24, -96, -87, -49, 17, -29, -91, -30, 8, 0, 32, 12, -102, 102, 0, 7, -82, -106, -78]}, mServiceData={0000180a-0000-1000-8000-00805f9b34fb=[120, -91, 4, 7, -82, -106, -78, 32, -54, -24, -96, 0, 7, -82, -106]}, mTxPowerLevel=-2147483648, mDeviceName=OnyxBeacon], mRssi=-63, mTimestampNanos=174691272168825}
我认为我记录的重要部分是:
mServiceData={0000180a-0000-1000-8000-00805f9b34fb=[120, -91, 4, 7, -82, -106, -78, 32, -54, -24, -96, 0, 7, -82, -106]}
如何从该 ServiceData 中提取我的 txPower 值?我检查了几个应用程序,我的 tx-power 是 -78。
通过用 ONYX_STANDARD_SERVICE 检查结果,我可以用 scanResult[6] = -78
得到这个值。
这是正确的方法吗?如果是,为什么?
我还在这个问题上发现了一些有趣的例子,其中提到了要从记录中读取的另一个值:
如果您查看此处,您会找到代码:
private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
哪一个(0x1804
、0x2A07
、0x0A
)是正确的?
有人可以向我解释获取 THERM_SERVICE
的示例代码是如何工作的也很好,但不是必需的:
private float parseTemp(byte[] serviceData) {
/*
* Temperature data is two bytes, and precision is 0.5degC.
* LSB contains temperature whole number
* MSB contains a bit flag noting if fractional part exists
*/
float temp = (serviceData[0] & 0xFF);
if ((serviceData[1] & 0x80) != 0) {
temp += 0.5f;
}
return temp;
}
请帮我读取广告数据和提取tx-Power。
1。如何从此 ServiceData 中提取我的 txPower 值?我检查了几个应用程序,我的 tx-power 是 -78
好吧,从实用的角度来看,iBeacon 配置文件中有两种类型的广告数据。
首先是制造商数据。由于这些类型,您可以读取信标的 Proximity UUID、Major、Minor 或传输功率值。这种类型可以从任何 iBeacon 的广告数据包中读取,与 ibeacon 设备制造商无关。可以看到how the layout of the data looks like and parse it in order to extract the proximity-specific values (you can as well find information about it here at page no 3).
第二个是服务数据。与第一种类型相反,这种类型可以自定义,例如 kontakt.io iBeacon 提供其唯一 ID,由 4 个 ASCII 符号固件版本和传输功率级别(从 0 到 7)组成。
2。通过用 ONYX_STANDARD_SERVICE 检查结果,我可以用 scanResult[6] = -78 得到这个值 这是正确的方法吗?如果是,为什么?
我还没有看到 Onyx Beacon 规范,但如果服务数据中包含 tx Power,那么我建议找出 byte/bytes 描述 Tx Power is/are 的位置。您的 iBeacon 提供商应该知道。
3。如何从此 ServiceData 中提取我的 txPower 值?我检查了几个应用程序,我的 tx-power 是 -78
如前所述,您可以默认从制造商数据中读取计算的传输功率。但是,如果 Onyx 信标在服务数据中提供了有关 tx 功率的任何其他信息,那么您应该从 Onyx spec-or-sth-like-that 文件中获取信息。
4.通过用 ONYX_STANDARD_SERVICE 检查结果,我可以用 scanResult[6] = -78 得到这个值 这是正确的方法吗?如果是,为什么?
URI Beacon specification 清楚地说明了包括txPower在内的每条信息在哪个位置。我认为 Onyx Beacon 与 Uri Beacon 没有太多共同点。
5.有人可以向我解释获取 THERM_SERVICE 的示例代码是如何工作的也很好,但不是必须的:
这里没有什么难的。根据代码片段,我假设在位置 0 的服务数据中有一个描述温度的值(范围从 0 到 255)。下一个字节指定小数点位置。 顺便说一下,这是你问的吗?
6.请帮助我阅读广告数据并提取 txPower :)
为了解析任何与 iBeacon 相关的数据,这里有一个返回 SparseArray 的简单代码,其中键表示数据类型和与类型绑定的字节帧。该代码在您解析从远程 IBeacon 设备读取的整个字节帧的假设下工作。
private static SparseArray<byte[]> extractMetaData(final byte[] scanRecord) {
int index = 0;
final SparseArray<byte[]> map = new SparseArray<byte[]>();
final int scanRecordLength = scanRecord.length;
while (index < scanRecordLength) {
final int length = scanRecord[index++];
if (length == 0) {
break;
}
final int type = Converter.asInt(scanRecord[index]);
if (type == 0) {
break;
}
final byte[] data = Arrays.copyOfRange(scanRecord, index + 1, index + length);
map.put(type, data);
index += length;
}
return map;
}
我建议深入 Bluetooth-LE--Android project。我学会了 通过检查代码获取有价值的信息。别忘了为 ofc 加注星标。
希望我至少澄清了你的问题。
OnyxBeacon 的传输 (TX) 功率,以及与 iBeacon 兼容的任何其他 BLE 设备,都可以从广告数据包中获取。这不需要连接到设备。此外,TX 功率值将根据功率级别而变化,因为 TX 功率值针对设备的每个功率级别进行了校准。 TX 功率是广告有效载荷的最后一个字节。有关 iBeacon 数据包结构的更多信息,请参见此处:http://www.havlena.net/en/location-technologies/ibeacons-how-do-they-technically-work/
下面是如何解析iBeacon数据包并获取TX power的示例:
BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice bluetoothDevice, final int rssi, final byte[] scanData) {
if (scanData[7] == 0x02 && scanData[8] == 0x15) { // iBeacon indicator
System.out.println("iBeacon Packet: %s", bytesToHexString(scanData));
UUID uuid = getGuidFromByteArray(Arrays.copyOfRange(scanData, 9, 25));
int major = (scanData[25] & 0xff) * 0x100 + (scanData[26] & 0xff);
int minor = (scanData[27] & 0xff) * 0x100 + (scanData[28] & 0xff);
byte txpw = scanData[29];
System.out.println("iBeacon Major = " + major + " | Minor = " + minor + " TxPw " + (int)txpw + " | UUID = " + uuid.toString());
}
}
};
public static String bytesToHexString(byte[] bytes) {
StringBuilder buffer = new StringBuilder();
for(int i=0; i<bytes.length; i++) {
buffer.append(String.format("%02x", bytes[i]);
}
return buffer.toString();
}
public static UUID getGuidFromByteArray(byte[] bytes)
{
ByteBuffer bb = ByteBuffer.wrap(bytes);
UUID uuid = new UUID(bb.getLong(), bb.getLong());
return uuid;
}