Android:iBeacon - 阅读其广告(例如txPower)

时间:2015-05-25 20:05:38

标签: bluetooth-lowenergy android-5.0-lollipop ibeacon ibeacon-android

我现在遇到一个问题,因为我试图从我的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,因此我调整了宗地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);

应该存储一个字节数组,但它总是返回null!唯一存储字节数组的东西,但我认为它存储整个记录是:

byte[] data = record.getServiceData(ONYX_STANDARD_SERVICE);

尝试继续使用ONYX_STANDARD_SERVICE我可以获得的数据我可以看到scanResult:

 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获取此值。

这是正确的方法,如果是这样,为什么?

我还在这个问题上找到了一些有趣的例子,其中提到了从记录中读取的另一个值:

https://github.com/google/uribeacon/blob/master/android-uribeacon/uribeacon-library/src/main/java/org/uribeacon/scan/compat/ScanRecord.java

如果你在这里查看,你会找到代码:

private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;

其中哪一个(0x18040x2A070x0A)是正确的?

如果有人能够解释我获取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。

2 个答案:

答案 0 :(得分:7)

可以从广告包获得OnyxBeacon的发送(TX)功率,以及与iBeacon兼容的任何其他BLE设备的发送(TX)功率。这不需要连接到设备。此外,TX功率值将根据功率水平而变化,因为TX功率值针对设备的每个功率水平进行校准。 TX功率是广告有效载荷的最后一个字节。有关iBeacon数据包结构的更多信息,请访问:http://www.havlena.net/en/location-technologies/ibeacons-how-do-they-technically-work/

以下是如何解析iBeacon数据包并获取TX功率的示例:

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;
}

答案 1 :(得分:1)

<强> 1。如何从此ServiceData中提取txPower值?我检查了几个应用程序,我的tx-power是-78

嗯,从实际的角度来看,iBeacon配置文件中有两种类型的广告数据。

第一个是制造商数据。由于这些类型,您可以阅读信标的Proximity UUID,Major,Minor或传输功率值。无论ibeacon设备制造商如何,都可以从任何iBeacon的广告包中读取该类型。您可以看到how the layout of the data looks like并对其进行解析,以便提取特定于邻近度的值(您也可以找到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,那么我建议找出描述Tx Power的字节/字节在哪个位置。您的iBeacon提供商应该知道它。

第3。如何从此ServiceData中提取txPower值?我检查了几个应用程序,我的tx-power是-78

如前所述,您可以默认从制造商数据中读取计算的传输功率。但是,如果Onyx信标提供有关服务数据中tx功率的任何其他信息,那么您应该从Onyx spec-or-sth-like-file获取信息。

<强> 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。我学会了 通过检查代码获得有价值的信息并且不要忘记明星。

希望我至少澄清一下你的问题。