現在の室温をtweetしよう @ keruru | 2016-05-06T14:56:01+09:00 | 8 分で読めます | 更新日時 2016-05-06T14:56:01+09:00

連休に自宅サーバをこれまで愛用していたHP社製microserverからRaspberry Pi3へリプレイスしました。microserverでは地味にRAID1+0環境にしてたりして安心確実ストレージとなっているのですが、日常からHDDを4本も回してなくていいんじゃ?と言う事が事はじめです。とは言えストレージサーバとしてはとても信頼おける状態となっていますので、時折WakeOnLanで起こしてはバックアップ先として活躍して頂く予定で、普段使いはRaspberry Pi3につないだシングルのHDDでも問題ないよね、という感じです。

さて普通にLinux環境が動くRaspberry Piですのでサーバ構築はそれこそ鼻歌交じりで完了します。何も躓くところはありません。そしてコンパクトになり各種センサーを接続するGPIOが接続しやすく、となると色々センサー繋ぎたくなりますよね。

我が家ではCITIZENの電波時計をリビングや寝室に置いてあり、これには温湿度計が付いています。脱衣所や窓辺にはそれぞれ脱衣所の室温や外気温(屋根裏にも設置してあります)を測るための温度計を設置してありますが、それぞれ独立した温度計でその時々の温度しか知る事が出来ませんしその場に行かねばわかりません。

じゃあRaspberry Piを設置するリビング位Raspberry Piに計測させて遠隔でも見れるようにしたらいいよね。と言う事でこの連休に色々パーツを買いそろえて表題の通り室温をTweetするまで作りました。

さて、こんな事は実はすでに先人が多く通った道なのでGoogleで検索するといっぱい記事が見つかります。「Raspberry Pi BME280」あたりで検索してみてください。BME280は何かというと今回用いた温湿度センサーで1000円ちょっとする部品ですが、1チップで温度も湿度も気圧も測れてお得でおススメです。

今回Raspberry Pi以外に用意したものとしては

  • AE-BME280 (秋月電子製温湿度気圧センサー)
  • ブレッドボード(試作に大活躍)
  • ジャンパーピン(オス-メス)
  • ジャンパーピン(オス-オス)
  • 十字配線ユニバーサル基板

こんな感じです。その他にもLIS3DHと言う3軸加速度センサーも一緒に買って回路に組んでますが、今回の室温をTweetするのには関係ない部分なので割愛。

さて、回路を組んで試験する処までは こちらのページ がとても参考になります。むしろこちらのページだけで十分でこんなエントリー要らないくらい!

Raspberry Piでの準備

Raspberry Piに入れているOSにより準備が異なってきます。Raspbianであれば

$ sudo raspi-config

これで設定画面が開きますのでAdvanced Optionを選びます。

Advanced Optionの中にI2Cの設定がありますので、選択し有効化。これでI2Cが使えるようになります。

またその他としてI2Cを扱うツールをインストールする必要があります。

$ sudo apt-get -y install i2c-tools python-smbus

これでまずは温度を取得するのに必要なツールがインストールされました。ここで一度再起動しておきましょう。

I2C通信の仕組みを知る

アナログセンサーを接続してアナログデータを取ったりした事はありますが、I2Cを触るのは初めてでした。センサー単体で動かしてよしよし、って言うページはとても多く見つかるんですが欲張りにセンサー2つ以上繋ぎたい場合は?となるとなかなかページ見つかりません。仕方ないので I2Cについて調べたら なんの事はない、バス接続で良いと知りました。という訳で2つのセンサーを繋いでみよう、とこんな回路にして接続してみました。AE-BME280をI2C通信として用いるためにはJ3と書かれたジャンパを半田でショートさせる必要があります。ちなみにLIS3DHの場合は裏面のABC3つのジャンパをショートさせます。これらはそれぞれ添付のマニュアルにちゃんと記載がありますのでちゃんと確認しましょう。

なお今回両方のセンサーを繋ぐため以下のようになってますが、今回のお題である室温をtweetするだけであれば右側のセンサーは不要です。

センサー側の接続が済んだらRaspberry Piに接続しますがI2Cはホットプラグ可能ですので電源入れたままで繋いで問題ありません。接続端子間違えないようにしましょうね。例えば今回のBME280もLIS3DHも電源電圧は3.3Vですのでうっかり5Vの端子に繋いじゃったりすると壊れてしまう可能性もゼロではありません。

接続したらi2cdetectコマンドを用いてraspberry piで接続を確認してみると

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

ばっちり認識されました。0x76の方が今回用いる温度センサーで0x18の方が今回用いない加速度センサーです。と言う事でI2Cに対応しているセンサーであれば測りたいセンサーをこんな感じでどんどん繋いで行ける!って事ですね。便利!

温度データを取得する

さて、I2Cデバイスとして認識するところまで来ました。いよいよここからデータを取りだします。本当はデータシートを読んで頑張らなくては本来いけない所なんでしょうけれども、 SWITCH SCIENCEさんが用意して下さっているスクリプト をまずは使って動作確認します。

$ wget https://raw.githubusercontent.com/SWITCHSCIENCE/BME280/master/Python27/bme280_sample.py
$ sudo python bme280_sample.py
temp : 28.97  ℃
pressure : 1017.31 hPa
hum :  34.95 %

このままツイートさせてもいいのですが加工したいのでスクリプトを修正

 #!/usr/bin/python
#coding: utf-8

import smbus
import time

import datetime
import locale

d = datetime.datetime.today()

bus_number  = 1
i2c_address = 0x76

bus = smbus.SMBus(bus_number)

digT = []
digP = []
digH = []

t_fine = 0.0
yymmdd = 0
hhmm = 0
temperature = 0
humidity = 0
pressure = 0

def writeReg(reg_address, data):
        bus.write_byte_data(i2c_address,reg_address,data)

def get_calib_param():
        calib = []

        for i in range (0x88,0x88+24):
                calib.append(bus.read_byte_data(i2c_address,i))
        calib.append(bus.read_byte_data(i2c_address,0xA1))
        for i in range (0xE1,0xE1+7):
                calib.append(bus.read_byte_data(i2c_address,i))

        digT.append((calib[1] << 8) | calib[0])
        digT.append((calib[3] << 8) | calib[2])
        digT.append((calib[5] << 8) | calib[4])
        digP.append((calib[7] << 8) | calib[6])
        digP.append((calib[9] << 8) | calib[8])
        digP.append((calib[11]<< 8) | calib[10])
        digP.append((calib[13]<< 8) | calib[12])
        digP.append((calib[15]<< 8) | calib[14])
        digP.append((calib[17]<< 8) | calib[16])
        digP.append((calib[19]<< 8) | calib[18])
        digP.append((calib[21]<< 8) | calib[20])
        digP.append((calib[23]<< 8) | calib[22])
        digH.append( calib[24] )
        digH.append((calib[26]<< 8) | calib[25])
        digH.append( calib[27] )
        digH.append((calib[28]<< 4) | (0x0F & calib[29]))
        digH.append((calib[30]<< 4) | ((calib[29] >> 4) & 0x0F))
        digH.append( calib[31] )

        for i in range(1,2):
                if digT[i] & 0x8000:
                        digT[i] = (-digT[i] ^ 0xFFFF) + 1

        for i in range(1,8):
                if digP[i] & 0x8000:
                        digP[i] = (-digP[i] ^ 0xFFFF) + 1

        for i in range(0,6):
                if digH[i] & 0x8000:
                        digH[i] = (-digH[i] ^ 0xFFFF) + 1

def readData():
        data = []
        for i in range (0xF7, 0xF7+8):
                data.append(bus.read_byte_data(i2c_address,i))
        pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
        temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
        hum_raw  = (data[6] << 8)  |  data[7]

        compensate_T(temp_raw)
        compensate_P(pres_raw)
        compensate_H(hum_raw)

def compensate_P(adc_P):
        global  t_fine
        pressure = 0.0

        v1 = (t_fine / 2.0) - 64000.0
        v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * digP[5]
        v2 = v2 + ((v1 * digP[4]) * 2.0)
        v2 = (v2 / 4.0) + (digP[3] * 65536.0)
        v1 = (((digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8)  + ((digP[1] * v1) / 2.0)) / 262144
        v1 = ((32768 + v1) * digP[0]) / 32768

        if v1 == 0:
                return 0
        pressure = ((1048576 - adc_P) - (v2 / 4096)) * 3125
        if pressure < 0x80000000:
                pressure = (pressure * 2.0) / v1
        else:
                pressure = (pressure / v1) * 2
        v1 = (digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096
        v2 = ((pressure / 4.0) * digP[7]) / 8192.0
        pressure = pressure + ((v1 + v2 + digP[6]) / 16.0)
        global press
        press = pressure/100

def compensate_T(adc_T):
        global t_fine
        v1 = (adc_T / 16384.0 - digT[0] / 1024.0) * digT[1]
        v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2]
        t_fine = v1 + v2
        temperature = t_fine / 5120.0
        global temp
        temp = temperature -4

def compensate_H(adc_H):
        global t_fine
        var_h = t_fine - 76800.0
        if var_h != 0:
                var_h = (adc_H - (digH[3] * 64.0 + digH[4]/16384.0 * var_h)) * (digH[1] / 65536.0 * (1.0 + digH[5] / 67108864.0 * var_h * (1.0 + digH[2] / 67108864.0 * var_h)))
        else:
                return 0
        var_h = var_h * (1.0 - digH[0] * var_h / 524288.0)
        if var_h > 100.0:
                var_h = 100.0
        elif var_h < 0.0:
                var_h = 0.0
        global hum
        hum = var_h

def setup():
        osrs_t = 1                      #Temperature oversampling x 1
        osrs_p = 1                      #Pressure oversampling x 1
        osrs_h = 1                      #Humidity oversampling x 1
        mode   = 3                      #Normal mode
        t_sb   = 5                      #Tstandby 1000ms
        filter = 0                      #Filter off
        spi3w_en = 0                    #3-wire SPI Disable

        ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode
        config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en
        ctrl_hum_reg  = osrs_h

        writeReg(0xF2,ctrl_hum_reg)
        writeReg(0xF4,ctrl_meas_reg)
        writeReg(0xF5,config_reg)

setup()
get_calib_param()
if __name__ == '__main__':
        try:
                readData()
        except KeyboardInterrupt:
                pass

        print d.strftime("%Y%m%d,%H:%M"),",%2.2f,%4.2f,%6.2f" % (temp, hum,press)

これで扱いやすいデータになりました。 所で実はここで校正データを入れてあります。114行目に"temp = temperature -4"とあり、ここの最後で値から4度引いています。これは何かというと組んだ回路で測定して誤差も少ない素晴らしいセンサーを使っているのですが、例えば近くにRaspberry Piと言う熱源がありますよね。ですのでここで表示される値が必ずしも我々の体感する室温か?というとたぶん高めに表示されると思います。ですのでいくつか温度計を用意して校正すると良いかと思います。

$ sudo python room_tweet.py
20160506,14:03 ,25.12,36.98,1017.93

いよいよtweetする部分

Raspberry Piからscriptでtweetするのには ttytter と言うのが流行っぽいです。でもリンク先を見に行くとTTYtter is dead.とか書いてますね(汗)

ttytterの使い方は こちらのページが詳しい です。

インストールしてまずは認証画面を開きます。 途中"Press RETURN/ENTER to continue “と言われるのでEnterを押しましょう。

$ sudo apt-get -y install ttytter
$ ttytter -ssl

すると認証用のURLが出てきますのでブラウザでその認証URLを開き、アプリケーション認証。出てくるPIN番号をまたTerminalに返してあげてください。

tweetするには

$ ttytter -ssl -status="tweet内容"

となりますので先ほどの温度取得pythonスクリプトで生成してあげればいいのですが他用途でもこの温度取得scriptは使っていますので(グラフを作成している)、別途簡単なshellscriptで先ほどのpythonスクリプトを叩いてtweetしています。

#!/bin/sh
export LANG=ja_JP.utf8
export LANGUAGE=japanese

 text=`sudo /path/room_tweet.py`
 time_value=`echo $text | awk -F, '{print $2}'`
 temp_value=`echo $text | awk -F, '{print $3}'`
 humidity_value=`echo $text | awk -F, '{print $4}'`
 hpa_value=`echo $text | awk -F, '{print $5}'`
 tweet="${time_value} 現在の室温は ${temp_value} 度、湿度は ${humidity_value} %、気圧は ${hpa_value} hPaです。"
 ttytter -ssl -status="${tweet}"

上記の通りsudoをscriptより実行していますのでroot_tweet.pyの実行はsudoersファイルを編集してNOPASSで実行できないと定期的に実行してくれません。あとはこれをcronで回すだけ! 気温測定のScriptとTweet部を別にしておく事でttytterが使えなくなったときの修正も楽ですし、特定の室温を超えたときだけtweetなんて条件文もちょちょいと書けていいかな。

こんな感じで定期的に室温をtweetしています。フォロワーさんの迷惑にならないように頻度は考えましょう。


© 2006 - 2021 Keruruのブログ

Powered by Hugo with theme Dream.

avatar
About Me

ペンネーム/Nick

けるる etc

お仕事

テクニカルライティング/システムエンジニア/ネットワークエンジニア

愛用中のPC
  • NEC LAVIE ProMobile
  • SAMSUNG Chromebook Pro
  • Surface Pro 4
  • ThinkPad T440s
  • GPD Pocket
愛用中のPDA/SmartPhone
  • iPhoneSE 2nd(MAIN/docomo)
  • Unihertz TiTAN(SUB/docomo/SIM FREE)
  • OPPO Reno-A(SUB/rakuten/SIM FREE)
  • iPad Pro 11inch(SUB/docomo/SIM FREE)
愛車
  • MITSUBISHI PAJERO mini ‘2012
  • HONDA CRF250RALLY ‘2018
  • MERIDA SCULTURA4000 ‘2015
  • Carry-Me ‘2016
  • GIOS PANTO ‘2007
  • R&M BD-1 ‘2006
旅の記録2020
行き先など 北海道 海外
2020 12 鬼怒川温泉旅行
2021 02 箱根温泉旅行
旅の記録2010
行き先など 北海道 海外
2010 05 函館観光旅行
2010 09 みなかみ温泉旅行
2011 09 Gios Pantoで自転車旅(札幌・夕張・帯広界隈)
2012 03 パジェミ納車記念上諏訪温泉旅行
2012 08 西伊豆旅行
2012 09 東北キャンプツーリング
2012 10 新婚旅行(NYC-CFO)
2013 09 パジェミで北海道、道東漫遊+念願の旭山動物園
2014 08 三菱スターキャンプ参加
2014 09 台湾旅行(台湾新幹線で高雄にも)
2015 03 九州旅行(うきは旅行)
2015 09 香港旅行
2016 09 北海道ツーリング
2016 09 上諏訪旅行
2017 09 台湾旅行(現地集合現地解散)
2018 05 鹿児島・熊本旅行
2018 09 タイ・チェンマイ旅行
2019 01 高知ツーリング
2019 05 沖縄弾丸旅行
2019 05 別府弾丸旅行
2019 09 ハワイ旅行(まったりホノルルAB&B)
旅の記録2000
行き先など 北海道 海外
2000 08 夏休みで北海道帰省
2001 06 漫画家さん妙高ツーリング
2001 09 RVF400で稚内・網走・釧路・富良野・夕張(初バイク)
2002 07 夏のフーリツーリング
2002 07 CBR954RRで森・函館・稚内・網走・根室・富良野・夕張
2002 09 乗鞍岳ツーリング
2003 09 自転車で北海道(ただし札幌出たあたりで挫折)
2004 09 DJEBEL200で2002年と同じコース
2005 09 DJEBEL200にタンデムで夕張・帯広・士幌・網走・稚内と逆回り
2006 07 大阪観劇の旅(中央線をひたすら乗っていった貧乏旅行)
2007 09 XT660Rでえりも辺りでひたすら道東だけを堪能した北海道ツーリング
2008 08 四国鉄道旅行(サンライズゆめで四国入り、四国内はひたすら鈍行旅
2009 09 台湾旅行(初海外旅行)
2009 09 鈴鹿エンデューロにミニベロで参戦旅行
(C)Keruru. All Rights Reserved