Bluetooth Low Energyの略でBluetooth 4.0規格の一部です。
特徴:
超低消費電力(ボタン電池で一年以上動作)
2.4GHz帯を使用
これまでのBluetooth(Classic Bluetooth)との互換性は無し
通信距離は2.5mから10m程度
同時接続数に制約無し(Classic Bluetoothでは最大7台)
BLEはGATT(Generic Attribute Profile)と呼ばれるクライアントサーバモデルで行われます。
デバイス(サーバ)の仕様はプロファイル、サービス、キャラクタリスティック、ディスクリプタから構成されています。
GATT(Generic Attribute Profile)
BLEデバイス間のデータ交換の論理的な仕様です。
データ構造の読み出し、データの読み書き、データの変更通知を行います。
GATTはサービス、キャラクタリスティック、ディスクリプタと呼ばれる3つの要素から構成されています。
プロファイルは1つ以上のサービスから構成されます。
サービスはプロファイルの機能を表します。
サービスは複数の入れ子になっているサービスと複数のキャラクタリスティックから構成されています。
単一の値を持った属性を表します。
自身の値と値へのアクセス方法を定義するプロパティ、複数のディスクリプタで構成されています。
ディスクリプタはキャラクタリスティックに付加情報が必要な際に用いられる属性値を表します。
キャラクタリスティックによってはディスクリプタが無いものもあります。
Androidは4.3(API Level 18)から対応しています。
android.bluetooth.*
Bluetoothの機能管理を行います。
BluetoothManagerからBluetoothAdapterを取得します。
端末のBluetoothを制御します。
Bluetoothデバイスのスキャンを行います。
GATTプロファイルを操作します。
サービスの検索、キャラクタリスティックのread/write、ディスクリプタの設定を行います。
BluetoothAdapterのスキャン結果として受け取ります。
Bluetoothデバイス情報です。
(GATT)サービス情報です。
キャラクタリスティック(BluetoothGattCharacteristic)を保持しています。
キャラクタリスティック情報です。
ディスクリプタ(BluetoothGattDescriptor)を保持しています(無いケースもあります)
ディスクリプタ情報です。
マニフェスト(AndroidManifest.xml)に以下の記述を追加します。
パーミッション設定
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
アプリがBLE対応端末のみに対応していることを宣言するには以下を追加します。
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter();
実行時にBluetoothが利用可能かどうかをチェックし、無効になっている場合はBluetoothを有効にする為の確認ダイアログを表示します。
BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter(); if (mBluetoothAdapter == null) { return false; } // Bluetooth機能が有効になっているかのチェック。無効の場合はダイアログを表示します。 if (mBluetoothAdapter.isEnabled()) { // Bluetoothが利用可 } else { // Bluetoothが利用不可。確認ダイアログを表示 Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); activity.startActivityForResult(enableBtIntent, 1); }
// 10秒後にスキャンを停止 private static final long SCAN_PERIOD = 10000; ... private void scanLeDevice(final boolean enable) { if (enable) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(new Runnable() { @Override public void run() { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } }, SCAN_PERIOD); mScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } ... } private LeDeviceListAdapter mLeDeviceListAdapter; ... // デバイススキャン後のコールバック関数 private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { runOnUiThread(new Runnable() { @Override public void run() { String msg = "name =" + device.getName() + ", bondstate = " + device.getBondState() + ", address = " + device.getAddress() + ", type" + device.getType() + ", uuid = " + device.getUuid().toString(); Log.d("Scan", msg);} }); } };
onLeScan()で返されるBluetoothDevice#connectGatt()を呼び出して接続します。
BluetoothDevice: BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)
private final BluetoothGattCallback callback = new BluetoothGattCallback() { // 接続状態が変更されたときに実行される @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { // 接続された if (newState == BluetoothProfile.STATE_CONNECTED) { Log.i(TAG, "Connected to GATT server."); // サービスを検索する Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices()); // 切断された } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { Log.i(TAG, "Disconnected from GATT server."); } } @Override // サービスの検索結果を返す public void onServicesDiscovered(BluetoothGatt gatt, int status) { // 成功 if (status == BluetoothGatt.GATT_SUCCESS) { // サービスのリストを取得 List<BluetoothGattService> gattService = getSupportedGattServices(address); for(BluetoothGattService service : gattService) { UUID uuid = service.getUuid(); // サービスからCharacteristicsのリストを取得 List<BluetoothGattCharacteristic> charastics = service.getCharacteristics(); // Characteristic に Notification の受信要求を設定 for(BluetoothGattCharacteristic charastic : charastics) { // gatt.setCharacteristicNotification(charastic, true); } } } else { Log.w(TAG, "onServicesDiscovered received: " + status); } } // 読み込み通知 @Override public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { // Characteristicの読込成功 } } // 書き込み通知 @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { // Characteristicの書込成功 } ... };
読込は非同期の為、読込要求と読込通知とからなります。
BluetoothGatt#readCharacteristic()を実行します。
結果はBluetoothGattCallback#onCharacteristicRead()に返ります。
mBluetoothGatt.readCharacteristic(characteristic);
public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { // Characteristicの読込成功 } }
書込は非同期の為、書込要求と書込通知とからなります。
BluetoothGatt#writeCharacteristic()を実行します。
結果はBluetoothGattCallback#onCharacteristicWrite()に返ります。
mBluetoothGatt.writeCharacteristic(characteristic);
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) { // Characteristicの書込成功 } }
BluetoothGatt#close()を実行します。
複数のデバイスを接続する場合、同時に接続処理を行うのではなく、順次接続を行うことが必要です。
接続結果を待たずに別のデバイスの接続を行うと動作が不安定になります。
また、スキャン実行中の接続も動作が不安定になります。
デバイスA,B,Cを接続するケース
1.デバイスAの接続
BluetoothDevice#connectGatt()
2.接続結果を待つ
BluetoothGattCallback#onConnectionStateChange()
3.デバイスBの接続
BluetoothDevice#connectGatt()
4.デバイスBの接続結果を待つ
BluetoothGattCallback#onConnectionStateChange()
5.デバイスCの接続
BluetoothDevice#connectGatt()
6.デバイスCの接続結果を待つ
BluetoothGattCallback#onConnectionStateChange()
Android端末(Nexus7 2013)で6台のBLEデバイスに接続し、操作を行うデモを展示しました。
BLEデバイスを複数接続
6台のデバイスを順次接続しています
明るさを6段階で変更
個別/同時に操作
3個のリレーを搭載し、個別/同時にON/OFF操作
LED電球(RGB)の色を操作