BME280とElasticserchを使って可視化してみよう


はじめに

温湿度・気圧センサモジュールであるBME280から取得したデータを、Elasticsearchにデータを投入して、Kibanaで分析するまでをやってみました。

こんな感じを目指します。

このスクリーンショットでは、センサーを2台しており、1台は有線で、もう1台は無線でデータ飛ばしています。
無線の方は、こちらの記事を参照してください。

必要なもの

作業に必要なものを揃えます。

  • BME280
  • ラズパイ
  • ElasticsearchとKibana

BME280

センサーですが、秋月電子通商さんからお買い上げしましょう。
このセンサーは、半田ごてが必要になります。ちょっとハードルが高いかもしれませんが、マイコンには最低限必要なスキルなので、出来るようになっていた方が良いです。

BME280使用 温湿度・気圧センサモジュールキット
http://akizukidenshi.com/catalog/g/gK-09421/

ラズパイ

GPIOが使えるラズパイを用意します。
セットアップ、I2Cの初期設定は記載しませんので、事前に済ませておいてください。
こちらを参考にしてください。

第39回「ラズベリーパイで温度・湿度・気圧をまとめて取得!AE-BME280でIC2通信」
https://deviceplus.jp/hobby/raspberrypi_entry_039/

ElasticsearchとKibana

色々な起動方法がありますが、Amazon Elasticsearch Serviceを使いました。
Amazon ESは、若干高めのサービスですが、マネージドサービスなので、運用面では比較的楽じゃないかなぁと思います。
コンソールでポチポチやれば、10分程度でインスタンスが作成できます。
以前は、EC2とかECS、オンプレでもやってましたが、運用周りが大変でしたので、それを考えると安いのかもしれません。

ラズパイでロジック作成

今回はNode.jsを使います。
Pythonでもやっていたのですが、Node.jsもなかなか書きやすいなぁと言った感じです。
非同期処理の部分が非常にわかりにくいのが難点ですが・・・。

ラズパイに適当にディレクトリを作成し、サクサク作業していきます。
Node.js、npmのインストールは、ここでは割愛します。

$ npm init
(エコーのところは割愛します)

必要なパッケージを追加します。

$ npm install --save bme280-sensor
$ npm install --save date-utils
$ npm install --save request

こんな感じになりました。

package.json
{
  "name": "bme280_nodejs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "bme280-sensor": "^0.1.6",
    "date-utils": "^1.2.21",
    "request": "^2.88.0",
  }
}

サンプルソースを参考に、ElasticsearchへのPUT部分を追記します。
https://www.npmjs.com/package/bme280-sensor

1秒おきにPUTしても・・・ということで、2分おきにPUTします。
keyの部分は、インデックスが肥大化しないように分割しようと思っていたのですが、とりあえずユニークなidとして使いました。
Node.jsの非同期処理がきちんと出来ていないと思うので、本気で使うときは注意してください。
あとでちゃんとやります。ごめんなさい。

index.js
require('date-utils');
var webclient = require("request");
const BME280 = require('bme280-sensor');

// The BME280 constructor options are optional.
// 
const options = {
  i2cBusNo   : 1, // defaults to 1
  i2cAddress : 0x76
};

const bme280 = new BME280(options);

// Read BME280 sensor data, repeat
//
const readSensorData = () => {
  bme280.readSensorData()
    .then((data) => {
      // temperature_C, pressure_hPa, and humidity are returned by default.
      // I'll also calculate some unit conversions for display purposes.
      //
      data.temperature_F = BME280.convertCelciusToFahrenheit(data.temperature_C);
      data.pressure_inHg = BME280.convertHectopascalToInchesOfMercury(data.pressure_hPa);

      console.log(`data = ${JSON.stringify(data, null, 2)}`);
      espost(data);
      setTimeout(readSensorData, 2000 * 60);
    })
    .catch((err) => {
      console.log(`BME280 read error: ${err}`);
      setTimeout(readSensorData, 2000 * 60);
    });
};

function espost(data) {
    var jdata = {};
    jdata.temperature = Math.round(data.temperature_C * 10)/10;
    jdata.humidity = Math.round(data.humidity * 10)/10;
    jdata.pressure_hPa = Math.round(data.pressure_hPa * 10)/10;
    var dt = new Date();
    jdata.dtjst = dt.toFormat("YYYY-MM-DDTHH24:MI:SS+0900");
    console.log(JSON.stringify(jdata));
    var key = dt.toFormat("YYYYMMDDHH24MISS");
    webclient({
      method: 'PUT',
      url: "https://xxx.yyy.zz/aaa/bbb/" + key,
      headers: {
        "content-type": "application/json"
      },
      body: JSON.stringify(jdata)
      }, function (error, response, body){
        console.log(body);
    });
}

// Initialize the BME280 sensor
//
bme280.init()
  .then(() => {
    console.log('BME280 initialization succeeded');
    readSensorData();
  })
  .catch((err) => console.error(`BME280 initialization failed: ${err} `));

なんとなく出来たら、起動してみましょう。
センサーから値を取れていれば、コンソールにログが表示されるはずです。

$ node index.js
{"temperature":26.1,"humidity":36.1,"pressure_hPa":1012.5,"dtjst":"2018-12-05T10:59:22+0900"}

可視化

Kibanaを使って可視化してみましょう。
詳しい操作は割愛しますが、Kibanaで見れるようにインデックスに追加します。

あとはVisualizeでグラフを作ったり、いろいろやってみてください。