#概要
BluemixのRaspberryPi登録レシピに登場するデバイス用のsampleプログラムは、どんなにセンサーがたくさん付いていようが固定の4項目のデータのみをBluemixに送信する作りになっている。
Raspberry Pi 2にセンサーを付け加えて固定4項目以外のデータをBluemixで取得するには、sampleプログラムのソースコードを修正してビルドすれば良い。その方法を整理する。
整理している内に長くなってきたので、(1)Sampleプログラムの仕組みの整理と(2)どこをどのように変更すればよいのかを分けることにした。
(1) 仕組みの理解
(2) センサーを付けてデータを拾う 温度センサーデジタル編
(3) センサーを付けてデータを拾う 温度センサーアナログ編
(4) センサーを付けてデータを拾う 温度センサーデジタル編(リベンジ)
(5) センサーを付けてデータを拾う 温度・湿度・気圧まとめて採取編 (これ)
番外編 『ムック「日経Linux ラズパイマガジン 2015年春号 」電子工作入門キット パーツセット』に入っていたもの
#今回のポイント
##ポイント1:複数のデータを纏めて採取する
センサーを色々手に入れたつもりが実は温度センサーしか持っていないことが判明したので、
他のセンサーを試してみることにした。
以下の条件に見合うセンサーを探した結果、温度・湿度・気圧の3つのデータを採取可能な『BME280搭載 温湿度・気圧センサモジュール』というものを使うことにした。
選定条件1:生活に密着したデータを採取できる(身近なところで気軽にデータを採取したい)
選定条件2:放置しておくだけで、人がいなくても動きのあるデータを得たい(楽してデータを採取したい)
選定条件3:Raspberry Pi 2で動く(or動きそう)という事例がある
選定条件4:見た目やサイズ感がシンプルで小さい
選定条件5:手ごろな値段
##ポイント2:はんだ付けから逃げない
『BME280搭載 温湿度・気圧センサモジュール』は「姉妹商品としてピンヘッダ実装済の物もある」とのことだが、「はんだづけカフェ」の存在を知ってしまったことと選定条件5(手ごろな値段)を考慮して、ピンヘッダ未実装の方を選択した。
(実際は差額の324円よりはんだづけカフェへの往復の交通費の方が高かった。。。)
##ポイント3:複数のデータを纏めてBluemixで確認
同時に採取するデータが増えた際に、RasPi上のソースコードやBluemix上のNode-REDの定義で何を増やせばよいかを実際に作って確認する。
#回路(ネタ)
今回はこちら↓をやってみる。
http://qiita.com/masato/items/027e5c824ae75ab417c1
過去にExcelで作った回路を真似して同じような書きっぷりで描いてみた。(Excelで作図)
#回路(設計)
元ネタの図の通りにFritzingで作ってみた。
BME280のパーツはここからから入手して、Fritzingにインポートした。
https://sites.google.com/site/takafuminakahrm1017/fritzing/
BME280 Barometric Pressure, Temperature and Humidity Sensor .fzpz
(ファイル名に空白を含む様なので注意)
#回路(実装)
Fritzingで作った絵の通りにつなげてみた。
BME280は、当然はんだ付けしてある ←ポイント2
#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
バージョンが表示されること。
##I2C有効化
Raspberry Pi 2はraspi-configから設定する。
# raspi-config
「8 Advanced Options」を選択して、「Select」を押下
再起動後にI2C用のモジュールが読み込まれていることを確認する。
$ lsmod | grep i2c
「i2c_bcm2708」が表示されること。
##I2C用ツールのインストール
# apt-get -y install i2c-tools
# reboot
##デバイスのアドレス確認
# i2cdetect -y 1
##PythonからI2Cバスをコントロールするためのツールのインストール
# apt-get -y install python-smbus
#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
画面出力例)
temp : 25.59 ℃
pressure : 1007.20 hPa
hum : 54.82 %
temp : 気温
pressure : 気圧
hum : 湿度
#Raspberry Pi 2上で気温・気圧・湿度を個別に読んでみる
3つのデータを個別に読めるようにするため、サンプルコード「bme280_sample.py」を手直しして以下の3つのプログラムを作成する。
$ 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
気温を取得するプログラム
compensate_T(temp_raw)
compensate_P(pres_raw)
compensate_H(hum_raw)
compensate_T(temp_raw)
# compensate_P(pres_raw)
# compensate_H(hum_raw)
print "temp : %-6.2f ℃" % (temperature)
print "%-6.2f" % (temperature)
気圧を取得するプログラム
compensate_T(temp_raw)
compensate_P(pres_raw)
compensate_H(hum_raw)
# compensate_T(temp_raw)
compensate_P(pres_raw)
# compensate_H(hum_raw)
print "pressure : %7.2f hPa" % (pressure/100)
print "%7.2f" % (pressure/100)
湿度を取得するプログラム
compensate_T(temp_raw)
compensate_P(pres_raw)
compensate_H(hum_raw)
# compensate_T(temp_raw)
# compensate_P(pres_raw)
compensate_H(hum_raw)
print "hum : %6.2f %" % (var_h)
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
#プログラムの改修内容
BluemixのRaspberryPi登録レシピに登場するデバイス用のsampleプログラムを次の通り修正する。
修正前のソースコードはこちらで参照可能
修正するファイル | 新規で追加するファイル |
---|---|
iotmain.c iot.h jsonator.c Makefile |
bme280.c |
追加・修正内容は以下の通り。
修正内容1
//bme280_temp.py
float getBme280Temp();
//bme280_pressure.py
float getBme280Pressure();
//bme280_hum.py
float getBme280Hum();
修正内容2
JsonMessage json_message = { DEVICE_NAME, getCPUTemp(), sineVal(
MIN_VALUE, MAX_VALUE, 16, count), GetCPULoad() };
JsonMessage json_message = { DEVICE_NAME, getCPUTemp(), sineVal(
MIN_VALUE, MAX_VALUE, 16, count), GetCPULoad(), getBme280Temp(), getBme280Pressure(), getBme280Hum() };
修正内容3
struct json {
char myname[100];
float cputemp;
float sine;
float cpuload;
};
struct json {
char myname[100];
float cputemp;
float sine;
float cpuload;
float bme280temp;
float bme280pressure;
float bme280hum;
};
修正内容4
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
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 .
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
#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);
}
#プログラムの改修手順
作業はRaspberryPi2にログインして行う。
実行時ユーザは次の通り
$ : pi
# : root
-
設定ファイルの退避
# cd /etc/iotsample-raspberrypi/
# cp -p device.cfg device.cfg.`date +%Y%m%d`_1
※これで、アンインストール(dpkg -P)してもフォルダとバックアップファイルが残るので安心。 -
必要パッケージのインストール
# apt-get install dpkg-dev build-essential devscripts
# apt-get install libssl-dev
-
ソースコード一式を入手
$ cd ~
$ git clone https://github.com/ibm-messaging/iot-raspberrypi.git
-
ソースコード修正・追加
$ cd ~/iot-raspberrypi/samples/c/
$ vi iotmain.c
$ vi iot.h
$ vi jsonator.c
$ vi Makefile
$ vi bme280.c
-
ビルド
$ debuild -b
署名のエラーは無視する。
#iotサービスの再インストール
-
アンインストール(古いのを)
# dpkg -P iot
-
インストール
# cd /home/pi/iot-raspberrypi/samples/
# dpkg -i ./iot_1.0-1_armhf.deb
-
サービスの確認
# service iot status
※起動している(okが表示される)こと。 -
設定ファイル作成
# cd /etc/iotsample-raspberrypi/
# cp -p device.cfg.`date +%Y%m%d`_1 device.cfg
※6.でいったん削除されてしまうので、1.で退避したファイルで復元 -
サービスの再起動
# service iot restart
※起動している(okが表示される)こと。 -
起動モードの確認
# service iot getdeviceid
※registerd mode で起動している(registerd modeが表示される)こと。
#Bluemix IoT Foundationサービスで確認
IoT Foundationのダッシュボードで、センサー情報欄にて確認する。
センサーの温度データを受信できた!
#所感
BME280のデータをC言語で採取する方法が分からず、先駆者のpythonサンプルが標準出力に出力する情報をCで拾う形にした。
pythonは初めて触った。
コマンドの出力(返り値ではなく標準出力)をCで拾う方法が分かったので、できることが随分広がったと思う。
#環境
Raspberry Pi 2 Model B
Raspbian
BME280搭載 温湿度・気圧センサモジュール
#参考
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