社長席の温度監視を支える技術。

はじめに

この記事は、こちらの記事で挙げた監視システムを構築した際の技術ログとなります。

オフィスの形状のせいか座席によって温度差があり、最北端の席に座っている社長がいつも「寒い、寒い」と震えているので、
Raspberry Pi2とAWS CloudWatchを使って、暑い場所と寒い場所の温度差を実際の数値で確認しました。

監視システムの概念図

ず.001

実際の監視画面

スクリーンショット_2016-03-09_15_58_19

実現方法

利用したパーツ類

製品名価格 [円]
Raspberry Pi MODEL B (PLUS) & 専用ケース model B+ Case(Clear) 5,480
Raspberry Pi(ラズベリーパイ)用 1ポート USB 電源アダプター1,460
BUFFALO 無線LAN子機 コンパクトモデル 11n技術・11g/b対応 WLI-UC-GNM1,700
Transcend microSDHCカード 32GB Class10 (無期限保証) TS32GUSDHC10E (FFP) 1,350
ELECOM LANケーブル CAT6準拠 Gigabit スーパーフラット 5m ブラック LD-GF/BK5585
普通のブレッドボード420
デジタル温度センサ(1wire)DS18B20+ 350
カーボン抵抗(炭素皮膜抵抗) 1/4W 4.7kΩ (100本入)100
ブレッドボード・ジャンパーコード(オス-オス)(10cm)20本セット 180
ブレッドボード・ジャンパーコード(オス-メス) 15cm(黒) (10本入)220
ブレッドボード・ジャンパーワイヤ EIC-J-L400
合計12,245 円
IMG_0727

前提条件

以下の手順はすべて、下記の環境で行いました。

  • Raspberry Pi2にインストールしたOS: Raspbian Jessie
  • 作業端末: iMac (OS X 10.11.3)
    • 有線LANインタフェース名:en0
    • 無線LANインタフェース名:en1

Raspberry Pi2のセットアップ

OSイメージ書き込み

Raspberry Pi公式サイトのダウンロードページ より、Raspbian (Raspberry Pi公式のDebian系Linux) をダウンロードします。

ダウンロード中に、OS Xの「ディスク ユーティリティ」(Disk Utility.app)を用いて下記を行っておくと良いでしょう。

  • SDカードをFAT32でフォーマット
    • SDカードドライブを選択して、「消去」ボタンを押下したあとに MS-DOS(FAT) を選択
  • SDカードドライブの識別子(例:disk2、disk3…)の確認
    • SDカードドライブを選択して、「情報」ボタンを押下したあとに出てくるウィンドウで「BSD装置ノード」を調べる

ダウンロード完了後、Raspberry Pi公式サイトのインストールガイド を参考に、下記コマンドを実行して、ダウンロードしたOSイメージをSDカードに書き込みます。 。そこそこの時間(数分〜数十分程度)がかかりますので、ゆっくり待ちます。

# ここでは下記を仮定しています
# * 上記手順で調べたSDカードドライブの識別子: diskn
# * ダウンロードしたOSイメージファイルパス: path/to/your/image.img

# パーティションをマウント解除
$ sudo diskutil unmountDisk /dev/diskn
# イメージ書き込み
$ sudo dd bs=1m if=path/to/your/image.img of=/dev/diskn

OS起動

下記を行い、OSを起動します。

  1. マイクロSDカード挿入
  2. LANケーブルで Raspberry Pi2 と 作業端末を直結
  3. (電源用)マイクロUSBケーブルとをコンセントへ接続

SSH接続

ディスプレイ・キーボードを直接Raspberry Pi2に繋げられば不要なのですが、今回はそれら無し(headless)でのセットアップを行うため、SSH接続経由で諸々の作業を行います。

起動直後のRaspberry Pi2のIPが不明なため、IPv6のリンクローカルマルチキャストアドレス(ff02::1)へping6して探り当てました。

# ff02::1 => リンクローカルマルチキャストアドレス
$ ping6 -I en0 ff02::1
PING6(56=40+8+8 bytes) fe80::ae87:a3ff:fe26:e76d%en0 --> ff02::1
16 bytes from fe80::ae87:a3ff:fe26:e76d%en0, icmp_seq=0 hlim=64 time=0.099 ms
16 bytes from fe80::bbbe:fdf7:757a:2150%en0, icmp_seq=0 hlim=64 time=0.635 ms
16 bytes from fe80::ae87:a3ff:fe26:e76d%en0, icmp_seq=1 hlim=64 time=0.105 ms
16 bytes from fe80::bbbe:fdf7:757a:2150%en0, icmp_seq=1 hlim=64 time=0.583 ms
...

# fe80::ae87:a3ff:fe26:e76d%en0はMacのIPなので
# fe80::bbbe:fdf7:757a:2150%en0こっちが正解

探り当てたIPv6アドレスにSSH接続します。

$ ssh pi@fe80::bbbe:fdf7:757a:2150%en0

# 初期ユーザ
## user_id: pi
## password: raspberry

raspi-config コマンドでの初期設定

$ sudo raspi-config

(お好みで)SSH接続後に上記コマンドを実行して、各種設定を行います。 少なくとも、Expand Filesystemは行ったほうが良いかと存じます。

  • Expand Filesystem:ルートパーティションサイズ拡大
  • Change Locale:ロケールを ja_JP.UTF8 UTF8 へ変更
  • Change Timezone:タイムゾーンを Asia > Tokyo へ変更

有線LAN・無線LAN設定

下記の設定変更・確認を行います。

  • 便宜上、有線LANのIPを固定割当
  • 無線LANのIP割当をDHCPで行う
$ sudo vi /etc/network/interfaces

# 便宜上、有線LANのIPを適当に固定割当にする
auto eth0
iface eth0 inet static
 address 192.168.11.100
 netmask 255.255.255.0

# 無線LAN接続情報は別ファイルに記載する
allow-hotplug wlan0
iface wlan0 inet dhcp
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

上記設定で指定してある無線LAN接続情報の設定ファイル: /etc/wpa_supplicant/wpa_supplicant.conf の内容は、こちらを参考に、wpa_passphraseコマンドを利用して記述します。

下記の部分は、自ネットワーク環境の情報に置き換えてください。

  • 無線LANのWPAパスフレーズ
  • 無線LANのSSID
$ sudo sh -c "wpa_passphrase 無線LANのSSID 無線LANのWPAパスフレーズ >> /etc/wpa_supplicant/wpa_supplicant.conf"

# 内容確認
$ sudo cat /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
    ssid="無線LANのSSID"
    psk=2b1d17284c5410ee5eaa.............
}

設定反映のため、再起動します。

$ sudo reboot

再起動後に、無線LANの接続を確認します。

# ...
# 再起動後
# ...

# wlan0のipv4アドレス (inetアドレス) が割り当てられていることを確認
$ ifconfig
wlan0     Link encap:イーサネット  ハードウェアアドレス xx:xx:xx:xx:xx:xx
          inetアドレス:192.168.3.xxx ブロードキャスト:192.168.3.255  マスク:255.255.255.0
...

# 接続している無線LANのSSIDも念のため確認
$ iwconfig
wlan0     IEEE 802.11bgn  ESSID:"{{無線LANのSSID}}"
...

以上で無線LAN接続が確認できました。

avahi (Zeroconf) 設定

avahiとは、Zeroconfのフリーの実装です。 マルチキャストDNSという技術により、難しい設定をすることなく、同一LAN内にて raspberrypi.local といった{{hostname}}.localという形式の名前で名前解決できるようになります。

設定しなくても問題ありませんが、パッケージをインストールする程度で使えるようになるので、インストールしておくと良いかと存じます。

# avahiのパッケージインストール
$ sudo apt-get install avahi-daemon

/etc/hostname/etc/hostsの内容を確認します。

$ sudo cat /etc/hostname
raspberrypi

$ sudo cat /etc/hosts
...
127.0.1.1 raspberrypi

Raspberry Pi2を再起動します。

$ sudo reboot

Raspberry Pi2再起動後、同一LAN内の他のホストから、raspberrypi.localに向けてpingを飛ばして名前解決の動作確認を行います。

作業端末がWindowsの場合、Appleのサイト から Windows 用 Bonjour をインストールする必要があるかと存じます。

$ ping raspberrypi.local
PING raspberrypi.local (192.168.3.222): 56 data bytes
64 bytes from 192.168.3.222: icmp_seq=0 ttl=64 time=23.439 ms
64 bytes from 192.168.3.222: icmp_seq=1 ttl=64 time=2.591 ms
...

vimインストール

デフォルトだと、viしかインストールされていないので、vimもインストールします。

$ sudo apt-get install vim

# vim ~/.bashrc
# 環境変数EDITOR追記
export EDITOR="vim"

AWS CLIインストール

aptのawscliパッケージをインストールします。

$ apt-cache search awscli
awscli - Universal Command Line Environment for AWS

$ sudo apt-get install awscli

温度センサ(DS18B20)回路・測定プログラム実装

bread

配線図のとおりに、回路接続を行います。

  • DS18B20の1番ピン (GND) – ラズパイGPIOのGNDのどれか
  • DS18B20の2番ピン (DQ) – ラズパイGPIO4
    • 3.3VとGPIO4ピンを抵抗で繋いでプルアップします
  • DS18B20の3番ピン (Vdd) – ラズパイGPIOの3.3Vのどれか

ピン配置は下記サイトを参考にしました。

1-Wireセットアップ

今回使用した温度センサ:DS18B20は、1-Wireというプロトコルで通信を行うことで測定値を取得できます。そのため、Raspberry Pi2側で1-Wireを有効化します。

/etc/modulesに下記の行を追記

$ sudo vim /etc/modules
w1-gpio
w1-therm

/boot/config.txtに下記の行を追記

$ sudo vim /boot/config.txt
dtoverlay=w1-gpio-pullup,gpiopin=4

最後にRaspberry Pi2を再起動する

$ sudo reboot

温度センサとRaspberry Pi2間の疎通確認

こちら を参考に疎通確認を行います。

正常に接続・設定できている場合、/sys/bus/w1/devices/内に、28-00000723c22dのような名前形式のディレクトリができます(環境により、このディレクトリ名は異なります)。存在しない場合は、配線・設定をもう一度確認してください。

$ ls -la  /sys/bus/w1/devices/
lrwxrwxrwx 1 root root 0  3月  7 14:49 28-00000723c22d -> ../../../devices/w1_bus_master1/28-00000723c22d
lrwxrwxrwx 1 root root 0  3月  7 14:48 w1_bus_master1 -> ../../../devices/w1_bus_master1
...

存在する場合、該当するディレクトリ内のw1_slaveという名前のファイルを表示してみます。 すると、下記のような文字列が確認できるはずです。

$ cat /sys/bus/w1/devices/28-00000723c22d/w1_slave
d7 01 4b 46 7f ff 09 10 55 : crc=55 YES
d7 01 4b 46 7f ff 09 10 55 t=29437

この文字列の、t=29437の部分の値がセ氏温度を1000倍した値を表しています。 無事に疎通確認ができましたでしょうか。

温度計測プログラム実装

上記の、sys/bus/w1/devices/28-00000723c22d/w1_slave で取得できるデータをうまいこと加工できれば、どんな言語でも良いのですが、 timofurrer/w1thermsensor というPythonライブラリが簡単そうでよかったので、 今回はPythonで実装して、/home/pi/pi_therm_sensor/PiThermSensor.pyへ設置しました。

# -*- coding: utf-8 -*-
from w1thermsensor import W1ThermSensor

def get_temperature():
    sensor = W1ThermSensor()
    temperature_celsius = sensor.get_temperature()
    return temperature_celsius

temperature = get_temperature()
print("{0:.3f}".format(temperature))

実行例: スクリーンショット 2016-03-07 17.04.59

CloudWatchへの送信処理実装

cloudwatch put-metric-data 用にIAMユーザ追加

Raspberry Pi2から、AWS CLIのコマンドによりCloudWatchへ測定した温度を送信する際に用いるIAMユーザを追加します。

  1. AWSマネジメントコンソールを開く
  2. IAM > ユーザ の順に遷移して、新規ユーザ作成ボタンを押下
  3. ユーザー名をお好みで入力(今回はIoTとした)。「ユーザーごとにアクセスキーを生成」はチェックしたままでOK
  4. ユーザ作成後に提示されるcredentials.csvファイルをダウンロード
  5. IAM > ユーザー 画面にて、 先ほど追加したユーザ名:IoT を検索してクリック
  6. アクセス許可タブ のページに存在する ポリシーのアタッチボタンを押下
  7. CloudWatchFullAccessポリシーを検索して選択し、ポリシーのアタッチボタンを押下

下記のような状態になっていれば大丈夫です。

iam

AWS CLIのプロファイル設定

上記手順でIAMユーザを作成した際のcredentials.csvをもとにプロファイルを設定します。 aws configureコマンド実行時に、秘匿情報の入力を要求されるので指示にしたがって入力します。

ここでは、作成するプロファイル名をiotとします。

aws configure --profile iot
# アクセスキー:credentials.csv の Access Key Id
# アクセスキーシークレット:credentials.csv の Secret Access Key
# リージョン:ap-northeast-1 (東京リージョン)

測定した温度をCloudWatchへ送信するシェルスクリプト実装

AWS CLIのコマンド aws cloudwatch put-metric-data で測定した温度を送信するシェルスクリプトを実装し、/home/pi/pi_therm_sensor/clowdwatch_put_temperature.shへ設置しました。

上記手順で作成したプロファイル:iotを用いて、測定した温度をraspberry_pi_temperatureというメトリクス名で送信しています。

#!/bin/bash

REGION="ap-northeast-1"
THERM_SENSOR_CMD="/usr/bin/python /home/pi/pi_therm_sensor/PiThermSensor.py"
TEMPERATURE=`$THERM_SENSOR_CMD`

echo "temperature: "$TEMPERATURE
/usr/local/bin/aws cloudwatch put-metric-data \
--profile iot \
--namespace "Pi" \
--metric-name "raspberry_pi_temperature" \
--dimensions "Host=pi" \
--unit "None" \
--value $TEMPERATURE \
--region $REGION

Cronで測定した温度を定期的にCloudWatchへ送信する

上記手順で作成したシェルスクリプトを、Cronで定期実行するように設定を追記します。

$ crontab -e

* * * * * /home/pi/pi_therm_sensor/clowdwatch_put_temperature.sh  >> /var/log/cron.log 2>&1

ただし、Raspbianの初期設定のままだと、/var/log/cron.logへログ出力がなされなかったので下記設定を行いました。

/etc/rsyslog.conf設定変更

$ sudo vim /etc/rsyslog.conf

# /var/log/messages に大量のエラーログが吐かれてしまうので、
# 最後にある下記設定をコメントアウト

# daemon.*;mail.*;\
#       news.err;\
#       *.=debug;*.=info;\
#       *.=notice;*.=warn       |/dev/xconsole

# 下記の行がコメントアウトされているので
# 有効にする
cron.*                          /var/log/cron.log

# rsyslog再起動
$ sudo service rsyslog restart

/var/log/cron.log を確認

$ sudo tail /var/log/cron.log
    ...
    Mar  2 16:55:18 raspberrypi CRON[3377]: (CRON) info (No MTA installed, discarding output)
    ...

# No MTA installed
# などと言われるので
# postfixをインストール
$ sudo apt-get install postfix mailutils

すべて正常に動作している場合、AWSマネジメントコンソールのCloudWatchにて、 raspberry_pi_temperatureで検索すれば、 下図のような画面が表示されるはずです。

スクリーンショット_2016-03-09_15_58_19

感想

Raspberry Pi2による温度計測については、

  • OS(Raspbian)側で、Raspberry PiのGPIOを用いたハードウェア制御の仕組みを用意してくれている
  • Raspberry Piブームのおかげで、Web上に参考になる先行事例がたくさんある
  • 一般的なスクリプト言語でプログラムを記述できる

といった理由により、とても簡単にできたと存じます。

また、CloudWatchによる温度の可視化・監視についても、AWS CLIを用いることで、 いくつかのコマンドを叩くだけで、簡単にできてしまいました。

便利なモノはたくさん揃っているので、これからは、手間がかかる/本質以外の箇所は既存のモノを組み合わせてスピーディーに解決し、 アイデアの本質的な部分へ最大限の力を注ぐことが大切なのではないでしょうか。

参考サイト

関連サービス

CloudWatch構築・運用