欢迎各位兄弟 发布技术文章
这里的技术是共享的
此文使用的ibeacon模块是april beacon,至于什么是ibeacon。本文不做解释,具体请自查。
一个april beacon里携带的信息如下
1 | <code class=" hljs ">0201061AFF4C0002159069BDB88C11416BAC3F33468C2788A3044B0378C60C09417072696C426561636F6E051250002003020A0000000000000000000000</code> |
具体是什么意思呢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <code class=" hljs vhdl">02
Number of bytes that follow in first AD structure01
Flags AD type06 Flags value 0x1A
= 000011010 bit 0
(OFF) LE Limited Discoverable Mode bit 1
(ON) LE General Discoverable Mode bit 2
(OFF) BR/EDR Not Supported bit 3
(ON) Simultaneous LE and BR/EDR to Same Device Capable (controller) bit 4
(ON) Simultaneous LE and BR/EDR to Same Device Capable (Host)1a Number of bytes that follow in second (and last) AD structure前面是常规智能硬件广播包部分ff (FF代表后面是Manufacture Data)4c 00
(组织标识,0x4c00苹果公司标识,https://www.bluetooth.org/en-us/specification/assigned-numbers/company-identifiers)02
(0x02
ibeacon标识位)15
(0x15,22个字节标识长度,uuid,major,minor总和的长度)90
69 bd b8-8c 11-41
6b-ac 3f-33
46 8c 27
88 a3 (Proximity UUID)04
4b(1099,major)03
78(888,minor)c6 (切记这里是补码,转化为原码就是-58,iBeacon的信号发出强度值,用来作为和RSSI一起测距的基准 ,txPower) 计算 C6 1100
0110 补码 1100
0101 反码 1011
1010 原码 -(32+16+8+2) -580c09 (未知)417072696c426561636f6e(AprilBeacon字符串对应的十六进制)051250002003020a0000000000000000000000(未知)</code> |
Proximity UUID :这是将你所有的beacon与其他人的beacon设备区别开的id!例如,目前在商店里某个区域分布着多个beacon形成一条“链带”,用于为顾客提供特定的服务,那么归属于同一条“链带”的beacon将分配到相同的proximity UUID。为这条“链带”设计的专用应用程序将会在后台使用这个UUID扫描到这条“链带”中的beacon设备。
major 编号:用于将相关的beacon标识为一组。例如,一个商店中的所有beacon将会分配到相同的major编号。通过这种方式,应用程序就能够知道顾客位于哪一家商店。
minor 标号:用于标识特定的beacon设备。例如一个商店中的每一个beacon设备都拥有唯一的minor编号,这样你才能够知道顾客位于商店中的哪个位置。
Measuring distance(测量距离)
最后一个值, TX power ,用于确定你和beacon之间距离有多近。根据这个值不但可以获得粗略的信息(比如靠近/远离/不在范围内等),也可以获取精确到米的距离(当然你也可以转换为以步为单位的距离)。那么如何实现?
TX power (上面例子中为0xC6=198,根据2的补码测得256-198=-58dBm)是距离设备1米测得的信号强度值(RSSI- Received Signal Strength Indication,接收到的信号强弱指标)。假如接收到的信号强度减弱了,那么我们可能在远离。只要知道1米距离的RSSI,以及当前的RSSI(我们可以从接收到的信号中一块获取到这些信息),那么计算出当前的距离是可能的。IOS已经实现了个这个功能,对于其它平台需要自己手动编码计算 。
一个简单的测距函数
1 2 3 4 5 6 7 8 9 10 11 12 13 | <code class="language-java hljs ">protected
static double calculateAccuracy(int
txPower, double
rssi) { if
(rssi == 0) { return
-1.0; // if we cannot determine accuracy, return -1. } double
ratio = rssi * 1.0
/ txPower; if
(ratio < 1.0) { return
Math.pow(ratio, 10); } else
{ double
accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111; return
accuracy; } }</code> |
在使用蓝牙时需要加权限
1 2 3 4 | <code class="language-xml hljs "> <uses-permission android:name="android.permission.BLUETOOTH"> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission></uses-permission></uses-permission></code> |
关键代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | <code class="language-java hljs ">package
cn.edu.zafu.ble;import
android.app.Activity;import
android.bluetooth.BluetoothAdapter;import
android.bluetooth.BluetoothDevice;import
android.bluetooth.BluetoothManager;import
android.content.Context;import
android.content.Intent;import
android.os.Bundle;import
android.util.Log;public
class MainActivity extends
Activity { private
BluetoothAdapter mBluetoothAdapter; @Override protected
void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); if
(mBluetoothAdapter == null
|| !mBluetoothAdapter.isEnabled()) { Intent enableBluetooth = new
Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBluetooth, 1); } mBluetoothAdapter.startLeScan(mLeScanCallback); } private
BluetoothAdapter.LeScanCallback mLeScanCallback = new
BluetoothAdapter.LeScanCallback() { @Override public
void onLeScan(final
BluetoothDevice device, final
int rssi, final
byte[] scanRecord) { int
startByte = 2; boolean
patternFound = false; // 寻找ibeacon while
(startByte <= 5) { if
(((int) scanRecord[startByte + 2] & 0xff) == 0x02
&& // Identifies // an // iBeacon ((int) scanRecord[startByte + 3] & 0xff) == 0x15) { // Identifies // correct // data // length patternFound = true; break; } startByte++; } // 如果找到了的话 if
(patternFound) { // 转换为16进制 byte[] uuidBytes = new
byte[16]; System.arraycopy(scanRecord, startByte + 4, uuidBytes, 0, 16); String hexString = bytesToHex(uuidBytes); // ibeacon的UUID值 String uuid = hexString.substring(0, 8) + "-" + hexString.substring(8, 12) + "-" + hexString.substring(12, 16) + "-" + hexString.substring(16, 20) + "-" + hexString.substring(20, 32); // ibeacon的Major值 int
major = (scanRecord[startByte + 20] & 0xff) * 0x100 + (scanRecord[startByte + 21] & 0xff); // ibeacon的Minor值 int
minor = (scanRecord[startByte + 22] & 0xff) * 0x100 + (scanRecord[startByte + 23] & 0xff); String ibeaconName = device.getName(); String mac = device.getAddress(); int
txPower = (scanRecord[startByte + 24]); Log.d("BLE",bytesToHex(scanRecord)); Log.d("BLE", "Name:"
+ ibeaconName + "\nMac:"
+ mac + " \nUUID:" + uuid + "\nMajor:"
+ major + "\nMinor:" + minor + "\nTxPower:"
+ txPower + "\nrssi:"
+ rssi); Log.d("BLE","distance:"+calculateAccuracy(txPower,rssi)); } } }; static
final char[] hexArray = "0123456789ABCDEF".toCharArray(); private
static String bytesToHex(byte[] bytes) { char[] hexChars = new
char[bytes.length * 2]; for
(int
j = 0; j < bytes.length; j++) { int
v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2
+ 1] = hexArray[v & 0x0F]; } return
new String(hexChars); } protected
static double calculateAccuracy(int
txPower, double
rssi) { if
(rssi == 0) { return
-1.0; // if we cannot determine accuracy, return -1. } double
ratio = rssi * 1.0
/ txPower; if
(ratio < 1.0) { return
Math.pow(ratio, 10); } else
{ double
accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111; return
accuracy; } }}</code> |
至此,本文也就结束,所谓初步,就是获取ibeacon模块的基本信息。
源码下载