Raspberry PiとSensorTagからMesubluにMQTT通信をする


## CC2650 SensorTag

2015年に発売された新しい[CC2650 SensorTag](http://www.tij.co.jp/tool/jp/cc2650stk)はBLE通信に対応したIoT開発キットです。第1世代のCC2541からバージョンアップして搭載するセンサーも増え省電力化もされているようです。搭載しているセンサーは以下の10種類です。

1. 光
* デジタル・マイク
* 磁気センサ
* 湿度
* 圧力
* 加速度計
* ジャイロスコープ
* 磁力計
* 物体温度
* 周囲温度

 SensorTagを使うとRaspberry PiにBlootoothのUSBアダプターが必要になりますが、面倒なブレッドボードの配線をしなくても簡単にBLE通信でセンサーデータの取得ができます。Raspberry Piで取得したデータはクラウドのメッセージブローカーに送ったり、閾値監視をしてアラートをあげたりとLinuxで好きなように加工することができます。

　Raspberry PiとSensorTagを使ってMQTTブローカーとメッセージの送受信を試してみます。

## Meshblu

　[Meshblu](https://github.com/octoblu/meshblu)は[Octblu](https://www.octoblu.com/)社がオープンソースで開発をしているIoTメッセージングプラットフォームです。[myThings](http://mythings.yahoo.co.jp/)の[「IDCF」チャンネル](http://www.idcf.jp/cloud/iot/)ではMQTTブローカーとして採用されています。HTTP REST、WebSocket、MQTT、CoAPなど複数の通信プロトコルに対応したIoTプラットフォームがいくつかありますが、Mesubluもそのうちの一つです。

　サーバー側で複数のプロトコルをブリッジしてくれるため、Raspberry PiのMQTTクライアントからパブリッシュしたメッセージをブラウザのWebSocketでサブスクライブすることもできます。

### クラウドにセットアップ

　Debian 8.2.0 64-bitまたはUbuntu 14.04 64-bitの仮想マシンを用意します。[こちら](http://qiita.com/masato/items/f9be4a15216fe29de7fb)を参考にしてMesubluをセットアップします。

　`list`コマンドを実行すると初期設定された「デバイス」一覧が表示されます。「デバイス」はMeshbluがIoTデバイスやWebサービス、人を抽象化したものです。「デバイス」のuuidとtokenをRaspberry PiやMQTTクライアントなどMesubluを通してコミュニケーションをとりたいものに割り当てて使います。ここでは「trigger-1」と「action-1」を使いメッセージを送受信します。

```bash
$ docker-compose run --rm iotutil list

> iotutil@0.0.1 start /app
> node app.js "list"

┌───────────┬──────────┬──────────────────────────────────────┐
│ keyword   │ token    │ uuid                                 │
├───────────┼──────────┼──────────────────────────────────────┤
│ trigger-1 │ d286ba8d │ ffa6934d-f1b3-467f-98b3-766b330d436d │
├───────────┼──────────┼──────────────────────────────────────┤
...
├───────────┼──────────┼──────────────────────────────────────┤
│ action-1  │ 8a83d71f │ b61d3398-ac99-4694-9dc4-dd632faf6f6a │
├───────────┼──────────┼──────────────────────────────────────┤
...
```

## Raspberry Pi

　[こちら](http://qiita.com/masato/items/16bf8b17ee4881179462)を参考にしてRaspberry Piがインターネットに接続できる状態から作業を進めます。先ほどクラウドの仮想マシンに割り当てたパブリックIPアドレスを指定してMeshbluの起動を確認します。`{"meshblu":"online"}`と出力すればMeshbluの起動に成功しています。

``` bash
$ curl http://{仮想マシンのパブリックIPアドレス}/status
```

### Node.js

　Node.jsは[node-arm](http://node-arm.herokuapp.com/)からパッケージをダウンロードしてインストールします。執筆時点では`node_latest_armhf.deb`のv4.xがRaspbian
Wheezyで安定して動作しないため`node_latest_armhf.deb`のv.0.12.6を使います。パッケージ名にご注意ください。

``` bash
$ wget http://node-arm.herokuapp.com/node_archive_armhf.deb
$ sudo dpkg -i node_archive_armhf.deb
$ node -v
v0.12.6
```

### Bluetooth

　[BlueZ](http://www.bluez.org/)はLinuxで動作するオープンソースのBluetoothスタックです。Raspbian Wheezyのパッケージマネージャーからインストールできるパッケージは少し古くBLEのサポートに問題があるため、新しいバージョンをソースコードからビルドして使います。最初にビルドに必要なパッケージをインストールします。

``` bash
$ sudo apt-get update
$ sudo apt-get install libdbus-1-dev libdbus-glib-1-dev libglib2.0-dev libical-dev libreadline-dev libudev-dev libusb-dev make
```

　ソースコードをダウンロードしてビルドとインストールをします。

``` bash
$ wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.36.tar.gz
$ tar xvf bluez-5.36.tar.gz
$ cd bluez-5.36
$ ./configure --disable-systemd
$ make
$ sudo make install
```

　hciconfigコマンドを使いBluetoothデバイスを有効にします。

``` bash
$ sudo hciconfig hci0 up
```

## SensorTagからBLE通信

　サンプルコードをダウンロードして必要なパッケージをインストールします。

``` bash
$ git clone https://github.com/masato/meshblu-sensortag.git
$ cd meshblu-sensortag
$ npm install
```

 `config.js`をMesubluのデバイス情報をもとに編集します。パブリックIPアドレスのファイアウォールは1883ポートを開き仮想マシンにポートフォワードしている必要があります。

　センサーデータをMQTTブローカーに送信するクライアントにするためMeshbluの[MQTTクライアントライブラリ](https://github.com/octoblu/node-meshblu-mqtt)を追加します。Raspberry Piのパブリッシュするプログラムにtrigger-1のuuidを割り当て、サブスクライブするプログラムにaction-1デバイスを割り当てます。

```js:config.js
var config = {
    waitTime: 5000,
    trigger_1_uuid: '{trigger-1デバイスのuuid}',
    trigger_1_token: '{trigger-1デバイスのuuid}',
    action_1_uuid: '{action-1デバイスのuuid}',
    action_1_token: '{action-1デバイスのtoken}',
    ip_address: '{仮想マシンのパブリックIPアドレス}',
    port: 1883
}

module.exports = config;
```

　以下のプログラムはRaspberry Piで物体温度(Object Temperature)、周囲温度(Ambient Temperature)、気圧(Pressure)の3つの環境データをSensorTagから取得します。データはJSON形式にフォーマットしてMeshbluのMQTTブローカーにMQTT通信でパブリッシュします。


```js:app-pub.js
'use strict';

var async = require('async'),
    SensorTag = require('sensortag'),
    Meshblu = require('meshblu-mqtt'),
    config = require('./config');

var meshblu = new Meshblu({
    'uuid': config.trigger_1_uuid,
    'token': config.trigger_1_token,
    'hostname': config.ip_address,
    'port': config.port
});

SensorTag.discover(function(sensorTag) {
    console.log('discovered: ' + sensorTag);

    sensorTag.on('disconnect', function() {
        console.log('Tag Disconnected');
        process.exit(0);
    });

    process.on('SIGINT', function() {
        sensorTag.disconnect();
    });

    async.waterfall([
        function(callback) {
            console.log('connectAndSetUp');
            sensorTag.connectAndSetUp(callback);
        },
        function(callback) {
            console.log('enableIrTemperature');
            sensorTag.enableIrTemperature(callback);
        },
        function(callback) {
            console.log('enableBarometricPressure');
            sensorTag.enableBarometricPressure(callback);
        },
        function(callback) {
            setTimeout(callback, 2000);
        },
        function(callback) {
            meshblu.connect(function(response){
                console.log('meshblu ready');
                async.forever(function(callback) {
                    async.series([
                        function(callback) {
                            sensorTag.readIrTemperature(function(error,
                                                                 objectTemperature,
                                                                 ambientTemperature) {
                                var payload = {
                                    objectTemperature: objectTemperature.toFixed(1),
                                    ambientTemperature: ambientTemperature.toFixed(1)
                                };
                                callback(null, payload);
                            });
                        },
                        function(callback) {
                            sensorTag.readBarometricPressure(function(err, pressure){
                                var payload = {
                                    pressure: pressure
                                };
                                callback(null, payload);
                            });
                        }
                    ],
                    function(err, res) {
                        console.log('物体温度: '+ res[0].objectTemperature+' ℃');
                        console.log('周囲温度: '+ res[0].ambientTemperature+' ℃');
                        console.log('気圧    : '+ res[1].pressure+' mBa');

                        meshblu.message({
                            devices: [config.action_1_uuid],
                            topic: 'message',
                            payload: {
                                objectTemperature: res[0].objectTemperature,
                                ambientTemperature: res[1].ambientTemperature,
                                pressure: res[1].pressure
                            }
                        });

                        setTimeout(callback, config.waitTime);
                    });
                },
                function(err) {
                    if (err) throw err;
                });
            });
        }
    ],
    function (err) {
       if (err) throw err;
    });
});
```

　SensorTag本体の横についている電源スイッチを押します。root権限で`npm start`コマンド経由でプログラムを実行するとRaspberry Piでセンサーデータが取得できます。このサンプルでは5秒間隔で計測したデータをMQTTブローカーにパブリッシュして、以下のようなログが標準出力に表示します。


``` bash
$ sudo npm start
物体温度: 16.4 ℃
周囲温度: 23.9 ℃
気圧    : 1020.98 mBa
```

## MQTTメッセージのサブスクライブ

　MQTTではブローカーが仲介してクライアント間でメッセージを送受信します。まずはRaspberry PiにMQTTクライアントの[Mosquitto](http://mosquitto.org/)をインストールしてメッセージのサブスクライブをテストします。

``` bash
$ sudo apt-get update
$ sudo apt-get mosquitto-clients
```

　Mosquittoクライアントにも同様にデバイスのuuidを割り当てます。trigger-1が送信したメッセージを受信するため、Mosquittoクライアントにはaction-1デバイスのuuidを割り当てます。

``` bash
$ mosquitto_sub \
  -h {仮想マシンのパブリックIPアドレス}  \
  -p 1883  \
  -t {action-1デバイスのuuid} \
  -u {action-1デバイスのuuid}  \
  -P {action-1デバイスのtoken}  \
  -d
```

　MQTTブローカーからサブスクライブしたメッセージが標準出力されます。

```bash
Subscribed (mid: 1): 0
 Received PUBLISH (d0, q0, r0, m0, '{action-1デバイスのuuid}', ... (257 bytes))
  {"topic":"message","data":{"devices":["{action-1デバイスのuuid}"],"topic":"message","payload":{"objectTemperature":"16.3","ambientTemperature":"23.1","pressure":1022.14},"callbackId":"8ebdc270-95b8-11e5-943c-e1cfdbaddec8","fromUuid":"{trigger-1デバイスのuuid}"}}
```

　次にNode.jsのプログラムを実行して同様にセンサーデータ取得してみます。

```js
'use strict';

var async = require('async'),
    Meshblu = require('meshblu-mqtt'),
    config = require('./config');

var meshblu = new Meshblu({
    'uuid': config.action_1_uuid,
    'token': config.action_1_token,
    'hostname': config.ip_address,
    'port': config.port
});

meshblu.on('message', function(message){
    console.log(message);
});
```

　Mosquittoクライアントと同様にaction-1デバイスのuuidを使いメッセージをサブスクライブしたメッセージが標準出力に表示されました。

```bash
$ npm run sub
{ devices: [ '{action-1デバイスのuuid}' ],
  topic: 'message',
  payload:
   { objectTemperature: '16.5',
     ambientTemperature: '22.9',
     pressure: 1022.19 },
  callbackId: '79da6970-95be-11e5-b0c4-e15124f00dff',
  fromUuid: 'trigger-1デバイスのuuid' }
```

## いろいろなデバイスをmyThingsにつなげるために

　コネクテッドデバイスをMeshbluと接続するには今回説明したようなuuidを間接的に割り当てる方法がプリミティブですが汎用的です。最後に他の方法をご紹介します。

 [Gateblu](https://gateblu.octoblu.com/)はインターネットに接続していないデバイスをMeshbluとコミュニケーション可能にするソフトウェアです。WindowsやOSXにインストールして使います。ホームオートメーションや[AllJoyn](https://allseenalliance.org/framework)のゲートウェイとして機能するので「IDCF」チャンネルと連携すれば多くの対応デバイスをmyThingsと組み合わせることができそうです。

　[Tentacle](https://tentacle.readme.io/)はマイコン用のライブラリです。[Arduino Uno](https://www.arduino.cc/en/Main/arduinoBoardUno)や[Particle](https://store.particle.io/)の[Photon](https://store.particle.io/?product=particle-photon)などのArduino互換のマイコンにArduino IDEからスケッチとしてインストールします。[Octoblu Disignerを使う](https://www.hackster.io/redaphid/code-free-iot-with-arduino-and-the-tentacle-on-octoblu-2774eb)とコードを書かずにブラウザのGUIからフローとピンの制御ができるようになります。

　何かの条件を満たしたら、何かの処理を実行するというmyThingsのイベント駆動の考え方は身近なマイクロサービスの良い例です。多くのデバイスやサービスをインターネットにつなげ、もっと簡単にタスクやワーカーを実行させる方法を考えていきたいと思います。