node.js(Johnny-Five)でBME280(温度/湿度/気圧)センサの値をクラウドに保存する


BME280は1チップのセンサICで温度と湿度、気圧の3つの値を取得できます。 
通信方法はI2CとSPIが選択できるが、ここではI2C接続とします。
スイッチサイエンスや秋月電子などから購入できます。
![BME280.jpg](https://qiita-image-store.s3.amazonaws.com/0/11566/611c52bc-5ff3-fb69-a506-b02772f6bb59.jpeg)
ここでは秋月電子から購入しました。I2C接続するために予めJ3はジャンパします。


johnny-fiveはNode.js上のフレームワーク(モジュール)です。
Firmataプロトコルを使って、ホスト(Windows,Mac,linux､ラズパイなど)からArduinoなどのマイコンを
制御することができます。

[Examples](hhttp://johnny-five.io/examples/)にはBME280に参考例が見当たらないが、
[公式サイトjohnny-five.io](http://johnny-five.io/news/) にはv0.9.45からBME280に対応しているようである。

今回はNiftyクラウドに保存します。

###検証

以下の接続する。
 BME280 　　     Arduino
 VCC    　<-> VCC(3.3V)
 SCK    　<-> A5
 SDI    　<-> A4
 GND    　<-> GND

Arduino Nano(互換)にfirmataを書き込み済みとする。
ホストはwindows7で試す

コマンドプロンプト(PwerShell)で作業用ディレクトリを開く。
「node -v 」 で　node.jsがインストール済みなのを確認する
「npm i johnny-five 」　でjohnny-fiveモジュールをインストールする。

以下　検証コード

```js:bme280.js
var five = require("johnny-five");
var board = new five.Board("COM8"); //ポート名指定はWindowsで必要なため、
board.on('ready', function () {
  var bme280 = new five.IMU({
    controller: "BME280",
    address: 0x76, // optional    
  });
  bme280.on("data", function(e,data) {
	if( this.barometer.pressure >90 ){		//気圧の初回値が変なので、異常値は読み飛ばす
		console.log("  celsius(摂氏)      : ", this.temperature.celsius);
		console.log("  fahrenheit(華氏)   : ", this.temperature.fahrenheit);
		console.log("  pressure(hPa)     : ", this.barometer.pressure *10);
		console.log("  relative humidity(相対湿度) : ", this.hygrometer.relativeHumidity);
		console.log("--------------------------------------");
		process.exit(); //終了
	}
  });
})
```

※this.barometer.pressureを10倍しているのはKpaで返されるため。

###実行結果

```code
PS C:\Users\XX\Documents\nodebots\mysolution>node  .\BME280.js
1467475451763 SerialPort COM8
1467475451771 Connected COM8
1467475456184 Repl Initialized
  celsius(摂氏)      :  27.7
  fahrenheit(華氏)   :  81.86
  pressure(hPa)     :  1006.3599999999999
  relative humidity(相対湿度) :  58.094
```
正常に取得できるようであるが、初回だけ気圧の値がおかしいので読み飛ばすようにした。

###　ラズパイをホストにする。
Raspberry PiとArduinoをUSBケーブルで接続します。

**node -v** でnode.jsのバージョンを確認します。
もし、0.x系なら、ラズパイのnode.jsが古いので、入れ換えます。
手順は
 http://make.kosakalab.com/make/electronic-work/nodejs_raspi/ 
を参考にしました。
詳細な手順は省略しますが、現時点での最新版のv6.2.2にします、

johnny-fiveパッケージのインストール
$ npm install johnny-five

前出の検証コードを実行してみます。

```code
pi@raspberrypi:~/work$ node bme280.js
1467490740052 Device(s) /dev/ttyUSB0
1467490740181 Connected /dev/ttyUSB0
1467490744655 Repl Initialized
  celsius(摂氏)      :  28.66
  fahrenheit(華氏)   :  83.59
  pressure(hPa)     :  1005.8499999999999
  relative humidity(相対湿度) :  64.082
--------------------------------------
```

nifty cloud に保存するためNifty　SDKインストールする。

npm install ncmb --save
以下のファイルを作成
＞var ncmb = new NCMB("アプリケーションキー","クライアントキー");
アプリ毎に付与されたアプリケーションキー,クライアントキーです。詳しくはnifty クラウドを参照


```js:temp2.js
/**
 BME280      Arduino
*/
var NCMB = require("ncmb");
var ncmb = new NCMB("アプリケーションキー","クライアントキー");

var five = require("johnny-five");
var board = new five.Board();

board.on('ready', function () {
  var bme280 = new five.IMU({
    controller: "BME280",
    address: 0x76,      // optional
    freq:1000 * 60      // optional
  });
var TempLog = ncmb.DataStore("Temperature2") ;
  bme280.on("data", function(e,data) {
        if( this.barometer.pressure >90 ){              //気圧の初回値が変なので、異常値は読み飛ばす
                console.log("  celsius(摂氏)      : ", this.temperature.celsius);
                console.log("  fahrenheit(華氏)   : ", this.temperature.fahrenheit);
                console.log("  pressure(hPa)     : ", this.barometer.pressure *10);
                console.log("  relative humidity(相対湿度) : ", this.hygrometer.relativeHumidity);
                console.log("--------------------------------------");
                 var tempLog = new TempLog() ;
                 tempLog
                 .set("date",(new Date()))
                 .set("celsius",this.temperature.celsius)
                 .set("pressure",this.barometer.pressure *10)
                 .set("humidity",this.hygrometer.relativeHumidity)
                 .save()
                 .then(function(tempLog){
                   console.log("message is saved.");
                   return  tempLog.update();
                 })
                .then(function(tempLog){
               });
        }
  });
})
board.on("error", function(err) {
        console.log("There was an error" + err);
});
```

** node temp2.js ** として実行します。

ニフティの管理画面でデータを確認します。

![FireShot Capture 9 - ニフティクラウドmobile backend_ - https___console.mb.cloud.nifty.com_.jpg](https://qiita-image-store.s3.amazonaws.com/0/11566/c9577f70-a2ec-0c00-c31c-30ae2b8e8e45.jpeg)

### ブラウザで表示してみる。

http://mb.cloud.nifty.com/doc/current/index.html
からncmb.min.jsをダウンロードする。

下記のようなテストのhtmlを作成する

```html
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <script src="ncmb.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script>
    <style>
    canvas{
        -moz-user-select: none;
        -webkit-user-select: none;
        -ms-user-select: none;
    }
    </style>
    <script>
        var data1 = {
            labels: [],
            datasets: [
                {
                    label: "Prime and Fibonacci1",
                    fillColor: "rgba(251,180,120,0.6)",
                    strokeColor: "rgba(254,230,170,1)",
                    pointColor: "rgba(254,230,124,1)",
                    pointStrokeColor: "#fff",
                    pointHighlightFill: "#fff",
                    pointHighlightStroke: "rgba(220,220,220,0.5)",
                    data: []
                }
            ]
        };
        var data2 = {
            labels: [],
            datasets: [
                {
                    label: "Prime and Fibonacci2",
                    fillColor: "rgba(251,120,196,0.6)",
                    strokeColor: "rgba(120,230,170,1)",
                    pointColor: "rgba(254,230,170,1)",
                    pointStrokeColor: "#fff",
                    pointHighlightFill: "#fff",
                    pointHighlightStroke: "rgba(220,220,220,0.5)",
                    data: []
                }
            ]
        };
        var data3 = {
            labels: [],
            datasets: [
                {
                    label: "Prime and Fibonacci3",
                    fillColor: "rgba(80,240,196,0.6)",
                    strokeColor: "rgba(254,230,170,1)",
                    pointColor: "rgba(254,120,170,1)",
                    pointStrokeColor: "#fff",
                    pointHighlightFill: "#fff",
                    pointHighlightStroke: "rgba(220,220,220,0.5)",
                    data: []
                }
            ]
        };


      function displayLineChart() {       
        var ncmb = new NCMB("アプリケーションキー","クライアントキー");
        var Temperature = ncmb.DataStore("Temperature2");
		        Temperature.order("date", true)
                .limit(120)
                .fetchAll()
                .then(function(results){
                    console.log("Successfully retrieved " + results.length );
                    for (var i = 0; i < results.length; i++) {
                        var object = results[i];
					    console.log(object.date.iso);
                        data1.labels[i] = i;
                        data2.labels[i] = i;
                        data3.labels[i] = i;
                        data1.datasets[0].data[i] =  object.celsius;
                        data2.datasets[0].data[i] =  object.pressure;
                        data3.datasets[0].data[i] =  object.humidity;
                    }
                    var ctx = document.getElementById("lineChart1").getContext("2d");
                    var options = { };
                    var lineChart = new Chart(ctx).Line(data1, {
                        scaleShowVerticalLines: false,
                        scaleShowHorizontalLines: false,
                        scaleOverride : true,
                        scaleSteps : 25,
                        scaleStepWidth : 0.5,
                        scaleStartValue : 20, 
                    });

                    var ctx = document.getElementById("lineChart2").getContext("2d");
                    var options = { };
                    var lineChart = new Chart(ctx).Line(data2, {
                        scaleShowVerticalLines: false,
                        scaleShowHorizontalLines: false,
                        scaleOverride : true,
                        scaleSteps : 25,
                        scaleStepWidth : 1.0,
                        scaleStartValue : 995, 
                    });

                    var ctx = document.getElementById("lineChart3").getContext("2d");
                    var options = { };
                    var lineChart = new Chart(ctx).Line(data3, {
                        scaleShowVerticalLines: false,
                        scaleShowHorizontalLines: false,
                        scaleOverride : true,
                        scaleSteps : 90,
                        scaleStepWidth : 1,
                        scaleStartValue : 10, 
                    });

                })
                .catch(function(err){
                    console.log(err);
                });
      }
    </script>
</head>
<body onload="displayLineChart();">
    <div class="box">
        <p><canvas id="lineChart1" height="250" width="720"></canvas></p>
        <p><canvas id="lineChart2" height="250" width="720"></canvas></p>
        <p><canvas id="lineChart3" height="250" width="720"></canvas></p>
    </div>
</body>
```

ローカル、またはサーバーにアップして、グラフ表示されればｏｋ。
小数点桁数を揃えてないなど、雑な表示であるがデータ確認が目的なのでとりあえず、よしとする。



以上