Raspberry Pi スマートホーム化計画 記事一覧
記事の内容を試す場合は自己責任でお願いいたします。
照度を取得したい これまでで、気温、湿度、気圧が取得できるようになりました。
次は何をセンシングするか・・・それは光、つまり照度です。
照度を取得することで、簡単に以下のようなことができるようになります。
照度センサーとスマートホーム一例
夜間に部屋に人がいることの判断 深夜電気を消し忘れている際に自動で消す 夜間の行動ログ 寝室で明るさから睡眠時刻の判断、記録 主に夜間に部屋が明るいか暗いかを判断できます。 昼間は太陽光があるので人の行動はあまり検知できません。
使用するセンサーについて 購入時期の関係で、私の手元にある照度センサーが2種類あります。
・TSL25721 (TSL2572) ・TSL2561
両方とも秋月電子で購入しましたが、現在はTSL25721 (TSL2572)しか販売していないようです。
今回はTSL25721はRaspberry Pi3、TSL2561はRaspberry Pi Zeroに接続して使用しようと思います。
TSL25721 接続する 秋月電子のサイトにRaspberry Piとの接続例とサンプルプログラムがあるので、そのまま利用してみます。
TSL25721使用 照度センサーモジュール: オプトエレクトロニクス 秋月電子通商-電子部品・ネット通販
電子部品,通販,販売,半導体,IC,LED,マイコン,電子工作TSL25721使用 照度センサーモジュール秋月電子通商 電子部品通信販売
TSL25721 Raspberry Pi Vin 3.3v (1番ピン) GND GND (6番ピン) 3v3 3.3v (1番ピン) 0E 繋がない INT 繋がない SDA GPIO2 (SDA) 3番ピン SCL GPIO3 (SCL) 5番ピン
接続したら、コマンドでI2Cで認識されているか確認します。
pi@raspberrypi3:/opt/TSL2572 $ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- 39 -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --
39番に認識されています。76番はBME280です。
サンプルプログラムを実行する 上記のように接続したら秋月のサンプルプログラムを実行してみます。 途中でiPhoneのライトを当ててみました。 光量の変化が反映されています。
pi@raspberrypi3:/opt/TSL2572 $ python3 TSL2572.py
init....
0 Lx
81.3 Lx
81.3 Lx
81.3 Lx
81.3 Lx
81.3 Lx
81.3 Lx
80.9 Lx
389.8 Lx
195.5 Lx
204.9 Lx
1114.4 Lx
2056.6 Lx
1730.9 Lx
2063.0 Lx
1615.8 Lx
1954.5 Lx
このままでは、光量を1分ごとにロギングするといった用途には不向きなプログラムなので、少し修正します。
TSL2572_2.py
#Sensor <-> RasPiHeader
#Vin <-> 01
#3V3 <-> 01
#GND <-> 09
#SCL <-> 05
#SDA <-> 03
#Python 2.7.16
import time
import smbus
i2c = smbus.SMBus(1)
#TSL2572 Register Set
TSL2572_ADR = 0x39
TSL2572_COMMAND = 0x80
TSL2572_TYPE_REP = 0x00
TSL2572_TYPE_INC = 0x20
TSL2572_ALSIFC = 0x66
TSL2572_SAI = 0x40
TSL2572_AIEN = 0x10
TSL2572_WEN = 0x80
TSL2572_AEN = 0x02
TSL2572_PON = 0x01
TSL2572_ENABLE = 0x00
TSL2572_ATIME = 0x01
TSL2572_WTIME = 0x03
TSL2572_AILTL = 0x04
TSL2572_AILTH = 0x05
TSL2572_AIHTL = 0x06
TSL2572_AIHTH = 0x07
TSL2572_PRES = 0x0C
TSL2572_CONFIG = 0x0D
TSL2572_CONTROL = 0x0F
TSL2572_ID = 0x12
TSL2572_STATUS = 0x13
TSL2572_C0DATA = 0x14
TSL2572_C0DATAH = 0x15
TSL2572_C1DATA = 0x16
TSL2572_C1DATAH = 0x17
#TSL2572 setings
atime = 0xC0
gain = 1.0
def initTSL2572() :
if (getTSL2572reg(TSL2572_ID)!=[0x34]) :
#check TSL2572 ID
return -1
setTSL2572reg(TSL2572_COMMAND | TSL2572_TYPE_INC | TSL2572_CONTROL,0x00)
setTSL2572reg(TSL2572_COMMAND | TSL2572_TYPE_INC | TSL2572_CONFIG,0x00)
setTSL2572reg(TSL2572_COMMAND | TSL2572_TYPE_INC | TSL2572_ATIME,atime)
setTSL2572reg(TSL2572_COMMAND | TSL2572_TYPE_INC | TSL2572_ENABLE,TSL2572_AEN | TSL2572_PON)
return 0
def setTSL2572reg(reg,dat) :
i2c.write_byte_data(TSL2572_ADR,reg,dat)
def getTSL2572reg(reg) :
dat = i2c.read_i2c_block_data(TSL2572_ADR,TSL2572_COMMAND | TSL2572_TYPE_INC | reg,1)
return dat
def getTSL2572adc() :
dat = i2c.read_i2c_block_data(TSL2572_ADR,TSL2572_COMMAND | TSL2572_TYPE_INC | TSL2572_C0DATA,4)
adc0 = (dat[1] << 8) | dat[0]
adc1 = (dat[3] << 8) | dat[2]
return[adc0,adc1]
#main
#print("init....")
if (initTSL2572()!=0) :
print("Failed. Check connection!!")
sys.exit()
measure_num=3 # Number of iterations
total=0
for sample_i in range(measure_num):
adc = getTSL2572adc()
cpl = 0.0
lux1 = 0.0
lux2 = 0.0
cpl = (2.73 * (256 - atime) * gain)/(60.0)
lux1 = ((adc[0] * 1.00) - (adc[1] * 1.87)) / cpl
lux2 = ((adc[0] * 0.63) - (adc[1] * 1.00)) / cpl
if ((lux1 <= 0) and (lux2 <= 0)) :
#print("0 Lx")
total = total + 0
elif (lux1 > lux2) :
#print("{:.1f} Lx".format(lux1))
total = total + lux1
elif (lux1 < lux2) :
#print("{:.1f} Lx".format(lux2))
total = total + lux2
time.sleep(0.2)
print("{:.1f} Lx".format(total / measure_num))
変更点としては、「init...」や各print文のコメントアウトと3回測定して平均値を出力するようにしています。 measure_numを変更すれば測定回数を変えられます。 他の部分はサンプルと同じです。
TSL2561 次はRaspberry Pi ZeroにTSL2561を接続して照度を取得してみます。
接続する ピン配置は同じでした。
TSL2561 Raspberry Pi Vin 3.3v (1番ピン) GND GND (6番ピン) 3v3 3.3v (1番ピン) 0E 繋がない INT 繋がない SDA GPIO2 (SDA) 3番ピン SCL GPIO3 (SCL) 5番ピン
I2Cで認識されているか確認します。
pi@raspberrypizero:~ $ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- 39 -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --
同様に39番で認識していました。こちらも76番はBME280です。
プログラムを実行する 秋月のTSL2572用のスクリプトが使えないか実験してみます。
pi@raspberrypizero:/opt/tsl2561 $ python3 tsl2561.py
Failed. Check connection!!
Traceback (most recent call last):
File "tsl2561.py", line 79, in <module>
sys.exit()
NameError: name 'sys' is not defined
だめでした。接続確認で失敗しているようです。
先人の知恵をお借りしてサンプルコードを拝借します。 下記サイトを参考にさせていただきました。
Raspberry pi 3でストロベリー・リナックス社製「TSL2561 照度センサ・モジュール メーカー品番:TSL2561」を使う(試行錯誤編) - Qiita
Rasberry pi 3でストロベリー・リナックス社製の「TSL2561 照度センサ・モジュール (メーカー品番:TSL2561)」を使うための奮闘記録です。TSL2561チップを使ったセンサーの…
pi@raspberrypizero:/opt/tsl2561 $ python tsl2561_3.py
Lux : 136.94852521
Lux : 136.663190584
値が取得できました。
同じような条件で比較する TSL2561 TSL2572 TSL2561とTSL2572でセンサーの値を比較してみます。
両方センサー部を上に向けてみました。
しかし、同じ部屋で同じような条件で取得しているのに、tsl2561とtsl2572ではlxの値が異なっています。
そこで、以下のサイトでtsl2561とtsl2572でそれぞれサンプルを公開されているので実行してみます。
RPZ-IR-Sensor (Raspberry Pi用 温度/湿度/気圧/明るさ/赤外線 ホームIoT拡張ボード) – Indoor Corgi
pi@raspberrypi3:/opt/TSL2572 $ python TSL2572_2.py
ADC Time : 200ms
ADC Gain : 8
ch0 : 0x150D
ch1 : 0x7AE
Lux : 65.9lux
pi@raspberrypizero:/opt/tsl2561 $ python tsl2561_2.py
ADC Time : 101ms
ADC Gain : High
ch0 : 0x829
ch1 : 0x2EB
Lux : 252.8lux
センサーが異なるので同じ値にはならないのかもしれませんが、なんか気分が良くないですね。。。
今度秋月を利用することがあれば、TSL2572をもう一つ購入しようかと思います。
同じセンサーで同じプログラムを使わないと良くないですね。
今回は最初のサイトのスクリプトをメインで使用させていただきたいと思います。https://qiita.com/boyaki_machine/items/a238e9d03455a2eea26e
TSL2572のときと同様に、3回計測して平均を出すようにスクリプトを修正します。
TSL2561.py
#!/usr/bin/python -u
# -*- coding: utf-8 -*-
import smbus
import time
# Strawberry Linux社の「TSL2561 照度センサ・モジュール」から
# I2Cでデータを取得するクラス
# https://strawberry-linux.com/catalog/items?code=12561
# 2016-05-03 Boyaki Machine
class SL_TSL2561:
def __init__(self, address, channel):
self.address = address
self.channel = channel
self.bus = smbus.SMBus(self.channel)
self.gain = 0x00 # 0x00=normal, 0x10=×16
self.integrationTime = 0x02 # 0x02=402ms, 0x01=101ms, 0x00=13.7ms
self.scale = 1.0
# センサ設定の初期化
self.setLowGain()
self.setIntegrationTime('default')
def powerOn(self):
self.bus.write_i2c_block_data(self.address, 0x80, [0x03])
time.sleep(0.5)
def powerOff(self):
self.bus.write_i2c_block_data(self.address, 0x80, [0x00])
# High Gainにセットする(16倍の感度?)
def setHighGain(self):
# High Gainにするとうまくrawデータが取れないことがある。
# 要原因調査 ( 5047固定値になる )
self.gain = 0x10
data = self.integrationTime | self.gain
self.bus.write_i2c_block_data(self.address, 0x81, [data])
self.calcScale()
# Low Gain(default) にセットする
def setLowGain(self):
self.gain = 0x00
data = self.integrationTime | self.gain
self.bus.write_i2c_block_data(self.address, 0x81, [data])
self.calcScale()
# 積分する時間の設定(1回のセンシングにかける時間?)
# val = shor, middle, logn(default)
def setIntegrationTime(self, val):
if val=='short':
self.integrationTime = 0x00 # 13.7ms scale=0.034
elif val=='middle':
self.integrationTime = 0x01 # 101ms scale=0.252
else:
self.integrationTime = 0x02 # defaultVal 402ms scale=1.0
data = self.integrationTime | self.gain
self.bus.write_i2c_block_data(self.address, 0x81, [data])
self.calcScale()
def getVisibleLightRawData(self):
data = self.bus.read_i2c_block_data(self.address, 0xAC ,2)
raw = data[1] << 8 | data[0] # 16bitで下位バイトが先
return raw
def getInfraredRawData(self):
data = self.bus.read_i2c_block_data(self.address, 0xAE ,2)
raw = data[1] << 8 | data[0] # 16bitで下位バイトが先
return raw
def getRawData(self):
data = self.bus.read_i2c_block_data(self.address, 0xAC ,4)
VL = data[1] << 8 | data[0] # 可視光 16bitで下位バイトが先
IR = data[3] << 8 | data[2] # 赤外線 16bitで下位バイトが先
return (VL,IR)
def calcScale(self):
_scale = 1.0
# integrationTimeによるスケール
if self.integrationTime == 0x01: # middle
_scale = _scale / 0.252
elif self.integrationTime == 0x00: # short
_scale = _scale / 0.034
# gainによるスケール
if self.gain == 0x00 : # gain 1
_scale = _scale * 16.0
self.scale = _scale
def getLux(self):
# センサ生データの取得
raw = self.getRawData()
# 65535の時はエラー出力にする実装
if raw[0] == 65535 or raw[1] == 65535:
return "Range Over"
# センサ設定により生データをスケールする
VLRD = raw[0] * self.scale
IRRD = raw[1] * self.scale
# 0の除算にならないように
if (float(VLRD) == 0):
ratio = 9999
else:
ratio = (IRRD / float(VLRD))
# Luxの算出
if ((ratio >= 0) & (ratio <= 0.52)):
lux = (0.0315 * VLRD) - (0.0593 * VLRD * (ratio**1.4))
elif (ratio <= 0.65):
lux = (0.0229 * VLRD) - (0.0291 * IRRD)
elif (ratio <= 0.80):
lux = (0.0157 * VLRD) - (0.018 * IRRD)
elif (ratio <= 1.3):
lux = (0.00338 * VLRD) - (0.0026 * IRRD)
elif (ratio > 1.3):
lux = 0
return lux
if __name__ == "__main__":
sensor = SL_TSL2561(0x39,1)
sensor.powerOn()
# sensor.setHighGain()
sensor.setIntegrationTime('default')
measure_num = 3
total = 0
for sample_i in range(measure_num):
#lux = str("{:.1f}".format(sensor.getLux()))
total = total + sensor.getLux()
#print str(sensor.getLux()) + "lx"
#print lux + " lx"
time.sleep(0.2)
print "{:.1f}".format(total / measure_num) + " lx"
最後の方を少しだけ修正しています。 ※python2系で実行してください。python3だとエラーになります。
Mackerelに送信する Mackerelにデータを送るようにしてみます。
Raspberry Pi Zero WHにMackerelを導入して死活監視と気温などのグラフ化を行う
Mackerelを導入してできることMackerelは簡単に言うとSaaS型の監視サービスです。疎通確認やCPU使用率などを監視して問題があるとSlackやメールにアラートを飛ばしてくれます。クラウド型なので、自宅が停電した場合も問題なく通...
Mackerelの形式に変換するシェルスクリプトを書きます。
2561と2572は適宜読み替えてください。
lumi.sh
#!/bin/bash
data=$(python /opt/tsl2561/tsl2561.py)
array=(${data//,/ })
VALUE=${array[0]}
SECONDS=`date '+%s'`
NAME='luminosity.room'
echo -e "${NAME}\t${VALUE}\t${SECONDS}"
実行権限も忘れずに。
$ chmod +x lumi.sh
あとはMackerelのコンフィグに登録します。
/etc/mackerel-agent/mackerel-agent.conf
[plugin.metrics.roomluminosity]
command = "/opt/mackerel/lumi.sh"
最終行に追加しました。
あとはMackerelエージェントの再起動を行います。
$ sudo systemctl restart mackerel-agent.service
グラフが取得できるようになれば完成です。
コメント