「Pythonを使ってアルプスのセンサネットワークモジュールでモーションデータの取得」で、python言語と使ってアルプスIoT Smart Moduleをアクセスしましたが、今回は、Raspberry Pi 3にNode.jsをインストールし、Node.jsのBLEモジュール「noble」を用いてアルプスIoT Smart Moduleの地磁気センサと加速度センサからモーションデータを取得します。
nobleモジュールは、Node.jsで動作するBLEモジュールで、次のようなBLEモジュールが提供されています。
- noble … Node.jsのBLEセントラル実装です。BLE機器を利用するもので、周辺のBLE機器をスキャンし、任意のGATTあるいはサービスに接続を行います
- bleno … Node.jsのBLEペリフェラル実装です。BLE機器そのもので定期的にアドバタイズを行う。BLEのペリフェラルデバイスを持っていなくてもNode.jsのモジュールblenoを利用することでアドバタイズを発信することができます。
nobleモジュールの詳細な仕様については、「sandeepmistry/noble」を参照してください。
アルプスIoT Smart Moduleへアクセスするための実行環境の作成
node.jsは、「Raspberry Pi 3にNode.jsのインストール」を参考にインストールしてください。
blenoが利用するBluetoothのプロトコルスタックのBlueZのインストールは次のコマンドで行ってください。
$ sudo apt-get install bluetooth bluez libbluetooth-dev libudev-dev
blenoはnpmを利用してを次のようにインストールしてください。
$ npm install bleno
確認用のプログラム「nobletest.js」を次に示します。stateがpoweredOnのときにstartScanning()を呼んでいます。 アドバタイズを受信するとnoble.on()のdiscoverに来ますので、受信したペリフェラルの内容、 ここではlocalNameとサービスのUUIDを表示しています。
var noble = require('noble'); noble.on('stateChange', function(state) { if (state === 'poweredOn') { noble.startScanning(); } else { noble.stopScanning(); } }); noble.on('discover', function(peripheral) { console.log('Found device with local name: ' + peripheral.advertisement.localName); peripheral.connect(function(error) { console.log('connected to peripheral: ' + peripheral.uuid); }); });
次のコマンドで実行すると、アルプスIoT Smart Moduleのローカル名「SNM00」、UUID「28a183e15896」が取得できます。
$ sudo node nobletest.js Found device with local name: SNM00 connected to peripheral: 28a183e15896
エラーメッセージ「Error: Module version mismatch. Expected 48, got 57」の処置方法
次のように作成したプログラムを実行すると、モジュールのバーションが不一致であるというエラーメッセージが表示される場合があります。
$ sudo node nobletest.js module.js:597 return process.dlopen(module, path._makeLong(filename)); ^ Error: Module version mismatch. Expected 48, got 57. at Error (native) at Object.Module._extensions..node (module.js:597:18) at Module.load (module.js:487:32) at tryModuleLoad (module.js:446:12) at Function.Module._load (module.js:438:3) at Module.require (module.js:497:17) at require (internal/module.js:20:19) at Object.(/home/pi/node_modules/bluetooth-hci-socket/lib/native.js:3:15) at Module._compile (module.js:570:32) at Object.Module._extensions..js (module.js:579:10
この場合、npmが原因のようで、次のようにすでに作成されているディレクトリ「node_modules」を削除して、npmを再インストールします。
$ sudo rm -r node_modules $ npm install
nodeとnpmのバージョンを次に示します。
$ node -v v8.4.0 $ npm –version 5.4.2
アルプスIoT Smart Moduleからモーションデータの取得
モーションデータ取得プログラム「writenoble.js」を次に示します。アルプスIoT Smart Moduleのサービスやcharacteristicsを確認するためにダンプルーチンも追加しています。65行目から67行目で取得したcharacteristicsをそれぞれCustom1、Custom2、Custom3に登録しています。69行目から76行目まででアルプスIoT Smart Moduleの設定を行っています。モーションデータはnotifyにより通視されるので、79行目でモーションデータを受け取っています。Custom1、Custom2、Custom3については、「Sensor Network Module評価キットApplication Note Command Guide」のAppendix1 Service1 Databaseを参照してください。
var noble = require('noble'); console.log('noble'); function bytes2str(data){ var str = ""; for (var i = 0; i < data.length; i++){ str += ('00' + (data[i].toString(16))).slice( -2 ); } return str ; } noble.on('stateChange', function(state) { console.log('on -> stateChange: ' + state); if (state === 'poweredOn') { noble.startScanning(); } else { noble.stopScanning(); } }); noble.on('scanStart', function() { console.log('on -> scanStart'); }); noble.on('scanStop', function() { console.log('on -> scanStop'); }); noble.on('discover', function(peripheral) { console.log('on -> discover: ' + peripheral); noble.stopScanning(); peripheral.on('connect', function() { console.log('on -> connect'); this.discoverServices(); }); peripheral.on('disconnect', function() { console.log('on -> disconnect'); }); peripheral.on('servicesDiscover', function(services) { console.log('on -> Service: ' + services); //各サービスを登録 var GenericAccess = services[0]; var GenericAttribute = services[1]; var PRIMARY_SERVICE = services[2]; GenericAccess.on('characteristicsDiscover', function(characteristics) { console.log('on -> GenericAccess:characteristicsDiscover: ' + characteristics); }); GenericAttribute.on('characteristicsDiscover', function(characteristics) { console.log('on -> GenericAttribute:characteristicsDiscover: ' + characteristics); }); PRIMARY_SERVICE.on('characteristicsDiscover', function(characteristics) { console.log('on -> PRIMARY_SERVICE:characteristicsDiscover: ' + characteristics); //各characteristicsを登録 var Custom1 = characteristics[0]; var Custom2 = characteristics[1]; var Custom3 = characteristics[2]; Custom1.write(new Buffer([0x01, 0x00]), true); Custom2.write(new Buffer([0x01, 0x00]), true); Custom3.write(new Buffer([0x2F, 0x03, 0x03]), true); Custom3.write(new Buffer([0x01, 0x03, 0x03]), true); Custom3.write(new Buffer([0x04, 0x03, 0x01]), true); Custom3.write(new Buffer([0x06, 0x04, 0x64, 0x00]), true); Custom3.write(new Buffer([0x2F, 0x03, 0x01]), true); Custom3.write(new Buffer([0x20, 0x03, 0x01]), true); Custom1.notify(true); Custom1.on('data', function(data, isNotification) { console.log('Custom1 = ' + bytes2str(data)); }); Custom2.notify(true); Custom2.on('data', function(data, isNotification) { console.log('Custom2 = ' + data[0].toString(16)); }); }); //各サービスのcharacteristicをdiscover実施 GenericAccess.discoverCharacteristics(); GenericAttribute.discoverCharacteristics(); PRIMARY_SERVICE.discoverCharacteristics(); }); peripheral.connect(); });
実行した結果を次に示します。
$ sudo node writenoble.js noble on -> stateChange: poweredOn on -> scanStart on -> discover: {"id":"28a183e15896","address":"28:a1:83:e1:58:96","addressType":"public","connectable":true,"advertisement":{"localName":"SNM00","serviceData":[],"serviceUuids":[],"solicitationServiceUuids":[],"serviceSolicitationUuids":[]},"rssi":-72,"state":"disconnected"} on -> scanStop on -> connect on -> Service: {"uuid":"1800","name":"Generic Access","type":"org.bluetooth.service.generic_access","includedServiceUuids":null},{"uuid":"1801","name":"Generic Attribute","type":"org.bluetooth.service.generic_attribute","includedServiceUuids":null},{"uuid":"47fe55d8447f43ef9ad9fe6325e17c47","name":null,"type":null,"includedServiceUuids":null} on -> GenericAccess:characteristicsDiscover: {"uuid":"2a00","name":"Device Name","type":"org.bluetooth.characteristic.gap.device_name","properties":["read"]},{"uuid":"2a01","name":"Appearance","type":"org.bluetooth.characteristic.gap.appearance","properties":["read"]},{"uuid":"2a02","name":"Peripheral Privacy Flag","type":"org.bluetooth.characteristic.gap.peripheral_privacy_flag","properties":["read","write"]},{"uuid":"2a04","name":"Peripheral Preferred Connection Parameters","type":"org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters","properties":["read"]} on -> GenericAttribute:characteristicsDiscover: {"uuid":"2a05","name":"Service Changed","type":"org.bluetooth.characteristic.gatt.service_changed","properties":["read","indicate"]} on -> PRIMARY_SERVICE:characteristicsDiscover: {"uuid":"686a9a3b4c2c4231b8719cfe92cc6b1e","name":null,"type":null,"properties":["read","notify"]},{"uuid":"078ff5d63c9347f5a30c05563b8d831e","name":null,"type":null,"properties":["read","notify"]},{"uuid":"b962bdd15a77479793a1ede8d0ff74bd","name":null,"type":null,"properties":["writeWithoutResponse","write"]} Custom1 = e01400000000c6830a0101000000000000000000 Custom1 = e01400000000c6830a0101000000000000000000 Custom1 = f214a60052ff7c0049f0e5ff6bfe6400310d0000 Custom1 = f214a9004dff7b004cf0e5ff11fec800310d0001 Custom1 = f214a6004cff7b0049f0f1ff20fe2c01310d0002 Custom1 = f214a90051ff800055f0e8ff1afe9001310d0003 Custom1 = f214aa004fff7c0049f0e2ff38fef401310d0004 Custom1 = f214a7004bff7b004ff0e5ff20fe5802310d0005 Custom1 = f214a70050ff7f004cf0e2ff38febc02310d0006 Custom1 = f214a9004fff7d004ff0e5ff23fe2003310d0007 Custom1 = f214a40052ff7c004cf0e5ff23fe8403310d0008
uuid | name | uuid | name | properties |
---|---|---|---|---|
1800 | Generic Access | 2a00 | Device Name | read |
2a01 | Appearance | read | ||
2a02 | Peripheral Privacy Flag | read write | ||
2a04 | Peripheral Preferred Connection Parameters | read | ||
1801 | Generic Attribute | 2a05 | Service Changed | read indicate |
47fe55d8447f43ef9ad9fe6325e17c47 | 686a9a3b4c2c4231b8719cfe92cc6b1e | read notify | ||
078ff5d63c9347f5a30c05563b8d831e | read notify | |||
b962bdd15a77479793a1ede8d0ff74bd | writeWithoutResponse write |