Raspberry Pi Zero W と BME280 モジュールを買って小屋裏部屋の温度を計測した件


今年の夏は猛暑と言われているが、暖かい空気は上に上るので、冷房を入れていなければ上階に行けば行くほど熱がこもることになる。

我が家には小屋裏部屋があるが、そこの温度が猛烈に気になったので、Raspberry Pi Zero W を買って計測してみることにした。

買ったもの

Raspberry Pi Zero W

今回使う Raspberry Pi Zero W はプログラミング教育などで話題になる通常の Raspberry Pi 3 とは違い、初代 Raspberry Pi クラスの CPU スペックで Ethernet インターフェイスすら割愛することで小型化を図ったモデルになる。W がついたモデルは WiFi / Bluetooth にも対応しており、今回計測したデータを WiFi 経由で送信できるので最適だと判断した。

ただ、ピンヘッダもついていない最も廉価なモデルは購入制限があったりして入手性はそこまでよくはないかと思う。

センサ

Raspberry Pi そのものは GPIO を搭載しているし、GPIO ヘッダから I2C や SPI を引き出せる。また、I2C のデータ信号線はプルアップ済みなので、そのまま直接接続するだけで I2C 通信できる。今回は温度・湿度・気圧を計測できる BME280 を搭載したモジュールを購入した。

準備

接続

通常、I2C バスのクロック信号およびデータ信号線はプルアップしておく必要がある。Arduino では実際にプルアップ用の抵抗が必要になるが、Raspberry Pi の場合は Raspberry Pi 側ですでにプルアップ済みになる。そのため、普通にモジュール間をワイヤーで接続するだけで通信可能になる。

Raspbian

OS とネットワーク

Raspberry Pi 側の OS は、今回は何も考えずに Raspbian を使った。Raspberry Pi Zero W の場合は USB, HDMI ともに小型なので、変換アダプタをかませて WiFi の設定を行う。今回の場合、Raspberry Pi Zero W 側の Mac アドレスを元に、DHCP 側で固定のローカル IP アドレスを配布するようにした。

host raspizero {
	hardware ethernet b8:27:eb:xx:xx:xx;
	fixed-address 192.168.1.20;
	option host-name "raspizero";
}

WiFi の設定が終わったら、後は ssh 越しに設定を続ける。

I2C

次に、I2C 周りの設定をする。sudo raspi-config し、

5 Interfacing Options」を選択して

I2C を有効にする。

次に、カーネルモジュールを有効にする。まず手動で

pi@raspizero:~ $ sudo modprobe i2c_bcm2835

し、I2C のデバイスファイル /dev/i2c-1 ができるか確認する。問題なくできれば次回起動時より自動的にカーネルモジュールを読み込むように、 /etc/modules に以下を書いておく。

i2c-dev
i2c-bcm2835

ユーザ pi を i2c グループに入れて、I2C デバイスにアクセスできるようにする。

pi@raspizero:~ $ sudo gpasswd -a pi i2c

I2C 関連のツールおよびライブラリをインストールしておく。

pi@raspizero:~ $ sudo apt-get install i2c-tools libi2c-dev

最後に、モジュールが正しく接続されているかを i2cdetect コマンドで確認する。

pi@raspizero:~ $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- 76 -- 

BME280 のデフォルトアドレスは 0x76 なので、76 が表示されていれば ok。

実際に読み出す

実際に読み出すだけなら、実はスイッチサイエンスが出しているサンプルの Python スクリプトを持ってきて sudo pip install smbus してから実行すればいい。ただ、今回は

  • 単純に自分で書いてみたかった
  • サンプルコードの計算式とデータシート上の計算式が異なっていた

ことから、C で書いてみた。

実際に書いてみて

読み出しそのものはデバイスファイルを通じてコマンドを発行、読み出すだけなのでそこまで難しくはない。問題は、

  • 実際に読み出したデータを 32 バイトあるキャリブレーションデータを使って計算しないと計測値が出ない。
  • キャリブレーションデータ読み出し後、ある程度成形する必要がある。また、連続したアドレスで読み出せるわけではないので、2 回に分けて読み出す必要がある。
  • 計測値計算の最終段まで算術乗算・除算なしにビットシフトと加減算だけで計算できるが、一部 64 ビット演算が必要。

と、割と工夫が必要だった。

また、湿度および気圧計算には気温データが必要で持ち回す必要がある。最終的な利便性を考えて、当初は C で書いていた読み出しコードを C++ で書き直してデータの持ち回しをするようにしてみた。

なお、自分が書いたコードはこちら。海面気圧を算出するための高度データは定数で持っているため、ここは適宜書き換える必要がある。

実際に計測してみて

まだデータは蓄積していないので、1 日での推移等は確認できていない。しかし、南中から 1 日の最高気温に達するまでに約 2 時間のタイムラグがあるのと同じように、最高気温に達してから小屋裏部屋が最高気温に達するまでに時間差があること、また、2 階までは断熱材が入っており、冷房を使っているにもかかわらず、小屋裏部屋は 43 度近くまで上昇することが確認できた。

一方、この程度の計測に Raspberry Pi Zero W はオーバースペック過ぎる。今回の要件は I2C 経由で計測したデータを WiFi 経由で送信できればいいので、今なら例えば ESP2866 といった Arduino 互換の WiFi モジュールでも目的を達成できればいいかと思う。