AndroidでBLEを取得する
はじめに
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
を使用していきます。
権限が必要なので権限を与えます。
<!-- 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" />
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