センサーで生活の乱れを可視化してみた( RaspberryPi + fluentd + Elasticsearch + Kibana )

# 1. はじめに
私生活を可視化することで、生活の乱れの改善につなげたいと思います。
お部屋に設置したセンサーから得られたデータ(光、音、温度)をKibanaでダッシュボード化しました。

* 書いたこと：データ取得用のスクリプトや、設定ファイルの内容 (ざっくり)
* 書いていないこと：諸々のインストールの方法

# 2. 全体の構成
![image.png](https://qiita-image-store.s3.amazonaws.com/0/18646/1049c0cc-9d9d-90a7-122e-67765959d171.png)


# 3. Sensor side

### 3-1. 環境
本体をテレビの影に隠しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/18646/d92cb4d8-3b4e-320b-e01e-f79f9645e5d1.png)

* ハードウェア
    * Raspberry Pi 3 ModelB
    * GrovePi+
    * Grove - Light Sensor
    * Grove - Sound Sensor
    * Grove - Temperature Sensor V1.2
* OS
    * RASPBIAN STRETCH LITE 9.1
* fluentd 0.12.40


### 3-2. センサーデータの取得
センサーデータを読み込むためのスクリプトを準備します。

```py:myroom.py
#!/usr/bin/python -u

from datetime import datetime
import numpy
import time
import grovepi
import math
import json

light_sensor = 0  # A0
sound_sensor = 1  # A1
temp_sensor  = 2  # A2

light_sensor_samples = 10
sound_sensor_samples = 5000
temp_sensor_samples  = 10
temp_sensor_version  = "1.2"

def get_light_level(analog_sensor):
    samples = []
    for i in range(light_sensor_samples):
        samples.append(grovepi.analogRead(analog_sensor))
    return numpy.median(samples)

def get_sound_level(analog_sensor):
    samples = []
    for i in range(sound_sensor_samples):
        samples.append(grovepi.analogRead(analog_sensor))
    return max(samples)

def get_temp_level(analog_sensor, version):
    samples = []
    for i in range(temp_sensor_samples):
        samples.append(grovepi.temp(analog_sensor, version))
    return numpy.median(samples)

if __name__ == '__main__':
    grovepi.pinMode(light_sensor,"INPUT")
    grovepi.pinMode(sound_sensor,"INPUT")
    grovepi.pinMode(temp_sensor,"INPUT")

    while True:
        light = get_light_level(light_sensor)
        sound = get_sound_level(sound_sensor)
        temp  = get_temp_level(temp_sensor, temp_sensor_version)
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        date = datetime.now().strftime("%Y-%m-%d")
        hour = int(datetime.now().strftime("%H"))
        wday = int(datetime.now().weekday())

        json_data = {
                "timestamp": timestamp,
                "hour": hour,
                "wday": wday,
                "light": light,
                "sound": sound,
                "temp": temp
                }
        encode_json_data = json.dumps(json_data)
        print encode_json_data
```

<br>
上記のスクリプトを実行して、標準出力をファイルに書き出します。

```bash
sudo python -u ./myroom.py >> /home/pi/myroom.log &
```

<br>
出力は以下のようになります。

```bash
$ tail /home/pi/myroom.log
{"sound": 255, "hour": 1, "temp": 18.82680514639611, "timestamp": "2017-10-18 01:18:37", "light": 566.0, "wday": 2}
{"sound": 255, "hour": 1, "temp": 18.82680514639611, "timestamp": "2017-10-18 01:19:10", "light": 554.0, "wday": 2}
{"sound": 375, "hour": 1, "temp": 18.82680514639611, "timestamp": "2017-10-18 01:19:43", "light": 564.0, "wday": 2}
{"sound": 255, "hour": 1, "temp": 18.82680514639611, "timestamp": "2017-10-18 01:20:16", "light": 554.0, "wday": 2}
{"sound": 255, "hour": 1, "temp": 18.82680514639611, "timestamp": "2017-10-18 01:20:48", "light": 566.5, "wday": 2}
{"sound": 259, "hour": 1, "temp": 18.82680514639611, "timestamp": "2017-10-18 01:21:21", "light": 557.5, "wday": 2}
{"sound": 255, "hour": 1, "temp": 18.82680514639611, "timestamp": "2017-10-18 01:21:54", "light": 568.0, "wday": 2}
{"sound": 255, "hour": 1, "temp": 18.82680514639611, "timestamp": "2017-10-18 01:22:27", "light": 555.0, "wday": 2}
{"sound": 255, "hour": 1, "temp": 18.82680514639611, "timestamp": "2017-10-18 01:22:59", "light": 555.0, "wday": 2}
{"sound": 255, "hour": 1, "temp": 18.82680514639611, "timestamp": "2017-10-18 01:23:32", "light": 552.0, "wday": 2}
```

### 3-3. fluentdの設定
fluentdの設定ファイルを準備します。
上記で出力したデータの増分を Server side の fluentd に forward します。

```:/home/pi/fluent/fluent.conf
<source>
  @type tail
  format json
  path /home/pi/myroom.log
  pos_file /home/pi/myroom.log.pos
  tag log.myroom
</source>

<match log.myroom>
  @type forward
  buffer_type file
  buffer_path /tmp/testlog-tmp.log
  <server>
    host [ホスト名]
    port 24224
  </server>
</match>
```


# 4. Server side
### 4-1. 環境
* さくらVPS 1GBプラン
* CentOS 7.4
* fluentd(td-agent) 0.12.40
* Elasticsearch 5.6.2
* Kibana 5.6.2

### 4-2. fluentd(td-agent)の設定

Sensor side から送られてきたデータをElasticsearchに格納します。

```:/etc/td-agent/td-agent.conf
<source>
  type forward
  port 24224
  bind 0.0.0.0
</source>

<match log.myroom>
  type elasticsearch
  host localhost
  port 9200
  index_name myroom
  logstash_format true
  logstash_prefix myroom
</match>
```

### 4-3. Elasticsearchの設定
ほとんどデフォルトのまま使っています。

```yaml:/etc/elasticsearch/elasticsearch.yml
(空)
```

### 4-4. Kibanaの設定
アクセス元IPを制限しないように設定します。

```yaml:/etc/kibana/kibana.yml
server.host: "0.0.0.0"
```


# 5. 完成したダッシュボード
私生活の乱れが可視化されました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/18646/1a6f72c7-1ef9-2abb-4daf-02054c760b9c.png)

説明を省いていますが、別途認証を入れています。公開すると防犯上よくないので気をつけましょう。