本文是關於Android的BLE藍牙連接以及 獲取藍牙RSSI的基本實現 , 基於SDK中的Sample略作修改
效果圖
關於RSSI
-
什麼是RSSI
Received Signal Strength Indicator , 接收的信號強度指示 , 單位是dbm , 無線發送層的可選部分 , 用來判定鏈接質量,以及是否增大廣播發送強度。它的實現是在反向通道基帶接收濾波器之後進行的。百度百科
-
關於接收率
一般爲負值,反映的是信號的衰減程度,理想狀態下(無衰減)Rssi值爲0dBm,實際情況是,即使藍牙設備捱得非常近,Rssi也只有-50dBm的強度,在傳輸過程中,不可避免要損耗。
一般情況下,經典藍牙強度
信號強 0dBm ~ -50dBm
信號中 -50dBm ~ -70dBm
信號弱 -70dBm ~ dBm低功耗藍牙分四級
4 0 ~ -60
3 -60 ~ -70
2 -70 ~ -80
1 -80 ~ -
Android中BLE藍牙獲取RSSI
Android平臺中,通過藍牙設備掃描回調和藍牙設備連接監聽兩種方式可以獲取到每個藍牙設備的RSSI。
-
測距理論
通過接收到的信號強弱測定信號點與接收點的距離,進而根據相應數據進行定位計算的一種定位技術。
獲取藍牙RSSI
-
藍牙權限
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
-
檢查是否支持BLE和藍牙
// Use this check to determine whether BLE is supported on the device. Then you can // selectively disable BLE-related features. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish(); } // Initializes a Bluetooth adapter. For API level 18 and above, get a reference to // BluetoothAdapter through BluetoothManager. final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); // Checks if Bluetooth is supported on the device. if (mBluetoothAdapter == null) { Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show(); finish(); return; }
-
獲取RSSI方法一: 藍牙設備掃描回調
/** * 掃描藍牙設備 * @param enable 開始/停止掃描 */ private void scanLeDevice(final boolean enable) { if (enable) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(() -> { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); invalidateOptionsMenu(); }, SCAN_PERIOD); mScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } }
// 設備掃描回調 private BluetoothAdapter.LeScanCallback mLeScanCallback = (device, rssi, scanRecord) -> { Log.i(TAG, "rssi: " + rssi); };
-
獲取RSSI方法二: 連接藍牙設備後讀取
- 先通過方法一的掃描設備拿到DeviceAddress
- 在服務中註冊監聽
- 通過綁定服務(BindService)管理生命週期
- 連接藍牙設備
- 循環讀取Rssi
//Service中註冊監聽 // Implements callback methods for GATT events that the app cares about. For example, // connection change and services discovered. private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { String intentAction; if (newState == BluetoothProfile.STATE_CONNECTED) { ``` } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { ``` } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); } else { Log.w(TAG, "onServicesDiscovered received: " + status); } } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { Log.i(TAG, "gatt: " + gatt.toString() + ", rssi: " + rssi + ", status: " + status); super.onReadRemoteRssi(gatt, rssi, status); if (status == BluetoothGatt.GATT_SUCCESS) { final Intent intent = new Intent(ACTION_READ_RSSI); intent.putExtra(EXTRA_DATA, String.valueOf(rssi)); sendBroadcast(intent); } } };
//綁定Service Intent gattServiceIntent = new Intent(this, BluetoothLeService.class); bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE); // Code to manage Service lifecycle. private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService(); if (!mBluetoothLeService.initialize()) { Log.e(TAG, "Unable to initialize Bluetooth"); finish(); } mBluetoothLeService.connect(mDeviceAddress); } @Override public void onServiceDisconnected(ComponentName componentName) { mBluetoothLeService = null; } };
private boolean isReadRssi = true; private Thread readRSSI; /** * 讀取藍牙RSSi線程 */ private void startReadRssi() { isReadRssi = true; int Rssi=0; readRSSI = (Thread)run() -> { while (isReadRssi){ try { sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } //如果讀取藍牙RSSi回調成功 if(mBluetoothLeService != null && mBluetoothLeService.getRssiVal()){ //獲取已經讀到的RSSI值 // Rssi=BluetoothLeService.getBLERSSI(); // mHandler.obtainMessage(READRSSI, Rssi).sendToTarget(); } } }; readRSSI.start(); } //停止讀取 private void stopReadRssi() { if (readRSSI != null) { isReadRssi = false; readRSSI = null; } }
源碼地址
項目源碼, 新增了距離計算
https://github.com/ElvisGuozs/BluetoothLeGatt