1
3

More than 1 year has passed since last update.

ラズパイの湿度、温度、気圧データをSpread sheetへ出力する。

Posted at

ラズパイの湿度、温度、気圧データを取得し、spread sheetへ出力するまでをまとめてみました。
pread sheetは、google driveに置いています。

環境

Python version:3.9.7
OS: windows: 10.0
Linux raspberrypi: 5.10.63+

プログラムの実行イメージ

ラズパイからgoogle driveにspread sheetを作成するまでの下準備は、下記にまとめたので参照してください。
ラズパイからGoogle DriveへGoogle Spread Sheetを作成してみた。

プログラムは、1分毎にラズパイのデータをspread sheetへ書き込みします。google drive内で操作しているフローチャートは、下記のようにしています。spread sheetがあるかどうかを確認し、なければ新規ファイルを作成し、header部分の書き込みあを行います。存在していれば、そのステップは、省略し、ログの書き込みを行っています。1分毎のデータ取得は、crontabを使って、プログラムをたたくようにしています。なお、spread sheetは、データを取得した日付で作成するようにしています。

Untitled Diagram (1).drawio.png

spread sheetは、こんな感じに出力しています。
キャプチャ.PNG

プログラム

プログラムは、pythonで書いています。ラズパイでは、bme280を使って湿度、温度、気圧のデータを取得しています。データを取得する部分は、bme280_custom.pyでは、行っています。メインのwrite_spread.pyファイルでは、google driveへのアクセスや取得したデータをspread sheetに書き込みを行っています。spread sheetが存在しているどうかは、アクセス権限を与えたgoogle drive のディレクトリのファイルの一覧を取得し、同じファイルが存在しているかを確認し、なければ、idを取得して、spread sheetにアクセスすることができます。なければ、フォルダのIDを使って新規にファイルを作成してからspead sheetへアクセスしています。ファイルへの追記では、1列に入力しているセルの個数を確認し、+1をして結果を記入するようにしています。

write_spread.py
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
import pprint
from datetime import datetime as dt 
import bme280_custom

scope = ['https://spreadsheets.google.com/feeds',
         'https://www.googleapis.com/auth/drive']
json_keyfile_path = 'サービスアカウントキー.json'

credentials = ServiceAccountCredentials.from_json_keyfile_name(
    json_keyfile_path, scope)

gauth = GoogleAuth()
gauth.credentials = credentials
drive = GoogleDrive(gauth)

#parameters
header =  ['date','pressure','temperature','humidity']
exsist_date_file = False

#make a file list 
file_list = drive.ListFile().GetList()

#make a date spread sheet. ex. 210203.
now = dt.now()
filename = now.strftime('%Y%m%d')
label = now.strftime('%m/%d,%H:%M')

#if today spread sheet exist.
for f in file_list:
    if f['title'] == filename:
        print(f['title'], '   \t', f['id'])
        # gspread authentication
        gc = gspread.authorize(credentials)
        # file select in spread sheet ID.
        workbook = gc.open_by_key(f['id'])
        exsist_date_file = True
       
if exsist_date_file == False:
    folder_id = '<フォルダのID>'
    f = drive.CreateFile({
        'title': filename,
        'mimeType': 'application/vnd.google-apps.spreadsheet',
        "parents": [{"id": folder_id}]})
    f.Upload()
    # gspread authentication
    gc = gspread.authorize(credentials)
    # file select in spread sheet ID.
    workbook = gc.open_by_key(f['id'])

# select worksheet
worksheet = workbook.sheet1
# Get the written work sheet data.
records = worksheet.col_values(1)

# write header.
if len(records) == 0:
    cell_list = worksheet.range('A1:D1')
    for num in range(4):
        cell_list[num].value = header[num]
    worksheet.update_cells(cell_list)
    records = worksheet.col_values(1)

# get the log 
pres,temp,hum = bme280_custom.readData()

worksheet.update_cell(len(records)+1 ,1, label)
worksheet.update_cell(len(records)+1 ,2, pres)
worksheet.update_cell(len(records)+1 ,3, temp)
worksheet.update_cell(len(records)+1 ,4, hum)

bme280を使って湿度、温度、気圧のデータを取得しています。
bme280_custom.pyでは、return p , t , hで湿度、温度、気圧を3つの返り値にして戻すようにしています。

bme280_custom.py
#coding: utf-8

from smbus import SMBus
import time

bus_number  = 1
i2c_address = 0x76

bus = SMBus(bus_number)

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

t_fine = 0.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)
	t = compensate_T(temp_raw)
	p = compensate_P(pres_raw)
	h = compensate_H(hum_raw)
	return p , t , h

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)

    #print "pressure : %7.2f hPa" % (pressure/100)
	return "%7.2f" % (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
	#print "temp : %-6.2f ℃" % (temperature)
	return "%.2f" % (temperature)

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
    #print "hum : %6.2f %" % (var_h)
	return "%.2f" % (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

crontabの設定

決まった時間にpythonのプログラムをたたくために、crontabの設定しています。

pi@raspberrypi:~ $ sudo crontab -l

# m h  dom mon dow   command
0-59 * * * * python3 write_spread.py

リンク

下記リンクを参照させていただきました。
(gspreadライブラリの使い方まとめ!Pythonでスプレッドシートを操作する)[https://tanuhack.com/library-gspread/#i-8]
(Python, PyDriveでGoogle Driveのファイルのリストを作成)[https://note.nkmk.me/python-pydrive-list-file/]

1
3
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
1
3