ラベル BLEcentral の投稿を表示しています。 すべての投稿を表示
ラベル BLEcentral の投稿を表示しています。 すべての投稿を表示

2015年12月10日木曜日


https://www.youtube.com/watch?v=vUbFB1Qypg8 より抜粋

本記事は以下の記事の続きになります。

[第一回] 生活で使えるBLEデバイス
[第二回] 生活で使えるBLEデバイス~ペアリング編~
[第三回] 生活で使えるBLE~アプリ間通信編~

はじめに

私事ですが、最近携帯をGalaxy S6に変更しました。(とても気に入っています)
しかしGalaxy S6は電池の容量が少ないらしく、日常的に使っていても少し電池の減りが早い気がします。
なんとか出来ないかと電池の消費などについて少し調べてみると、充電回数を減らすことや過充電を行わないことが電池の寿命を延ばすことに繋がるようです。

ということで、今回はBLEデバイスを使って少しでも携帯の電池寿命の延命を行いたいと思います。

環境
  • 端末
    • Nexus 5(Android 6.0)
BLEデバイスは鳴動可能で、物理ボタンがあるモノにしました。今後もいろいろ遊べそうです。

やりたいこと

1. 過充電を防いで電池の寿命を長く保ちたい。
2. 家の中で携帯をすぐ無くすので、居場所を特定したい。

イメージとしては以下のよう感じです。

1. 過充電防止

図1 過充電防止

2. 携帯の位置通知
図2 携帯の位置通知

BLEデバイスのサービスの確認
まず、購入したBLEデバイスを実際に接続してサービスを確認しましょう。
以下のようなサービスがあるようです。
サービス名
UUID
説明
Generic Access
1800
 デバイス名などの情報取得
Immediate Alert
1802
アラームを鳴らす
Link Loss
1803
接続が切れたときの挙動を設定する
Tx Power
1804
BLEの送信のパワー
Battery Service
180f
バッテリーの状態
Battery ServiceとImmediate Alertのサービスがあるので、やりたいことは実現出来そうです。
では、実際に作ってみましょう。

実際に作ってみる

1. 過充電防止

充電状態が90%を超えたら、BLEデバイスへ通知を送るようにしたい。
ただし、電源接続している時だけ通知が欲しいので、ACTION_POWER_CONNECTEDを契機に、バッテリーの状態を監視するサービスを常駐させるようにしたいと思います。

構成としては以下の通りです。

図3 過充電防止-構成

では次に、Android側の実装に移ります。

使用するUUID
サービスのImmediate Alertを使用します。
Alert Levelに値(0 or 1or 2)を設定することで通知を行えるようです。

public static final UUID ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
public static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
AndroidManifestに宣言
<service android:name=".power.BatteryMonitorService" android:enabled="true"/>
<service android:name=".ble.BluetoothLeService" android:enabled="true"/>

<receiver android:name=".power.PowerConnectedReceiver" android:enabled="true" android:exported="false">
    <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
            <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
    </intent-filter>
</receiver>
PowerConnectedReciverの実装
電源の接続/切断を受けるレシーバーで、電源接続を契機にバッテリーの監視を行い、電源の切断を契機にバッテリーの監視を終了します。
public class PowerConnectedReceiver extends BroadcastReceiver {

    private static final String TAG = "BleNotify.PowerConnectedReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive : " + intent.getAction());

        if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
            Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
            context.startService(serviceIntent);
        } else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
            Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
            context.stopService(serviceIntent);
        }
    }
}
BatteryMonitorServiceの実装
起動時にバッテリーの状態変化を監視するサービスで、バッテリーが90%以上になるとブロードキャストを送信します。
public class BatteryMonitorService extends Service {

    private static final String TAG = "BleNotify.BatteryMonitorService";
    private ChargingOnReceiver mChargingOnReceiver;
    private boolean isRegisteredChargingReceiver = false;

    class ChargingOnReceiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
            int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
            float batteryPct = level / (float)scale;
            Log.d(TAG, "change battery state : " + batteryPct*100 + "%");
            if (batteryPct > 0.9) {
                Intent notify = new Intent(BluetoothLeService.ACTION_CALL_BATTERY_NOTIFY);
                LocalBroadcastManager.getInstance(context).sendBroadcast(notify);
                Log.d(TAG, "send broadcast Notify");
            }
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
        mChargingOnReceiver = new ChargingOnReceiver();
        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        registerReceiver(mChargingOnReceiver, filter);
        isRegisteredChargingReceiver = true;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "starting the BatteryMonitorService.");
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "terminate the BatteryMonitorService.");
        // close process
        if (isRegisteredChargingReceiver) {
            unregisterReceiver(mChargingOnReceiver);
        }
        super.onDestroy();
    }
}
BLEデバイスへ通知
BattryMonitorServiceからの通知を受けて、BLEデバイスへアラームの鳴動要求を通知します。
public class BluetoothLeService  extends Service {

    private BluetoothGatt mBluetoothGatt;

    public final static String ACTION_CALL_BATTERY_NOTIFY =
            "com.brilliant.blenotify.ble.le.ACTION_CALL_BATTERY_NOTIFY";

〜中略〜
    class GattRequestReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "onReceive : " + intent.getAction());
            if (mBluetoothGatt == null) {
                Log.e(TAG, "GattService is not connected...");
                return;
            }

            if (ACTION_CALL_BATTERY_NOTIFY.equals(intent.getAction())) {
                BluetoothGattCharacteristic c =
                        getCharacteristic(GattAttributes.ALERT_SERVICE_UUID,
                                GattAttributes.ALERT_LEVEL_UUID);
                if (c != null) {
                    // 1 : vibrator
                    // 2 : sound 
                    int level = 2;
                    c.setValue(new byte[]{(byte) level});
                    mBluetoothGatt.writeCharacteristic(c);
                }
            }
        }
    }

    public BluetoothGattCharacteristic getCharacteristic(UUID sid, UUID cid) {
        BluetoothGattService s = mBluetoothGatt.getService(sid);
        if (s == null) {
            Log.w(TAG, "Service NOT found :" + sid.toString());
            return null;
        }
        BluetoothGattCharacteristic c = s.getCharacteristic(cid);
        if (c == null) {
            Log.w(TAG, "Characteristic NOT found :" + cid.toString());
            return null;
        }
        return c;
    }
このようにすることで、充電中で90パーセントを超えると音を鳴らして通知してくれます。
過充電を防ぐことで、電池の寿命を長持ちさせましょう。

2. 携帯の位置通知
次携帯の位置通知は、BLEデバイス側に物理ボタンがあるので、押された場合に端末側にて鳴動等で位置を知らせます。
今回は端末がバイブレーションするところまで作ります。

構成としては以下の通り。
図4 携帯の位置通知-構成


NotificationをONに設定
まずはBLEデバイスからの通知を受け取る為に設定を行います。
サービス内のキャラクタリスティックスにNotification設定をONにすることで、BLEデバイスからの通知を受けることが出来ます。
調べてみると、Battery Service内にある「00002a1b」から始まるキャラクタリスティックスがどうやらNotificationのプロパティを持っているようです。
このキャラクタリスティックスを利用すれば、BLEデバイスからの通知を受けることが出来そうです。
※取得したキャラクタリスティックスはBluetoothGattCharacteristic#getProperties()で確認出来ます。
Blutooth SIGで定義されているBattery ServiceにはBattery Levelしかいないようなので、カスタムで追加されているようです。

「Power State Lebel(00002a1b)」の参考:
https://groups.google.com/d/msg/android-group-japan/8PffzGRfMms/0gtEcPdjQY8J

public static final UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb");
public static final UUID BATTERY_LEVEL_STATE_UUID = UUID.fromString("00002a1b-0000-1000-8000-00805f9b34fb");
通知を受ける準備(NotificationをON)
BluetoothGattCharacteristic c =
        getCharacteristic(GattAttributes.BATTERY_SERVICE_UUID,
        GattAttributes.BATTERY_LEVEL_STATE_UUID);

if (c != null) {
    final int charaProp = c.getProperties();
    if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
        Log.d(TAG, "has PROPERTY_NOTIFY");
    }
    mBluetoothGatt.setCharacteristicNotification(c, true);
}
BLEデバイスから通知を受ける
通知はボタンを押された時だけに限定します。
通知されたデータの1byte目でボタンの状態がわかります。
public class BluetoothLeService  extends Service {

    public final static String ACTION_FINDME_NOTIFY =
            "com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY";

〜中略〜

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            UUID uuid = characteristic.getUuid();
            Log.e(TAG, "onCharacteristicChanged : " + characteristic.getUuid());
            if (GattAttributes.BATTERY_LEVEL_STATE_UUID.equals(uuid)) {
                // For all other profiles, writes the data formatted in HEX.
                final byte[] data = characteristic.getValue();
                Log.d(TAG, "BATTERY_LEVEL_STATE_UUID received : " + new String(data));
                if (data != null && data.length > 0) {
                    // if button pressed.
                    if (data[0] == 1) {
                        Intent intent = new Intent(ACTION_FINDME_NOTIFY);
                        sendBroadcast(intent);
                        Log.d(TAG, "send broadcast ACTION_FINDME_NOTIFY.");
                     } else {
                        Log.d(TAG, "Button is not pressed.");
                    }
                }
            } else {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            }
        }
FindMeRecieverの実装
BLEデバイスから通知を受けたときの動作を実装します。
public class FindMeReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        long[] pattern = {3000, 1000, 3000, 1000};
        vibrator.vibrate(pattern, -1);
    }
}
AndrodManifestにも以下を追加しておきます。
<uses-permission android:name="android.permission.VIBRATE"/>
<receiver android:name=".findme.FindMeReceiver" android:enabled="true" android:exported="false"/>
     <intent-filter/>
        <action android:name="com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY" />
     </intent-filter/>
</receiver/>

これで、BLEデバイスから通知があったら端末がブルブルと震えてくれるのでどこに置いたかわかるようになりました。

さいごに

以上で「生活で使えるBLEデバイス」シリーズは終了となります。
いかがでしたでしょうか。

BLEの接続方法から実際のデータ通信までの方法を紹介してきましたが、BLEを利用するにあたって多少の苦労がありました。
BLEデバイスの持っているプロファイルに関して、独自に追加されているサービスやキャラクタリスティックスは情報がなかったり、デバイス毎にどのサービスをどの機能に利用しているか等が不明だったりします。(今回で言うところのPower State Lebel)
BluetoothやBLEでの通信のとっつきにくさはこのあたりも関係しているような気がします。

しかし、コツさえ掴んでしまえばアイデア次第で自由なモノ作りが可能な為、様々な分野で活躍できる技術であると思います。
今回までの記事が、そのコツを掴むまでのお手伝いになれば幸いです。

[第四回] 生活で使えるBLEデバイス~実用編~


https://www.youtube.com/watch?v=vUbFB1Qypg8 より抜粋

本記事は以下の記事の続きになります。

[第一回] 生活で使えるBLEデバイス
[第二回] 生活で使えるBLEデバイス~ペアリング編~
[第三回] 生活で使えるBLE~アプリ間通信編~

はじめに

私事ですが、最近携帯をGalaxy S6に変更しました。(とても気に入っています)
しかしGalaxy S6は電池の容量が少ないらしく、日常的に使っていても少し電池の減りが早い気がします。
なんとか出来ないかと電池の消費などについて少し調べてみると、充電回数を減らすことや過充電を行わないことが電池の寿命を延ばすことに繋がるようです。

ということで、今回はBLEデバイスを使って少しでも携帯の電池寿命の延命を行いたいと思います。

環境
  • 端末
    • Nexus 5(Android 6.0)
BLEデバイスは鳴動可能で、物理ボタンがあるモノにしました。今後もいろいろ遊べそうです。

やりたいこと

1. 過充電を防いで電池の寿命を長く保ちたい。
2. 家の中で携帯をすぐ無くすので、居場所を特定したい。

イメージとしては以下のよう感じです。

1. 過充電防止

図1 過充電防止

2. 携帯の位置通知
図2 携帯の位置通知

BLEデバイスのサービスの確認
まず、購入したBLEデバイスを実際に接続してサービスを確認しましょう。
以下のようなサービスがあるようです。
サービス名
UUID
説明
Generic Access
1800
 デバイス名などの情報取得
Immediate Alert
1802
アラームを鳴らす
Link Loss
1803
接続が切れたときの挙動を設定する
Tx Power
1804
BLEの送信のパワー
Battery Service
180f
バッテリーの状態
Battery ServiceとImmediate Alertのサービスがあるので、やりたいことは実現出来そうです。
では、実際に作ってみましょう。

実際に作ってみる

1. 過充電防止

充電状態が90%を超えたら、BLEデバイスへ通知を送るようにしたい。
ただし、電源接続している時だけ通知が欲しいので、ACTION_POWER_CONNECTEDを契機に、バッテリーの状態を監視するサービスを常駐させるようにしたいと思います。

構成としては以下の通りです。

図3 過充電防止-構成

では次に、Android側の実装に移ります。

使用するUUID
サービスのImmediate Alertを使用します。
Alert Levelに値(0 or 1or 2)を設定することで通知を行えるようです。

public static final UUID ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
public static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
AndroidManifestに宣言
<service android:name=".power.BatteryMonitorService" android:enabled="true"/>
<service android:name=".ble.BluetoothLeService" android:enabled="true"/>

<receiver android:name=".power.PowerConnectedReceiver" android:enabled="true" android:exported="false">
    <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
            <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
    </intent-filter>
</receiver>
PowerConnectedReciverの実装
電源の接続/切断を受けるレシーバーで、電源接続を契機にバッテリーの監視を行い、電源の切断を契機にバッテリーの監視を終了します。
public class PowerConnectedReceiver extends BroadcastReceiver {

    private static final String TAG = "BleNotify.PowerConnectedReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive : " + intent.getAction());

        if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
            Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
            context.startService(serviceIntent);
        } else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
            Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
            context.stopService(serviceIntent);
        }
    }
}
BatteryMonitorServiceの実装
起動時にバッテリーの状態変化を監視するサービスで、バッテリーが90%以上になるとブロードキャストを送信します。
public class BatteryMonitorService extends Service {

    private static final String TAG = "BleNotify.BatteryMonitorService";
    private ChargingOnReceiver mChargingOnReceiver;
    private boolean isRegisteredChargingReceiver = false;

    class ChargingOnReceiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
            int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
            float batteryPct = level / (float)scale;
            Log.d(TAG, "change battery state : " + batteryPct*100 + "%");
            if (batteryPct > 0.9) {
                Intent notify = new Intent(BluetoothLeService.ACTION_CALL_BATTERY_NOTIFY);
                LocalBroadcastManager.getInstance(context).sendBroadcast(notify);
                Log.d(TAG, "send broadcast Notify");
            }
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
        mChargingOnReceiver = new ChargingOnReceiver();
        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        registerReceiver(mChargingOnReceiver, filter);
        isRegisteredChargingReceiver = true;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "starting the BatteryMonitorService.");
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "terminate the BatteryMonitorService.");
        // close process
        if (isRegisteredChargingReceiver) {
            unregisterReceiver(mChargingOnReceiver);
        }
        super.onDestroy();
    }
}
BLEデバイスへ通知
BattryMonitorServiceからの通知を受けて、BLEデバイスへアラームの鳴動要求を通知します。
public class BluetoothLeService  extends Service {

    private BluetoothGatt mBluetoothGatt;

    public final static String ACTION_CALL_BATTERY_NOTIFY =
            "com.brilliant.blenotify.ble.le.ACTION_CALL_BATTERY_NOTIFY";

〜中略〜
    class GattRequestReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "onReceive : " + intent.getAction());
            if (mBluetoothGatt == null) {
                Log.e(TAG, "GattService is not connected...");
                return;
            }

            if (ACTION_CALL_BATTERY_NOTIFY.equals(intent.getAction())) {
                BluetoothGattCharacteristic c =
                        getCharacteristic(GattAttributes.ALERT_SERVICE_UUID,
                                GattAttributes.ALERT_LEVEL_UUID);
                if (c != null) {
                    // 1 : vibrator
                    // 2 : sound 
                    int level = 2;
                    c.setValue(new byte[]{(byte) level});
                    mBluetoothGatt.writeCharacteristic(c);
                }
            }
        }
    }

    public BluetoothGattCharacteristic getCharacteristic(UUID sid, UUID cid) {
        BluetoothGattService s = mBluetoothGatt.getService(sid);
        if (s == null) {
            Log.w(TAG, "Service NOT found :" + sid.toString());
            return null;
        }
        BluetoothGattCharacteristic c = s.getCharacteristic(cid);
        if (c == null) {
            Log.w(TAG, "Characteristic NOT found :" + cid.toString());
            return null;
        }
        return c;
    }
このようにすることで、充電中で90パーセントを超えると音を鳴らして通知してくれます。
過充電を防ぐことで、電池の寿命を長持ちさせましょう。

2. 携帯の位置通知
次携帯の位置通知は、BLEデバイス側に物理ボタンがあるので、押された場合に端末側にて鳴動等で位置を知らせます。
今回は端末がバイブレーションするところまで作ります。

構成としては以下の通り。
図4 携帯の位置通知-構成


NotificationをONに設定
まずはBLEデバイスからの通知を受け取る為に設定を行います。
サービス内のキャラクタリスティックスにNotification設定をONにすることで、BLEデバイスからの通知を受けることが出来ます。
調べてみると、Battery Service内にある「00002a1b」から始まるキャラクタリスティックスがどうやらNotificationのプロパティを持っているようです。
このキャラクタリスティックスを利用すれば、BLEデバイスからの通知を受けることが出来そうです。
※取得したキャラクタリスティックスはBluetoothGattCharacteristic#getProperties()で確認出来ます。
Blutooth SIGで定義されているBattery ServiceにはBattery Levelしかいないようなので、カスタムで追加されているようです。

「Power State Lebel(00002a1b)」の参考:
https://groups.google.com/d/msg/android-group-japan/8PffzGRfMms/0gtEcPdjQY8J

public static final UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb");
public static final UUID BATTERY_LEVEL_STATE_UUID = UUID.fromString("00002a1b-0000-1000-8000-00805f9b34fb");
通知を受ける準備(NotificationをON)
BluetoothGattCharacteristic c =
        getCharacteristic(GattAttributes.BATTERY_SERVICE_UUID,
        GattAttributes.BATTERY_LEVEL_STATE_UUID);

if (c != null) {
    final int charaProp = c.getProperties();
    if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
        Log.d(TAG, "has PROPERTY_NOTIFY");
    }
    mBluetoothGatt.setCharacteristicNotification(c, true);
}
BLEデバイスから通知を受ける
通知はボタンを押された時だけに限定します。
通知されたデータの1byte目でボタンの状態がわかります。
public class BluetoothLeService  extends Service {

    public final static String ACTION_FINDME_NOTIFY =
            "com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY";

〜中略〜

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            UUID uuid = characteristic.getUuid();
            Log.e(TAG, "onCharacteristicChanged : " + characteristic.getUuid());
            if (GattAttributes.BATTERY_LEVEL_STATE_UUID.equals(uuid)) {
                // For all other profiles, writes the data formatted in HEX.
                final byte[] data = characteristic.getValue();
                Log.d(TAG, "BATTERY_LEVEL_STATE_UUID received : " + new String(data));
                if (data != null && data.length > 0) {
                    // if button pressed.
                    if (data[0] == 1) {
                        Intent intent = new Intent(ACTION_FINDME_NOTIFY);
                        sendBroadcast(intent);
                        Log.d(TAG, "send broadcast ACTION_FINDME_NOTIFY.");
                     } else {
                        Log.d(TAG, "Button is not pressed.");
                    }
                }
            } else {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            }
        }
FindMeRecieverの実装
BLEデバイスから通知を受けたときの動作を実装します。
public class FindMeReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        long[] pattern = {3000, 1000, 3000, 1000};
        vibrator.vibrate(pattern, -1);
    }
}
AndrodManifestにも以下を追加しておきます。
<uses-permission android:name="android.permission.VIBRATE"/>
<receiver android:name=".findme.FindMeReceiver" android:enabled="true" android:exported="false"/>
     <intent-filter/>
        <action android:name="com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY" />
     </intent-filter/>
</receiver/>

これで、BLEデバイスから通知があったら端末がブルブルと震えてくれるのでどこに置いたかわかるようになりました。

さいごに

以上で「生活で使えるBLEデバイス」シリーズは終了となります。
いかがでしたでしょうか。

BLEの接続方法から実際のデータ通信までの方法を紹介してきましたが、BLEを利用するにあたって多少の苦労がありました。
BLEデバイスの持っているプロファイルに関して、独自に追加されているサービスやキャラクタリスティックスは情報がなかったり、デバイス毎にどのサービスをどの機能に利用しているか等が不明だったりします。(今回で言うところのPower State Lebel)
BluetoothやBLEでの通信のとっつきにくさはこのあたりも関係しているような気がします。

しかし、コツさえ掴んでしまえばアイデア次第で自由なモノ作りが可能な為、様々な分野で活躍できる技術であると思います。
今回までの記事が、そのコツを掴むまでのお手伝いになれば幸いです。

2015年11月12日木曜日


本記事は以下の記事の続きになります。
[第一回] 生活で使えるBLEデバイス
[第二回] 生活で使えるBLEデバイス~ペアリング編~

はじめに

前回は端末側でのBLE検知と接続までの方法をまとめました。
そして今回はセントラル(端末)とペリフェラル(BLEデバイス)での通信方法に関して触れていきたいと思います。

環境
前回記事と同様に以下の環境で行います。
  • Nexus 5(端末)
  • Nexus 9(BLEデバイス)
データの送受信に関して

独自サービス
今回のデータ送受信では、セントラル(GATT Client)側からペリフェラル(GATT Server)へ接続し、サービス内の必要なキャラクタリスティクスにアクセスして、データ(Value)の読み書きを行います。
なので、今回のデータ送受信に使用するサービスとキャラクタリスティクスを定義しておきます。
例として、以下のように定義しておきます。

・サービス(図1 のService部分)
SERVICE_UUID = "00000001-0000-1000-8000-2f97f3b2dcd5";

・キャラクタリスティクス(図2 のCharacterri部分)
CHAR_READ_UUID = "00000010-0000-1000-8000-2f97f3b2dcd5";
→データ読み込み用
CHAR_WRITE_UUID = "00000011-0000-1000-8000-2f97f3b2dcd5";
→データ書き込み用

図1 GATT Server & GATT Client

アドバタイジングについて
前回からNexus 9をペリフェラルとして機能させていますが、どのようになっていたのでしょうか。
GATT通信の方法と併せて、Android端末でのアドバタイジング方法を簡単に説明していきます。(Bluetooth機能の確認と位置情報の権限取得は前回記事を参照)


図2 アドバタイジング

まずはBluetoothLeAdvertiserの取得を行います。
BluetoothLeAdvertiserは端末のアドバタイジング開始/停止の操作等を行えるクラスです。

BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager != null) {
    BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
}
次にGATT Serverのインスタンスを取得します。(BluetoothManager#openGattServer)
取得する際に引数として、BluetoothGattServerCallbackを渡します。
このコールバックにて読み書き等、セントラルから要求が行われた際の動作を実装していくようになります。
ペリフェラル機能を実装していく上で本体となる部分です。
mGattServer = mBluetoothManager.openGattServer(this, new BLEServer());

class BLEServer extends BluetoothGattServerCallback {
    //セントラルから読み込み要求が来ると呼ばれる
    public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId,
            int offset, BluetoothGattCharacteristic characteristic) {
    }

    //セントラルから書き込み要求が来ると呼ばれる
    public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId,
            BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded,
                int offset, byte[] value) {
    }
}
次は宣言しておいたサービスとキャラクタリスティクスをGATT Serverに設定していきます。
ここでGATT Serverに設定することで、セントラルから独自宣言したサービスを検知することが可能になります。

この時、読み込み用のキャラクタリスティクスには読み込みの、書き込み用のキャラクタリスティクスには書き込みのプロパティと権限を付与しています。
キャラクタリスティクスの権限とプロパティを正しく設定出来ていないと、読み込み/書き込みに失敗してしまうので注意してください。
private void setServices() {
    //serviceUUIDを設定BluetoothGattService service = new BluetoothGattService(
            UUID.fromString(Constants.SERVICE_UUID),
            BluetoothGattService.SERVICE_TYPE_PRIMARY);

    //characteristicUUIDを設定
    BluetoothGattCharacteristic charRead = new BluetoothGattCharacteristic(
            UUID.fromString(Constants.CHAR_READ_UUID),
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ);

    BluetoothGattCharacteristic charWrite = new BluetoothGattCharacteristic(
            UUID.fromString(Constants.CHAR_WRITE_UUID),
            BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattCharacteristic.PERMISSION_WRITE);

    //characteristicUUIDをserviceUUIDにのせる
    service.addCharacteristic(charRead);
    service.addCharacteristic(charWrite);

    //serviceUUIDをサーバーにのせる
    mGattServer.addService(service);
}
次にアドバタイジング時の設定(AdvertiseSettings)とデータ(AdvertiseData)の設定を行います。
そして、アドバタイジングの設定の準備が出来たらBluetoothLeAdvertiser#startAdvertisingで、アドバタイジングを開始します。
//AdvertiseSettingsの設定
private AdvertiseSettings buildAdvertiseSettings() {
    AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
    settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER);
    settingsBuilder.setTimeout(0);
    return settingsBuilder.build();
}

//AdvertiseDataの設定
private AdvertiseData buildAdvertiseData() {
    AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
    dataBuilder.addServiceUuid(ParcelUuid.fromString(Constants.SERVICE_UUID));
    dataBuilder.setIncludeDeviceName(true);
    return dataBuilder.build();
}

//Advertiseの開始
private void startAdvertising() {
    setServices();
    AdvertiseSettings settings = buildAdvertiseSettings();
    AdvertiseData data = buildAdvertiseData();
    mAdvertiseCallback = new SimpleAdvertiseCallback();
    mBluetoothLeAdvertiser.startAdvertising(settings, data,mAdvertiseCallback);
}

//Advertiseの成功可否
private class SimpleAdvertiseCallback extends AdvertiseCallback {
    @Override
    public void onStartFailure(int errorCode) {
        super.onStartFailure(errorCode);
        Log.d(TAG, "Advertising failed");
    }

    @Override
    public void onStartSuccess(AdvertiseSettings settingsInEffect) {
        super.onStartSuccess(settingsInEffect);
        Log.d(TAG, "Advertising successfully started");
    }
}
アドバタイジングを終了する時はBluetoothLeAdvertiser#stopAdvertisingを呼びます。
この時、GATT Serverのcloseも忘れずに。
private void stopAdvertising() {
    Log.d(TAG, "Service: Stopping Advertising");
    if (mGattServer != null) {
        mGattServer.clearServices();
        mGattServer.close();
        mGattServer = null;
    }
    if (mBluetoothLeAdvertiser != null) {
        mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
        mAdvertiseCallback = null;
    }
}
以上で、Nexus 9がペリフェラルとして機能するようになります。
アドバタイジングが開始された後、セントラル(Nexus 5)側から検知出来るようになっていることでしょう。

そして、定義したサービスとGATT Serverによって、データの読み書きを行う準備も出来ました。
では、実際にデータの読み書きを行ってみましょう。

データの読み込み
セントラル側からペリフェラルのキャラクタリスティクスデータを読み込む手順です。

図3 データの読み込み
<セントラル(Nexus 5)側>
接続済みのBluetoothGattから読み込み用キャラクタリスティクスを取得して、読み込み要求(BluetoothGattl#readCharacteristic)を行います。
public void readCharacteristic() {
    BluetoothGattCharacteristic read = mBluetoothLeService.getCharacteristic(
            GattAttributes.SERVICE_UUID,
            GattAttributes.CHAR_READ_UUID);
    mBluetoothGatt.readCharacteristic(read);
}

public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) {
    BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid));
    if (s == null) {
        Log.w(TAG, "Service NoT found :" + sid);
        return null;
    }
    BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid));
    if (c == null) {
        Log.w(TAG, "Characteristic NOT found :" + cid);
        return null;
    }
    return c;
}
読み込み要求を行い、成功するとBluetoothGattCallback#onCharacteristicReadが呼び出されます。
その引数に渡されるBluetoothGattCharacteristicにペリフェラルからのレスポンスを受け取ることが出来ます。
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
        BluetoothGattCharacteristic characteristic, int status) {
    final byte[] data = characteristic.getValue();
    Log.d(TAG, "onCharacteristicRead : " +  new String(data));
}

<ペリフェラル(Nexus 9)側>
セントラル側から読み込み要求が行われると、BluetoothGattServerCallback#onCharacteristicReadRequestに通知が来ます。
セントラルに対して送りたいデータをGattServer#sendResponseにセットすることで、セントラルに任意のデータを送信することが出来ます。
//セントラルからReadRequestが来ると呼ばれる
public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId,
        int offset, BluetoothGattCharacteristic characteristic) {
    //セントラルに任意の文字を返信する
    if (UUID.fromString(Constants. CHAR_READ_UUID).equals(characteristic.getUuid())) {
        String response  = "your message.";
        byte value[] = response.getBytes();
        mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
    }
}

データの書き込み
セントラルからペリフェラルへキャラクタリスティクスデータを書き込む手順です。

図4 データの書き込み
<セントラル(Nexus 5)側>
接続が完了したBluetoothGattから書き込み用キャラクタリスティクスを取得し、書き込みたいデータをセットすることでペリフェラル側へデータを送ることが出来ます。
※書き込み権限のないキャラクタリスティクスに書き込み要求(BluetoothGatt#writeCharacteristic)を行うと戻り値に false が返り、書き込みに失敗します。
public void writeCharacteristic() {
    BluetoothGattCharacteristic write = getCharacteristic(
            UUID.fromString(GattAttributes.SERVICE_UUID),
            UUID.fromString(GattAttributes.CHAR_WRITE_UUID));
    String message = "your message";
    write.setValue(message);
    mBluetoothGatt.writeCharacteristic(characteristic);
}

public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) {
    BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid));
    if (s == null) {
        Log.w(TAG, "Service NoT found :" + sid);
        return null;
    }
    BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid));
    if (c == null) {
        Log.w(TAG, "Characteristic NOT found :" + cid);
        return null;
    }
    return c;
}
<ペリフェラル(Nexus 9)側>
セントラル側から書き込み要求がされると、BluetoothGattServerCallback#onCharacteristicWriteRequestに通知が来ます。 セントラルから書きこまれた内容はcharacteristicから取得することが出来ます。
 また、処理が終わる時には必ずGattServer#sendResponseを呼んでください。

//セントラルから書き込み要求が来ると呼ばれる
public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId,
        BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded,
        int offset, byte[] value) {
    Log.d(TAG, "onCharacteristicWriteRequest");
    if (UUID.fromString(Constants.CHAR_WRITE_UUID).equals(characteristic.getUuid())) {            
        final byte[] data = characteristic.getValue();
        Log.d(TAG, "onCharacteristicRead : " +  new String(data));
        mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);          
    }
}

さいごに

以上がAndroid間でのBLE通信(読み書き)の手順です。

今回までで、BLE接続、通信を行えるようになりました。
なので次回からはタイトル通り、生活の中でBLEデバイスを使ったアイデアを考えてみたいと思います。

[第三回] 生活で使えるBLE~アプリ間通信編~


本記事は以下の記事の続きになります。
[第一回] 生活で使えるBLEデバイス
[第二回] 生活で使えるBLEデバイス~ペアリング編~

はじめに

前回は端末側でのBLE検知と接続までの方法をまとめました。
そして今回はセントラル(端末)とペリフェラル(BLEデバイス)での通信方法に関して触れていきたいと思います。

環境
前回記事と同様に以下の環境で行います。
  • Nexus 5(端末)
  • Nexus 9(BLEデバイス)
データの送受信に関して

独自サービス
今回のデータ送受信では、セントラル(GATT Client)側からペリフェラル(GATT Server)へ接続し、サービス内の必要なキャラクタリスティクスにアクセスして、データ(Value)の読み書きを行います。
なので、今回のデータ送受信に使用するサービスとキャラクタリスティクスを定義しておきます。
例として、以下のように定義しておきます。

・サービス(図1 のService部分)
SERVICE_UUID = "00000001-0000-1000-8000-2f97f3b2dcd5";

・キャラクタリスティクス(図2 のCharacterri部分)
CHAR_READ_UUID = "00000010-0000-1000-8000-2f97f3b2dcd5";
→データ読み込み用
CHAR_WRITE_UUID = "00000011-0000-1000-8000-2f97f3b2dcd5";
→データ書き込み用

図1 GATT Server & GATT Client

アドバタイジングについて
前回からNexus 9をペリフェラルとして機能させていますが、どのようになっていたのでしょうか。
GATT通信の方法と併せて、Android端末でのアドバタイジング方法を簡単に説明していきます。(Bluetooth機能の確認と位置情報の権限取得は前回記事を参照)


図2 アドバタイジング

まずはBluetoothLeAdvertiserの取得を行います。
BluetoothLeAdvertiserは端末のアドバタイジング開始/停止の操作等を行えるクラスです。

BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager != null) {
    BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
}
次にGATT Serverのインスタンスを取得します。(BluetoothManager#openGattServer)
取得する際に引数として、BluetoothGattServerCallbackを渡します。
このコールバックにて読み書き等、セントラルから要求が行われた際の動作を実装していくようになります。
ペリフェラル機能を実装していく上で本体となる部分です。
mGattServer = mBluetoothManager.openGattServer(this, new BLEServer());

class BLEServer extends BluetoothGattServerCallback {
    //セントラルから読み込み要求が来ると呼ばれる
    public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId,
            int offset, BluetoothGattCharacteristic characteristic) {
    }

    //セントラルから書き込み要求が来ると呼ばれる
    public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId,
            BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded,
                int offset, byte[] value) {
    }
}
次は宣言しておいたサービスとキャラクタリスティクスをGATT Serverに設定していきます。
ここでGATT Serverに設定することで、セントラルから独自宣言したサービスを検知することが可能になります。

この時、読み込み用のキャラクタリスティクスには読み込みの、書き込み用のキャラクタリスティクスには書き込みのプロパティと権限を付与しています。
キャラクタリスティクスの権限とプロパティを正しく設定出来ていないと、読み込み/書き込みに失敗してしまうので注意してください。
private void setServices() {
    //serviceUUIDを設定BluetoothGattService service = new BluetoothGattService(
            UUID.fromString(Constants.SERVICE_UUID),
            BluetoothGattService.SERVICE_TYPE_PRIMARY);

    //characteristicUUIDを設定
    BluetoothGattCharacteristic charRead = new BluetoothGattCharacteristic(
            UUID.fromString(Constants.CHAR_READ_UUID),
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ);

    BluetoothGattCharacteristic charWrite = new BluetoothGattCharacteristic(
            UUID.fromString(Constants.CHAR_WRITE_UUID),
            BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattCharacteristic.PERMISSION_WRITE);

    //characteristicUUIDをserviceUUIDにのせる
    service.addCharacteristic(charRead);
    service.addCharacteristic(charWrite);

    //serviceUUIDをサーバーにのせる
    mGattServer.addService(service);
}
次にアドバタイジング時の設定(AdvertiseSettings)とデータ(AdvertiseData)の設定を行います。
そして、アドバタイジングの設定の準備が出来たらBluetoothLeAdvertiser#startAdvertisingで、アドバタイジングを開始します。
//AdvertiseSettingsの設定
private AdvertiseSettings buildAdvertiseSettings() {
    AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
    settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER);
    settingsBuilder.setTimeout(0);
    return settingsBuilder.build();
}

//AdvertiseDataの設定
private AdvertiseData buildAdvertiseData() {
    AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
    dataBuilder.addServiceUuid(ParcelUuid.fromString(Constants.SERVICE_UUID));
    dataBuilder.setIncludeDeviceName(true);
    return dataBuilder.build();
}

//Advertiseの開始
private void startAdvertising() {
    setServices();
    AdvertiseSettings settings = buildAdvertiseSettings();
    AdvertiseData data = buildAdvertiseData();
    mAdvertiseCallback = new SimpleAdvertiseCallback();
    mBluetoothLeAdvertiser.startAdvertising(settings, data,mAdvertiseCallback);
}

//Advertiseの成功可否
private class SimpleAdvertiseCallback extends AdvertiseCallback {
    @Override
    public void onStartFailure(int errorCode) {
        super.onStartFailure(errorCode);
        Log.d(TAG, "Advertising failed");
    }

    @Override
    public void onStartSuccess(AdvertiseSettings settingsInEffect) {
        super.onStartSuccess(settingsInEffect);
        Log.d(TAG, "Advertising successfully started");
    }
}
アドバタイジングを終了する時はBluetoothLeAdvertiser#stopAdvertisingを呼びます。
この時、GATT Serverのcloseも忘れずに。
private void stopAdvertising() {
    Log.d(TAG, "Service: Stopping Advertising");
    if (mGattServer != null) {
        mGattServer.clearServices();
        mGattServer.close();
        mGattServer = null;
    }
    if (mBluetoothLeAdvertiser != null) {
        mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
        mAdvertiseCallback = null;
    }
}
以上で、Nexus 9がペリフェラルとして機能するようになります。
アドバタイジングが開始された後、セントラル(Nexus 5)側から検知出来るようになっていることでしょう。

そして、定義したサービスとGATT Serverによって、データの読み書きを行う準備も出来ました。
では、実際にデータの読み書きを行ってみましょう。

データの読み込み
セントラル側からペリフェラルのキャラクタリスティクスデータを読み込む手順です。

図3 データの読み込み
<セントラル(Nexus 5)側>
接続済みのBluetoothGattから読み込み用キャラクタリスティクスを取得して、読み込み要求(BluetoothGattl#readCharacteristic)を行います。
public void readCharacteristic() {
    BluetoothGattCharacteristic read = mBluetoothLeService.getCharacteristic(
            GattAttributes.SERVICE_UUID,
            GattAttributes.CHAR_READ_UUID);
    mBluetoothGatt.readCharacteristic(read);
}

public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) {
    BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid));
    if (s == null) {
        Log.w(TAG, "Service NoT found :" + sid);
        return null;
    }
    BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid));
    if (c == null) {
        Log.w(TAG, "Characteristic NOT found :" + cid);
        return null;
    }
    return c;
}
読み込み要求を行い、成功するとBluetoothGattCallback#onCharacteristicReadが呼び出されます。
その引数に渡されるBluetoothGattCharacteristicにペリフェラルからのレスポンスを受け取ることが出来ます。
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
        BluetoothGattCharacteristic characteristic, int status) {
    final byte[] data = characteristic.getValue();
    Log.d(TAG, "onCharacteristicRead : " +  new String(data));
}

<ペリフェラル(Nexus 9)側>
セントラル側から読み込み要求が行われると、BluetoothGattServerCallback#onCharacteristicReadRequestに通知が来ます。
セントラルに対して送りたいデータをGattServer#sendResponseにセットすることで、セントラルに任意のデータを送信することが出来ます。
//セントラルからReadRequestが来ると呼ばれる
public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId,
        int offset, BluetoothGattCharacteristic characteristic) {
    //セントラルに任意の文字を返信する
    if (UUID.fromString(Constants. CHAR_READ_UUID).equals(characteristic.getUuid())) {
        String response  = "your message.";
        byte value[] = response.getBytes();
        mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
    }
}

データの書き込み
セントラルからペリフェラルへキャラクタリスティクスデータを書き込む手順です。

図4 データの書き込み
<セントラル(Nexus 5)側>
接続が完了したBluetoothGattから書き込み用キャラクタリスティクスを取得し、書き込みたいデータをセットすることでペリフェラル側へデータを送ることが出来ます。
※書き込み権限のないキャラクタリスティクスに書き込み要求(BluetoothGatt#writeCharacteristic)を行うと戻り値に false が返り、書き込みに失敗します。
public void writeCharacteristic() {
    BluetoothGattCharacteristic write = getCharacteristic(
            UUID.fromString(GattAttributes.SERVICE_UUID),
            UUID.fromString(GattAttributes.CHAR_WRITE_UUID));
    String message = "your message";
    write.setValue(message);
    mBluetoothGatt.writeCharacteristic(characteristic);
}

public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) {
    BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid));
    if (s == null) {
        Log.w(TAG, "Service NoT found :" + sid);
        return null;
    }
    BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid));
    if (c == null) {
        Log.w(TAG, "Characteristic NOT found :" + cid);
        return null;
    }
    return c;
}
<ペリフェラル(Nexus 9)側>
セントラル側から書き込み要求がされると、BluetoothGattServerCallback#onCharacteristicWriteRequestに通知が来ます。 セントラルから書きこまれた内容はcharacteristicから取得することが出来ます。
 また、処理が終わる時には必ずGattServer#sendResponseを呼んでください。

//セントラルから書き込み要求が来ると呼ばれる
public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId,
        BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded,
        int offset, byte[] value) {
    Log.d(TAG, "onCharacteristicWriteRequest");
    if (UUID.fromString(Constants.CHAR_WRITE_UUID).equals(characteristic.getUuid())) {            
        final byte[] data = characteristic.getValue();
        Log.d(TAG, "onCharacteristicRead : " +  new String(data));
        mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);          
    }
}

さいごに

以上がAndroid間でのBLE通信(読み書き)の手順です。

今回までで、BLE接続、通信を行えるようになりました。
なので次回からはタイトル通り、生活の中でBLEデバイスを使ったアイデアを考えてみたいと思います。

Related Posts Plugin for WordPress, Blogger...