NodeJSでBLE通信ができるnobleライブラリでkonashiとつなげたメモ

先日の記事で、NodeJSでBLE通信ができるnobleライブラリでkonashiとつなげたメモです。

今回やりたいこと

今回やりたいことは以下のとおりです。

  • Raspberry PiでBlueTooth関連のライブラリが入っていてBlueToothが使える状態が前提で進める。
  • NodeJSでnobleライブラリを使って、konashiにアクセス。
  • 1秒毎にLED ON/OFFしつつ、アナログ入力を計測する動きにする。

NodeJSでnobleライブラリを使う

早速使っていきます。Raspberry PiでBlueTooth関連のライブラリが入っていてBlueToothが使える状態が前提です。

NodeJSでは特に込み入ったことはなく、

npm install noble

でインストールします。

konashiを操作するためのUUID

konashiを操作するためのUUIDは本家のサイトを参考にします。

konashi – Documents

NodeJSに変数として保持しておきます。

var noble = require('noble');

// KONASHI自体のサービスID
var KONASHI_SERVICE_UUID = '229bff0003fb40da98a7b0def65c2d4b';
// 操作したいpinのID
var KONASHI_ANALOG_INPUT_PINID   =  '229b300803fb40da98a7b0def65c2d4b';
var KONASHI_PIO_SETTING_PINID    =  '229b300003fb40da98a7b0def65c2d4b';
var KONASHI_PIO_OUTPUT_PINID     =  '229b300203fb40da98a7b0def65c2d4b';

実際のコード

実際のコードは以下のとおりです。

オリジナルlittleBits Bluetooth(konashi)モジュールは、アナログ入力ピン AIO0、デジタル出力ピン PIO2で入出力をやり取りしています。

※このpinルールは開発中のものなので変更される可能性があります。そのときは読み替えましょう。

var noble = require('noble');

// KONASHI自体のサービスID
var KONASHI_SERVICE_UUID = '229bff0003fb40da98a7b0def65c2d4b';
// 操作したいpinのID
var KONASHI_ANALOG_INPUT_PINID   =  '229b300803fb40da98a7b0def65c2d4b';
var KONASHI_PIO_SETTING_PINID    =  '229b300003fb40da98a7b0def65c2d4b';
var KONASHI_PIO_OUTPUT_PINID     =  '229b300203fb40da98a7b0def65c2d4b';
// 各CHARACTERISTICSをUUIDから判断してcharacteristic格納する変数
var KONASHI_CHARACTERISTICS_ANALOG_READ;
var KONASHI_CHARACTERISTICS_PIO_SETTINGS;
var KONASHI_CHARACTERISTICS_PIO_OUTPUT;

// LED ON/OFF
var led_toggle = false;

// 状態がパワーONだったらスキャンに移行
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');
});

// discover 機器が発見されたら
noble.on('discover', function(peripheral) {
    console.log('on -> discover: ' + peripheral);
    // まずスキャンをとめる
    noble.stopScanning();

    // KONASHI接続時のイベント
    peripheral.on('connect', function() {
        console.log('on -> connect');
        this.discoverServices();
    });
    // KONASHI切断時のイベント
    peripheral.on('disconnect', function() {
        console.log('on -> disconnect');
    });

    // 見つけたサービス(機器)へのアクセス
    peripheral.on('servicesDiscover', function(services) {

        for(i = 0; i < services.length; i++) {

            // サービスがKONASHI_SERVICE_UUIDと一致した時だけ処理
            if(services[i]['uuid'] == KONASHI_SERVICE_UUID){

                // サービスのcharacteristic捜索
                services[i].on('includedServicesDiscover', function(includedServiceUuids) {
                    console.log('on -> service included services discovered [' + includedServiceUuids + ']');
                    this.discoverCharacteristics();
                });

                // characteristic取得イベント
                services[i].on('characteristicsDiscover', function(characteristics) {

                    // characteristics配列から必要なCHARACTERISTICSをUUIDから判断してcharacteristic格納
                    for(j = 0; j < characteristics.length; j++) {
                        // アナログ入力 characteristic
                        if( KONASHI_ANALOG_INPUT_PINID == characteristics[j].uuid ){
                            console.log("KONASHI_CHARACTERISTICS_ANALOG_READ exist!!");
                            KONASHI_CHARACTERISTICS_ANALOG_READ = characteristics[j];
                        }
                        // PIO設定 characteristic
                        // デジタル入出力を担当するPIO全部に出力するようにお願いする
                        if( KONASHI_PIO_SETTING_PINID == characteristics[j].uuid ){
                            console.log("KONASHI_PIO_SETTING_PINID exist!!");
                            KONASHI_CHARACTERISTICS_PIO_SETTINGS = characteristics[j];
                            // PIOを全部出力に空けとく 11111111(255)  ex) 11111110(254)
                            KONASHI_CHARACTERISTICS_PIO_SETTINGS.write(new Buffer([255]), true);
                        }
                        // デジタル出力 characteristic
                        if( KONASHI_PIO_OUTPUT_PINID == characteristics[j].uuid ){
                            console.log("KONASHI_PIO_OUTPUT_PINID exist!!");
                            KONASHI_CHARACTERISTICS_PIO_OUTPUT = characteristics[j];
                        }
                    }

                    // 実際の点滅させるところ
                    setInterval(function(){
                        // ANALOG_READ
                        /*
                        入力を監視 0~1.3でくる(0V~1.3Vという意味)
                        ・ボタンモジュールを押す場合
                            ON = 0.000 / OFF = 1.3 みたいにくる 1.0あたりをしきい値にするといい
                        ・DIMMERつまみモジュールの場合
                            ツマミひねると、0~0.23~0.56~0.89~1.12~1.3 みたいにくる
                        */
                        KONASHI_CHARACTERISTICS_ANALOG_READ.read(function(error, data) {
                            if (data) {
                                console.log( 'value:' + (data[1] + data[0]*256)/1000 );
                            }
                        });
                        // 実際の点滅
                        // DEGITAL OUTPUT PIO2
                        if(led_toggle){
                            // LED ON
                            console.log("LED ON");
                            KONASHI_CHARACTERISTICS_PIO_OUTPUT.write(new Buffer([255]), true);
                        } else {
                            // LED OFF
                            console.log("LED OFF");
                            KONASHI_CHARACTERISTICS_PIO_OUTPUT.write(new Buffer([0]), true);
                        }
                        // LED ON/OFFの反転
                        led_toggle = !led_toggle;
                    }, 1000);

                });

                services[i].discoverIncludedServices();
            }
        }

    });

    // 機器との接続開始
    peripheral.connect();
});

こちらで、アナログ入力が計測でき、デジタル出力でLEDなどOUTPUTモジュールをくっつけると繰り返しON/OFFされます。

Raspberry Piで起動した時の様子です。

nodejs-noble-konashi-connect_2

1秒毎にLED ON/OFFしつつ、アナログ入力を計測してますね。

アナログ入力についてはスライドレバー(SLIDE DIMMER)モジュールでどうなるか図で起こしてみました。

image_20151217_213521_11

つまり、1.3Vを0%~100%で値が来るようになっています。中間50%が0.65あたりになります。

やるとしてチェックタイミングも今の1秒ですと滑らかではないでしょう。0.2秒程度でやれば、きっとスムーズに度合いを伝えることも可能そうです。

また、ボタンモジュールの場合は0.0と1.3になるので、自分が判定する場合は、50%である0.65あたりをしきい値にON/OFFを判断しています。

かなり泥臭いことをやっている+参考記事

本コードかなり泥臭いことをやっているいます。BLEもkonashiもよくわからないまま進めていたので、まず確実性を高めるためにBLE上の全機器を捜索。しかも、konashiをみつけても油断せず、characteristicsについても全部捜索。該当するものを変数に保持して使う挙句に、PIOについても、とりあえず255を与えて全PINを出力に向けてます。

このあたり、もう少し扱いに慣れてくれば、シンプルにしていきたいところです。

そして、nobleの文献は私としては以下の記事がとても参考になりました。

ありがたやありがたや。

余談:いろいろBLE接続くり返していると、デジタル出力だけうまくいかないことがある(原因はまだわからず)

image_20151217_213544_12

これ結構ハマりました。

konashi自体なのかBLE規格のクセかもしれませんが、konashi littleBitsに対していろいろBLE接続くり返していると、デジタル出力だけうまくいかないことがあります。

BLEの専有と解放がうまくいってない予感。 まあ、いろんな機器で取得してみてればそういうこともありますね。

アナログ入力はだいたい取れてるだけに、LEDがつかないわけで、あれー!?コードが悪い???ってなります。

その時は、おちつきましょう。konashiを一旦電源外してOFFにしてリセットしましょう。そうすれば大丈夫でした。

konashi littleBitsの場合はモジュールを一度パチっとはずして付け直します。

image_20151217_213549_13

littleBitsモジュールにすると、こうやってプラスマイナスを気にせず、気軽に接続を外せて試せるところが素敵なところですね。

また、まれにkonashi littleBitsモジュールの先のOUTPUTモジュールの接触不良ってこともあるので、そのあたりはやっぱり付け直しつつトライアンドエラーで行きましょう。

image_20151217_213553_14

基本はkonashiを一旦電源外してOFFにしてリセットで、だいたいなんとかなります。

実戦的には、OFFリセット後なるべく単一の機器(この場合Raspberry Piなど)でkonashiとの確保しくというのも大切そうです。

余談:noble以外にもblenoっていうのがあるけど?

npmライブラリ群で似た名前があったりするのはよくあるのですが、よい記事を見つけました。

しかもnodeのモジュールがある。作者もbleaconと同じ人。
※nobleもblenoも作者が一緒!

一緒の方らしいです。すげー。

nodejs-noble-konashi-connect_3

(他にも気になるライブラリあるなー)

おわりに

いかがでしたでしょうか。

これができると、Raspberry PiがBLEの接続基地として使いつつ、SocketIOサーバーを立てればリアルタイムに色々なことが出来そうです。

それでは、よきRaspberry Pi+NodeJS+BlueTooth Low Energy+littleBits Lifeを!