質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.35%

  • Android Studio

    2715questions

    Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

  • Arduino

    352questions

    Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

  • Bluetooth

    153questions

    Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

ボタンを押すことなく、受信Characteristicの値を常時表示したい (BluetoothLeGattの改変)

解決済

回答 2

投稿 2017/11/21 02:27 ・編集 2017/11/21 15:00

  • 評価
  • クリップ 0
  • VIEW 118

tmn

score 6

前提・実現したいこと

Android StuioのサンプルにあるBluetoothLeGattを改変し、Genuino101とBLE通信を行うアプリを作成しています。
GenuinoのCharacteristicの値を適当な時間ごとに変化させるように設定し、Android側でNotificationをセットしています。
現在はAndroid側からGenuino側に送信はできていますが、受信した値を表示することができていません。その値をボタンを押すことなく表示したいと考えています。
Notificationの設定方法等アドバイスお願いします。

LeGattとの主な変更点

BluetoothLeService部のonServicesDiscoverd実行時にNotificationを設定。
ControlActivity部のdisplayGattServices、servicesListClickListner等の消去。
標準で用意されている心拍数の測定・表示等に関する部分の消去。

BluetoothLeService.javaを改変したもの(抜粋)

/* resDataTextにCharacteristicの値を入れたい
   Genuino_UUIDはサービスUUID Genuino_Readは受信UUID Genuino_Writeは送信UUIDとしています */

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            String intentAction;
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                intentAction = ACTION_GATT_CONNECTED;
                broadcastUpdate(intentAction);
                Log.e(TAG, "Connected to GATT server.");
                Log.e(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                intentAction = ACTION_GATT_DISCONNECTED;
                Log.e(TAG, "Disconnected from GATT server.");
                broadcastUpdate(intentAction);
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
                BluetoothGattService myService = mBluetoothGatt.getService(UUID.fromString(Genuino_UUID));
                BluetoothGattCharacteristic characteristic = myService.getCharacteristic(UUID.fromString(Genuino_Read));
                mBluetoothGatt.setCharacteristicNotification(characteristic, true);

                BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(CLIENT_CHARACTERISTIC_CONFIG));
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                mBluetoothGatt.writeDescriptor(descriptor);
            } else {
                Log.e(TAG, "onServicesDiscovered received: " + status);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic characteristic,
                                         int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        }
    };

    private void broadcastUpdate(final String action) {
        final Intent intent = new Intent(action);
        sendBroadcast(intent);
    }

    private void broadcastUpdate(final String action,
                                 final BluetoothGattCharacteristic characteristic) {
        final Intent intent = new Intent(action);
        if (UUID.fromString(Genuino_Read).equals(characteristic.getUuid())) {
            final byte[] data = characteristic.getValue();
            if (data != null && data.length > 0) {
                intent.putExtra(EXTRA_DATA, data);
            }
        }
        sendBroadcast(intent);
    }


    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.readCharacteristic(characteristic);
    }

    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                              boolean enabled) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);

        if (Genuino_UUID.equals(characteristic.getUuid())) {
            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                    UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            mBluetoothGatt.writeDescriptor(descriptor);
        }
    }

    public void sendData(byte[] bytes){
        BluetoothGattService myService = mBluetoothGatt.getService(UUID.fromString(Genuino_UUID));
        BluetoothGattCharacteristic characteristic = myService.getCharacteristic(UUID.fromString(Genuino_Write));
        characteristic.setValue(bytes);
        mBluetoothGatt.writeCharacteristic(characteristic);
    }
}

DeviceControlActivity.javaを改変したもの(抜粋)

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
            if (!mBluetoothLeService.initialize()) {
                Log.e(TAG, "Unable to initialize Bluetooth");
                finish();
            }
            mBluetoothLeService.connect(mDeviceAddress);
        }
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBluetoothLeService = null;
        }
    };

    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
                invalidateOptionsMenu();
            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
                invalidateOptionsMenu();
            } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {

            } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
                byte[] rsvData = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA);
                if (rsvData != null) {
                    int sensorValue = convByteToInt(rsvData[0]);
                    resDataText.setText("[" + String.valueOf(sensorValue) + "]");
                }
            }
        }
    };

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
        if (mBluetoothLeService != null) {
            final boolean result = mBluetoothLeService.connect(mDeviceAddress);
            Log.d(TAG, "Connect request result=" + result);
        }
    }


    private static IntentFilter makeGattUpdateIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
        intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
        return intentFilter;
    }

    class ButtonClickListener implements OnClickListener {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.genuino_send0:
                    byte[] off = new byte[8];
                    off[0] = 0;
                    mBluetoothLeService.sendData(off);    //送信
                    break;

                case R.id.genuino_send1:
                    byte[] on = new byte[8];
                    on[0] = 1;
                    mBluetoothLeService.sendData(on);    //送信
                    break;

                default:
                    break;
            }
        }
    }
}

試したこと

いくつかLogで確認したところ、BluetoothLeServiceの中のbroadcastUpdate(ACTION_DATA_AVAILABLE, characteristic)がうまく機能していないことは確認ができました。
が、どういじればいいか分からない状況です。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

onServicesDiscoveredの
mBluetoothGatt.writeDescriptor(descriptor);
の次の行に
Log.d(TAG, "Notification UUID = " + characteristic.getUuid());
を入れると
正しいUUIDが取れていますか?

投稿 2017/12/01 08:58

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/01 22:21 編集

    回答ありがとうございます。
    ご指摘の修正加えてLogを確認してみましたが、UUIDどころかLogが出てきません。

    onServicesDiscoverdの各行間でLogを出力しチェックすると、
    BluetoothGattCharacteristic characteristic = myService.getCharacteristic(UUID.fromString(Genuino_Read));の後ろ
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(CLIENT_CHARACTERISTIC_CONFIG));の後ろ
    mBluetoothGatt.setCharacteristicNotification(characteristic, true);の後ろ
    ではLogが出力され正しいUUIDを確認しました。
    しかしそれ以外の部分ではLogが出力されなかったです。

    キャンセル

  • 2017/12/04 11:44

    各行でチェックはいいですね
    ということは、ログが出なくなった行があやしいですが
    なにかエラー出ていませんか?

    descriptor.setValue()でエラーだとすると、
    descriptor.setValue()の前に、
    descriptor.getPermissions()で値を見てみるとか。

    ちなみに、提示のソースコードは、
    私の知識では問題なさそうに見えますので、
    Genuino101側の設定かなーと思っています。

    GooglePlayのBLEScannerとかnRF Connectとか
    既存のアプリを使用して、
    Genuino101のNotificationを受け取れますか?

    キャンセル

  • 2017/12/04 19:11

    何度もご回答ありがとうございます。

    ご指摘箇所にdescriptor.getPermissions()を挿入し、
    テストしてみるとなぜか値が常時更新されるようになりました。
    その後はdescriptor.getPermissions()の部分を消しても動作することを確認しました。
    Android Studioのアップデートや、Genuinoの設定を変更することなく
    動くようになりましたので、正直どこが原因でなぜこのようになっているかは分かりません。笑

    ですが、hillackenさんのご指摘のおかげで理解が深まり、解決できたと思っております。
    親身に答えてくださり本当に助かりました。ありがとうございます。

    キャンセル

  • 2017/12/04 22:10

    動いたようでよかったです。
    androidデバイス内のbluetoothモジュールに設定が残ったままだったかもしれませんね。

    キャンセル

+1

broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic)がうまく機能していないことは確認ができました。

というのはどういう状況でしょうか?
BluetoothLeService.javaの、onCharacteristicReadまたはonCharacteristicChangedは呼び出されていますか?
DeviceControlActivity.javaの、onReceiveは呼び出されていますか?


if (rsvData != null) {
int sensorValue = convByteToInt(rsvData[0]);
resDataText.setText("[" + String.valueOf(sensorValue) + "]");
}

↑ここを↓このように変更したら何かしら表示されますか?

            if (rsvData != null && rsvData.length > 0) {
                final StringBuilder stringBuilder = new StringBuilder(rsvData.length);
                for (byte byteChar : rsvData) {
                    stringBuilder.append(String.format("%02X ", byteChar));
                }
                resDataText.setText(stringBuilder.toString());
            }

投稿 2017/11/30 16:03

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/30 18:14

    回答ありがとうございます。
    BluetoothLeService.java内のonCharacteristicReadとonCharacteristicChangedの部分が実行されていません。
    上記の部分が実行されないので、onReceiveは呼び出されますが、ACTION_DATA_AVAILABLEに変わることがないので、DeviceControlActivity.javaのonReceive内の
    } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
    部分が実行されていないです。
    そのためご指摘いただいた修正を加えても表示が変わることはありません。
    Notify?Notification?の使い方が誤っているとは思っているのですが、正しい記述方法が分からない状態です。

    分かりにくい書き方で申し訳ございませんが、ご指導お願いします。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.35%

関連した質問

同じタグがついた質問を見る

  • Android Studio

    2715questions

    Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

  • Arduino

    352questions

    Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

  • Bluetooth

    153questions

    Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。