記事の内容を試す場合は自己責任でお願いいたします。
- Raspberry Pi Zero WH OSインストール
- Raspberry Pi Zero WHを使ってAmazon Echo Flexから音を出す
- Raspberry Piと赤外線LEDで家電を操作する
- Raspberry PiとBME280を利用して気温、湿度、気圧を測定する
- Raspberry Pi Zero WHにMackerelを導入して死活監視を行う
- Raspberry Piで照度を取得する TSL2572 TSL2561
- AlexaからRaspberry Piを経由して家電を音声で操作する
- AlexaをRaspberry PiのNodeREDから喋らせる
- Raspberry PiとAlexaでオリジナルスキルを作る 「今日のご飯は?」
- Raspberry Pi とSlackとLINE Messaging APIでLINEから家電を操作する
- Raspberry Piで収集したセンサー情報をMachinistに送信する
- Raspberry Piを使ってAlexaからゴミの日のお知らせをする
- Raspberry Piでダイソーのリモートシャッターを使う
- 2台のRaspberry PiとMySQLでレプリケーションを構成する
- iPhoneからRaspberry Piを経由して家電を操作する
- Raspberry PiでWebサーバを立ててブラウザから家電を操作する
照度を取得したい
これまでで、気温、湿度、気圧が取得できるようになりました。
次は何をセンシングするか・・・それは光、つまり照度です。
照度を取得することで、簡単に以下のようなことができるようになります。
主に夜間に部屋が明るいか暗いかを判断できます。
昼間は太陽光があるので人の行動はあまり検知できません。

使用するセンサーについて
購入時期の関係で、私の手元にある照度センサーが2種類あります。
・TSL25721 (TSL2572)
・TSL2561
両方とも秋月電子で購入しましたが、現在はTSL25721 (TSL2572)しか販売していないようです。
今回はTSL25721はRaspberry Pi3、TSL2561はRaspberry Pi Zeroに接続して使用しようと思います。
TSL25721
接続する
秋月電子のサイトにRaspberry Piとの接続例とサンプルプログラムがあるので、そのまま利用してみます。
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分ごとにロギングするといった用途には不向きなプログラムなので、少し修正します。
#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
だめでした。接続確認で失敗しているようです。
先人の知恵をお借りしてサンプルコードを拝借します。
下記サイトを参考にさせていただきました。

pi@raspberrypizero:/opt/tsl2561 $ python tsl2561_3.py
Lux : 136.94852521
Lux : 136.663190584
値が取得できました。
同じような条件で比較する TSL2561 TSL2572
TSL2561とTSL2572でセンサーの値を比較してみます。
両方センサー部を上に向けてみました。

しかし、同じ部屋で同じような条件で取得しているのに、tsl2561とtsl2572ではlxの値が異なっています。
そこで、以下のサイトでtsl2561とtsl2572でそれぞれサンプルを公開されているので実行してみます。
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回計測して平均を出すようにスクリプトを修正します。
#!/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にデータを送るようにしてみます。

Mackerelの形式に変換するシェルスクリプトを書きます。
2561と2572は適宜読み替えてください。
#!/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のコンフィグに登録します。
[plugin.metrics.roomluminosity]
command = "/opt/mackerel/lumi.sh"
最終行に追加しました。
あとはMackerelエージェントの再起動を行います。
$ sudo systemctl restart mackerel-agent.service
グラフが取得できるようになれば完成です。

コメント