さくらIoT x node-RED on Bluemix で会議室の空き状況を表示させるまでの3日間(2.5日目)

[1日目](http://qiita.com/kkoiwai/items/196cf8136c5a633493c0) では、IBM BluemixにNode-REDを導入し、WebSocketでデータを受信して、Ambientというグラフ表示サービスにデータを連携するところまで進みました。
[2日目](http://qiita.com/kkoiwai/items/7b311708c42dbdae6aca)では、受信したデータをNoSQL DB(Cloudant)にとりあえず保存するのと、Webサイトを作るところまで行きました。
[3日目](http://qiita.com/kkoiwai/items/3b0f2acaadd81128ae7a)で、保存したデータを読める形にして、利用率を計算しました。
時間が前後してしまいましたが、さくらIoT Platformが無事届きましたので、Arduioを使って、実際に接続してみたいと思います。

結果から言うと、Node-RED部分は（ほぼ）想定通り動きました！！

---

目次

- Arduinoとの合体
- Arduinoのプログラム
- Node-REDとの接続
 - 不要なkeepaliveをフィルターする
- ドアセンサの接続

---

## Arduinoとの合体

ここは、[さくらのIoT Platform βをArduinoと繋げてWebSocketサービスに連携するまで](http://qiita.com/Lupin3/items/96e6e0ddfda8147ff035)を参考にさせて頂きました。
[最後の手順](http://qiita.com/Lupin3/items/96e6e0ddfda8147ff035#5arduino%E3%81%AB%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%82%80)にあるとおり、Arduinoのライブラリに、[公式のサンプルプログラム](https://github.com/sakura-internet/SakuraIOArduino/blob/master/examples/Standard/Standard.ino)をインストールしておかないと、コンパイルできません。

<img width="712" alt="スクリーンショット 2017-01-15 15.08.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/135431/7bc67a20-bff8-10fe-66f1-93aded893ffc.png">


## Arduinoのプログラム

[公式のサンプルプログラム](https://github.com/sakura-internet/SakuraIOArduino/blob/master/examples/Standard/Standard.ino)をほとんどそのまま使わせてもらいました。GitHubはこちら。

https://github.com/kkoiwai/SakuraIoT_DoorSensor

IoT Platformには、128のチャンネルがあり、そのチャンネルそれぞれに、8バイト（オクテット）のデータを送ることができます。

当社の会議室は、利用中以外はドアを開けておくルールになっています。
なので、Arduinoにドアセンサ（[こんなの](http://akizukidenshi.com/catalog/g/gP-04025/)）を接続して、一つの部屋にひとつのチャンネルを割り当て、ドアが開いていればゼロ、ドアが閉まっていればイチを送るようにしました。

また、なるべくリアルタイムにデータを取得できるよう、5秒おきにループを回すことにしたのですが、毎回通信していたらそれなりに通信量がかさんでしまうので、状態が変わったときにだけデータを送ることにします。

---

```c
#include <SakuraIO.h>

SakuraIO_I2C sakuraio;

// 接続するセンサの数
const int numSensors = 3;

// ドアセンサを接続するArduino上のピン
const int connectedPins[] = {2,3,4};

// 上記sensorPinに該当するチャンネル
const int dataChannels[] = {0,1,2};

// 上記sensorPinの前回の値 (0:ドア開放 1:ドア閉扉）
int prevStatus[numSensors];

void setup() {

  // さくらIoTのセットアップ
  Serial.begin(9600);
  Serial.print("Waiting to come online");
  for(;;){
    if( (sakuraio.getConnectionStatus() & 0x80) == 0x80 ) break;
    Serial.print(".");
    delay(1000);
  }
  Serial.println("");

  
  uint8_t request[33] = {};
  uint8_t response[33] = {};


  // ProductID
  uint16_t pid = sakuraio.getProductID();
  Serial.print("PID ");
  Serial.println(pid);

  // UniqueID
  sakuraio.getUniqueID((char *)response);
  Serial.print("UID ");
  Serial.println((char *)response);

  // Version
  sakuraio.getFirmwareVersion((char *)response);
  Serial.print("Ver ");
  Serial.println((char *)response);

  // Connection Status
  uint8_t connectionStatus = sakuraio.getConnectionStatus();
  Serial.print("Status ");
  Serial.println(connectionStatus);

  //getSignalQuarity
  uint8_t signalQuarity = sakuraio.getSignalQuarity();
  Serial.print("Quality ");
  Serial.println(signalQuarity);


  // センサーピンの設定
  // Pullup抵抗を接続するのが面倒なので、INPUTではなくINPUT_PULLUPを設定。
  // ただしOn/OffとHIGH/LOWが逆になる点に注意。
  
  for(int i =0; i < numSensors; i++){
    pinMode(connectedPins[i], INPUT_PULLUP);
  }
  
}


void loop() {

  // Unixtime
  uint32_t unixtime = (uint32_t)(sakuraio.getUnixtime()/1000UL);
  Serial.print("Unixtime ");
  Serial.println(unixtime);

  // Tx Queue
  uint8_t ret;
  
 int currentPinStatus;

for(int i =0; i < numSensors; i++){
    // 現時点のドアセンサの状態を取得
    // INPUT_PULLUPなので、HIGH=off(0), LOW=on(1)
    if( digitalRead(connectedPins[i])== HIGH) {
      currentPinStatus = 0;
    }else{
      currentPinStatus = 1;
    }

    // もし前回の値と異なっていたら、queueに登録
    if( prevStatus[i] != currentPinStatus) {
      prevStatus[i] = currentPinStatus;
      Serial.print("Enqueue (Pin");
      Serial.print(connectedPins[i]);
      Serial.print(") ");
      Serial.println(currentPinStatus);
      
      ret = sakuraio.enqueueTx((uint8_t)dataChannels[i], (int32_t)currentPinStatus);
      Serial.println(ret);
    }
  }

  uint8_t avail;
  uint8_t queued;
  sakuraio.getTxQueueLength(&avail, &queued);
  Serial.print("Tx Available=");
  Serial.print(avail);
  Serial.print(" Queued=");
  Serial.println(queued);

  // queue に溜まっていたら送信
  if(queued > 0){
    ret = sakuraio.send();
    Serial.print("Send ");
    Serial.println(ret);
  }

  delay(5000);
}
```
---

## Node-REDとの接続

なんてこと無い、1日目に作ったWebSocket受信ノードのアドレスを変更するだけです。
<img width="205" alt="スクリーンショット 2017-01-14 17.58.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/135431/3fabef91-4b06-73de-fa37-199e23760bbb.png">

<img width="446" alt="スクリーンショット 2017-01-14 17.57.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/135431/9a139400-9c04-ff21-70a5-20adc4d10a72.png">


<img width="830" alt="スクリーンショット 2017-01-14 18.07.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/135431/8eaf2b9a-4574-e335-1806-712ca82224a1.png">

---

###不要な情報をフィルターする

実際に接続してみると、数秒おきに、keepaliveが飛んでくるので、これを無視するように、フィルターを追加しました。

<img width="398" alt="スクリーンショット 2017-01-14 18.08.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/135431/f350a8e6-a17b-c33f-4b2d-1039c7588fbc.png">

<img width="830" alt="スクリーンショット 2017-01-14 18.07.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/135431/6f2cc91f-f12c-e356-4130-5ffe4f89c6b9.png">

「更新情報のみ保存」の中身

```js
if( msg.payload.type =="channels" ){
    return msg;
}else{
    msg.payload = null;
    return null;
}
```

モジュール全体

```js
[{"id":"99a2e322.3dbee","type":"websocket in","z":"396465eb.1d8e22","name":"WebSocket (sakura)","server":"","client":"df973c4.18d10c","x":114,"y":2071,"wires":[["1dc0a90b.5a5a7f","79fb8120.0b87c"]]},{"id":"1dc0a90b.5a5a7f","type":"debug","z":"396465eb.1d8e22","name":"WebSocket受信データ","active":true,"console":"false","complete":"payload","x":169.03572409493586,"y":2142.2857789993286,"wires":[]},{"id":"52487252.24dfdc","type":"function","z":"396465eb.1d8e22","name":"Global変数の更新","func":" msg.payload.payload.channels.forEach(function(v) {\n     context.global.data[v.channel] = v.value;\n\n});\n\nmsg.payload = JSON.stringify(context.global.data);\n\nreturn msg;","outputs":1,"noerr":0,"x":439.46428244454523,"y":2141.2142763137817,"wires":[["a45c41fa.5c5e5"]]},{"id":"a45c41fa.5c5e5","type":"debug","z":"396465eb.1d8e22","name":"Global変数に保存された値","active":true,"console":"false","complete":"payload","x":675.4642824445452,"y":2140.7142763137817,"wires":[]},{"id":"79fb8120.0b87c","type":"json","z":"396465eb.1d8e22","name":"","x":319.58928244454523,"y":2072.2142763137817,"wires":[["bff12351.e8cac8"]]},{"id":"3350a9c9.c1dafe","type":"cloudant out","z":"396465eb.1d8e22","name":"Cloudantへ保存","cloudant":"","database":"iot_data","service":"IOTテスト-cloudantNoSQLDB","payonly":true,"operation":"insert","x":712.2142824445452,"y":2072.7142763137817,"wires":[]},{"id":"bff12351.e8cac8","type":"function","z":"396465eb.1d8e22","name":"更新情報のみ保存","func":"if( msg.payload.type ==\"channels\" ){\n    return msg;\n}else{\n    msg.payload = null;\n    return null;\n}","outputs":1,"noerr":0,"x":491.71428244454523,"y":2071.7142763137817,"wires":[["3350a9c9.c1dafe","52487252.24dfdc"]]},{"id":"a545b0a9.1ad358","type":"comment","z":"396465eb.1d8e22","name":"さくらIoT Platform から受信","info":"","x":147.57143729073664,"y":2021,"wires":[]},{"id":"df973c4.18d10c","type":"websocket-client","z":"","path":"wss://api.sakura.io/ws/v1/xxxxxxxxxxxxxxx","wholemsg":"false"}]
```

---

##ドアセンサの接続

arduinoのソースコードで、2,3,4 ピンを使うように設定しています。
それらのピンと、GNDのピンを、それぞれドアセンサを接続します。
<img width="597" alt="スクリーンショット 2017-01-14 18.26.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/135431/b1ef52e2-f35e-e6fa-f1ba-7957202b5451.png">

ドアセンサのリード線には、こちらの　[TJC8コネクタ](http://akizukidenshi.com/catalog/g/gC-09247/)を半田付けしました。

![File_000.jpg](https://qiita-image-store.s3.amazonaws.com/0/135431/5f9d309e-ae3d-f833-9c15-9b3e73c43322.jpeg)




試しに、2ピンをGNDとショートさせると、こんな感じで、空き状況が分かるようになりました。
<img width="475" alt="スクリーンショット 2017-01-14 18.28.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/135431/6386e93e-63f9-ce9d-586c-72b11b4f9bfb.png">


## 戻る

[1日目](http://qiita.com/kkoiwai/items/196cf8136c5a633493c0) - IBM BluemixにNode-REDを導入し、WebSocketでデータを受信して、Ambientというグラフ表示サービスにデータを連携するところまで
[2日目](http://qiita.com/kkoiwai/items/7b311708c42dbdae6aca) - 受信したデータをNoSQL DB(Cloudant)にとりあえず保存するのと、Webサイトを作るところまで
[3日目](http://qiita.com/kkoiwai/items/3b0f2acaadd81128ae7a) - 保存したデータを読める形にして、利用率を計算するところまで