Raspberry Pi で気温・湿度を取得するウェザーステーションを作ってみた

スポンサーリンク

Здравствуйте!
この記事は、スタートトゥデイ工務店 Advent Calendar 18日目の記事です。
お約束事ですが、私の個人的な意見・経験に基づくものであり、私の雇用者、所属団体には一切の関係はありませんし、イロイロ気になるところがあるかもしれませんが、そこんとこお察しください。

はじめに

とあるMashup Awardsのとあるハッカソンイベントで作った作品を解体したおかげでRaspberry Pi 3が余ってたり、手元に手頃な温湿度センサーモジュールが転がっていたり、ほんの出来心から、ウェザーステーションを作ってみました。

  • Raspberry Pi 3を使って
  • Raspibian Jessieを使用しています
  • Raspberry Pi のインストール、初期設定については、説明しません
  • 温湿度センターには am2320 を使用して、i2c で接続しています
  • センサーの読み出しでは Ruby を使っています
  • センサーでの測定値は Logger で log に出力しています

使用したもの

ガジェット
Raspberry Pi 3
OS
Raspbian Jessie
センサ
AM2320

温湿度センサーを取り付けて、Raspbianの設定をする

温湿度センサーをブレッドボード上に設置

センサー取り付け

簡単に示すと、以下のようになっています。

たまたまT型の接続キットを持っていたので使っていますが、ピンから接続しても問題ありません。

Raspbianの設定 – i2c の有効化

Raspberry Piの初期状態ではi2c機能が有効化されていないため、有効化する必要があります。

$ sudo raspi-config

表示されるメニューの『7 Advanced Option』を選択します。

i2c 有効化 その1

『5 Interfacting Options』を選択し、『P5 I2C』を選択します。

i2c 有効化 その2

i2c 有効化 その3

I2C接続を有効化してもよい?(意訳)と聞かれているので、『はい』を選択し、その後のページも『OK』を選びます。

i2c 有効化 その4

i2c 有効化 その5

その後、一旦、再起動します。(再起動しますか?というダイアログが表示されるので、『はい』を選択します)

Raspbianの設定 – i2c-tools のインストール

i2c接続するセンサーとの疎通確認を行うために、i2c-toolsというパッケージをインストールします。

$ sudo apt-get install -y i2c-tools

Raspbianの設定 – i2cのグループにユーザーを追加する

ここでは、piユーザ(初期ユーザ)でi2cにアクセスできるように、i2cグループに追加します。

$ sudo adduser pi i2c

Raspbianの設定 - 設定ファイルの修正

/boot/config.txt に以下の内容を追記します。

dtparam=i2c_arm=on

Raspbianの設定 – カーネルモジュールの自動読み込み

起動時にカーネルモジュールに自動的に読み込ませるために、/etc/modulesに以下を追記します。

i2c-bcm2835
i2c-dev

以上、設定したら、再度、再起動します。

再起動後、カーネルモジュールが読み込まれているか確認をします。

$ lsmod
Module                  Size  Used by
bnep                   10340  2
hci_uart               17943  1
btbcm                   5929  1 hci_uart
bluetooth             326105  22 bnep,btbcm,hci_uart
brcmfmac              186403  0
brcmutil                5661  1 brcmfmac
cfg80211              427855  1 brcmfmac
rfkill                 16037  4 cfg80211,bluetooth
snd_bcm2835            20447  0
snd_pcm                75762  1 snd_bcm2835
snd_timer              19288  1 snd_pcm
snd                    51908  3 snd_bcm2835,snd_timer,snd_pcm
bcm2835_gpiomem         3040  0
bcm2835_wdt             3225  0
uio_pdrv_genirq         3164  0
uio                     8000  1 uio_pdrv_genirq
i2c_dev                 5859  0
i2c_bcm2708             4834  0
ipv6                  347594  34

i2c_bcm2708, i2c_devが存在すればOKです。

疎通確認

先程インストールした i2c-tools の i2cdetect コマンドを利用して、疎通確認を行います。

$ sudo 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: -- -- -- -- -- -- -- -- -- -- -- -- 5c -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

AM2320のアドレスである 0x5cが検出されました。
ちなみに、AM2320はセンサー自体の発熱による湿度誤差を軽減するために、休止状態になることがあります。
そのため、i2cdetectコマンドをなげても検出されないことがありますが、何度かコマンドを実行すると、検出されます。

温度と湿度を取得するコード

まず、Rubyからi2cを操作するために、i2c Gemをインストール擦る必要があります。

$ sudo gem install i2c

i2c経由でAM2320でデータを取得します

#!/usr/bin/env ruby

require 'rubygems'
require 'i2c'

class AM2321

  def initialize(path, address = 0x5c)
    @device = I2C.create(path)
    @address = address
  end

  def crc16(data)
    crc = 0xFFFF
    data.each do |b|
      crc ^= b;
      8.times do
        if (crc & 0x01) != 0 then
          crc = crc >> 1
          crc ^= 0xA001
        else
      crc = crc >> 1
        end
      end
    end
    return crc
  end

  def read
    # Wake up sensor
    begin
      @device.write(@address, "")
    rescue
      # ignore
    end

    # Read sensor values
    begin
      s = @device.read(@address, 8, "\x03\x00\x04")
    rescue
      return nil
    end
    func_code, ret_len, hum_h, hum_l, temp_h, temp_l, crc_l, crc_h = s.bytes.to_a
    orig_crc = (crc_h << 8) | crc_l
    hum = (hum_h << 8) | hum_l
    temp = (temp_h << 8) | temp_l

    # Calc CRC
    crc = crc16(s[0,6].bytes)

    return nil if crc != orig_crc
    return hum/10.0, temp/10.0
  end

end

sensor = AM2321.new('/dev/i2c-1')

temp, hum = sensor.read

puts "気温:#{temp.to_s}, 湿度:#{hum.to_s}"
$ sudo ruby test.rb
気温:23.9, 湿度:37.2

Loggerで出力するようにしてみる

Loggerを使い、/var/log/weatherbox/に出力するようにしてみます

#!/usr/bin/env ruby

require 'rubygems'
require 'i2c'
require 'date'
require 'json'
require 'logger'
require 'fileutils'

class AM2321

  def initialize(path, address = 0x5c)
    @device = I2C.create(path)
    @address = address
  end

  def crc16(data)
    crc = 0xFFFF
    data.each do |b|
      crc ^= b;
      8.times do
        if (crc & 0x01) != 0 then
          crc = crc >> 1
          crc ^= 0xA001
        else
          crc = crc >> 1
        end
      end
    end
    return crc
  end

  def read
    # Wake up sensor
    begin
      @device.write(@address, "")
    rescue
      # ignore
    end

    # Read sensor values
    begin
      s = @device.read(@address, 8, "\x03\x00\x04")
    rescue
      return nil
    end

    func_code, ret_len, hum_h, hum_l, temp_h, temp_l, crc_l, crc_h =
s.bytes.to_a
    orig_cc = (crc_h << 8) | crc_l
    hum = (hum_h << 8) | hum_l
    temp = (temp_h << 8) | temp_l

    # Calc CRC
    crc = crc16(s[0,6].bytes)

    return nil if crc != orig_cc
    return temp/10.0, hum/10.0
  end
end


logdir = "/var/log/weatherbox/"
FileUtils.mkdir("#{logdir}") unless FileTest.exist?("#{logdir}")

logfile = Logger.new("#{logdir}weatherbox.log", "daily")
logfile.formatter = proc do |severity, datetime, progname, message|
  "#{message}\n"
end


sensor = AM2321.new('/dev/i2c-1')

loop do
  temp, hum = sensor.read
  d = Time.now
  date = d.strftime("%Y-%m-%d %H:%M:%S")

  data = Hash.new
  data["Temperature"] = temp
  data["Humidity"] = hum

  json = Hash.new
  json["Time"] = date
  json["Data"] = data

  logfile.info(json.to_json)
  sleep(5)
end

このコードを実行すると、/var/log/weatherbox/weatherbox.logに対して、以下のようなデータが出力されます。

# Logfile created on 2016-12-18 22:59:57 +0900 by logger.rb/v1.2.7
{"Time":"2016-12-18 22:59:57","Data":{"Temperature":23.9,"Humidity":36.9}}
{"Time":"2016-12-18 23:15:03","Data":{"Temperature":23.7,"Humidity":37.0}}
{"Time":"2016-12-18 23:15:08","Data":{"Temperature":23.7,"Humidity":37.0}}
{"Time":"2016-12-18 23:15:16","Data":{"Temperature":23.6,"Humidity":37.0}}
{"Time":"2016-12-18 23:15:21","Data":{"Temperature":23.6,"Humidity":37.0}}
{"Time":"2016-12-18 23:15:26","Data":{"Temperature":23.6,"Humidity":37.0}}

今後の流れ

Raspberry PiでAM2320という温湿度センサーを使って温度と湿度を取得しました。
現時点では、Raspberry Pi内にデータを格納しているので、次回、fluentdを使って、クラウドへデータを保存するようにします。(えっっっ)

それでは、до свидания!

コメント

タイトルとURLをコピーしました