Raspberry PiでSQLiteに温度データを蓄えてみよう!

20170729-blog-1

こんにちは、ゆきです!

夏の暑い時期までにRaspberry Piで家庭菜園用自動水やり機を作りたいと思っていたのに、あれよあれよという間にもう7月も終わりですね( ˘ω˘ )

さて、前回Raspberry Piで温度センサーDHT11を使って室温を計測する方法について紹介しましたが、今日は取得したデータをSQliteに保存する方法についてご紹介したいと思います。

前回の記事は以下です。今回はその続きから。

SQLiteってなんなのさ?

既にご存知かもしれませんが、SQLiteとはアプリケーションに組み込む事を目的とした軽量な無償のデータベースのことです。個人が片手間に作るアプリケーション用としては十分なデータベースであり、Pythonからも簡単に扱えます。

データベースがファイルとして生成され、データベースの移動も簡単なので取り扱いがすっごく楽ちん。また、WEBアプリケーションからも呼び出す事ができるので、今後温度の推移をウェブから確認したい時にも重宝しそうです。

今回はそんなSQLiteを使って、DHT11から取り込んだ情報を保管する仕組みを構築したいと思います。

環境構築

今回はDHT11で取得した温度・湿度データをSQLiteで保存するPythonスクリプトを、crontabで30分毎に動作させたいと思います。

基本的にPythonにはSQLiteが組み込まれているので、データベースの準備は不要です。一方、crontabを使用するのに、1点作業が必要なので先にご紹介します。

MTAの設定

Raspberry PiにはデフォルトでMTA(Mail Transfer Agent)がインストールされていないので、まずはpostfixをインストールします。これがないとcronが動かないのだ。

sudo apt-get install postfix

インストールが始まると、設定が聞かれますが、とりあえずno configurationでOK。

とりあえずここまでで前準備は完了。

DHT11のデータをSQLiteに保存するスクリプト

前回の記事と、QiitaのPythonでSQLiteの記事をベースに次のように書き換えてみました。このファイルはdht11.pyと同じフォルダに保存します。

# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
import sqlite3
import dht11
import time
import datetime

# initialize GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()

# read data using pin 14
instance = dht11.DHT11(pin=14)

while True:
    result = instance.read()
    if result.is_valid():
        TIME = str(datetime.datetime.now())
        TEMP = result.temperature
        HUMID =  result.humidity
        #以下のプリントは無くても良い。
        print("Last valid input: " + TIME)
        print("Temperature: %d C" % TEMP)
        print("Humidity: %d %%" % HUMID)
        #データが取れたのでブレイクしてSQLiteに保存
        break;

# SQLiteのデータベースの名前と保管場所を指定。
#このコードはdht11.pyと同じ場所に置く必要があります。DBも同じ場所にしてみました。
dbname = '/home/pi/Python-Script/DHT11_Python/dht11_1.db'
# データベース内のテーブルの名前
dbtable = 'sensor1'
# SQLiteへの接続
conn = sqlite3.connect(dbname)
c = conn.cursor()

# SQLiteにテーブルがあるかどうか確認するクエリ
checkdb = conn.execute("SELECT * FROM sqlite_master WHERE type='table' and name='%s'" % dbtable)
# もしテーブルがなかったら新規でテーブルを作成する
if checkdb.fetchone() == None:
    # ID、タイムスタンプ、温度、湿度の4列のテーブルを作成するクエリを作成。IDは自動附番。
    create_table = '''create table ''' + dbtable + '''(id integer primary key autoincrement, timestamp varchar(20),
                  temp real, humid real)'''
    # クエリを実行
    c.execute(create_table)
    # 変更を保存する
    conn.commit()

# SQL文に値をセットする場合は,Pythonのformatメソッドなどは使わずに,
# セットしたい場所に?を記述し,executeメソッドの第2引数に?に当てはめる値を
# タプルで渡す.
# 温度、湿度、タイムスタンプを保存。
sql = 'insert into sensor1 (timestamp, temp, humid) values (?,?,?)'
data= (TIME, TEMP, HUMID)
c.execute(sql, data)
conn.commit()

#接続を切る
conn.close()

SQLiteは①データベースの接続、②クエリの登録、③クエリの実行、④結果の保存、の流れでプログラムを組んでいけばよいです。

上記のソースから該当箇所を抜粋すると以下のような形で、①は1,2行目、②3,4行目、③5行目、④6行目というように処理しています。

conn = sqlite3.connect(dbname)
c = conn.cursor()
sql = 'insert into sensor1 (timestamp, temp, humid) values (?,?,?)'
data= (TIME, TEMP, HUMID)
c.execute(sql, data)
conn.commit()

セキュリティ対策大丈夫かは判らん(; ・`д・´)

難しい事は他のサイトに任せよう

crontabの設定

crontabの設定については、「決まった時間に処理する(.Make)」の記事が詳しいです。

私の例でいえば、以下のように設定しています。

crontabの設定
crontabの設定
0,30 * * * * python /home/pi/Python-Script/DHT11_Python/store-sqlite.py

上記の場合、毎時0分と30分の時に、pythonのコマンドでstore-sqlite.pyを実行します。

後は時間になれば自動的にファイルが実行され、以下のような感じで保存されます。
ちなみに上記のスクリプトだけだとデータベースの中身を確認しづらいので、そのスクリプトについては最後にご紹介します。DBを移動してFirefoxで見るのが楽というサイトもあるのだけれど、DBを移動する手間すらメンドクサイので簡単な動作確認くらいはこれでやっています。

データ増えた時は…また考えます。

SQLiteの保存結果
SQLiteの保存結果

nanoエディタについて

crontab -e でcrontabの設定ファイルを開いた際に、nanoエディタという編集ツールで起動します。ちょっと癖があるので簡単に使い方メモ。

テキストの編集はWindowsのテキストエディタと変わりませんが保存方法が。

変更を保存するには^OのWriteOut(保存)する必要がありますが、^Oをどう入力すればよいか判らねぇ…。調べてみたら^はCTLのことらしいです。つまりCTL+Oの意味。

いまだにviエディタすら使いこなせないおじさんにはつらいです( ˘•ω•˘ )

押した後はファイル名が出るので、Enterキーを押して決定。最後にCTL+XでExitしましょう。じゃないとちゃんと保存が反映されません。

SQLiteデータベースの中身の確認と削除

ちょっと一時しのぎのテストスクリプトなので何ですが、テーブルを一度削除するスクリプトと、テーブルの中身を確認するスクリプトを置いておきます。

# -*- coding: utf-8 -*-
import sqlite3

#SQliteのテーブルの中身を確認する
def read_table(dbname,dbtable):
    conn = sqlite3.connect(dbname)
    c = conn.cursor()

    select_sql = 'select * from sensor1'
    for row in c.execute(select_sql):
        print(row)

    conn.close()

#SQliteのテーブルを削除する
def del_table(dbname,dbtable):
    conn = sqlite3.connect(dbname)
    c = conn.cursor()
    sql = "drop table "+dbtable
    c.execute(sql,)
    conn.commit()

#メイン関数
if __name__ =='__main__':
    #データベース名
    dbname = '/home/pi/Python-Script/DHT11_Python/dht11_1.db'
    #テーブル名
    dbtable = 'sensor1'

    #使いたくないほうをコメントアウトして実行
    #del_table(dbname,dbtable)
    read_table(dbname,dbtable)

次は本格的にきゅうりの鉢からデータを取得していきます!

以上!