Raspberry Pi 3とGenuino 101を手に入れたのでガーッとBLE通信します。
下記については詳しい説明は書きません。
- Raspberry Pi 3について
- Node.jsについて
- nobleについて
- Genuino 101について
- BLE通信について
また、Raspberry Pi 3からGenuino 101に対して接続するときに、アドバタイズパケットに含まれる情報ではなく、MACアドレスを直接記述して接続します。
一応、伏せ字にしましたので、xxxxxxxxxxxxという記述があったら、お手元のGenuino 101のMACアドレスと差し替えて試してください。
Genuino 101側
Genuino 101について、下記を参考にさせていただきました。ありがとうございました。
キャラクタリスティックなどの設計からしなければ!と思っていたけど、スケッチの例が充実していたので、スケッチの例 > CurieBLE > ButtonLED
をそのまま使用することにしました。
スケッチが想定しているであろう下記のような回路を作成しました。
セントラルからの接続がない状態の動作としては、スイッチが押されている間はLEDが点灯し、押されていない間は点灯しません。
スイッチにはプルダウン抵抗を加え、スイッチが押されている間はHIGH、押されていない間はLOWとなるようにします。
Raspberry Pi 3側
Node.jsのnobleライブラリを使用して、Genuino 101からの通知を受け取ります。
アドバタイズパケットの確認
nobleのリポジトリに含まれているサンプルコード advertisement-discovery.jsを使用して、Genuino 101が出してるアドバタイズパケットを確認します。
peripheral discovered (xxxxxxxxxxxx with address <xx:xx:xx:xx:xx:xx, public>, connectable true, RSSI -68:
hello my local name is:
ButtonLE
can I interest you in any of the following advertised services:
["19b10010e8f2537e4f6cd104768a1214"]
上記の出力の中に、サンプルスケッチの中のblePeripheral.setLocalName("ButtonLED");
で指定されているローカルネームと、BLEService ledService("19B10010-E8F2-537E-4F6C-D104768A1214");
で指定されているUUIDがハイフンなしで含まれています。
サービスの構成を確認
nobleのリポジトリに含まれているサンプルコード peripheral-explorer.jsを使用して、サンプルスケッチが定義しているledServiceの構成を確認します。
実行時に下記のように前述のアドバタイズパケットの受信時の出力に含まれているMACアドレスをコロンなしで指定します。
$ sudo node peripheral-explorer.js xxxxxxxxxxxx
すると、サンプルスケッチで定義されているCharacteristicのプロパティや現在の値などが出力されます。
peripheral with ID xxxxxxxxxxxx found
Local Name = ButtonLE
Service Data =
Service UUIDs = 19b10010e8f2537e4f6cd104768a1214
services and characteristics:
1800 (Generic Access)
2a00 (Device Name)
properties read
value 47454e55494e4f203130312d38323841 | 'GENUINO 101-828A'
2a01 (Appearance)
properties read
value 0000 | ''
2a04 (Peripheral Preferred Connection Parameters)
properties read
value 4000780000005802 | '@xX'
1801 (Generic Attribute)
19b10010e8f2537e4f6cd104768a1214
19b10011e8f2537e4f6cd104768a1214
properties read, write
value 00 | ''
19b10012e8f2537e4f6cd104768a1214
properties read, notify
value 00 | ''
スイッチの状態を受信
確認したServiceの構成に合わせて、ボタンの状態をRaspberry Pi 3で受信します。
var noble = require('noble');
var ledServiceUuid = '19b10010e8f2537e4f6cd104768a1214';
var ledCharacteristicUuid = '19b10011e8f2537e4f6cd104768a1214';
var buttonCharacteristicUuid = '19b10012e8f2537e4f6cd104768a1214';
var peripheralIdOrAddress = process.argv[2].toLowerCase();
// Bluetoothデバイスの状態変更時の処理
noble.on('stateChange', function(state) {
if (state === 'poweredOn') {
// ペリフェラルのスキャンを開始
noble.startScanning();
} else {
noble.stopScanning();
}
});
// ペリフェラル発見時の処理
noble.on('discover', function(peripheral) {
if (peripheral.id === peripheralIdOrAddress || peripheral.address === peripheralIdOrAddress) {
// ペリフェラルのスキャンを停止
noble.stopScanning();
console.log('peripheral with ID ' + peripheral.id + ' found');
peripheral.once('disconnect', function() {
console.log('disconnected');
process.exit(0);
});
// ペリフェラルとの接続を開始
peripheral.connect(function(error) {
console.log('connected');
// サービス探索を開始
peripheral.discoverServices([], onServicesDiscovered);
});
}
});
// サービス発見時の処理
function onServicesDiscovered(error, services) {
console.log('services discovered');
services.forEach(function(service) {
if (service.uuid == ledServiceUuid) {
// キャラクタリスティック探索を開始
service.discoverCharacteristics([], onCharacteristicDiscovered);
}
});
}
// キャラクタリスティック発見時の処理
function onCharacteristicDiscovered(error, characteristics) {
console.log('characteristics discovered');
characteristics.forEach(function(characteristic) {
if (characteristic.uuid == ledCharacteristicUuid) {
characteristic.on('read', onLedCharacteristicRead);
} else if (characteristic.uuid == buttonCharacteristicUuid) {
characteristic.on('read', onButtonCharacteristicRead);
// データ更新通知の受け取りを開始
characteristic.notify(true, function(error) {
console.log('buttonCharacteristic notification on');
});
}
});
}
// ledCharacteristicのデータ読み出し時の処理
// (現在のこのコードでは呼ばれることがない想定です)
function onLedCharacteristicRead(data, isNotification) {
console.log('ledCharacteristic read response value: ', data.readInt8(0));
}
// buttonCharacteristicのデータ読み出し時、もしくは更新時の処理
function onButtonCharacteristicRead(data, isNotification) {
if (isNotification) {
// データ更新通知による呼び出し
console.log('buttonCharacteristic notification value: ', data.readInt8(0));
} else {
// データ読み出し時の呼び出し
console.log('buttonCharacteristic read response value: ', data.readInt8(0));
}
}
上記コードを`button_led_central.js"として保存して、下記のように実行します。
sudo node button_led_central.js xxxxxxxxxxxx
接続後、ボタンの押下に合わせて値が出力されます。
peripheral with ID xxxxxxxxxxxx found
connected
services discovered
characteristics discovered
buttonCharacteristic notification on
buttonCharacteristic notification value: 1
buttonCharacteristic notification value: 0
buttonCharacteristic notification value: 1
buttonCharacteristic notification value: 0
buttonCharacteristic notification value: 1
buttonCharacteristic notification value: 0
buttonCharacteristic notification value: 1
buttonCharacteristic notification value: 0
buttonCharacteristic notification value: 1
buttonCharacteristic notification value: 0
最後に
Raspberry Pi 3側でもLEDを光らせたりしたかったけど夜も深まってきたのであきらめました…。
Genuino 101のスケッチ書き込みのときの具合が微妙なこと以外は、安定して動作しているようなので、しばらく遊べそうです。