ラズパイで部屋の見える化してみる、その1

# はじめに
## 制作経緯
4月からなんの間違いかweb系企業に入社してしまったringo
研修で触ったこともないLaravelやらMySQLやらAnsibleに触ることになってしまった。
ということで勉強がてら部屋にあったラズパイとセンサーを使って部屋の見える化をします。
以前[ESP8266とRaspberryPiで温度監視botを作る](https://qiita.com/ringo156/items/53a3a0466dcf21495cb7)というタイトルで似たようなことをやってたみたいですね。

## 仕様を決める

ざっくり下記のような条件を満たすようにしようと思います。

- 温度・湿度・気圧をモニタリングする
- 家の中だけでなく外から見えるようにしたい
- 今のデータだけでなく1日の変化などをグラフィカルに表示したい

# 構成

## 使用するもの

- ラズパイ、本記事で使用したのは3b+
- 温湿度センサーBME280
- 0.96インチOLED

## 全体構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147601/7b3693d1-81cb-a5c6-fecc-5170c5a9d02b.png)

仕様をもとに構成を考えます。
センサーとOLEDはブレッドボードに刺してI2C通信で接続します。
取得したデータはラズパイに保存するとともにCONOHA上に立てられたインスタンスに投げるようにします。
処理手順は以下のようにします。

1. センサーからデータの取得＆処理
2. 液晶に表示
3. csvに保存
4. クラウドにデータを投げる
5. DBに保存
6. webページ上で表示

の手順で処理を作っていこうと思います。
この記事では1~3までを説明します。

# センサー

## 配線
I2C通信なのでSDIとSCKをつなぐだけ、モジュールは3.3Vなのでそれだけ注意すること
`i2cdetect -y 1`で確認して認識されてたらオッケー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147601/dee32f76-04d6-c462-3900-259d98121cdd.png)

画像では他にも接続されていますが、0x3CがOLEDのアドレスで、0x76がBME280のアドレスになります。


I2Cではプルアップが必要とか色々あるけどセンサー側の基板に乗っているとして進めます。
ただ、I2C通信自体はノイズに強いわけではないのであまり引き伸ばしたりしないほうがいいかも。

## 値の取得
ライブラリはSWITCHCIENCEのサンプルを使用しました。
[ SWITCHSCIENCE/BME280](https://github.com/SWITCHSCIENCE/BME280)
Python2用に書かれているのでちょっと編集します。
変更点としては

- print部分の書き方をPython3用に書き換え
- 取得した生データを補正する関数内でprintしてたのを使いやすいように返り値で取得できるように変更

編集したコードが[コチラ](https://github.com/ringo156/BME280/blob/master/Python27/bme280_sample.py)になります。
また、動かすのにsmbusが必要になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147601/a6fc5d13-c335-87cb-4822-f3f35b8ea537.png)

ターミナル上で値の取得が確認できました。

# 液晶に表示

使用した液晶はSSD1306搭載のOLEDモジュールです。
どこで購入したのか覚えてないので書けないのですが、どこで買ってもだいたい同じだと思います。
ライブラリはAdafruitが公開しているものを使用しました。
[adafruit/Adafruit_Python_SSD1306](https://github.com/adafruit/Adafruit_Python_SSD1306)

動かすのにちょっとコツが必要です。
[ラズパイにて、有機ELディスプレイのサンプルコードを動かす](https://qiita.com/kotaproj/items/56501848f031724db148)
↑の記事を参考にしてpyenv上で必要なライブラリをインストールしてOLEDを使えるようにします。
Adafruit_Python_SSD1306/examples/stats.pyを参考にbme280の処理を書き足していきます。

```python
# 画面のクリア
draw.rectangle((0,0,width,height), outline=0, fill=0)
sensor_data = bme280.readData() # センサーデータの取得
temp = "%6.2f" % (sensor_data[0])
draw.text((x, top), "Temp =" + temp + " °C", font = font, fill = 255)
press = "%7.2f" % (sensor_data[1])
draw.text((x, top + 8), "Press = " + press + " hPa", font = font, fill = 255)
hum = "%6.2f" % (sensor_data[2])
draw.text((x, top + 16), "Hum =" + hum + " %", font = font, fill = 255)
# 画面の表示
disp.image(image)
disp.display()
```

whileループの中の処理を抜き出しました。
処理の内容としてはセンサーからデータを取得してきて、1行ずつ表示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147601/768b6029-dc28-afd2-946f-042d78a8dd84.png)


取得したデータをOLEDに表示することができました。

# csvに保存

クラウドに保存と言いましたがひとまずcsvに保存していきます。

```python
# ファイル書き込み処理
date = str(datetime.date.today())
nowtime = datetime.datetime.now()
# ファイルがあったら上書きする
if(os.path.exists(path + date +".csv")):
    f = open(path + date +".csv", 'a')
    f.write(str(nowtime.hour) + ':' + str(nowtime.minute) + ':' + str(nowtime.second) + ',')
    f.write(temp + ',' + press + ',' + hum + ' \n')
    f.close()
# なかったら生成する
else:
    f = open(path + date +".csv", 'w')
    f.write("date,Temp,Press,Hum\n")
    f.write(str(nowtime.hour) + ':' + str(nowtime.minute) + ':' + str(nowtime.second) + ',')
    f.write(temp + ',' + press + ',' + hum + ' \n')
    f.close()
```

日付で区切ってcsvに保存するように処理を書きました。
出力されたグラフをエクセルで表示するとこんな感じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147601/0b113bc2-180e-486b-64eb-c058b6af8720.png)

# おわりに

最終的にできたプログラムをgistに載せています。
[raspi_logger.py](https://gist.github.com/ringo156/cd1dec5f838763c2eeac9c54136b0418)
次回はLaravelとクラウドを使ってAPIを作成してブラウザ上でグラフの表示に挑戦しようと思います。