Software/Android

AndroidでBLE(Bluetooth Low Energy)を使用する

1.BLE(Bluetooth Low Energy)について

Bluetooth Low Energyの略でBluetooth 4.0規格の一部です。

特徴:
超低消費電力(ボタン電池で一年以上動作)
2.4GHz帯を使用
これまでのBluetooth(Classic Bluetooth)との互換性は無し
通信距離は2.5mから10m程度
同時接続数に制約無し(Classic Bluetoothでは最大7台)

2.BLEの通信についての基礎知識

BLEはGATT(Generic Attribute Profile)と呼ばれるクライアントサーバモデルで行われます。
デバイス(サーバ)の仕様はプロファイル、サービス、キャラクタリスティック、ディスクリプタから構成されています。

gatt.png

プロファイル

GATT(Generic Attribute Profile)
BLEデバイス間のデータ交換の論理的な仕様です。
データ構造の読み出し、データの読み書き、データの変更通知を行います。

GATTはサービス、キャラクタリスティック、ディスクリプタと呼ばれる3つの要素から構成されています。
プロファイルは1つ以上のサービスから構成されます。

サービス

サービスはプロファイルの機能を表します。
サービスは複数の入れ子になっているサービスと複数のキャラクタリスティックから構成されています。

キャラクタリスティック

単一の値を持った属性を表します。
自身の値と値へのアクセス方法を定義するプロパティ、複数のディスクリプタで構成されています。

ディスクリプタ

ディスクリプタはキャラクタリスティックに付加情報が必要な際に用いられる属性値を表します。
キャラクタリスティックによってはディスクリプタが無いものもあります。

3.AndroidでのBLE

Androidは4.3(API Level 18)から対応しています。

Bluetooth パッケージ

android.bluetooth.*

BluetoothManager

Bluetoothの機能管理を行います。
BluetoothManagerからBluetoothAdapterを取得します。

BluetoothAdapter

端末のBluetoothを制御します。
Bluetoothデバイスのスキャンを行います。

BluetoothGatt

GATTプロファイルを操作します。
サービスの検索、キャラクタリスティックのread/write、ディスクリプタの設定を行います。

BluetoothDevice

BluetoothAdapterのスキャン結果として受け取ります。
Bluetoothデバイス情報です。

BluetoothGattService

(GATT)サービス情報です。
キャラクタリスティック(BluetoothGattCharacteristic)を保持しています。

BluetoothGattCharacteristic

キャラクタリスティック情報です。
ディスクリプタ(BluetoothGattDescriptor)を保持しています(無いケースもあります)

BluetoothGattDescriptor

ディスクリプタ情報です。

4.アプリの実装

パーミッション

マニフェスト(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();

BLEの有効化

実行時に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) 

BluetoothGattCallbackの実装

	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()

Embedded Technology 2015のデモについて

Android端末(Nexus7 2013)で6台のBLEデバイスに接続し、操作を行うデモを展示しました。

同時接続

BLEデバイスを複数接続
6台のデバイスを順次接続しています

LED照明

明るさを6段階で変更
個別/同時に操作

スイッチ

3個のリレーを搭載し、個別/同時にON/OFF操作

LED電球

LED電球(RGB)の色を操作


YASHIRO Masayuki

添付ファイル: filegatt.png 2551件 [詳細]

BC::labsへの質問は、bc9-dev @ googlegroups.com までお願い致します。
トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   最終更新のRSS
Last-modified: 2015-12-03 (木) 14:20:12 (3068d)