以前、Bosch社の環境センサ BME280 を Raspberry Pi の I2C バスに2個並列に繋いで、計測の信頼性を高める手法を紹介しました。今回はこれに、Rohm社の BH1750 光センサを加えて計測項目を増やしてみます。今回追加するのは、Rohm社のBH1750光センサです。I2Cセンサモジュールとしては、似て非なるピンアサインのGY-30とGY-302の2種類を入手することが出来ます。
どちらのモジュールもBME280の時と同様、次の要領でI2Cアドレスを違えることが出来ます。
-
- 0x23 デフォルト
- 0x5c ADRに電圧を加えてHigh
この機能を利用して、2個のBME280と2個のBH1750を1枚の基板上にレイアウトするための配線を設計します。まずはGY-30ではこのようになります。
両センサのGNDのピンアサインに親和性が乏しく、線が交叉する箇所が出来てしまいます。次に、GY302で設計してみましょう。
綺麗に配線させることが出来ました。こちらのモジュールを採用することにして、実際にユニバーサル基板に組んでゆきます。
適当な銅線を図3の要領でユニバーサル基板上に編んでゆき、コネクタピンと共にはんだ付け。ちなみにこの銅線、CAT5ケーブル端材の芯線を使っています。
実際の運用時に基板剥き出しは印象悪いので、梱包に使われるウレタンスポンジで包み、タイラップ止めにしてみました。
出来上がったセンサスティックは、実家の居間の片隅に設置したRaspberry Pi 2台にそれぞれ1セットずるI2C接続され、本記事執筆時にはもう1年以上稼働を続けています。
接続したセンサを早速Raspberry PiからI2Cバススキャンしてみましょう。
1 2 3 4 5 6 7 8 9 10 11 |
$ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- 23 -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- 5c -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- 76 77 $ |
問題無く4つの応答がありました。既にBME280を使って計測している機体なので、今回新たにBH1750を扱うのに必要なパッケージはこちら。
1 |
$ sudo apt install python-smbus |
実際に動いているPythonスクリプトはこのようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
import sys, os, urllib2, json, requests, time, smbus sys.path.append(os.getcwd() + "/Adafruit_Python_BME280") from Adafruit_BME280 import * ## DEVICE KEY ts_key = "################" ## ALTITUDE altitude = 75 data1 = {'Temp':'0', 'Humid':'0', 'PressRaw':'0', 'PressZero':'0', 'Lux':'0'} data2 = {'Temp':'0', 'Humid':'0', 'PressRaw':'0', 'PressZero':'0', 'Lux':'0'} def setDatum(sen, dat): dat['Temp'] = sen.read_temperature() dat['Humid'] = sen.read_humidity() dat['PressRaw'] = sen.read_pressure() / 100 if dat['Temp'] != 0 and dat['PressRaw'] != 0: dat['PressZero'] = dat['PressRaw'] + (dat['PressRaw'] * 9.81 * altitude) / (287 * (273.15 + dat['Temp'])) else: dat['PressZero'] = 0 def get_CPUtemp(): f = open("/sys/class/thermal/thermal_zone0/temp","r") tmp = 0 for t in f: tmp = t[:2]+"."+t[2:5] f.close() return float(tmp) def get_Lux(addr): bus = smbus.SMBus(1) lux = bus.read_i2c_block_data(addr,0x10) return (lux[0]*256+lux[1])/1.2 class ThingSpeak: def __init__(self,apiKey): self.apiKey = apiKey def regist(self): request = "field1=" + str(round(data1['Temp'],2)) + \ "&field2=" + str(round(data2['Temp'],2)) + \ "&field3=" + str(round(data1['Humid'],2)) + \ "&field4=" + str(round(data2['Humid'],2)) + \ "&field5=" + str(round(data1['PressZero'],2)) + \ "&field6=" + str(round(data2['PressZero'],2)) + \ "&field7=" + str(round(data1['Lux'],2)) + \ "&field8=" + str(round(data2['Lux'],2)) # "&field8=" + str(round(cputemp,2)) url = "https://api.thingspeak.com/update?key=" + self.apiKey headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"} res = requests.post(url, headers=headers, data=request) print res return res ## MAIN ## #BME280 try: sensor1 = BME280(t_mode=BME280_OSAMPLE_8, p_mode=BME280_OSAMPLE_8, h_mode=BME280_OSAMPLE_8, address=0x76) setDatum(sensor1, data1) except: print "BME280#1 Failure" data1['Temp'] = data1['Humid'] = data1['PressRaw'] = data1['PressZero'] = 0 time.sleep(1) try: sensor2 = BME280(t_mode=BME280_OSAMPLE_8, p_mode=BME280_OSAMPLE_8, h_mode=BME280_OSAMPLE_8, address=0x77) setDatum(sensor2, data2) except: print "BME280#2 Failure" data2['Temp'] = data2['Humid'] = data2['PressRaw'] = data2['PressZero'] = 0 #BH1750 time.sleep(1) try: data1['Lux'] = get_Lux(addr=0x23) except: print "BH1750#1 Failure" data1['Lux'] = 0 time.sleep(1) try: data2['Lux'] = get_Lux(addr=0x5c) except: print "BH1750#2 Failure" data2['Lux'] = 0 #CPU_TEMP cputemp = get_CPUtemp() print '-- Data --' print 'CPU Temp = {0:0.2f} deg C'.format(cputemp) print 'Illumi1 = {0:0.2f} lux'.format(data1['Lux']) print 'Illumi2 = {0:0.2f} lux'.format(data2['Lux']) print 'Temp1 = {0:0.2f} deg C'.format(data1['Temp']) print 'Temp2 = {0:0.2f} deg C'.format(data2['Temp']) print 'Humidity1 = {0:0.2f} %'.format(data1['Humid']) print 'Humidity2 = {0:0.2f} %'.format(data2['Humid']) print 'Pressure1 = {0:0.2f} hPa'.format(data1['PressRaw']) print 'Pressure2 = {0:0.2f} hPa'.format(data2['PressRaw']) print 'PressureZ1 = {0:0.2f} hPa'.format(data1['PressZero']) print 'PressureZ2 = {0:0.2f} hPa'.format(data2['PressZero']) print '-- ThingSpeak --' thingDevice = ThingSpeak(ts_key) thingDevice.regist() |
これをThingSpeak上でみると、
ThingSpeakはチャンネル当たりの最大フィールド数が8個なので、これでいっぱいいっぱい。似たようなデータをだらだら発するのではなく、ローカルで平均取ったり比較したりして、精度や濃度の高いデータセットにしてから送信するしくみが今後の課題です。