お天気時計の作成(その6:照度センサ)

Raspberry pi zero 2Wを入手したので備忘録として書きます。

 

今回は照度センサ(BH1750)のGY-302モジュールを使用して明るさを測定します。

明るさによってLCDのLEDの明るさを変更してみたいと思います。

 

照度センサ

Amazonで下記の光センサを購入しました。

 

BH1750を使用した明るさの測定方法は以下のURLを参考にしました。

🌞️⚫BH1750を使って明るさを計測する - ⭐|ラズベリーパイのレシピ (zenn.dev)

 

Raspberry pi zeroとの接続

Raspberry pi

BH1750

3.3V(1)

Vcc

GND(9)

GND

GPIO3(5)

SCL

GPIO2(3)

SDA

GNG(9) or open ADDR

※ADDRは後で3.3Vへ接続を変更しています。

Raspberry piの設定

I2C通信の設定

今回はI2C通信で制御しますので、I2Cを使用できるように設定します。


$ sudo raspi-config

 

接続デバイスの確認

i2cdetectコマンドを使用してI2Cで接続しているデバイスの確認を行います。

下記の用のI2Cのアドレス23hのデバイスが接続されています。(ADDR:GND接続時)

※ADDRへ3.3V接続時はアドレス5Chとなりました。


BH1750の制御モジュールのインストール

pipコマンドで公開されているBH1750の制御モジュールをインストールします。


$ pip install adafruit-circuitpython-bh1750

 

インストールしたファイルは下記に格納されます。

/home/tomtomst/.local/lib/python3.9/site-packages

サンプルプログラム


import time
import board
import adafruit_bh1750

def main():
    # 初期化
    i2c = board.I2C()
    sensor = adafruit_bh1750.BH1750(i2c)

    # ルクスの表示
    for _ in range(5):
        time.sleep(1)
        print("%.2f Lux"%sensor.lux)
    return

if __name__ == "__main__":
    main()

サンプルプログラムの実行結果

蛍光灯を点けた状態だと262ルクス、消した状態(真っ暗)で0ルクスでした。

手で影を作ると20ルクス程度になるので正常に動作していそうです。

I2Cアドレス

センサのADDR端子を3.3Vへ接続すると、I2Cのデバイスアドレスは0x5cになります。

先のサンプルプログラムは、デバイスアドレスは指定せずにデフォルトの0x23にアクセスしていましたが、

0x5cへアクセスしたい場合は、下記のように8行目で0x5cを追加することで、0x5cのアドレスを指定することができます。


    sensor = adafruit_bh1750.BH1750(i2c,0x5c)

 

LCDの明るさの変更

これまでのLCDのLED点灯は、GPIOの出力をHighレベルとしていました。

これをPWM出力することで明るさを変更しようと思います。

照度センサで周りが暗い場合は、PWM出力で10%の明るさ、

周りが明るい場合は、100%の明るさとします。

 

初期設定

下記のようにGPIO23を100Hzのpwmピンに設定します。

dutyは0でスタートしておきます。


# libフォルダのライブラリを参照できるようにする。
import sys
sys.path.append('./lib')

#---- LCD LED PWM set ----
import RPi.GPIO as GPIO
# GPIOのピン番号指定を「BCM」に設定します
GPIO.setmode(GPIO.BCM)
# LED用のピンを「Out」に設定します
GPIO.setup(23,GPIO.OUT)
led_pwm = GPIO.PWM( 23 , 100) #pwm 100Hz
led_pwm.start(0)


#---------------------------------------------------------
#人感センサ

import RPi.GPIO as GPIO
import threading
import datetime

PIR_PIN =27
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIR_PIN,GPIO.IN)
PIR_count = 0

人検知時の明るさ設定

callback関数(人検知したときのLED点灯する関数)に照度センサの値が50lux以上の場合は、LEDの明るさをpwm10%に設定する処理を追加しました。

これまで使用していたLCD_led関数は使用しないのでコメントアウトしています。

変更した箇所は赤字です。

読みだした明るさ値(lux)は他の関数でも使用するのでglobal変数として宣言しておきます。


#人感センサ入力を割り込み設定する
# 割り込みルーチンでLED点灯して30sタイマを起動する。
def callback(pin):
    global PIR_count,old_PIR_timer,lux
    PIR_count = PIR_count + 1
    #LCD_led_(23,1)
    #照度センサ読み出し
    BH1750_sensor = adafruit_bh1750.BH1750(i2c,0x5c)
    lux = round(BH1750_sensor.lux , 1)
    #明るさ判定
    if lux > 50: #50lux以上で100%でLED点灯
        led_pwm.ChangeDutyCycle(100)
    else:
        led_pwm.ChangeDutyCycle(10)
    print("LED on ",datetime.datetime.now(),lux,"lux")
    
    new_PIR_timer = threading.Timer(30.0, PIR_check)
    old_PIR_timer.cancel()
    new_PIR_timer.start()
    old_PIR_timer = new_PIR_timer
    
#GPIO.add_event_detect(PIR_PIN,GPIO.RISING,callback=callback)

#---------------------------------------------------------------------
# 30s後人がいない場合LEDを消灯してタイマも停止する。
def PIR_check():
    global PIR,PIR_count,old_PIR_timer
    #print("人検知",PIR_count,"LED消灯")
    print("LED off",datetime.datetime.now())

    #LCD_led(23,0)
    led_pwm.ChangeDutyCycle(0)
    old_PIR_timer.cancel()

#old_PIR_timer = threading.Timer(60.0, PIR_check)
#old_PIR_timer.start()

def PIR_count_time():
    import datetime
    global PIR_count,humi,temp,lux
    PIR_count_timer = threading.Timer(300.0, PIR_count_time)
    PIR_count_timer.start()
    now = datetime.datetime.now()
    time_now = now.time().strftime("%H:%M:%S")
    #humi, temp = sensor.read()
    print(time_now,f'{temp:.01f}',"℃",f'{humi:.01f}',"%","PIR=",PIR_count,lux,"lux")
    PIR_count = 0
#--------------------------------------------------------------------

初期設定メイン関数とメイン関数01

起動時のLEDは100%で点灯する設定にしました。


def setup_main():
    global temp,humi
    LCD_set()     #LCDの初期設定
    #LCD_led(23,1) #LCDのLED点灯
    led_pwm.ChangeDutyCycle(100)
    setup_disp()  #起動中表示
    time.sleep(1) #1秒wait
    
    #今の日時を取得
    today_n,time_n,now_M_S,now_S = now_daytime()
    #時計表示
    time_disp(today_n,time_n)
    #温度取得
    humi, temp = Adafruit_DHT.read_retry(sensor, DHT_pin)
    if humi is not None and temp is not None:
        #温度表示
        temp_disp(temp,humi) 
    else:
        print('Failed to get reading. Try again!')
        
    while True:
        if check_wifi():
            print('Wi-Fi is available.')
            break
        else:
            print('Wi-Fi is not available.')
        
        time.sleep(1)

    #お天気を取得
    cor,weather,weather_url = weather_get()
    #お天気をLCDへ表示
    weather_disp(cor,weather,weather_url)
    #weather_text_disp(cor,weather)    
    #weather_icon_disp()    
#-------------------------------------------------

def main_01():
    global touch_x,touch_y,temp,humi
    
    now_S_old = "--"
    (touch_x,touch_y) = (0,0)
    
    while True:   
        #今の日時を取得
        today_n,time_n,now_M_S,now_S = now_daytime()
        
        if now_S != now_S_old: #1秒に1回処理するためにこの処理を追加
            #0秒になったら時計表示
            if now_S == "00" :
                time_disp(today_n,time_n)
                print(today_n,time_n)
                        
            if now_S[1] == "0": #10秒毎に処理
                #温度取得
                humi, temp = Adafruit_DHT.read_retry(sensor, DHT_pin)

                if humi is not None and temp is not None:
                    #print('Temp={0:0.1f}*C  Humidity={1:0.1f}%'.format(temp, humi))
                    #温度表示
                    temp_disp(temp,humi)
                    #weather_icon_disp()
                else:
                    print('Failed to get reading. Try again!')
                
            #天気予報表示
            if now_M_S == "00:00":            
                print(time_n)
                i = 0
                while (i < 10):
                    if check_wifi():
                        print('Wi-Fi is available.')
                        #お天気を取得
                        cor,weather,weather_url = weather_get()
                        #お天気をLCDへ表示
                        weather_disp(cor,weather,weather_url)
                        break
                    else:
                        print('Wi-Fi is not available.')        
                    time.sleep(1)

        now_S_old = now_S #1秒の切り替わりを判定するために前の秒数を保存

        #print(touch_x,touch_y,toggle)
        sel = touch_sel(touch_x,touch_y)
        if sel == "end" or sel == "poff":
            print(sel)
            time.sleep(1)
            poff_disp(sel)
            return sel    
        (touch_x,touch_y) = (0,0)
    

メインプログラム


if __name__ == '__main__':

    # libフォルダのライブラリを参照できるようにする。
    import sys
    sys.path.append('./lib')
    from LCD_led import LCD_led
    from LCD_disp import LCD_set,setup_disp,time_disp,now_daytime
    from LCD_disp import temp_disp,weather_disp,weather_text_disp,weather_icon_disp
    from LCD_disp import touch_disp,poff_disp
    from weather_get import weather_get
    from check_wifi import check_wifi
    import time

    #---DHT22温度センサの初期設定-----
    import Adafruit_DHT
    sensor = Adafruit_DHT.DHT22
    DHT_pin = 26
    #------------------

    setup_main()
    touch_disp("")
    
    
    #---- 照度センサ設定 ---
    import board
    import adafruit_bh1750
    i2c = board.I2C()
    BH1750_sensor = adafruit_bh1750.BH1750(i2c,0x5c)
    lux = round(BH1750_sensor.lux , 1)
    
    #人検知の割り込みを有効にする
    GPIO.add_event_detect(PIR_PIN,GPIO.RISING,callback=callback)
    #60秒後にPIR_check関数を起動するタイマを設定する
    old_PIR_timer = threading.Timer(60.0, PIR_check)
    #タイマをスタートする
    old_PIR_timer.start()
    
    #5分(300秒)間隔で人検知回数を出力する
    PIR_count = 0
    PIR_count_time()

    sel = main_01()
    
    # import osでシャットダウンできるようにする
    import os
    import RPi.GPIO as GPIO

    time.sleep(1)
    if sel =="end":
        GPIO.cleanup()
        sys.exit()
    if sel == "poff":
        os.system('sudo shutdown -h now')

実行結果