📶

AndroidでBLEを取得する

2024/05/14に公開

はじめに

BLEの仕様や取得がややこしかったのでまとめておきます。

1.BLEについて

1.1概要

Bluetooth Low Energyの略で、低電力で通信が可能なものです。

BLE機器は

  • セントラル機器
  • ペリフェラル機器

に分かれます。
セントラル機器はスマホ等のBluetooth機器に接続する側の機器(親機)
ペリフェラル機器はイヤホン等の接続される側の機器です。(子機)

セントラル機器はスキャンという動作を行いペリフェラル機器が発しているアドバタイズ信号を検出することにより周囲にあるBluetooth機器を検出しています。ヘッタクソな図

検出しただけでは通信は確立しておらずGATT通信というものを行うことで接続が確立します。

今回の記事ではAndroidでアドバタイズしている機器を検出する方法について触れていくので接続方法を知りたい方は別の記事へお願いします。

1.2BLEの種類

BLEにはイヤホン等の機器だけではなく、BLEビーコンと呼ばれるものがありアドバタイズの仕組みを利用して情報を発信しています。
通信を確立して双方向通信を行うことはできず、ブロードキャストに特化しています。
そのためお店等にビーコンを設置してビーコンの電波を拾っている人にだけクーポンを与えるなど簡易的な位置推定等に使用されています。
iBeaconなどが有名です。

1.3機器の識別

BLEの中で機器の判別ができそうなものは次のようなものがあります。

  • MACアドレス
  • ペリフェラルUUID
  • サービスUUID
  • キャラクタリスティックUUID


引用:https://monomonotech.jp/kurage/webbluetooth/uuid.html

ペリフェラルがデバイス
サービスがディレクトリ
キャラクタリスティックがファイル
のイメージが近いと思います。

この中でアドバタイズパケットから取得できるのは

  • MACアドレス
  • サービスUUID

の二つです他のは接続が確立しないと取れません。

サービスUUIDは個人でも設定できるので予め設定しておいたのをシステムに保存しておいて機器を特定するのが主流かなと思います。

2.周囲のBLEを取得する

2.1実装

ビーコンに特化したライブラリ(AltBeaconなど)もありますが、今回は全てのBLE機器が検出できるようにBluetoothLeScannerを使用していきます。

権限が必要なので権限を与えます。

AndroidManifest.xml
    <!-- Bluetooth パーミッション -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

    <!-- 位置情報パーミッション -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
GetBLE.kt
class GetBLE {
    private val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
    private val bluetoothLeScanner: BluetoothLeScanner? = bluetoothAdapter?.bluetoothLeScanner
    private var scanCallback: ScanCallback? = null

    @SuppressLint("MissingPermission")
    fun startScan() {
        bluetoothLeScanner?.let { scanner ->
            if (scanCallback == null) {
                scanCallback = object : ScanCallback() {
                    override fun onScanResult(callbackType: Int, result: ScanResult) {
                        super.onScanResult(callbackType, result)
                        val device: BluetoothDevice = result.device
                        val uuids = result.scanRecord?.serviceUuids
                        val receiveRssi = result.rssi

                        uuids?.forEach { uuid ->
                            val uuidString = uuid.uuid.toString()
                            val logMessage = "Device: ${device.address}, UUID: $uuidString, RSSI: $receiveRssi"
                            Log.d("GetBLE", logMessage) // リアルタイムでログに出力
                        }
                    }

                    override fun onScanFailed(errorCode: Int) {
                        super.onScanFailed(errorCode)
                        Log.e("GetBLE", "Scan failed with error code $errorCode")
                    }
                }
                scanner.startScan(scanCallback)
                Log.d("GetBLE", "scan started")
            } else {
                Log.d("GetBLE", "Scan already running")
            }
        } ?: run {
            Log.e("GetBLE", "BluetoothLeScanner is not initialized")
        }
    }


    @SuppressLint("MissingPermission")
    fun stopScan() {
        scanCallback?.let { bluetoothLeScanner?.stopScan(it) }
        scanCallback = null
        Log.d("GetBLE", "scan stopped")
    }
}

このクラスのstartScan()を実行すると検出したBLEのMACアドレス,サービスUUID,RSSIがログに出力されます。

結果
2024-05-14 13:40:31.795 17624-17624 BluetoothAdapter        com.hogehoge.bleapplication            D  isLeEnabled(): ON
2024-05-14 13:40:31.806 17624-17675 BluetoothLeScanner      com.hogehoge.bleapplication            D  onScannerRegistered() - status=0 scannerId=4 mScannerId=0
2024-05-14 13:40:31.815 17624-17624 GetBLE                  com.hogehoge.bleapplication            D  scan started
2024-05-14 13:40:31.902 17624-17624 GetBLE                  com.hogehoge.bleapplication            D  Device: 47:C7:C7:9E:05:02, UUID: 0000fe9f-0000-1000-8000-00805f9b34fb, RSSI: -56
2024-05-14 13:40:31.914 17624-17624 GetBLE                  com.hogehoge.bleapplication            D  Device: 5D:D0:FC:92:22:6E, UUID: 0000fef3-0000-1000-8000-00805f9b34fb, RSSI: -94
2024-05-14 13:40:31.924 17624-17624 GetBLE                  com.hogehoge.bleapplication            D  Device: 6E:C9:6C:DA:12:BE, UUID: 8ebc2114-4abd-ba0d-b7c6-ff0a0020004d, RSSI: -77
2024-05-14 13:40:31.944 17624-17624 GetBLE                  com.hogehoge.bleapplication            D  Device: 47:3E:92:B7:4A:45, UUID: 8ebc2114-4abd-ba0d-b7c6-ff0a00200037, RSSI: -83
2024-05-14 13:40:31.946 17624-17624 GetBLE                  com.hogehoge.bleapplication            D  Device: 70:DF:87:F3:EC:10, UUID: 8ebc2114-4abd-ba0d-b7c6-ff0a0020000c, RSSI: -71
2024-05-14 13:40:32.031 17624-17624 GetBLE                  com.hogehoge.bleapplication            D  Device: 75:BF:25:C8:5D:1C, UUID: 0000fef3-0000-1000-8000-00805f9b34fb, RSSI: -81
2024-05-14 13:40:32.049 17624-17624 GetBLE                  com.hogehoge.bleapplication            D  Device: 55:D9:53:05:D2:63, UUID: 0000fef3-0000-1000-8000-00805f9b34fb, RSSI: -82

~以下略~

こんな感じに取れます
stopScan()を実行するとスキャンが止まります。

2.2解説

BLEスキャンの結果はresultに格納されています。
result内には

result.device
result.scanRecord
result.rssi

が含まれています。

よく使うやつについて軽く触れておきます

device

デバイスの情報が格納されています。
device.name:機器の名前
device.address:MACアドレス
device.type:デバイスの種類(BluetoothDevice.DEVICE_TYPE_LEこういうのがとれる)

scanRecord

生のbyteなどが格納されています
scanRecord.serviceUuids:サービスのUUID
scanRecord.bytes:byteデータそのまま
scanRecord.serviceDataサービスに紐づけられたデータ(センサデータとか自由に入れれる)

rssi

電波強度
以上!

おわりに

BLE機器はスキャンするだけでもかなりの情報を取得できるので上手に使いましょう。
初心者がまとめたものなので間違い等あると思います。
あくまで参考にしていただけるとありがたいです。

参考資料

【サルでもわかるBLE入門】(1) BLEの基礎
↑のシリーズ
Bluetooth(BLE)の仕様とセキュリティについて | CSL

Discussion