BluemixでRaspberryPi2のセンサーデータを拾う (5)センサーを付けてデータを拾う　温度・湿度・気圧まとめて採取編

#<i class="fa fa-cubes" style="font-size:1em;"></i>概要
[BluemixのRaspberryPi登録レシピ](https://developer.ibm.com/recipes/tutorials/raspberry-pi-4/)に登場する[デバイス用のsampleプログラム](https://github.com/ibm-messaging/iot-raspberrypi/releases/tag/1.0.2)は、どんなにセンサーがたくさん付いていようが固定の4項目のデータのみをBluemixに送信する作りになっている。

Raspberry Pi 2にセンサーを付け加えて固定4項目以外のデータをBluemixで取得するには、[sampleプログラムのソースコード](https://github.com/ibm-messaging/iot-raspberrypi/blob/master/samples/c/)を修正してビルドすれば良い。その方法を整理する。

整理している内に長くなってきたので、(1)Sampleプログラムの仕組みの整理と(2)どこをどのように変更すればよいのかを分けることにした。

[(1)　仕組みの理解](http://qiita.com/getapojim/items/b76ea2cfadaff6dfd159)
[(2)　センサーを付けてデータを拾う　温度センサーデジタル編](http://qiita.com/getapojim/items/0f2b5178bfaddafcde9f)
[(3)　センサーを付けてデータを拾う　温度センサーアナログ編](http://qiita.com/getapojim/items/12e5cb64a8046ab033e9)
[(4)　センサーを付けてデータを拾う　温度センサーデジタル編（リベンジ）](http://qiita.com/getapojim/items/0ea4c7369d342d5b00d5)
(5)　センサーを付けてデータを拾う　温度・湿度・気圧まとめて採取編　(これ)
番外編 [『ムック「日経Linux ラズパイマガジン 2015年春号 」電子工作入門キット パーツセット』に入っていたもの](http://qiita.com/getapojim/items/c90edd38c0ad9d5eb379)

#<i class="fa fa-cube" style="font-size:1em;"></i>今回のポイント
##ポイント1：複数のデータを纏めて採取する
[センサーを色々手に入れたつもりが実は温度センサーしか持っていないことが判明した](http://qiita.com/getapojim/items/c90edd38c0ad9d5eb379)ので、
他のセンサーを試してみることにした。
以下の条件に見合うセンサーを探した結果、温度・湿度・気圧の3つのデータを採取可能な[『BME280搭載　温湿度・気圧センサモジュール』](https://www.switch-science.com/catalog/2236/)というものを使うことにした。
　選定条件1：生活に密着したデータを採取できる（身近なところで気軽にデータを採取したい）
　選定条件2：放置しておくだけで、人がいなくても動きのあるデータを得たい（楽してデータを採取したい）
　選定条件3：Raspberry Pi 2で動く（or動きそう）という事例がある
　選定条件4：見た目やサイズ感がシンプルで小さい
　選定条件5：手ごろな値段

##ポイント2：はんだ付けから逃げない
[『BME280搭載　温湿度・気圧センサモジュール』](https://www.switch-science.com/catalog/2236/)は[「姉妹商品としてピンヘッダ実装済の物もある」](https://www.switch-science.com/catalog/2323/)とのことだが、[「はんだづけカフェ」の存在を知ってしまった](http://qiita.com/getapojim/items/0ea4c7369d342d5b00d5#リベンジのポイント)ことと選定条件5（手ごろな値段）を考慮して、[ピンヘッダ未実装の方](https://www.switch-science.com/catalog/2236/)を選択した。
（実際は差額の324円よりはんだづけカフェへの往復の交通費の方が高かった。。。）

##ポイント3：複数のデータを纏めてBluemixで確認
同時に採取するデータが増えた際に、RasPi上のソースコードやBluemix上のNode-REDの定義で何を増やせばよいかを実際に作って確認する。

#<i class="fa fa-cube" style="font-size:1em;"></i>回路（ネタ）
今回はこちら↓をやってみる。
http://qiita.com/masato/items/027e5c824ae75ab417c1

過去にExcelで作った回路を真似して同じような書きっぷりで描いてみた。（Excelで作図）
![温度・湿度・気圧を測定するための回路.png](https://qiita-image-store.s3.amazonaws.com/0/85506/9ea3460b-e051-9146-9163-ecd8f2860d61.png)

#<i class="fa fa-cube" style="font-size:1em;"></i>回路（設計）
元ネタの図の通りにFritzingで作ってみた。
BME280のパーツはここからから入手して、[Fritzing](http://fritzing.org/download/)にインポートした。
https://sites.google.com/site/takafuminakahrm1017/fritzing/
BME280 Barometric Pressure, Temperature and Humidity Sensor .fzpz
（ファイル名に空白を含む様なので注意）
![温度・湿度・気圧を測定するための回路.png](https://qiita-image-store.s3.amazonaws.com/0/85506/3857e3de-958f-d5cd-e11b-7efcb14c2fd0.png)

#<i class="fa fa-cube" style="font-size:1em;"></i>回路（実装）
Fritzingで作った絵の通りにつなげてみた。
BME280は、**当然はんだ付けしてある**　←ポイント2
![温度・湿度・気圧デジタル_回路(実装).jpg](https://qiita-image-store.s3.amazonaws.com/0/85506/f8b1e66a-247c-4099-9164-ca2cba283714.jpeg)

#<i class="fa fa-cube" style="font-size:1em;"></i>Raspberry Pi 2上でI2Cの有効化
作業はRaspberry Pi 2にログインして行う。
実行時ユーザは次の通り
$ : pi
\# : root

##WiringPiの導入
`# cd /var/tmp`
`# git clone git://git.drogon.net/wiringPi`
`# cd wiringPi`
`# ./build`

導入確認のためにバージョンを確認してみる。
`# gpio -v`
![IMG_3201.png](https://qiita-image-store.s3.amazonaws.com/0/85506/d9a090fd-ea0c-3ec4-392b-eddcac1bf67c.png)
バージョンが表示されること。

##I2C有効化
Raspberry Pi 2はraspi-configから設定する。
`# raspi-config`

「8 Advanced Options」を選択して、「Select」を押下
![I2C有効化1.png](https://qiita-image-store.s3.amazonaws.com/0/85506/fa010037-ad76-44f2-02ce-a801720b2dd4.png)

「A7 I2C」を選択して、「Select」を押下
![I2C有効化2.png](https://qiita-image-store.s3.amazonaws.com/0/85506/f2cefe9e-06cd-b0e9-9108-bc3d12ce313b.png)

「はい」を押下
![I2C有効化3.png](https://qiita-image-store.s3.amazonaws.com/0/85506/503bfe65-0895-dc15-a0a1-2764a104d544.png)

「了解」を押下
![I2C有効化4.png](https://qiita-image-store.s3.amazonaws.com/0/85506/504e2fea-ac0f-a89d-feea-67e2a6d0e6cc.png)

「はい」を押下
![I2C有効化5.png](https://qiita-image-store.s3.amazonaws.com/0/85506/5e9dc6a1-89f4-2098-e945-948a1a8f5ede.png)

「了解」を押下
![I2C有効化6.png](https://qiita-image-store.s3.amazonaws.com/0/85506/f5e0055f-663b-6348-2dbe-f2584050ca22.png)

「Finish」を押下。どれが選択されていても良い。
![I2C有効化7.png](https://qiita-image-store.s3.amazonaws.com/0/85506/4b420e82-90aa-9077-649a-cbaa4fb12e1a.png)

「はい」を押下。再起動される。
![I2C有効化8.png](https://qiita-image-store.s3.amazonaws.com/0/85506/b7ff4425-541b-800f-97e6-737f59f9d874.png)

再起動後にI2C用のモジュールが読み込まれていることを確認する。
`$ lsmod | grep i2c`
「i2c_bcm2708」が表示されること。

##I2C用ツールのインストール
`# apt-get -y install i2c-tools`
`# reboot`

##デバイスのアドレス確認
`# i2cdetect -y 1`

![IMG_3203.png](https://qiita-image-store.s3.amazonaws.com/0/85506/98e385cb-e8bb-bb95-d3ea-ccf203e5b776.png)
アドレス(76)が表示されること。

##PythonからI2Cバスをコントロールするためのツールのインストール
`# apt-get -y install python-smbus`

![IMG_3205.png](https://qiita-image-store.s3.amazonaws.com/0/85506/1cc3519e-cb3d-67b3-5ada-24113bd44420.png)

#<i class="fa fa-cube" style="font-size:1em;"></i>Raspberry Pi 2上で気温・気圧・湿度を読んでみる

参考サイトの通りに、スイッチサイエンスのBMEリポジトリにあるpythonのサンプルコード「bme280_sample.py」をダウンロード・実行してみる。
画面に気温・気圧・湿度をまとめて出力する。
実行にはroot権限が必要

`$ mkdir -p ~/bin`
`$ cd ~/bin`
`$ wget https://raw.githubusercontent.com/SWITCHSCIENCE/BME280/master/Python27/bme280_sample.py`
`$ ll bme280_sample.py`
`$ sudo python ./bme280_sample.py`

![IMG_3206.png](https://qiita-image-store.s3.amazonaws.com/0/85506/1d86526f-84e5-a2b4-407a-2ef29b9fd15d.png)


画面出力例）

```bash
temp : 25.59  ℃
pressure : 1007.20 hPa
hum :  54.82 ％
```

temp　　　：　気温
pressure　：　気圧
hum　　　：　湿度

#<i class="fa fa-cube" style="font-size:1em;"></i>Raspberry Pi 2上で気温・気圧・湿度を個別に読んでみる
３つのデータを個別に読めるようにするため、サンプルコード「bme280_sample.py」を手直しして以下の３つのプログラムを作成する。

`$ cd ~/bin`
`$ cp bme280_sample.py bme280_temp.py`
`$ cp bme280_sample.py bme280_presssure.py`
`$ cp bme280_sample.py bme280_hum.py`
`$ vi bme280_temp.py`
`$ vi bme280_presssure.py`
`$ vi bme280_hum.py`

![IMG_3207.png](https://qiita-image-store.s3.amazonaws.com/0/85506/2692bbc4-4ea1-a04d-dfe3-58401789c16f.png)

気温を取得するプログラム

```py:bme280_temp.py(修正前　69～71行目)
	compensate_T(temp_raw)
	compensate_P(pres_raw)
	compensate_H(hum_raw)
```

```py:bme280_temp.py(修正後)
	compensate_T(temp_raw)
	# compensate_P(pres_raw)
	# compensate_H(hum_raw)
```

```py:bme280_temp.py(修正前　103行目)
	print "temp : %-6.2f ℃" % (temperature) 
```

```py:bme280_temp.py(修正後)
	print "%-6.2f" % (temperature) 
```

気圧を取得するプログラム

```py:bme280_presssure.py(修正前　69～71行目)
	compensate_T(temp_raw)
	compensate_P(pres_raw)
	compensate_H(hum_raw)
```

```py:bme280_presssure.py(修正後)
	# compensate_T(temp_raw)
	compensate_P(pres_raw)
	# compensate_H(hum_raw)
```

```py:bme280_presssure.py(修正前　95行目)
	print "pressure : %7.2f hPa" % (pressure/100)
```

```py:bme280_presssure.py(修正後)
	print "%7.2f" % (pressure/100)
```

湿度を取得するプログラム

```py:bme280_hum.py(修正前　69～71行目)
	compensate_T(temp_raw)
	compensate_P(pres_raw)
	compensate_H(hum_raw)
```

```py:bme280_hum.py(修正後)
	# compensate_T(temp_raw)
	# compensate_P(pres_raw)
	compensate_H(hum_raw)
```

```py:bme280_hum.py(修正前　117行目)
	print "hum : %6.2f ％" % (var_h)
```

```py:bme280_hum.py(修正後)
	print "%6.2f" % (var_h)
```

実行してみる。
それぞれ画面に気温・気圧・湿度を個別に出力する。
実行にはroot権限が必要

`$ cd ~/bin/`
`$ ll bme280_temp.py bme280_pressure.py bme280_hum.py`
`$ sudo python ./bme280_temp.py`
`$ sudo python ./bme280_pressure.py`
`$ sudo python ./bme280_hum.py`

![IMG_3208.png](https://qiita-image-store.s3.amazonaws.com/0/85506/893fe48c-0c5e-24e8-7a4c-7a6352410565.png)

#<i class="fa fa-cube" style="font-size:1em;"></i>プログラムの改修内容

[BluemixのRaspberryPi登録レシピに登場するデバイス用のsampleプログラム](https://github.com/ibm-messaging/iot-raspberrypi/releases/tag/1.0.2)を次の通り修正する。
[修正前のソースコードはこちらで参照可能](https://github.com/ibm-messaging/iot-raspberrypi/tree/master/samples/c)

|修正するファイル|新規で追加するファイル|
|:--|:--|
|iotmain.c<br>iot.h<br>jsonator.c<br>Makefile|bme280.c|

追加・修正内容は以下の通り。

修正内容1

```c:iotmain.c(修正前　61行目)

```

```c:iotmain.c(修正後)
//bme280_temp.py
float getBme280Temp();

//bme280_pressure.py
float getBme280Pressure();

//bme280_hum.py
float getBme280Hum();

```

修正内容2

```c:iotmain.c(修正前　152～153行目)
		JsonMessage json_message = { DEVICE_NAME, getCPUTemp(), sineVal(
				MIN_VALUE, MAX_VALUE, 16, count), GetCPULoad() };
```

```c:iotmain.c(修正後)
		JsonMessage json_message = { DEVICE_NAME, getCPUTemp(), sineVal(
				MIN_VALUE, MAX_VALUE, 16, count), GetCPULoad(), getBme280Temp(), getBme280Pressure(), getBme280Hum() };
```

修正内容3

```c:iot.h(修正前　22～27行目)
  struct json {
	  char myname[100];
	  float cputemp;
	  float sine;
	  float cpuload;
  };
```

```c:iot.h(修正後)
  struct json {
	  char myname[100];
	  float cputemp;
	  float sine;
	  float cpuload;
	  float bme280temp;
	  float bme280pressure;
	  float bme280hum;
  };
```

修正内容4

```c:jsonator.c(修正前　50行目)

```

```c:jsonator.c(修正後)
	strcat(jsonReturned, ",");

	strcat(jsonReturned, "\"bme280temp\":");
	sprintf(buffer, "%.2f", passedrpi.bme280temp);
	strcat(jsonReturned, buffer);
	strcat(jsonReturned, ",");

	strcat(jsonReturned, "\"bme280pressure\":");
	sprintf(buffer, "%.2f", passedrpi.bme280pressure);
	strcat(jsonReturned, buffer);
	strcat(jsonReturned, ",");

	strcat(jsonReturned, "\"bme280hum\":");
	sprintf(buffer, "%.2f", passedrpi.bme280hum);
	strcat(jsonReturned, buffer);

```

修正内容5

```c:Makefile(修正前　12～14行目)
iot: iotmain.c cpustat.c mac.c mqttPublisher.c jsonator.c iot.h jsonReader.c
	export LIBRARY_PATH=$(COMPILELIBDIR):$(LIBRARY_PATH)
	$(CC) iotmain.c cpustat.c mac.c mqttPublisher.c jsonator.c cJSON.c jsonReader.c -o $@ -l$(LIBNAME) -lpthread -lssl -lm -L $(COMPILELIBDIR) -I .
```

```c:Makefile(修正後)
iot: iotmain.c cpustat.c mac.c mqttPublisher.c jsonator.c iot.h jsonReader.c bme280.c
	export LIBRARY_PATH=$(COMPILELIBDIR):$(LIBRARY_PATH)
	$(CC) iotmain.c cpustat.c mac.c mqttPublisher.c jsonator.c cJSON.c jsonReader.c bme280.c -o $@ -l$(LIBNAME) -lpthread -lssl -lm -L $(COMPILELIBDIR) -I .
```

追加内容1

```C:bme280.c
#include <stdio.h>
#include <stdlib.h>
#define BUF 256
 
float getBme280Temp();
float getBme280Pressure();
float getBme280Hum();

float getBme280Temp(){
	FILE	*fp;
	char	*cmdline = "python /home/pi/bin/bme280_temp.py";
	if ( (fp=popen(cmdline,"r")) ==NULL) {
		perror ("can not exec commad");
		exit(EXIT_FAILURE);
	}
	char buf[BUF];
	fgets(buf, sizeof(buf), fp);
	(void) pclose(fp);
 
	return atof(buf);
}

float getBme280Pressure(){
	FILE	*fp;
	char	*cmdline = "python /home/pi/bin/bme280_pressure.py";
	if ( (fp=popen(cmdline,"r")) ==NULL) {
		perror ("can not exec commad");
		exit(EXIT_FAILURE);
	}
	char buf[BUF];
	fgets(buf, sizeof(buf), fp);
	(void) pclose(fp);
 
	return atof(buf);
}

float getBme280Hum(){
	FILE	*fp;
	char	*cmdline = "python /home/pi/bin/bme280_hum.py";
	if ( (fp=popen(cmdline,"r")) ==NULL) {
		perror ("can not exec commad");
		exit(EXIT_FAILURE);
	}
	char buf[BUF];
	fgets(buf, sizeof(buf), fp);
	(void) pclose(fp);
 
	return atof(buf);
}
```

#<i class="fa fa-cube" style="font-size:1em;"></i>プログラムの改修手順
作業はRaspberryPi2にログインして行う。
実行時ユーザは次の通り
$ : pi
\# : root

1. 設定ファイルの退避
`# cd /etc/iotsample-raspberrypi/`
``# cp -p device.cfg device.cfg.`date +%Y%m%d`_1``
※これで、アンインストール(dpkg -P)してもフォルダとバックアップファイルが残るので安心。

2. 必要パッケージのインストール
`# apt-get install dpkg-dev build-essential devscripts`
`# apt-get install libssl-dev`

3. ソースコード一式を入手
`$ cd ~`
`$ git clone https://github.com/ibm-messaging/iot-raspberrypi.git`

4. ソースコード修正・追加
`$ cd ~/iot-raspberrypi/samples/c/`
`$ vi iotmain.c`
`$ vi iot.h`
`$ vi jsonator.c`
`$ vi Makefile`
`$ vi bme280.c`

5. ビルド
`$ debuild -b`
署名のエラーは無視する。

#<i class="fa fa-cube" style="font-size:1em;"></i>iotサービスの再インストール

1. アンインストール（古いのを）
`# dpkg -P iot`

2. インストール
`# cd /home/pi/iot-raspberrypi/samples/`
`# dpkg -i ./iot_1.0-1_armhf.deb`

3. サービスの確認
`# service iot status`
※起動している(okが表示される)こと。

4. 設定ファイル作成
`# cd /etc/iotsample-raspberrypi/`
``# cp -p device.cfg.`date +%Y%m%d`_1 device.cfg``
※6.でいったん削除されてしまうので、1.で退避したファイルで復元

5. サービスの再起動
`# service iot restart`
※起動している(okが表示される)こと。

6. 起動モードの確認
`# service iot getdeviceid`
※registerd mode で起動している(registerd modeが表示される)こと。

#<i class="fa fa-cube" style="font-size:1em;"></i>Bluemix IoT Foundationサービスで確認
IoT Foundationのダッシュボードで、センサー情報欄にて確認する。
センサーの温度データを受信できた！
![BluemixでBME280の気温・気圧・湿度を表示.png](https://qiita-image-store.s3.amazonaws.com/0/85506/4355c2b1-af42-4972-05a2-344042deb01c.png)

<!--
#<i class="fa fa-cube" style="font-size:1em;"></i>Bluemix Node-REDでメール&tweetする。
採取したデータを、Node-REDアプリを使ってtweetとメール通知をする。
-->

#<i class="fa fa-cube" style="font-size:1em;"></i>所感
BME280のデータをC言語で採取する方法が分からず、先駆者のpythonサンプルが標準出力に出力する情報をCで拾う形にした。
pythonは初めて触った。
コマンドの出力(返り値ではなく標準出力)をCで拾う方法が分かったので、できることが随分広がったと思う。

#<i class="fa fa-cube" style="font-size:1em;"></i>環境

[Raspberry Pi 2 Model B](https://www.raspberrypi.org/products/raspberry-pi-2-model-b/)
[Raspbian](https://www.raspberrypi.org/downloads/raspbian/)
[BME280搭載　温湿度・気圧センサモジュール](https://www.switch-science.com/catalog/2236/)

#<i class="fa fa-book" style="font-size:1em;"></i>参考
Fritzingダウンロード
http://fritzing.org/download/

Fritzing用のBME280のパーツ
https://sites.google.com/site/takafuminakahrm1017/fritzing/
BME280 Barometric Pressure, Temperature and Humidity Sensor .fzpz
（ファイル名に空白を含む様なので注意）

はんだづけカフェ
http://handazukecafe.com/

popenでコマンドの出力を読み込む
http://kaworu.jpn.org/c/popenでコマンドの出力を読み込む

C言語アプリケーションに Pythonを組み込む
http://d.hatena.ne.jp/Wacky/20060103/1136292735

Google （検索文字列：python C言語 popen()）
https://www.google.co.jp/search?q=python+C言語+popen()

Python3の文字列について。%記法とformat()記法の対応関係
http://auewe.hatenablog.com/entry/2013/10/16/083627