BLEを使ってAndroidとマイクロビットをつなげるまで(2)

IoT

こんにちは。ECF Tech ブログ 担当 Michiです。

前回に続いて、今回もAndroidでマイクロビットと接続するまでのプログラムのご紹介をしたいと思います。

前回はマイクロビットとの接続要求をし、接続完了時に呼ばれる下のコールバックメソッドの説明までをさせていただきました。

public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    Log.d("onConnect","change");
    if( newState == BluetoothProfile.STATE_CONNECTED){
        gatt.discoverServices();
    }
}

というわけで、その続きから進めたいとおもいます。接続が正しく完了すると、引数 newStateに定数STATE_CONNECTEDが渡されてコールされますので、その値を判断し接続時の処理を行なっています。接続が完了すると、サービスを探す段階に移行します。この処理はdiscoverServices()によって行われます。

サービスが見つかった場合は、下記のコールバックメソッドがコールされます。

public void onServicesDiscovered(BluetoothGatt gatt, int status) {
    mGatt = gatt;
    if( status == BluetoothGatt.GATT_SUCCESS ){
        Log.d("onServicesDiscovered","success");
        List<BluetoothGattService> list = gatt.getServices();
        for( BluetoothGattService service : list){
            //加速度サービスの確保
            if( service.getUuid().toString().equals(ACCEL_SERVICE) ) {
                mService = service;
                //通知ペースを変更
                BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(ACCEL_PERIOD));
                characteristic.setValue(160,BluetoothGattCharacteristic.FORMAT_UINT16,0);
                //Descriptorを通知モードに書き換え
                characteristic = service.getCharacteristic(UUID.fromString(ACCEL_DATA));
                mGatt.setCharacteristicNotification(characteristic,true);
                //Descriptorの取得
                BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(NOTIFY_DESCRIPTOR));
                //通知設定に変更
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                //Descriptorを新たにcharacteristicsに書き込む
                mGatt.writeDescriptor(descriptor);
            }
        }
    }
}

ここからは、マイクロビット固有の処理が入っています。分割してみていきます。

gerServicesメソッドでサービスの一覧を取得します。

List<BluetoothGattService> list = gatt.getServices();

取得したサービスの一覧をひとつずつ見て、利用したいサービスを探します。今回は、加速度サービスを探すものとします。

for( BluetoothGattService service : list){

GATTでは、サービスをUUIDと呼ばれる識別IDを用いて識別します。どんなサービスにどのUUIDが割り当てられているかはこちらのマイクロビットの仕様から確認することができます。加速度サービスにあたるUUIDは定数を用いてあらかじめ定義しています。

private final String ACCEL_SERVICE = "e95d0753-251d-470a-a062-fa1922dfa9a8";

なので、下のようなif文を用いて該当サービスを探します。

if( service.getUuid().toString().equals(ACCEL_SERVICE) ) {

サービスが取得出来たら、その中に含まれるchractersitics(キャラクタリスティクス)を使ってマイクロビットとのデータ送受信を始めます。characteristicsはサービスが持つ属性値といったところです。マイクロビットの加速度サービスでは、次の2つのデータを操作することができます。

  • Accelerometer Data(加速度値):加速度X、Y、Zの各値
  • Accelerometer Period(加速度通知間隔):マイクロビットが加速度値を何msごとに通知するか

詳しくは、マイクロビット仕様より確認することができます。

では、これらの値の操作に入っていきます。まずは、加速度の通知間隔を160msに設定しています。characteristicsも個々にUUIDを持っているので、その値を使って該当するインスタンスを探します。インスタンスの持つsetValueメソッドで通知間隔を設定しています。setValueの引数は順に、書き込むint値、データフォーマット、書き込み位置です。データフォーマットは仕様に記載があります。UINT16は符号なし2バイト整数です。書き込み位置は0バイト目からとなります。

//通知ペースを変更
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(ACCEL_PERIOD));
characteristic.setValue(160,BluetoothGattCharacteristic.FORMAT_UINT16,0);

次に加速度値を取得するための準備です。加速度値を取得できるcharacteristicsは、通知モードのON/OFFができるようになっています。デフォルトはOFFですのでONに設定します。

ONにするには、setCharacteristicsNotificationをtrueにし、さらにDescriptorという設定データを通知モードに変更します。手順としては次のように行います。

//Descriptorを通知モードに書き換え
characteristic = service.getCharacteristic(UUID.fromString(ACCEL_DATA));
mGatt.setCharacteristicNotification(characteristic,true);
//Descriptorの取得
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(NOTIFY_DESCRIPTOR));
//通知設定に変更
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
//Descriptorを新たにcharacteristicsに書き込む
mGatt.writeDescriptor(descriptor);

通知設定が完了すると、マイクロビットから加速度値の通知が来るようになります。通知が来るたびに下のコールバックメソッドが呼ばれることになります。

public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
    Log.d("onCharacteristic","change");
    //加速度値なら
    if( characteristic.getUuid().toString().equals(ACCEL_DATA) ){
        //値を取得する
        byte[] t = characteristic.getValue();
        // 2バイトごとにx,y,zの値が符号付2バイト整数(SINT16)で渡されるので、
        // バイト配列を分割して取得
        final int x = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16,0);
        final int y = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16,2);
        final int z = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16,4);

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                TextView textView = findViewById(R.id.accel_x);
                textView.setText("加速度X:"+x);
                textView = findViewById(R.id.accel_y);
                textView.setText("加速度Y:"+y);
                textView = findViewById(R.id.accel_z);
                textView.setText("加速度Z:"+z);
            }
        });
    }
}

上記コメントのとおりですが、加速度値はX、Y、Zがそれぞれまとめて6バイトのデータとして提供されます。データの取得はgetIntValueで行います。getIntValueメソッドの引数は順に、データフォーマット、データ開始位置です。加速度値のデータはSINT16(符号つき2バイトint)で0バイト目からX値、2バイト目からY値、4バイト目からZ値がセットされているので、第2引数は0、2、4となっています。上のプログラム例では、もらった値を随時TextViewに反映させています。

以上で、説明は終わりです。最後までありがとうございました。全体のソースコードはgithubにて提供しております。こちらからご覧いただけます。

マイクロビットではほかにも様々な値の取得、設定ができるので、ぜひ仕様を参考に色々試してみてください。アプリと連携した新しい楽しみ方ができるかもしれません。


合同会社イー・シー・エフでは、子ども向けプログラミングなどの教育講座を実施しています。プログラミング教室の案内や教育教材の情報は、下記よりご確認ください。

ECFエデュケーション

タイトルとURLをコピーしました