6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ラズパイで温度湿度気圧を測る

Last updated at Posted at 2017-12-02

#モチベーション
センサを使った何かをやってみたかったから、温度・湿度・気圧あたりでも計測してみるか。

#使用したもの
・RaspberryPiZeroW
・BME280センサモジュール(ピンヘッダ実装済み)

#仕様
・5分に1回、温度・湿度・気圧を測ってcsvで直近50回のデータを保存しておく。
・csvからグラフを描画してpng画像として保存しておく。
・png画像をWebサーバにあげてどこからでも確認できるようにする。
・うろ覚えだけど、たしかI2Cを有効にする設定をしないといけなかった気がするので、その辺は各自調べてくださいね。

#事前準備
I2Cの有効化とPythonでI2Cを扱うための準備をするよ。

##I2C有効化

I2C有効化
pi@raspberrypi:~ $sudo raspi-config

2019-09-08 (2).png
「5」を選択

2019-09-08 (3).png
「P5」を選択

2019-09-08 (4).png
「Yes」を選択

2019-09-08 (5).png
「Ok」で完了

##必要なモジュールのダウンロード

2つダウンロード
pi@raspberrypi:~ $sudo apt-get install i2c-tools
pi@raspberrypi:~ $sudo apt-get install python-smbus

準備終了。

#ブレッドボード
bme280_ブレッドボード.png

#回路図
bme280_回路図.png

#ソースコード(計測・csv保存)
参考にリンクを貼っておいたけど、スイッチサイエンスさんがサンプルコードを公開しているのでそれに付け足していく。
直近50回分(5分*50回=250分前まで)の計測データだけcsvでそれぞれ保存してる。
形式は「年,月,日,時,分,計測値\n」
csvの保存先は/var/www/html/

bme280_sample.py

#Save the temperature, humidity, and atmospheric pressure obtained from bme280 in csv
#csv format:
#year,month,date,hour,min,val
#coding: utf-8
#2017/09/23
#2017/10/26

from smbus import SMBus
import time
import csv
import datetime

bus_number  = 1
i2c_address = 0x76
MAX_DATA=50

bus = SMBus(bus_number)

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

t_fine = 0.0

d=datetime.datetime.today()

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
	ary_pressure=["0,0,0,0,0,0\n" for i in range(MAX_DATA)]
	
	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)  

	print("pressure : %7.2f hPa" % (pressure/100))

	fp=open("/var/www/html/pressure.csv","rb")
	line=fp.readline()
	while line:
		ary_pressure.pop(0)
		ary_pressure.append(line)
		line=fp.readline()
	ary_pressure.pop(0)
	ary_pressure.append(str(d.year)+","+str(d.month)+","+str(d.day)+","+str(d.hour)+","+str(d.minute)+","+str(pressure/100)+"\n")
	fp.close()
	
	fp=open("/var/www/html/pressure.csv","w")
	fp.writelines(ary_pressure)
	fp.close()

def compensate_T(adc_T):
	global t_fine
	ary_temp=["0,0,0,0,0,0\n" for i in range(MAX_DATA)]
	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
	print("temp : %-6.2f " % (temperature))

	fp=open("/var/www/html/temp.csv","rb")
	line=fp.readline()
	while line:
		ary_temp.pop(0)
		ary_temp.append(line)
		line=fp.readline()
	ary_temp.pop(0)
	ary_temp.append(str(d.year)+","+str(d.month)+","+str(d.day)+","+str(d.hour)+","+str(d.minute)+","+str(temperature)+"\n")
	fp.close()
	
	fp=open("/var/www/html/temp.csv","w")
	fp.writelines(ary_temp)
	fp.close()

def compensate_H(adc_H):
	global t_fine
	ary_hum=["0,0,0,0,0,0\n" for i in range(MAX_DATA)]
	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
	print("hum : %6.2f %%" % (var_h))
	
	fp=open("/var/www/html/hum.csv","rb")
	line=fp.readline()
	while line:
		ary_hum.pop(0)
		ary_hum.append(line)
		line=fp.readline()
	ary_hum.pop(0)
	ary_hum.append(str(d.year)+","+str(d.month)+","+str(d.day)+","+str(d.hour)+","+str(d.minute)+","+str(var_h)+"\n")
	fp.close()
	
	fp=open("/var/www/html/hum.csv","w")
	fp.writelines(ary_hum)
	fp.close()

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

#ソースコード(png画像生成・サーバに送信)
FTPサーバにpng画像あげて、自宅にいなくても自宅の温度とかがわかる。
温度が低すぎたり、湿度が不快だったらLINEにメッセージを飛ばす。
(LINEにメッセージを飛ばすことについては解説しません。)
こちらも生成した画像は/var/www/html/に保存。
グラフの描画にはmatplotlibを使ってる。

###修正箇所
・ラベルが見切れてしまう問題を修正しました。
・気圧があまり変化しなかったとき、y軸が指数表記になってしまうことがあったのを最近修正しました。

env_graph.py
#Graph the temperature, humidity, pressure and upload it to the FTP server.
#coding: utf-8
#2017/09/23
#2017/10/04
#2017/10/26

import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import csv
from pylab import *
from ftplib import FTP
import re
import requests
import os

from linebot import LineBotApi
from linebot.models import TextSendMessage

MAX_RANGE=50
URL_PATH="/var/www/html/"

def drawingTemp():
    
    temp=[0 for i in range(MAX_RANGE)]
    date=[0 for i in range(MAX_RANGE)]
    span=[]

    for i in range(MAX_RANGE):
        span.append(1000/MAX_RANGE*i)

    fp=open(URL_PATH+"temp.csv","rb")
    reader=csv.reader(fp)
    for row in reader:
        temp.pop(0)
        temp.append(float(row[5]))
        date.pop(0)
        #month/date_hour:minute
        date.append("%02d"%int(row[1])+"/"+"%02d"%int(row[2])+"_"+"%02d"%int(row[3])+":"+"%02d"%int(row[4]))
    fp.close()
    
    if(temp[MAX_RANGE-1]<=20.0):
    	sendMsgToLine("WARNING:temp is under 20C!!")

    fig=plt.figure(figsize=(16,9))
    ax=fig.add_subplot(1,1,1)
    plt.title("Temperature")
    plt.gca().get_yaxis().get_major_formatter().set_useOffset(False)
    plt.xlabel("month/date_hour:minute")
    plt.ylabel("degree Celsius")
    plt.plot(temp,color="m")
    plt.xticks(range(MAX_RANGE),date)
    grid(True)
    labels=ax.set_xticklabels(date,rotation=90,fontsize="small")

    plt.savefig(URL_PATH+"temp.png",bbox_inches="tight")

def drawingPressure():
    
    pressure=[0 for i in range(MAX_RANGE)]
    date=[0 for i in range(MAX_RANGE)]
    span=[]

    for i in range(MAX_RANGE):
        span.append(1000/MAX_RANGE*i)

    fp=open(URL_PATH+"pressure.csv","rb")
    reader=csv.reader(fp)
    for row in reader:
        pressure.pop(0)
        pressure.append(float(row[5]))
        date.pop(0)
        #month/date_hour:minute
        date.append("%02d"%int(row[1])+"/"+"%02d"%int(row[2])+"_"+"%02d"%int(row[3])+":"+"%02d"%int(row[4]))
    fp.close()

    #Warn if the air pressure acquired in the last 6 times keeps falling
    flg=True
    for i in range(MAX_RANGE-6,MAX_RANGE-1):
        if(pressure[i]<pressure[i+1]):
            flg=False
            break
    if(flg):
        sendMsgToLine("WARNING:Barometric pressure keeps falling for 30 consecutive minutes")

    fig=plt.figure(figsize=(16,9))
    ax=fig.add_subplot(1,1,1)
    plt.title("Pressure")
    plt.gca().get_yaxis().get_major_formatter().set_useOffset(False)
    plt.xlabel("month/date_hour:minute")
    plt.ylabel("Hectopascals")
    plt.plot(pressure,color="c")
    plt.xticks(range(MAX_RANGE),date)
    grid(True)
    labels=ax.set_xticklabels(date,rotation=90,fontsize="small")

    plt.savefig(URL_PATH+"pressure.png",bbox_inches="tight")

def drawingHum():
    
    hum=[0 for i in range(MAX_RANGE)]
    date=[0 for i in range(MAX_RANGE)]
    span=[]

    for i in range(MAX_RANGE):
        span.append(1000/MAX_RANGE*i)

    fp=open(URL_PATH+"hum.csv","rb")
    reader=csv.reader(fp)
    for row in reader:
        hum.pop(0)
        hum.append(float(row[5]))
        date.pop(0)
        #month/date_hour:minute
        date.append("%02d"%int(row[1])+"/"+"%02d"%int(row[2])+"_"+"%02d"%int(row[3])+":"+"%02d"%int(row[4]))
    fp.close()
    
    if(hum[MAX_RANGE-1]>=70.0):
    	sendMsgToLine("WARNING:Hum is over 70%!!")
    	
    if(hum[MAX_RANGE-1]<40.0):
    	sendMsgToLine("WARNING:Hum is under 40%!!")
        
    fig=plt.figure(figsize=(16,9))
    ax=fig.add_subplot(1,1,1)
    plt.title("Humidity")
    plt.gca().get_yaxis().get_major_formatter().set_useOffset(False)
    plt.xlabel("month/date_hour:minute")
    plt.ylabel("percent")
    plt.plot(hum,color="g")
    plt.xticks(range(MAX_RANGE),date)
    grid(True)
    labels=ax.set_xticklabels(date,rotation=90,fontsize="small")

    plt.savefig(URL_PATH+"hum.png",bbox_inches="tight")

def sendMsgToLine(msg):
    Channel_Access_Token="XXXXXXXXXX"
    User_Id="XXXXXXXXXX"
    Line_Bot_Api=LineBotApi(Channel_Access_Token)
    Line_Bot_Api.push_message(User_Id,TextSendMessage(text=msg))

print("start drawing Temp...")
drawingTemp()
print("successful")

print("start drawing Pressure...")
drawingPressure()
print("successful")

print("start drawing Hum...")
drawingHum()
print("successful")

print("connect to http server...")
ftp=FTP("FTP_Server","usrid","passwd")
print("successful")

#only first time
#send to html
#fp=open("../../var/www/html/index.html","rb")
#ftp.storbinary("STOR public_html/index.html",fp)
#fp.close()

#send temp to http
print("send temp.png to http server...")
fp=open(URL_PATH+"temp.png","rb")
ftp.storbinary("STOR public_html/temp.png",fp)
fp.close()
print("successful")

#send pressure to http
print("send pressure.png to http server...")
fp=open(URL_PATH+"pressure.png","rb")
ftp.storbinary("STOR public_html/pressure.png",fp)
fp.close()
print("successful")

#send hum to http
print("send hum.png to http server...")
fp=open(URL_PATH+"hum.png","rb")
ftp.storbinary("STOR public_html/hum.png",fp)
fp.close()
print("successful")

ftp.close()
print("all complete!")

#実行結果
俺の部屋の環境はこうです。
温度
temp.png
気圧
pressure.png
湿度
hum.png

#参考
BME280搭載 温湿度・気圧センサモジュール ピンヘッダ実装済
BME280サンプルコード
matplotlibで軸のオフセット表記を禁止させる
fritzingで使えるbme280のパーツ

6
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?