Raspberry pi に構築したnode.jsで温度センサを取得する


今回は[BMP180](https://www.adafruit.com/products/1603)を使って、node.jsで値を取得する。

## Raspberry pi と BMP180を物理的に接続する
[この方のブログ](http://www.dougpace.com/2014/04/16/raspberry-pi-as-a-temperature-logger/)がすごいよかった。
以下のように接続する


RasPi　　　　　BMP180
3.3V　＜＝＝＞ VIN
GND　 ＜＝＝＞ GND
SCL　 ＜＝＝＞ SCL
SDA　 ＜＝＝＞ SDA

## Raspberry pi でI2Cを使えるようにする

ラズパイで下記のコマンドを打つ

```
sudo nano /etc/modules
```

以下の２文を追記する

```
i2c-bcm2708
i2c-dev
```

ブラックリストからI2Cを除く

```
sudo nano /etc/modprobe.d/raspi-blacklist.conf
```



以下の文に#をつけてコメントアウトを行う
（なければスルーでいいと思います）

```
blacklist i2c-bcm2708
```

それに加えて以下のコマンドを実行し、config.txtの編集を行う

```
sudo vim /boot/config.txt
```

以下を追記する

```
#以下を追記
device_tree=bcm2708-rpi-b.dtb
device_tree_param=i2c1=on
device_tree_param=spi=on
```

必要なソフトウェアのインストール

```
sudo apt-get install i2c-tools
```

リブートを行った

```
sudo shutdown -r now
```

最後に本当に接続できているかの確認を行う

```
sudo i2cdetect -y 1
```
以下の表示が出ればおっけー

```
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- 77                        

```

## BMP180のデータを取得する

一応、BMP180と互換性がある[BMP085](https://www.adafruit.com/products/391)のライブラリが使えるらしく[bmp085](https://www.npmjs.com/package/bmp085)や[bmp085-sensor](https://www.npmjs.com/package/bmp085-sensor)を試したが、動かなかった。

原因はbmp085、bmp085-sensorのnodeライブラリで使われている[i2c](https://www.npmjs.com/package/i2c)ライブラリがnodeのv0.12系で動かないためらしい、しかし[rasp2c](https://www.npmjs.com/package/rasp2c)ライブラリならI2Cの通信が行えるライブラリとして使えるので、Githubに上がっていた[bmp085-sensor](https://github.com/dbridges/bmp085/blob/master/index.js)のコードで[i2c](https://www.npmjs.com/package/i2c)を利用している部分を[rasp2c](https://www.npmjs.com/package/rasp2c)に置き換えた。置き換えたコードが以下


```js:bmp180.js

var async = require('async');
var rasp2c = require('rasp2c');

module.exports = function BMP085(options) {
  var sensor = function() {};
  // var wire = new i2c(options.address);
  var call = {};

  var BMP085_CONTROL_REGISTER  = 0xF4;
  var BMP085_SELECT_TEMP       = 0x2E;
  var BMP085_SELECT_PRESSURE   = 0x34;
  var BMP085_CONVERSION_RESULT = 0xF6;
  var BMP085_XLSB              = 0xF7;

  sensor.scan = function () {
    rasp2c.detect(function(err, result) {
      if (err) {
        console.log(err);
      } else {
        console.log(result);
      }
    });
  };

  function toS16(high, low) {
      if (high > 127)
          high -= 256;
      return (high << 8) + low;
  }

  function toU16(high, low) {
    return (high << 8) + low;
  }

  sensor.calibrate = function () {
    rasp2c.dump(options.address, '0xAA-0xBF', function(err, result) {
      if (err) {
        console.log(err);
      } else {
        console.log(result);
        cal = {
          ac1: toS16(result[0], result[1]),
          ac2: toS16(result[2], result[3]),
          ac3: toS16(result[4], result[5]),
          ac4: toU16(result[6], result[7]),
          ac5: toU16(result[8], result[9]),
          ac6: toU16(result[10], result[11]),
          b1:  toS16(result[12], result[13]),
          b2:  toS16(result[14], result[15]),
          mb:  toS16(result[16], result[17]),
          mc:  toS16(result[18], result[19]),
          md:  toS16(result[20], result[21])
        };
      }
    });
  };

  sensor.read = function (call) {
    async.waterfall([
      function (callback) {
        // Write select pressure command to control register
        rasp2c.set(options.address, BMP085_CONTROL_REGISTER, [BMP085_SELECT_PRESSURE + (options.mode << 6)], function(err, result) {
          if (err) {
            console.log(err);
          } else {
            console.log(result);
          }
        });
        setTimeout(function () {
          callback(null); }, 28);
      },
      function (callback) {
        // Read uncalibrated pressure.
        rasp2c.dump(options.address, '0xF6-0xF8', function(err, result) {
          if (err) {
            console.log(err);
          } else {
            console.log(result);
            callback(null, ((result[0] << 16) + (result[1] << 8) + result[2]) >> (8 - options.mode));
          }
        });
      },
      function (pressure, callback) {
        rasp2c.set(options.address, BMP085_CONTROL_REGISTER, [BMP085_SELECT_TEMP], function(err, result) {
          if (err) {
            console.log(err);
          } else {
            console.log(result);
          }
        });
        setTimeout(function () {
          callback(null, pressure); }, 8);
      },
      function (pressure, callback) {
        rasp2c.dump(options.address, '0xF6-0xF7', function(err, result) {
          if (err) {
            console.log(err);
          } else {
            console.log(result);
            callback(null, [pressure, toU16(result[0], result[1])]);
          }
        });
      }
    ], function (err, res) {
      if (err)
        call(err, {});
      var uncal_pressure = res[0];
      var uncal_temp = res[1];
      
      // Get calibrated temp
      var x1 = 0;
      var x2 = 0;
      var x3 = 0;
      var b3 = 0;
      var b4 = 0;
      var b5 = 0;
      var b6 = 0;
      var b7 = 0;
      var p = 0;

      x1 = ((uncal_temp - cal.ac6) * cal.ac5) >> 15;
      x2 = (cal.mc << 11) / (x1 + cal.md);
      b5 = x1 + x2;
      
      var corrected_temp = ((b5 + 8) >> 4) / 10.0;
      if (options.units !== 'metric'){
        corrected_temp = (9 * corrected_temp / 5) + 32;
      }
      // Get calibrated pressure
      x1 = 0;
      x2 = 0;
      x3 = 0;
      b3 = 0;
      b4 = 0;
      b5 = 0;
      b6 = 0;
      b7 = 0;
      p = 0;

      x1 = ((uncal_temp - cal.ac6) * cal.ac5) >> 15;
      x2 = (cal.mc << 11) / (x1 + cal.md);
      b5 = x1 + x2;

      b6 = b5 - 4000;
      x1 = (cal.b2 * (b6 * b6) >> 12) >> 11;
      x2 = (cal.ac2 * b6) >> 11;
      x3 = x1 + x2;
      b3 = (((cal.ac1 * 4 + x3) << options.mode) + 2) / 4;
      x1 = (cal.ac3 * b6) >> 13;
      x2 = (cal.b1 * ((b6 * b6) >> 12)) >> 16;
      x3 = ((x1 + x2) + 2) >> 2;
      b4 = (cal.ac4 * (x3 + 32768)) >> 15;
      b7 = (uncal_pressure - b3) * (50000 >> options.mode);

      if (b7 < 0x80000000)
          p = (b7 * 2) / b4;
      else
          p = (b7 / b4) * 2;

      x1 = (p >> 8) * (p >> 8);
      x1 = ((x1 * 3038) >> 16);
      x2 = ((-7357 * p) >> 16);
      p = p + ((x1 + x2 + 3791) >> 4);

      if (options.units !== 'metric'){
        p /= 3386.0;
      }
      call(err, {pressure: p,
                 temperature: corrected_temp});
    });
  };

  sensor.calibrate();

  return sensor;
};

```

そしてこれを下記のコードで呼ぶ

```js:example.js
var BMP085 = require('./bmp180.js');

var sensor = BMP085({address: 0x77,
                     mode: 3,
                     units: 'metric'});

sensor.read(function (err, data) {
  console.log("pressure:" +data.pressure);
  console.log("temperature:" +data.temperature);
});

```

すると結果が以下のようになり、情報の取得をおこなえる

```
[ 27,
  93,
  251,
  232,
  199,
  77,
  129,
  185,
  99,
  209,
  70,
  158,
  25,
  115,
  0,
  36,
  128,
  0,
  209,
  246,
  9,
  179 ]
[rasp2c] Raspberry PI revision 000d found
[rasp2c] Using I2C bus 1
[ 157, 164, 128 ]

[ 105, 141 ]
pressure:101143.22125314194
temperature:27.6

```

結構苦労だった・・・