Raspberry Pi zero whのBLEモジュールとAndroidアプリ(react-native)を繋げるのに少し苦労したので備忘録として書きます。
環境
ここでは、Raspberry Pi zero wh と Android(react-native) の間でBLEを使った通信をすることを想定しています。
なお、Raspberry Pi側のプログラムはgolangで書きます。
準備
BLE開発に必要な概念
これだけはまず知っておいた方がいい、という基礎知識です。
BLE概論系の記事には色々と難しい言葉が並んでいますが、まず覚える必要があるのは次の2つだけです。
- サーバー(ペリフェラル)
- クライアント(セントラル)
サーバー
サーバー(ペリフェラル)は、デバイス側を表します。つまりここではRaspberry Pi側です。
クライアント
クライアント(セントラル)はここではAndroid側です。
サーバーはRaspberry Pi、クライアントはAndroid。これだけ覚えておきましょう。
BLEのアプリケーションを識別するのに必要な値
BLEモジュールと通信するために、そのBLEモジュールを使っているアプリケーションを識別する値が必要になります。これが以下の二つです。
- MACアドレス
- UUID (service UUIDとcharacteristic UUIDの2種)
ここで、MACアドレスはBLEモジュールに固有の値で、 hciconfig
などで確認することができます。
2種のUUIDはアプリケーション側で設定できる値で、任意の値を使うことができます。
MACアドレスの確認
ではまずBLEモジュールのMACアドレスを確認します。Raspberry Piで以下のコマンドを実行してください。
pi@raspberrypi:~ $ sudo hciconfig
hci0: Type: Primary Bus: UART
BD Address: B8:26:EB:BA:3C:11 ACL MTU: 1021:8 SCO MTU: 64:1
UP RUNNING PSCAN
RX bytes:15221 acl:0 sco:0 events:530 errors:0
TX bytes:17899 acl:18 sco:0 commands:722 errors:0
pi@raspberrypi:~ $
ここでのMACアドレスはB8:26:EB:BA:3C:11
ですね。メモしておきましょう。
golangでBLEサーバーの作成
まずはただ動いて欲しいので、github.com/paypal/gattというライブラリのサンプルをそのまま使います。 https://github.com/paypal/gatt
こいつをビルドしてRaspberry Pi上で実行しましょう。(sudo
を忘れないように)
pi@raspberrypi:~ $ sudo ./gatt_server_lnx
2018/04/07 09:48:34 dev: hci0 up
2018/04/07 09:48:34 dev: hci0 reset
2018/04/07 09:48:34 dev: hci0 down
2018/04/07 09:48:34 dev: hci0 opened
State: PoweredOn
2018/04/07 09:48:34 BD Addr: B8:26:EB:BA:3C:11
2018/04/07 09:48:34 Generating attribute table:
2018/04/07 09:48:34 handle type props secure pvt value
2018/04/07 09:48:34 0x0001 0x2800 0x02 0x00 *gatt.Service [ 00 18 ]
2018/04/07 09:48:34 0x0002 0x2803 0x02 0x00 *gatt.Characteristic [ 02 03 00 00 2A ]
2018/04/07 09:48:34 0x0003 0x2a00 0x02 0x00 *gatt.Characteristic [ 47 6F 70 68 65 72 ]
2018/04/07 09:48:34 0x0004 0x2803 0x02 0x00 *gatt.Characteristic [ 02 05 00 01 2A ]
2018/04/07 09:48:34 0x0005 0x2a01 0x02 0x00 *gatt.Characteristic [ 00 80 ]
2018/04/07 09:48:34 0x0006 0x2803 0x02 0x00 *gatt.Characteristic [ 02 07 00 02 2A ]
2018/04/07 09:48:34 0x0007 0x2a02 0x02 0x00 *gatt.Characteristic [ 00 ]
2018/04/07 09:48:34 0x0008 0x2803 0x02 0x00 *gatt.Characteristic [ 02 09 00 03 2A ]
2018/04/07 09:48:34 0x0009 0x2a03 0x02 0x00 *gatt.Characteristic [ 00 00 00 00 00 00 ]
2018/04/07 09:48:34 0x000A 0x2803 0x02 0x00 *gatt.Characteristic [ 02 0B 00 04 2A ]
2018/04/07 09:48:34 0x000B 0x2a04 0x02 0x00 *gatt.Characteristic [ 06 00 06 00 00 00 D0 07 ]
2018/04/07 09:48:34 Generating attribute table:
2018/04/07 09:48:34 handle type props secure pvt value
2018/04/07 09:48:34 0x0001 0x2800 0x02 0x00 *gatt.Service [ 00 18 ]
2018/04/07 09:48:34 0x0002 0x2803 0x02 0x00 *gatt.Characteristic [ 02 03 00 00 2A ]
...略
react-native側
react-native側は、 https://github.com/innoveit/react-native-ble-manager というライブラリを使って通信します。
コード片で申し訳ないのですが、こんな感じのコードを書きます。
startScan() {
if (!this.state.scanning) {
this.setState({peripherals: new Map()});
BleManager.scan([], 3, true).then((results) => {
console.log('Scanning...');
this.setState({scanning: true});
console.log(results)
});
}
BleManager.getConnectedPeripherals([]).then((results) => {
console.log(results);
var peripherals = this.state.peripherals;
for (var i = 0; i < results.length; i++) {
var peripheral = results[i];
peripheral.connected = true;
peripherals.set(peripheral.id, peripheral);
console.log(peripheral)
this.setState({ peripherals });
}
});
BleManager.connect("B8:26:EB:BA:3C:11").then(() => {
console.log('Connected');
}).catch((error) => {
// Failure code
console.log(error);
})
BleManager.retrieveServices("B8:26:EB:BA:3C:11").then((peripheralInfo) => {
// Success code
console.log('Peripheral info:', peripheralInfo);
});
const data = stringToBytes("piyo");
console.log(data)
BleManager.write("B8:26:EB:BA:3C:11", "09fc95c0-c111-11e3-9904-0002a5d5c51b", "16fe0d80-c111-11e3-b8c8-0002a5d5c51b", data).then(() => {
// Success code
console.log('Write: ' + data);
}).catch((error) => {
// Failure code
console.log(error);
});
}
ここで大事な点が2点あります。まず1つ目は、 read, write, notifyの前には必ずBleManager.retrieveServices()を実行しなくてはいけない ことです。
普通にドキュメントに書いてあるのですが、忘れがちみたいです。
https://github.com/innoveit/react-native-ble-manager/issues/259
次に、2つのUUIDについてです。これらはpaypal/gattのexampleに書いてあります。
まず、serviceUUIDは https://github.com/paypal/gatt/blob/4ae819d591cfc94c496c45deb55928469542beec/examples/service/count.go#L13 です。
そして、characteristicUUIDは https://github.com/paypal/gatt/blob/4ae819d591cfc94c496c45deb55928469542beec/examples/service/count.go#L20 です。
雑に書きましたがこんな感じです。