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

2016年3月23日水曜日



はじめに


Linkingが発表されてからおよそ3か月が経過して、Linkingを利用したいくつかのアプリがプレイストアにアップされています。その中には弊社がリリースした「忘れ物防止」や「迷子防止」、「お天気予報通知」アプリもあります。今回の記事では、Linkingを利用してどのように「忘れ物防止」や「迷子防止」、「お天気予報通知」のアプリが実現されているかの説明を行っていきたいと思います。

Linkingを利用したアプリの実装方法について



はじめに


Linkingが発表されてからおよそ3か月が経過して、Linkingを利用したいくつかのアプリがプレイストアにアップされています。その中には弊社がリリースした「忘れ物防止」や「迷子防止」、「お天気予報通知」アプリもあります。今回の記事では、Linkingを利用してどのように「忘れ物防止」や「迷子防止」、「お天気予報通知」のアプリが実現されているかの説明を行っていきたいと思います。

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月27日金曜日

https://linkingiot.com/developer/#developers より引用
はじめに

NTTドコモ等の複数の国内企業が連携して「Linking」というプラットフォームが発表されました。

公開されたサイトを見てみると、どうやらLinkingとはIoT(Internet of Things)に関係するらしいフレーズが散りばめられています。
  • すべてのモノが、ネットでつながる
  • デバイス開発者も、アプリ開発者も、そしてユーザーも。
  • Linkingプラットフォームが、つくるをつなぐ。
さて、Linkingとは一体どういったものなのでしょうか。

すべてがつながる「Linking」とは

https://linkingiot.com/developer/#developers より引用
はじめに

NTTドコモ等の複数の国内企業が連携して「Linking」というプラットフォームが発表されました。

公開されたサイトを見てみると、どうやらLinkingとはIoT(Internet of Things)に関係するらしいフレーズが散りばめられています。
  • すべてのモノが、ネットでつながる
  • デバイス開発者も、アプリ開発者も、そしてユーザーも。
  • Linkingプラットフォームが、つくるをつなぐ。
さて、Linkingとは一体どういったものなのでしょうか。

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デバイスを使ったアイデアを考えてみたいと思います。

2015年11月4日水曜日


http://developer.android.com/intl/ja/about/versions/jelly-bean.html から引用

この記事は以下の記事の続きになります。
[第一回] 生活で使えるBLEデバイス

はじめに

前回の記事では、BluetoothとBLEおさらいをしました。
では今回はAndroid端末からのBLEデバイス検知とペアリングを行う方法を紹介します。

環境

今回はNexus 5から周辺のBLE端末(Nexus9)を検知して、接続を試みます。

  • Nexus 5(OS 6.0)
  • Nexus 9(OS 6.0)
Nexus 5(検知する側)
以下のサンプルアプリを元に、BLEデバイスの検知と接続方法を説明します。
BluetoothLeGatt

図1 BluetoothLeGatt

ただし、実装方法が一部古いままの為、以下の修正を加えています。(詳細は後述)
  1. RuntimePermission対応(「Bluetooth機能を利用する」の項目を参照)
  2. BLEスキャン時のAPIの修正(「BLEデバイスの検知」の項目を参照)
Nexus 9(BLE端末)
以下のサンプルアプリをインストールしておき、BLE端末としての役割をもたせています。
BluetoothAdvertisements


図2 BluetoothAdvertisements


では、実際にBLEデバイスの検知と接続を行う実装方法を紹介していきます。

BLEデバイスの検知と接続

Bluetooth機能を利用する
まずはじめに、Bluettoth機能を利用する宣言を行います。
AndroidManifest.xmlに宣言するパーミッションは以下の通りです。
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
また、BLEの機能を利用する場合は以下の宣言も必要です。
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
※端末がBLEに対応しているかの確認
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
    Toast.makeText(this, "BLE未対応端末です", Toast.LENGTH_SHORT).show();
    finish();
}

さらに、Android 6.0からBLEの利用には位置情報の権限が必要になりました。

よって、マニフェストにも「ACCESS_COARSE_LOCATION」または「ACCESS_FINE_LOCATION」の宣言が必要になります。
 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
または
 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
しかし、それだけではBLE機能を使用することは出来ません。。

位置情報の権限はプロテクションレベルが「Dangerous」になるので、ユーザーが権限を許可しない限りBLEの機能は使用することが出来ません。
※RuntimePermissionの詳細はこちら

よって、BLE機能を利用する前には、位置情報の権限の利用が許可されているかの確認を行い、ユーザーが許可をしていなければ許可を行うように促します。

許可されているかのチェックと権限取得の要求
private boolean checkPermission() {
    if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_LOCATION_STATE);
        return false;
    }
    return true;
}

許可/不許可の結果は onRequestPermissionsResult で判別出来ます。
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (PERMISSIONS_REQUEST_LOCATION_STATE == requestCode) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 許可された場合
            Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT).show();
        } else {
            // 不許可だった場合
            Toast.makeText(this, "権限を拒否されました", Toast.LENGTH_SHORT).show();
            finish();
        }
    }
}
事前準備としては以上です。
次はBluetooth関連クラスを使用していきます。

BluetoothAdapterの取得
まずはBluetoothAdapterを取得します。
(BluetoothAdapterは、すべてのBluetooth相互作用のためのエントリー・ポイントです。)
final BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
次に、端末のBluetoothが有効になっているかの確認を行います。
もし、Bluetoothが無効であればユーザーに有効にするように促します。
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}

BLEデバイスの検知
次にBLEデバイスの検知方法を紹介します。
サンプルアプリでは、BLEを検知する為にBluetoothAdapter#startLeScanを使用していますが、APIレベル21から非推奨となり、現在はBluetoothLeScannerを利用するようになりました。
使用方法は以下の通りです。

先ほど取得したBluetoothAdapterからBluetoothLeScannerを取得します。
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
BluetoothLeScannerを取得したら、以下のAPIを利用してスキャンの開始/停止を制御します。
そして、BLE機器が検知された場合、ScanCallback#onScanResultが呼び出され、ScanResultからBluetoothDeviceが取得出来ます。

BLEデバイスのスキャン開始

BLEデバイスのスキャン停止
BLEスキャンのCallback
// Device scan callback.
private ScanCallback mScanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, final ScanResult result) {
        super.onScanResult(callbackType, result);
        if (result != null && result.getDevice() != null) {
            runOnUiThread(new Runnable() {
               @Override
               public void run() {
                   mLeDeviceListAdapter.addDevice(result.getDevice());
                   mLeDeviceListAdapter.notifyDataSetChanged();
               }
            });
        }
    }
};
これで周辺のBLE機器の検知がすることが出来ました。
では次に、検知したデバイスに接続を行います。

ペアリング(GATTサーバーに接続)方法
ペアリングと銘打ってますが、BLEデバイスと通信を行う際にはペアリングをする必要はありません。(対応していればペアリングを行うことも可能です)
BLEデバイスの情報を取得するには、GATTサーバーに接続を行うことで、BLEデバイスの情報を読みとることが可能です。

GATTサーバーに接続するには先ほど検知したBluetoothDeviceのBluetoothDevice#connectGattメソッドを使用します。
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
接続が確立されると、BluetoothGattCallback#onConnectionStateChangeが呼ばれます。
newState が BluetoothProfile.STATE_CONNECTEDであれば接続が完了している状態です。

接続が確認出来たら、BluetoothGatt#discoverServicesにより、Gattサーバーの情報を検索します。
結果は BluetoothGattCallback#onServicesDiscovered が呼び出されます。

@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    String intentAction;
    if (newState == BluetoothProfile.STATE_CONNECTED) {
        mBluetoothGatt.discoverServices();
    }
}

@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
    super.onServicesDiscovered(gatt, status);
    serviceList = gatt.getServices();
    // サービスの内容を取得等処理を行う
    // 取得したサービスからBLEデバイスの情報を取得する
}
以上が、BLEデバイス検知から接続までの方法になります。

では最後に、BLEデバイスの情報を取りまとめるGATTについての説明をします。

Generic Attribute Profile (GATT)について
GATTとは、前回の記事で言うところのBluetooth 4.0で使用出来るプロファイルです。

GATTプロファイルは、"attribute"として知られる、BLE link上での短いデータの送受信の一般的な仕様で、現在のBLEアプリケーションプロファイルは、全て、GATTをベースにしています。

※Bluetooth SIGは、BLE端末のための多くのプロファイルを定義します。
※プロファイルは、特定のアプリケーションにおける端末の動作仕様です。
※端末は1つ以上のプロファイルを実装可能です。


図3 Generic Attribute Profile (GATT)について
https://developer.bluetooth.org/TechnologyOverview/Pages/GATT.aspx より引用

・Attribute Protocol (ATT)
GATTは、Attribute Protocol (ATT)の上位に組み込まれています。
GATT/ATTとしても参照されます。
ATTは、BLEデバイス上で動作するよう最適化されています(数バイト使用します)
各attributeは、Universally Unique Identifier (UUID)によりユニークに識別され、ユニークに情報を識別するために使われるstring IDのため標準化された128-bitフォーマットとなります。
ATTにより転送されたattributeは、characteristicおよびserviceとしてフォーマットされています。

・Characteristic
characteristicは1つの値と0-nのcharacteristicに言及するdescriptorを含みます。
characteristicはtypeとみなされ、classに似たものとなります。

・Descriptor
Descriptorは、characteristic値を記述する定義されたattributeです。
例えば, characteristicの値が許容可能な範囲を人間が読めるdescriptionとして定義されるものであったり, characteristicの値の単位を表すものであったりします。

・Service
serviceは、characteristicを集めたものです。
例えば, "Heart rate Monitor"と呼ばれるサービスには"heart rate measurement"という名のcharacteristicが含まれます。
既存のGATTベースのprofile/serviceリストをbluetooth.orgで入手可能です。

※これらのサービスやキャラクタリスティックは、Bluetooth SIG が標準として定義していますが、デバイス開発者が独自に定義することも可能です。

GATTプロファイルのサービスとその中にあるCharacteristicを読み取ることで、BLEデバイスの情報を読み出すことが出来ます。

また、GATT通信はサーバークライアントモデルであるため、基本的にはサーバーが機能や情報を保持し、クライアントがそれを利用することになります。

GATTクライアント
 データを利用する機器

GATTサーバー
 データを保持する機器

GATTクライアントとGATTサーバーは接続確立後、2つの端末がどのように通信し合うかのか決定します。
※今回であれば、Nexus 5(client、つまり端末)とNexus 9(server、つまりBLEデバイス)があると考えて下さい。

接続が確立すると、GATTメタデータの他への転送を開始します。
転送するデータの種類により、どちらかがサーバーとして動作します。

例えば、
BLEデバイスがセンサーデータを端末へレポートしたい場合、BLEデバイスがサーバーとして動作するのが理にかなっていると考えられます。
BLEデバイスが端末からアップデートを受信したい場合は、端末がサーバーとして動作するのが理にかなっていると考えられます。

本記事で使用したアプリにおいては、Nexus 5はGATTクライアントとして動作しています。
Nexus 5側のアプリ(GATTクライアント)は、Nexus 9(GATTサーバー)からデータを読み取り、アプリ内で解釈することで連携を行っている。という構成になっています。

さいごに

今回はBLEデバイスの検知から接続までをまとめました。

サンプルアプリでBLEの検知と接続を試すことは出来ますが、非推奨になっている点とBLE機能を使用する為の権限が増えている点に御留意いただければと思います。

次回はBLEデバイスからの情報の読み書きを行い、実際にBLE端末とデータのやり取りをしてみたいと思います。

[第二回] 生活で使えるBLE~ペアリング編~


http://developer.android.com/intl/ja/about/versions/jelly-bean.html から引用

この記事は以下の記事の続きになります。
[第一回] 生活で使えるBLEデバイス

はじめに

前回の記事では、BluetoothとBLEおさらいをしました。
では今回はAndroid端末からのBLEデバイス検知とペアリングを行う方法を紹介します。

環境

今回はNexus 5から周辺のBLE端末(Nexus9)を検知して、接続を試みます。

  • Nexus 5(OS 6.0)
  • Nexus 9(OS 6.0)
Nexus 5(検知する側)
以下のサンプルアプリを元に、BLEデバイスの検知と接続方法を説明します。
BluetoothLeGatt

図1 BluetoothLeGatt

ただし、実装方法が一部古いままの為、以下の修正を加えています。(詳細は後述)
  1. RuntimePermission対応(「Bluetooth機能を利用する」の項目を参照)
  2. BLEスキャン時のAPIの修正(「BLEデバイスの検知」の項目を参照)
Nexus 9(BLE端末)
以下のサンプルアプリをインストールしておき、BLE端末としての役割をもたせています。
BluetoothAdvertisements


図2 BluetoothAdvertisements


では、実際にBLEデバイスの検知と接続を行う実装方法を紹介していきます。

BLEデバイスの検知と接続

Bluetooth機能を利用する
まずはじめに、Bluettoth機能を利用する宣言を行います。
AndroidManifest.xmlに宣言するパーミッションは以下の通りです。
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
また、BLEの機能を利用する場合は以下の宣言も必要です。
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
※端末がBLEに対応しているかの確認
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
    Toast.makeText(this, "BLE未対応端末です", Toast.LENGTH_SHORT).show();
    finish();
}

さらに、Android 6.0からBLEの利用には位置情報の権限が必要になりました。

よって、マニフェストにも「ACCESS_COARSE_LOCATION」または「ACCESS_FINE_LOCATION」の宣言が必要になります。
 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
または
 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
しかし、それだけではBLE機能を使用することは出来ません。。

位置情報の権限はプロテクションレベルが「Dangerous」になるので、ユーザーが権限を許可しない限りBLEの機能は使用することが出来ません。
※RuntimePermissionの詳細はこちら

よって、BLE機能を利用する前には、位置情報の権限の利用が許可されているかの確認を行い、ユーザーが許可をしていなければ許可を行うように促します。

許可されているかのチェックと権限取得の要求
private boolean checkPermission() {
    if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_LOCATION_STATE);
        return false;
    }
    return true;
}

許可/不許可の結果は onRequestPermissionsResult で判別出来ます。
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (PERMISSIONS_REQUEST_LOCATION_STATE == requestCode) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 許可された場合
            Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT).show();
        } else {
            // 不許可だった場合
            Toast.makeText(this, "権限を拒否されました", Toast.LENGTH_SHORT).show();
            finish();
        }
    }
}
事前準備としては以上です。
次はBluetooth関連クラスを使用していきます。

BluetoothAdapterの取得
まずはBluetoothAdapterを取得します。
(BluetoothAdapterは、すべてのBluetooth相互作用のためのエントリー・ポイントです。)
final BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
次に、端末のBluetoothが有効になっているかの確認を行います。
もし、Bluetoothが無効であればユーザーに有効にするように促します。
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}

BLEデバイスの検知
次にBLEデバイスの検知方法を紹介します。
サンプルアプリでは、BLEを検知する為にBluetoothAdapter#startLeScanを使用していますが、APIレベル21から非推奨となり、現在はBluetoothLeScannerを利用するようになりました。
使用方法は以下の通りです。

先ほど取得したBluetoothAdapterからBluetoothLeScannerを取得します。
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
BluetoothLeScannerを取得したら、以下のAPIを利用してスキャンの開始/停止を制御します。
そして、BLE機器が検知された場合、ScanCallback#onScanResultが呼び出され、ScanResultからBluetoothDeviceが取得出来ます。

BLEデバイスのスキャン開始

BLEデバイスのスキャン停止
BLEスキャンのCallback
// Device scan callback.
private ScanCallback mScanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, final ScanResult result) {
        super.onScanResult(callbackType, result);
        if (result != null && result.getDevice() != null) {
            runOnUiThread(new Runnable() {
               @Override
               public void run() {
                   mLeDeviceListAdapter.addDevice(result.getDevice());
                   mLeDeviceListAdapter.notifyDataSetChanged();
               }
            });
        }
    }
};
これで周辺のBLE機器の検知がすることが出来ました。
では次に、検知したデバイスに接続を行います。

ペアリング(GATTサーバーに接続)方法
ペアリングと銘打ってますが、BLEデバイスと通信を行う際にはペアリングをする必要はありません。(対応していればペアリングを行うことも可能です)
BLEデバイスの情報を取得するには、GATTサーバーに接続を行うことで、BLEデバイスの情報を読みとることが可能です。

GATTサーバーに接続するには先ほど検知したBluetoothDeviceのBluetoothDevice#connectGattメソッドを使用します。
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
接続が確立されると、BluetoothGattCallback#onConnectionStateChangeが呼ばれます。
newState が BluetoothProfile.STATE_CONNECTEDであれば接続が完了している状態です。

接続が確認出来たら、BluetoothGatt#discoverServicesにより、Gattサーバーの情報を検索します。
結果は BluetoothGattCallback#onServicesDiscovered が呼び出されます。

@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    String intentAction;
    if (newState == BluetoothProfile.STATE_CONNECTED) {
        mBluetoothGatt.discoverServices();
    }
}

@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
    super.onServicesDiscovered(gatt, status);
    serviceList = gatt.getServices();
    // サービスの内容を取得等処理を行う
    // 取得したサービスからBLEデバイスの情報を取得する
}
以上が、BLEデバイス検知から接続までの方法になります。

では最後に、BLEデバイスの情報を取りまとめるGATTについての説明をします。

Generic Attribute Profile (GATT)について
GATTとは、前回の記事で言うところのBluetooth 4.0で使用出来るプロファイルです。

GATTプロファイルは、"attribute"として知られる、BLE link上での短いデータの送受信の一般的な仕様で、現在のBLEアプリケーションプロファイルは、全て、GATTをベースにしています。

※Bluetooth SIGは、BLE端末のための多くのプロファイルを定義します。
※プロファイルは、特定のアプリケーションにおける端末の動作仕様です。
※端末は1つ以上のプロファイルを実装可能です。


図3 Generic Attribute Profile (GATT)について
https://developer.bluetooth.org/TechnologyOverview/Pages/GATT.aspx より引用

・Attribute Protocol (ATT)
GATTは、Attribute Protocol (ATT)の上位に組み込まれています。
GATT/ATTとしても参照されます。
ATTは、BLEデバイス上で動作するよう最適化されています(数バイト使用します)
各attributeは、Universally Unique Identifier (UUID)によりユニークに識別され、ユニークに情報を識別するために使われるstring IDのため標準化された128-bitフォーマットとなります。
ATTにより転送されたattributeは、characteristicおよびserviceとしてフォーマットされています。

・Characteristic
characteristicは1つの値と0-nのcharacteristicに言及するdescriptorを含みます。
characteristicはtypeとみなされ、classに似たものとなります。

・Descriptor
Descriptorは、characteristic値を記述する定義されたattributeです。
例えば, characteristicの値が許容可能な範囲を人間が読めるdescriptionとして定義されるものであったり, characteristicの値の単位を表すものであったりします。

・Service
serviceは、characteristicを集めたものです。
例えば, "Heart rate Monitor"と呼ばれるサービスには"heart rate measurement"という名のcharacteristicが含まれます。
既存のGATTベースのprofile/serviceリストをbluetooth.orgで入手可能です。

※これらのサービスやキャラクタリスティックは、Bluetooth SIG が標準として定義していますが、デバイス開発者が独自に定義することも可能です。

GATTプロファイルのサービスとその中にあるCharacteristicを読み取ることで、BLEデバイスの情報を読み出すことが出来ます。

また、GATT通信はサーバークライアントモデルであるため、基本的にはサーバーが機能や情報を保持し、クライアントがそれを利用することになります。

GATTクライアント
 データを利用する機器

GATTサーバー
 データを保持する機器

GATTクライアントとGATTサーバーは接続確立後、2つの端末がどのように通信し合うかのか決定します。
※今回であれば、Nexus 5(client、つまり端末)とNexus 9(server、つまりBLEデバイス)があると考えて下さい。

接続が確立すると、GATTメタデータの他への転送を開始します。
転送するデータの種類により、どちらかがサーバーとして動作します。

例えば、
BLEデバイスがセンサーデータを端末へレポートしたい場合、BLEデバイスがサーバーとして動作するのが理にかなっていると考えられます。
BLEデバイスが端末からアップデートを受信したい場合は、端末がサーバーとして動作するのが理にかなっていると考えられます。

本記事で使用したアプリにおいては、Nexus 5はGATTクライアントとして動作しています。
Nexus 5側のアプリ(GATTクライアント)は、Nexus 9(GATTサーバー)からデータを読み取り、アプリ内で解釈することで連携を行っている。という構成になっています。

さいごに

今回はBLEデバイスの検知から接続までをまとめました。

サンプルアプリでBLEの検知と接続を試すことは出来ますが、非推奨になっている点とBLE機能を使用する為の権限が増えている点に御留意いただければと思います。

次回はBLEデバイスからの情報の読み書きを行い、実際にBLE端末とデータのやり取りをしてみたいと思います。

2015年10月28日水曜日


http://googledevelopers.blogspot.jp/2015/07/lighting-way-with-ble-beacons.html から引用

はじめに

弊社のブログでは様々なiOS + BLEやBLEデバイスの開発の取り組みを紹介してきました。

ということで!

Android Marshmallowの公開もされましたので、これを機にAndroid 6.0 + BLEに関しての記事を掲載していきたいと思います。

今回は第一回目として、BluetoothとBLEのおさらいをしていきながら、今後作るアプリやサービスのイメージを膨らませていきましょう。

Bluetooth

Bluetoothの特徴

  • 無線通信(数mから数十m程度の距離間での通信が可能)
  • 小型で低消費電力
  • 暗号化通信される
  • 混信する可能性がとても低い
Bluetoothは無線接続の状態を意識せずに常時接続したままでの使用状況に適しているので、日常的に身につけるものなどとの相性がとても良いです。
また、近距離で少し大き目のデータでも機器間で通信を行うことも出来ます。

特にPCのマウスやキーボード、ワイヤレスイヤホン、ヘッドフォンなどにも使用されています。
煩わしいケーブルを排除出来るので、作業スペース等がスッキリしてとても使いやすいです。

使用例:
  • マウスやキーボードのパソコン周辺機器
  • オーディオ機器
  • スキャナ/プリンタ

BLE(Bluetooth Low Energy)の特徴

  • 小型で電池消費量が極少(ボタン電池で1年以上) 
  • ペアリングを行わなくても他デバイスに通知が可能(ブロードキャスト通信) 
  • 通信速度は低い
Bluetooth4.0はBluetooth3.0にBLEの技術を統合したもので、BLEとはBluetooth 4.0以降の機能の一部を指します。筆者自身勘違いをしていたのですが、Bluetooth4.0 = BLEというわけではありません。
Bluetooth3.0規格の拡張版がBluetooth4.0であり、その機能の一部がBLEです。

ただし、BLE機能は過去バージョンとの下方互換がまったくない為、BLEのみに対応したデバイスと3.0までのBluetoothデバイスとは接続を行うことが出来ない点に注意が必要です。

BLEデバイスは以下の2種類に分類されます。

Bluetooth Smart

 BLEでのみ通信を行う。従来のBluetooth機器との接続不可。

Bluetooth Smart Ready

 BLEで通信をする子機との通信に対応し、従来のBluetooth機器との接続可。

※ロゴマークに関してはこちらを参照してください。

※動画も公開しています。

BLEは常時データをやり取りする必要がなく、1回のデータ量も少ない用途に向いています。
超低消費電力なので、配置してからしばらく電池交換をする手間が必要ありません。
また、ペアリングを行わなくても他デバイスへの通知が可能なことから、通りがかっただけの人などを集客する効果も見込まれています。

使用例:
  • ライフログリストバンド
  • 運動用センサー(スピード/ケイデンス/心拍センサー)
  • 忘れ物防止タグ
  • 降水確立を知らせる傘立て(※)
  • ごみの収集日を知らせるごみ箱(※)
  • スマートウォッチ
※こちらを参照

その他にも生活で使用するもの以外でもユニークなものがこちらで紹介されています。

さて、特徴や使用例をいくつか挙げていきました。

ここまででおさらいしてきたBluetoothの特徴や既に販売されているものや実施されているサービスを踏まえつつ、次はAndroidへと目を向けていきましょう。

Android & Bluetooth

ではAndroidではどのようにBluetoothの制御を行っているのでしょうか。
ここではAndroidのBluetoothアーキテクチャと、Bluetoothのプロファイルについて触れたいと思います。
※アプリケーション側の実装方法などは次回以降紹介します。


Bluetoothアーキテクチャ

アプリケーションは、android.bluetoothのAPIを使いBluetoothハードウェアとの総合通信を行います。
内部的に、Binder IPCメカニズムを介してBluetooth processをコールします。
Bluetooth system serviceはJNIを介してBluetooth stackと通信を行います。
また、Binder IPCを介してアプリと通信を行います。
system serviceにより、開発者は様々なBluetooth profileへのアクセスが可能となります。

下図が、Bluetooth stackの一般的な構造となります。


      
https://source.android.com/devices/bluetooth.html より引用

Bluetooth system service
packages/apps/BluetoothにあるBluetooth system serviceは、Android appとしてパッケージされ、Bluetooth serviceおよびprofileをAndroid framework layerに実装します。このアプリはJNI経由でHAL layerをコールします。

JNI
android.bluetoothと連携しているJNIは、packages/apps/Bluetooth/jniにあります。JNIコードは、HAL layerにコールし、端末が発見された時などのように、特定のBluetoothオペレーションが発生した際にHALからコールバックを受信します。

このような構造で、AndroidはアプリケーションからBluetoothの機能を使用することが出来ます。

アプリケーション開発においては特に、Application Framework部とBluetooth Process部を意識することになりますが、このような構造を知っておくことで、不具合などが発生した場合のデバッグなどにも役立つと思います。

そして、次にBluetooth Process部にあるプロファイルに関して簡単に説明します。

プロファイル

プロファイルというのは簡単に言うと、Bluetooth機器が何を出来るかを定義したものです。
様々な機器と無線通信を行う性質上、どのような順番・タイミングで、どんな種類の情報を転送すべきか、という機器の「使い方」にあたる手順を共通化しておく必要がある。
この手順を機器の特性ごとに標準化したものが、プロファイルです。

参考:
Bluetoothプロファイル 【 Bluetooth Profile 】

接続するBluetooth機器同士が同じプロファイルに対応していることで、その機能が利用できますが、定義されていないと使用することが出来ません。
実際に使用する際にはプロファイルをよく理解し、適切なものを使用しましょう。

・主なBluetoothプロファイル(一部)
HID(Human Interface Device Profile) 入力機器を扱うためのプロファイル
HSP(Headset Profile) ヘッドセットと通信するためのプロファイル
HFP(Hands-Free Profile) ハンズフリー通話をするためのプロファイル
A2DP(Advanced Audio Distribution Profile) 高音質のステレオ音声を伝送するためのプロファイル
AVRCP(Audio/Video Remote Control Profile) AV機器のコントロール(再生、早送り等)を行うためのプロファル
FTP(File Transfer Profile) ファイル転送プロファイル

・4.0から使用出来るBluetoothプロファイル
ANP(Alert Notification Profile) 電話やメールなどの着信を通知するプロファイル
BLP(Blood Pressure Profile) 血圧計から血圧情報を伝送するためのプロファイル
CPP(Cycling Power Profile) サイクリング時の力などを情報を伝送するためのプロファイル
CSCP(Cycling Speed and Cadence Profile) サイクリング時のスピードや回転数などの情報を伝送するためのプロファイル
FMP(Find Me Profile) 遠隔からアラームやバイブレーションを鳴動させ、装置の場所を調べるためのプロファイル
GLP(Glucose Profile) 血糖値の情報を伝送するためのプロファイル
HOGP(HID over GATT Profile) マウスやキーボードなどを接続するためのプロファイル
HTP(Health Thermometer Profile) 体温計の情報を伝送するためのプロファイル
HRP(Heart Rate Profile) 心拍計の情報を伝送するためのプロファイル
IPSP (Internet Protocol Support Profile) IPv6/6LoWPAN経由でインターネットに接続するプロファイル
PASP(Phone Alert Status Profile) 電話着信時の鳴動などを他の機器から止めるためのプロファイル
PXP(Proximity Profile) 互いの機器間の距離をモニタリングするためのプロファイル
RSCP(Running Speed and Cadence Profile) ランニング時のスピードや歩幅などの情報を伝送するためのプロファイル
ScPP(Scan Parameters Profile) 装置のスキャンをするためのプロファイル
TIP(Time Profile) 時刻情報を通知するためのプロフィール
プロファイルの参考:

さいごに

今回はBluetoothやBLEに関してのおさらいを行いましたがいかがだったでしょうか。
BluetoothやBLEを使用したアプリやサービスのイメージは膨らみましたか?

次回からは実際にAndroidアプリケーションでBLEの検知、ペアリング方法を紹介したいと思います。

[第一回] 生活で使えるBLEデバイス


http://googledevelopers.blogspot.jp/2015/07/lighting-way-with-ble-beacons.html から引用

はじめに

弊社のブログでは様々なiOS + BLEやBLEデバイスの開発の取り組みを紹介してきました。

ということで!

Android Marshmallowの公開もされましたので、これを機にAndroid 6.0 + BLEに関しての記事を掲載していきたいと思います。

今回は第一回目として、BluetoothとBLEのおさらいをしていきながら、今後作るアプリやサービスのイメージを膨らませていきましょう。

Bluetooth

Bluetoothの特徴

  • 無線通信(数mから数十m程度の距離間での通信が可能)
  • 小型で低消費電力
  • 暗号化通信される
  • 混信する可能性がとても低い
Bluetoothは無線接続の状態を意識せずに常時接続したままでの使用状況に適しているので、日常的に身につけるものなどとの相性がとても良いです。
また、近距離で少し大き目のデータでも機器間で通信を行うことも出来ます。

特にPCのマウスやキーボード、ワイヤレスイヤホン、ヘッドフォンなどにも使用されています。
煩わしいケーブルを排除出来るので、作業スペース等がスッキリしてとても使いやすいです。

使用例:
  • マウスやキーボードのパソコン周辺機器
  • オーディオ機器
  • スキャナ/プリンタ

BLE(Bluetooth Low Energy)の特徴

  • 小型で電池消費量が極少(ボタン電池で1年以上) 
  • ペアリングを行わなくても他デバイスに通知が可能(ブロードキャスト通信) 
  • 通信速度は低い
Bluetooth4.0はBluetooth3.0にBLEの技術を統合したもので、BLEとはBluetooth 4.0以降の機能の一部を指します。筆者自身勘違いをしていたのですが、Bluetooth4.0 = BLEというわけではありません。
Bluetooth3.0規格の拡張版がBluetooth4.0であり、その機能の一部がBLEです。

ただし、BLE機能は過去バージョンとの下方互換がまったくない為、BLEのみに対応したデバイスと3.0までのBluetoothデバイスとは接続を行うことが出来ない点に注意が必要です。

BLEデバイスは以下の2種類に分類されます。

Bluetooth Smart

 BLEでのみ通信を行う。従来のBluetooth機器との接続不可。

Bluetooth Smart Ready

 BLEで通信をする子機との通信に対応し、従来のBluetooth機器との接続可。

※ロゴマークに関してはこちらを参照してください。

※動画も公開しています。

BLEは常時データをやり取りする必要がなく、1回のデータ量も少ない用途に向いています。
超低消費電力なので、配置してからしばらく電池交換をする手間が必要ありません。
また、ペアリングを行わなくても他デバイスへの通知が可能なことから、通りがかっただけの人などを集客する効果も見込まれています。

使用例:
  • ライフログリストバンド
  • 運動用センサー(スピード/ケイデンス/心拍センサー)
  • 忘れ物防止タグ
  • 降水確立を知らせる傘立て(※)
  • ごみの収集日を知らせるごみ箱(※)
  • スマートウォッチ
※こちらを参照

その他にも生活で使用するもの以外でもユニークなものがこちらで紹介されています。

さて、特徴や使用例をいくつか挙げていきました。

ここまででおさらいしてきたBluetoothの特徴や既に販売されているものや実施されているサービスを踏まえつつ、次はAndroidへと目を向けていきましょう。

Android & Bluetooth

ではAndroidではどのようにBluetoothの制御を行っているのでしょうか。
ここではAndroidのBluetoothアーキテクチャと、Bluetoothのプロファイルについて触れたいと思います。
※アプリケーション側の実装方法などは次回以降紹介します。


Bluetoothアーキテクチャ

アプリケーションは、android.bluetoothのAPIを使いBluetoothハードウェアとの総合通信を行います。
内部的に、Binder IPCメカニズムを介してBluetooth processをコールします。
Bluetooth system serviceはJNIを介してBluetooth stackと通信を行います。
また、Binder IPCを介してアプリと通信を行います。
system serviceにより、開発者は様々なBluetooth profileへのアクセスが可能となります。

下図が、Bluetooth stackの一般的な構造となります。


      
https://source.android.com/devices/bluetooth.html より引用

Bluetooth system service
packages/apps/BluetoothにあるBluetooth system serviceは、Android appとしてパッケージされ、Bluetooth serviceおよびprofileをAndroid framework layerに実装します。このアプリはJNI経由でHAL layerをコールします。

JNI
android.bluetoothと連携しているJNIは、packages/apps/Bluetooth/jniにあります。JNIコードは、HAL layerにコールし、端末が発見された時などのように、特定のBluetoothオペレーションが発生した際にHALからコールバックを受信します。

このような構造で、AndroidはアプリケーションからBluetoothの機能を使用することが出来ます。

アプリケーション開発においては特に、Application Framework部とBluetooth Process部を意識することになりますが、このような構造を知っておくことで、不具合などが発生した場合のデバッグなどにも役立つと思います。

そして、次にBluetooth Process部にあるプロファイルに関して簡単に説明します。

プロファイル

プロファイルというのは簡単に言うと、Bluetooth機器が何を出来るかを定義したものです。
様々な機器と無線通信を行う性質上、どのような順番・タイミングで、どんな種類の情報を転送すべきか、という機器の「使い方」にあたる手順を共通化しておく必要がある。
この手順を機器の特性ごとに標準化したものが、プロファイルです。

参考:
Bluetoothプロファイル 【 Bluetooth Profile 】

接続するBluetooth機器同士が同じプロファイルに対応していることで、その機能が利用できますが、定義されていないと使用することが出来ません。
実際に使用する際にはプロファイルをよく理解し、適切なものを使用しましょう。

・主なBluetoothプロファイル(一部)
HID(Human Interface Device Profile) 入力機器を扱うためのプロファイル
HSP(Headset Profile) ヘッドセットと通信するためのプロファイル
HFP(Hands-Free Profile) ハンズフリー通話をするためのプロファイル
A2DP(Advanced Audio Distribution Profile) 高音質のステレオ音声を伝送するためのプロファイル
AVRCP(Audio/Video Remote Control Profile) AV機器のコントロール(再生、早送り等)を行うためのプロファル
FTP(File Transfer Profile) ファイル転送プロファイル

・4.0から使用出来るBluetoothプロファイル
ANP(Alert Notification Profile) 電話やメールなどの着信を通知するプロファイル
BLP(Blood Pressure Profile) 血圧計から血圧情報を伝送するためのプロファイル
CPP(Cycling Power Profile) サイクリング時の力などを情報を伝送するためのプロファイル
CSCP(Cycling Speed and Cadence Profile) サイクリング時のスピードや回転数などの情報を伝送するためのプロファイル
FMP(Find Me Profile) 遠隔からアラームやバイブレーションを鳴動させ、装置の場所を調べるためのプロファイル
GLP(Glucose Profile) 血糖値の情報を伝送するためのプロファイル
HOGP(HID over GATT Profile) マウスやキーボードなどを接続するためのプロファイル
HTP(Health Thermometer Profile) 体温計の情報を伝送するためのプロファイル
HRP(Heart Rate Profile) 心拍計の情報を伝送するためのプロファイル
IPSP (Internet Protocol Support Profile) IPv6/6LoWPAN経由でインターネットに接続するプロファイル
PASP(Phone Alert Status Profile) 電話着信時の鳴動などを他の機器から止めるためのプロファイル
PXP(Proximity Profile) 互いの機器間の距離をモニタリングするためのプロファイル
RSCP(Running Speed and Cadence Profile) ランニング時のスピードや歩幅などの情報を伝送するためのプロファイル
ScPP(Scan Parameters Profile) 装置のスキャンをするためのプロファイル
TIP(Time Profile) 時刻情報を通知するためのプロフィール
プロファイルの参考:

さいごに

今回はBluetoothやBLEに関してのおさらいを行いましたがいかがだったでしょうか。
BluetoothやBLEを使用したアプリやサービスのイメージは膨らみましたか?

次回からは実際にAndroidアプリケーションでBLEの検知、ペアリング方法を紹介したいと思います。

2014年2月13日木曜日


2014年2月の日本アンドロイドの会定例会に参加してきました。

https://www.android-group.jp/event/event28.html

iBeaconとはどんなもので、アンドロイドで実現する場合に注意すべきことは何かなどを、この方面で活躍されている方を招いて勉強するという内容でした。

まず、今度の2/15、16に会津でBLEハッカソンを企画されている、Aka Beacon で有名なGClue の佐々木陽氏が、iBeacon とは、UUID、Major、Minor でビーコンを区別し、Immediate/Near/Far/Unknown などの近さが取得できるものですよ、ということを自作したデバイスを使ってデモを行いながら、非常に軽やかに説明されました。

また、iOSのバックグラウンド処理についても触れて、アプリがバックグラウンドにいてもRegion IN/OUTのイベントを受信でき、15秒間は動作可能ということも述べられていました。結局、もっとバックグラウンド動作を伸ばす方法はあるみたいですが…。

アンドロイドは、各アプリがビーコンを監視する部分を独自でもつため、ビーコンを利用するアプリが立ち上がるほど、電力消費が大きくなるとのこと。対して、iOSは、フレームワーク部分がビーコンの監視を行ってくれているので、ビーコンを使うアプリがたくさんいても省電力になっているとのこと。だから、アンドロイドでもビーコンを扱うサービスを作り、省電力な設計を行う必要があるとおっしゃっていました。

あとは、エコシステム、Appcessoryを中心とする最近のビジネス状況について、BLEデバイスのモジュール化のベンチャーが増えていることなどを説明してくれました。

続いて、Applixで研究開発をされている日向さんがビーコンの電波特性について、非常にわかりやすく解説してくれました。屋内測位をやっていると、電波特性というものに敏感になるもので、なんでこんなに状況によって電波強度がかわるのか深く知りたくなってきます。日向さんの調べたところによると、床や壁などに当たって跳ね返ってくる反射波との干渉により、場所によって電波の強弱が変わってしまうということです。また、電波強度と距離の関係式も、2、3mくらいまでなら大体合っているが、距離が遠くなるに連れて、実際の値とのずれが大きくなってくるとのこと。屋内測位をやったときもFarのビーコンは無視すると非常にうまく行きましたから、納得です。日向さんの考えでは、RSSIからもとめる距離の精度も対数をとった値なら実用に耐えられるのでは、とのこと。

あとのお二人は、iBeaconを使った事例でした。

元頓知ドットさんのおでかけスクラップサービス"tab"は、失敗事例などいくつか紹介しており、非常に参考になりました。

残念ながら、帰阪するため参加できたのはここまででした。

iBeaconでブームとなったBLEの流れですが、アンドロイドでちゃんとしたサービスが展開されるのはまだまだ先なのかなという印象を受けました。

[コラム] 日本アンドロイドの会2月定例会に参加してきました。


2014年2月の日本アンドロイドの会定例会に参加してきました。

https://www.android-group.jp/event/event28.html

iBeaconとはどんなもので、アンドロイドで実現する場合に注意すべきことは何かなどを、この方面で活躍されている方を招いて勉強するという内容でした。

まず、今度の2/15、16に会津でBLEハッカソンを企画されている、Aka Beacon で有名なGClue の佐々木陽氏が、iBeacon とは、UUID、Major、Minor でビーコンを区別し、Immediate/Near/Far/Unknown などの近さが取得できるものですよ、ということを自作したデバイスを使ってデモを行いながら、非常に軽やかに説明されました。

また、iOSのバックグラウンド処理についても触れて、アプリがバックグラウンドにいてもRegion IN/OUTのイベントを受信でき、15秒間は動作可能ということも述べられていました。結局、もっとバックグラウンド動作を伸ばす方法はあるみたいですが…。

アンドロイドは、各アプリがビーコンを監視する部分を独自でもつため、ビーコンを利用するアプリが立ち上がるほど、電力消費が大きくなるとのこと。対して、iOSは、フレームワーク部分がビーコンの監視を行ってくれているので、ビーコンを使うアプリがたくさんいても省電力になっているとのこと。だから、アンドロイドでもビーコンを扱うサービスを作り、省電力な設計を行う必要があるとおっしゃっていました。

あとは、エコシステム、Appcessoryを中心とする最近のビジネス状況について、BLEデバイスのモジュール化のベンチャーが増えていることなどを説明してくれました。

続いて、Applixで研究開発をされている日向さんがビーコンの電波特性について、非常にわかりやすく解説してくれました。屋内測位をやっていると、電波特性というものに敏感になるもので、なんでこんなに状況によって電波強度がかわるのか深く知りたくなってきます。日向さんの調べたところによると、床や壁などに当たって跳ね返ってくる反射波との干渉により、場所によって電波の強弱が変わってしまうということです。また、電波強度と距離の関係式も、2、3mくらいまでなら大体合っているが、距離が遠くなるに連れて、実際の値とのずれが大きくなってくるとのこと。屋内測位をやったときもFarのビーコンは無視すると非常にうまく行きましたから、納得です。日向さんの考えでは、RSSIからもとめる距離の精度も対数をとった値なら実用に耐えられるのでは、とのこと。

あとのお二人は、iBeaconを使った事例でした。

元頓知ドットさんのおでかけスクラップサービス"tab"は、失敗事例などいくつか紹介しており、非常に参考になりました。

残念ながら、帰阪するため参加できたのはここまででした。

iBeaconでブームとなったBLEの流れですが、アンドロイドでちゃんとしたサービスが展開されるのはまだまだ先なのかなという印象を受けました。

2013年11月21日木曜日



本日、大阪IMPビルで開かれた、BluetoothSIG主催のBluetoothトレーニングイベントに参加してきました。

https://www.bluetooth.org/ja-jp/Pages/qualification-training-sessions.aspx

私自身BluetoothSIGのイベントに参加するのは初めてなのですが、BLEによる盛り上がりを受けてなのか、アジアでは東京、大阪、ソウル、上海と連続して本イベントが開かれ、BluetoothSIGが今回のイベントに非常に力を入れているのがわかりました。またこれ以降も、ブレイクスルー・アワード 2014(12/4受付締切、1/6結果発表)、1月にはCES、2月にはMWCとイベントが続きます。スポンサー企業を中心にこの流れを維持し、マーケットを開拓していこうというムードが伝わってきました。

ざっと、内容を記載します。

      前半      

BluetoothSIGからのあいさつ
  Marriot Winquist (Bluetooth SIG)

Bluetoothの基礎概観(Part1)
  Masamitsu Suzuki  (Texas Instruments)

  • Bluetoothの歴史
  • アーキテクチャの説明
  • プロファイルの説明
    • BR/EDR(クラシックBT)のプロファイル
    • BLEのプロファイル

Bluetoothの基礎概観(Part2)
  Masahiko Seki (MCPC/Sony)
  • GATT-Based Profile 概観

MCPC プレゼンテーション
 モバイルシステム検定試験の案内

 ※MCPC(モバイルコンピューティング推進コンソーシアム)は、
  モバイルコンピューティングの健全な発展のためと環境整備のために
  設立された組織で、研究機関、企業などにより運営されています。
  (http://www.mcpc-jp.org/)

Texas Instruments プレゼンテーション
 自社商品「SensorTag」の紹介


      後半      

Interoperabiliy & Testing
  Sakai Itsuo (MCPC/TUV), Asami Yokoi(Frontline)

Qualification and Listing
  Takayuki Shimada (UL vs Ltd)

Frontline社アナライザの紹介

Ellisys社のアナライザ紹介

BluetoothSIGのマーケティングプログラムの紹介
 再びMarriotさん


以上。

前半のアーキテクチャやプロファイルは、一度アンドロイドのミドル層のBluetoothの開発に携わったこともあり、だいたい知っていましたので、「ああ、そうだったなあ」と忘れてた記憶が呼び起されて、いい復習になりました。HIDプロファイルは、単なる土管で、実装者はUSBのHIDファンクションを使わないといけないということをおっしゃっていて、以前からUSBのHIDと、BluetoothのHIDは似てるけど同じものなの?と思っていたのですが、そのなぞが解けました。

これから様々なGATTベースのプロファイルがBLEで導入されるらしいです。世の中に出回っていないものはまだBluetoothSIGのワーキンググリープ内で検討中らしいです。講演で紹介されていたそのようなプロファイルの中に、「Indoor Positionning」というプロファイルがありました。BLEを使った測位は、このブログの中でも取り組んでいますが、電波の精度に問題があります。しかし、BluetoothSIGの中で検討されているということはまだまだあきらめてはいけないという気になりますね。

後半になると、会場の雰囲気が変わりました。みなメモをとるぞ~という体勢になりました。私もそうなのですが、みなBluetoothの認証試験の仕組みややり方を知りたがっていたのでしょう。最初のSakaiさんの説明は、わかっている人には非常に詳しく、ノウハウが詰まった内容となっていたのでしょうが、私には使用している言葉(Componentとか、Subsystemとかいう言葉)が理解できず、ほとんど頭に入ってきませんでした。ただし、次の嶋田さんのレクチャーは、まずComponentやSubsystemという言葉の説明からされていたので、とてもわかりやすかったです。Sakaiさんと嶋田さんの順番が逆だったなら、Sakai さんの説明がよくわかっただろうなあ、と思いました。残念です。

トレーニングとは関係ありませんが、お昼に参加者全員分のお弁当が用意されていたのには驚きました。おかげでお昼代が浮きました。また、午前と午後に15分ほどの休憩時間が入ったのですが、コーヒーが用意されていました。単純に、BluetoothSIGっていいね!って思いました。ほんと。

今回は、BluetoothSIGの方たちの意気込みを感じることができ、たいへん貴重な体験となりました。iBeaconをとっかかりにこのブログを始めましたが、iBeaconという枠組みが非常に小さな枠組みであることを痛感しました。iBeaconは、Appleの作ったiOSのLocation機能の一部です。BLEの波はそれよりもずっと広大で、スマートフォン、ウェアラブル、家電などを巻き込んでいくものです。BLEの未来は明るいです。

追記

正直言って、iBeaconだけではネタが尽きかけていたので、今後はBLEに視野を広げブログ更新していきます。


[コラム] Bluetooth トレーニングイベントに参加してきました。



本日、大阪IMPビルで開かれた、BluetoothSIG主催のBluetoothトレーニングイベントに参加してきました。

https://www.bluetooth.org/ja-jp/Pages/qualification-training-sessions.aspx

私自身BluetoothSIGのイベントに参加するのは初めてなのですが、BLEによる盛り上がりを受けてなのか、アジアでは東京、大阪、ソウル、上海と連続して本イベントが開かれ、BluetoothSIGが今回のイベントに非常に力を入れているのがわかりました。またこれ以降も、ブレイクスルー・アワード 2014(12/4受付締切、1/6結果発表)、1月にはCES、2月にはMWCとイベントが続きます。スポンサー企業を中心にこの流れを維持し、マーケットを開拓していこうというムードが伝わってきました。

ざっと、内容を記載します。

      前半      

BluetoothSIGからのあいさつ
  Marriot Winquist (Bluetooth SIG)

Bluetoothの基礎概観(Part1)
  Masamitsu Suzuki  (Texas Instruments)

  • Bluetoothの歴史
  • アーキテクチャの説明
  • プロファイルの説明
    • BR/EDR(クラシックBT)のプロファイル
    • BLEのプロファイル

Bluetoothの基礎概観(Part2)
  Masahiko Seki (MCPC/Sony)
  • GATT-Based Profile 概観

MCPC プレゼンテーション
 モバイルシステム検定試験の案内

 ※MCPC(モバイルコンピューティング推進コンソーシアム)は、
  モバイルコンピューティングの健全な発展のためと環境整備のために
  設立された組織で、研究機関、企業などにより運営されています。
  (http://www.mcpc-jp.org/)

Texas Instruments プレゼンテーション
 自社商品「SensorTag」の紹介


      後半      

Interoperabiliy & Testing
  Sakai Itsuo (MCPC/TUV), Asami Yokoi(Frontline)

Qualification and Listing
  Takayuki Shimada (UL vs Ltd)

Frontline社アナライザの紹介

Ellisys社のアナライザ紹介

BluetoothSIGのマーケティングプログラムの紹介
 再びMarriotさん


以上。

前半のアーキテクチャやプロファイルは、一度アンドロイドのミドル層のBluetoothの開発に携わったこともあり、だいたい知っていましたので、「ああ、そうだったなあ」と忘れてた記憶が呼び起されて、いい復習になりました。HIDプロファイルは、単なる土管で、実装者はUSBのHIDファンクションを使わないといけないということをおっしゃっていて、以前からUSBのHIDと、BluetoothのHIDは似てるけど同じものなの?と思っていたのですが、そのなぞが解けました。

これから様々なGATTベースのプロファイルがBLEで導入されるらしいです。世の中に出回っていないものはまだBluetoothSIGのワーキンググリープ内で検討中らしいです。講演で紹介されていたそのようなプロファイルの中に、「Indoor Positionning」というプロファイルがありました。BLEを使った測位は、このブログの中でも取り組んでいますが、電波の精度に問題があります。しかし、BluetoothSIGの中で検討されているということはまだまだあきらめてはいけないという気になりますね。

後半になると、会場の雰囲気が変わりました。みなメモをとるぞ~という体勢になりました。私もそうなのですが、みなBluetoothの認証試験の仕組みややり方を知りたがっていたのでしょう。最初のSakaiさんの説明は、わかっている人には非常に詳しく、ノウハウが詰まった内容となっていたのでしょうが、私には使用している言葉(Componentとか、Subsystemとかいう言葉)が理解できず、ほとんど頭に入ってきませんでした。ただし、次の嶋田さんのレクチャーは、まずComponentやSubsystemという言葉の説明からされていたので、とてもわかりやすかったです。Sakaiさんと嶋田さんの順番が逆だったなら、Sakai さんの説明がよくわかっただろうなあ、と思いました。残念です。

トレーニングとは関係ありませんが、お昼に参加者全員分のお弁当が用意されていたのには驚きました。おかげでお昼代が浮きました。また、午前と午後に15分ほどの休憩時間が入ったのですが、コーヒーが用意されていました。単純に、BluetoothSIGっていいね!って思いました。ほんと。

今回は、BluetoothSIGの方たちの意気込みを感じることができ、たいへん貴重な体験となりました。iBeaconをとっかかりにこのブログを始めましたが、iBeaconという枠組みが非常に小さな枠組みであることを痛感しました。iBeaconは、Appleの作ったiOSのLocation機能の一部です。BLEの波はそれよりもずっと広大で、スマートフォン、ウェアラブル、家電などを巻き込んでいくものです。BLEの未来は明るいです。

追記

正直言って、iBeaconだけではネタが尽きかけていたので、今後はBLEに視野を広げブログ更新していきます。


2013年11月4日月曜日

11月2日(土)に、スマベン(=スマートフォン勉強会)関西が開かれました。

http://sumaben.jp/?KansaiSpecial05BLE

今回は、メインスピーカーに上原昭宏氏を迎えて、Bluetooth Low Energyの勉強会をするということで私も参加してきました。

参加者はハードウェアの製造をされる方からソフト開発者、ウェブサービス開発者、マスコミ関係者まで幅広く、マッシュアップが非常に期待される顔ぶれでした。それほどBLE/iBeaconに対する各分野からの関心が高いということでしょう。

[コラム] スマベン関西に参加してきました。

11月2日(土)に、スマベン(=スマートフォン勉強会)関西が開かれました。

http://sumaben.jp/?KansaiSpecial05BLE

今回は、メインスピーカーに上原昭宏氏を迎えて、Bluetooth Low Energyの勉強会をするということで私も参加してきました。

参加者はハードウェアの製造をされる方からソフト開発者、ウェブサービス開発者、マスコミ関係者まで幅広く、マッシュアップが非常に期待される顔ぶれでした。それほどBLE/iBeaconに対する各分野からの関心が高いということでしょう。

2013年10月16日水曜日

iBeaconで使えるビーコンがなんとか3つ揃いましたので、測位を試してみました。


使用したビーコン

  1. iPhone5c(Peripheralとして動作するiPhoneアプリ)
  2. BLE Mini (RedBearLab社)
  3. RaspberryPI(+ Bluz iBeacon)

屋内測位をやってみました

iBeaconで使えるビーコンがなんとか3つ揃いましたので、測位を試してみました。


使用したビーコン

  1. iPhone5c(Peripheralとして動作するiPhoneアプリ)
  2. BLE Mini (RedBearLab社)
  3. RaspberryPI(+ Bluz iBeacon)

2013年10月11日金曜日


iBeacon は、iOSでBLEを利用できるようにしたもの、という認識でしたが、調べてみるといろいろと知っておかないといけないことがあるようです。

例えば、ビーコンを表現したCLBeaconというクラスがCoreLocationフレームワークにありますが、信号を受信できるビーコンは、Apple社のベンダー情報が設定されていないと行けないことがわかりました。どうもAppleとのNDA契約がないと勝手にiBeaconの製品を販売できないことになっているようです。

また、CoreLocationフレームワークは、GPSやネットワークを使った測位全般を扱うフレームワークですが、そこにBLEを使った領域観測の窓口があるのは、アプリ開発者にとって直にBluetoothのプロファイルを扱わなくてもよいというメリットがあります。

調べた内容は、「iBeacon開発」(ダウンロードはこちら)にまとめましたので、ご覧ください。

iBeaconの仕組を調べてみました


iBeacon は、iOSでBLEを利用できるようにしたもの、という認識でしたが、調べてみるといろいろと知っておかないといけないことがあるようです。

例えば、ビーコンを表現したCLBeaconというクラスがCoreLocationフレームワークにありますが、信号を受信できるビーコンは、Apple社のベンダー情報が設定されていないと行けないことがわかりました。どうもAppleとのNDA契約がないと勝手にiBeaconの製品を販売できないことになっているようです。

また、CoreLocationフレームワークは、GPSやネットワークを使った測位全般を扱うフレームワークですが、そこにBLEを使った領域観測の窓口があるのは、アプリ開発者にとって直にBluetoothのプロファイルを扱わなくてもよいというメリットがあります。

調べた内容は、「iBeacon開発」(ダウンロードはこちら)にまとめましたので、ご覧ください。

2013年10月10日木曜日

BLEでどういったことができるのか、現状で手に入るBLEモジュールとそのサンプルプログラムを動かしてみました。今回はRedBearLab社の2つを使用しました。



BLE Shield

Arduino用のシールドです。
2013/10/07現在でArduino Uno、Arduino Mega、Arduino Leonardoの3つに対応しています。
公式サイトで提供されているサンプルスケッチはFirmataプロトコルと呼ばれるArduinoを制御できる汎用プロトコルをBLE経由で使用できるものです。



公式サイトからダウンロードできるファイルは次の3つから構成され、それぞれ次のライセンスが記載されていました。
・BLEライブラリ(MITライセンス)
・BLE用Firmataライブラリ(LGPLライセンス)
・サンプルスケッチ(LGPLライセンス)
比較的扱いやすいライセンスが適用されています。

Arduinoに装着し、サンプルスケッチを書き込めば直ぐに使用できました。iPhone用のサンプルプログラムをAppStoreからダウンロードし、実行します。接続画面からArduinoに接続するとArduinoの操作画面が表示されます。操作画面からはArduinoの各ピンの電圧のON/OFFや値の読み取りが行えます。

サンプルスケッチではBLE経由のFirmataプロトコルの通信のみとなっていますが、内部実装を見たところ、通常のシリアル通信のようなやり取りもできるようになっていますので、自分でプロトコル設計をすれば独自のことも行えそうです。

BLE Mini

UARTインターフェースを持ったBLEモジュールです。
このBLEモジュールにはPINが6本あり、内2本がTX、RXのUARTインターフェースとなっており、標準的なシリアル通信が行うことができます。UARTインターフェースなのでArduinoに限らずRaspberry Pi、BeagleBone、Netduino、RENESAS、PICと幅広いボードで利用可能できそうです。




BLE Shield同様にFirmataプロトコル用のサンプルスケッチが提供されています。
※このサンプルスケッチはArduino Uno用になっており、Arduino Leonardoで動作させるには修正が必要でした。

BLE Miniはファームウェアの書き換えが可能で、後述のiBeaconのように単独での動作も可能になります。公式サイトによるとファームウェアの開発環境についてはまだベータ版ということですが、今後の広がりに期待が持てます。

iBeaconとBLE Mini

BLE MiniにはArduinoのような別のマイコンに接続せず、
単独でiBeaconとなるファームウェアが提供されています。
2013/10/07現在は正式な仕様が公開されておらず、
このファームウェアは試験評価用という位置づけですが、
こちらもiPhone用のサンプルプログラムが公開されており、
どのように動作するかを体験することができます。




非常に汎用的ですので応用すれば自分たちでBLEを用いたハードウェアを創ることもできます。BLEは省電力かつ手軽に使えるということからこれを使ったデバイスが増えていくことが期待されますので、これからもこういったモジュールを追って行きたいと思います。


なお、今回紹介したRedBearLab社のBLEモジュールは技術基準適合は受けておりません。電波暗室や電波障害を起こさない十分に広い敷地・建屋内で実験を行ってください。不用意に電波を発射すると、日本の法律に反する可能性がありますのでご注意ください。

[Tips] BLEモジュールを試してみました

BLEでどういったことができるのか、現状で手に入るBLEモジュールとそのサンプルプログラムを動かしてみました。今回はRedBearLab社の2つを使用しました。



BLE Shield

Arduino用のシールドです。
2013/10/07現在でArduino Uno、Arduino Mega、Arduino Leonardoの3つに対応しています。
公式サイトで提供されているサンプルスケッチはFirmataプロトコルと呼ばれるArduinoを制御できる汎用プロトコルをBLE経由で使用できるものです。



公式サイトからダウンロードできるファイルは次の3つから構成され、それぞれ次のライセンスが記載されていました。
・BLEライブラリ(MITライセンス)
・BLE用Firmataライブラリ(LGPLライセンス)
・サンプルスケッチ(LGPLライセンス)
比較的扱いやすいライセンスが適用されています。

Arduinoに装着し、サンプルスケッチを書き込めば直ぐに使用できました。iPhone用のサンプルプログラムをAppStoreからダウンロードし、実行します。接続画面からArduinoに接続するとArduinoの操作画面が表示されます。操作画面からはArduinoの各ピンの電圧のON/OFFや値の読み取りが行えます。

サンプルスケッチではBLE経由のFirmataプロトコルの通信のみとなっていますが、内部実装を見たところ、通常のシリアル通信のようなやり取りもできるようになっていますので、自分でプロトコル設計をすれば独自のことも行えそうです。

BLE Mini

UARTインターフェースを持ったBLEモジュールです。
このBLEモジュールにはPINが6本あり、内2本がTX、RXのUARTインターフェースとなっており、標準的なシリアル通信が行うことができます。UARTインターフェースなのでArduinoに限らずRaspberry Pi、BeagleBone、Netduino、RENESAS、PICと幅広いボードで利用可能できそうです。




BLE Shield同様にFirmataプロトコル用のサンプルスケッチが提供されています。
※このサンプルスケッチはArduino Uno用になっており、Arduino Leonardoで動作させるには修正が必要でした。

BLE Miniはファームウェアの書き換えが可能で、後述のiBeaconのように単独での動作も可能になります。公式サイトによるとファームウェアの開発環境についてはまだベータ版ということですが、今後の広がりに期待が持てます。

iBeaconとBLE Mini

BLE MiniにはArduinoのような別のマイコンに接続せず、
単独でiBeaconとなるファームウェアが提供されています。
2013/10/07現在は正式な仕様が公開されておらず、
このファームウェアは試験評価用という位置づけですが、
こちらもiPhone用のサンプルプログラムが公開されており、
どのように動作するかを体験することができます。




非常に汎用的ですので応用すれば自分たちでBLEを用いたハードウェアを創ることもできます。BLEは省電力かつ手軽に使えるということからこれを使ったデバイスが増えていくことが期待されますので、これからもこういったモジュールを追って行きたいと思います。


なお、今回紹介したRedBearLab社のBLEモジュールは技術基準適合は受けておりません。電波暗室や電波障害を起こさない十分に広い敷地・建屋内で実験を行ってください。不用意に電波を発射すると、日本の法律に反する可能性がありますのでご注意ください。

2013年10月4日金曜日


最近よく耳にするiBeaconとはなんでしょうか。Appleはまだ明言していないようですが、いろいろなサイトを読むと、Bluetooth 4.0 で導入されたBLE(=Bluetooth Low Energy)をiOSで使えるようにしたものの総称のようです。iOS7から実装されています。

今、流行のiBeaconとは?


最近よく耳にするiBeaconとはなんでしょうか。Appleはまだ明言していないようですが、いろいろなサイトを読むと、Bluetooth 4.0 で導入されたBLE(=Bluetooth Low Energy)をiOSで使えるようにしたものの総称のようです。iOS7から実装されています。

Related Posts Plugin for WordPress, Blogger...