Categories
Linux Raspberry Pi

Raspberry Pi light sensor project

Intro

I ultimately want to turn off the connected display when it is nighttime and the lights have been turned off. And I want it to turn itself back on during daylight. The reason is because my RPi-driven slideshow is running and somoeone may be sleeping in that room.

This is till a work in progress. Pardon our dust and gibberish. What I’ve already found out is too important to delay publication.

Equipment and skills
How to turn off and on an HDMI port with a Raspberry Pi 4

Honestly this is the most significant thing I have found in this investigation. The methods used for older RPis do not work! In other words you can run vcgencmd display_power 0 and clever variations of that command until you’re blue in the face and the thnig stubbornly won’t turn off. tvservice -o ? Nope. That’ll suggest that command was deprecated and use kmsprint instead.

But I can say as of this writing (Jan ’24) the kms* commands are not mature and do not permit you to turn off the display. kmsprint tells you some stuff, but it does not allow you to set things. Remember RPi is for the education and hobbyist crowd so we have to give them the slack to experiment and try new things, even when they aren’t fully formed.

Instead they give you a way to restore the old commands. Edit the file /boot/config.txt.

Make it look like this:

#Enable DRM VC4 V3D driver
#use the fake kms driver in place of the native kms driver so we can  control hdmi power -DrJ 1/24
##dtoverlay=vc4-kms-v3d
dtoverlay=vc4-fkms-v3d

Reboot. Congrats you are now using the fake kms driver (fkms) and now have compatibility with the old commands. But instead of using tvservice, for my purposes, I think vcgencmd is better because the frame buffer state is not lost.

So now this command will indeed turn off the display:

vcgencmd display_power 0 # turn hdmi display off

vegcmd display_power 1 # turns the HDMI display back on

vcgencmd display_power 0 # turn hdmi display off

Prepare for our light sensor

I really don’t know if I’ll ever get the light sensor to work or not. Anticipating that it will, I have created this GPIO callback routine in python which in my dreams will turn off the HDMI display when the room is dark and turn it back on when the ambient light crosses a threshold. Who knows… But the code is pretty cool because it permits you to play with it as well using software command you send to a GPIO pin.

I call it gpio_basic.py:

import RPi.GPIO as GPIO
import time
import os
import datetime

GPIO.setmode(GPIO.BCM)
channel=4
GPIO.setup(channel, GPIO.IN)
reading = GPIO.input(channel)
print('Initial Reading',reading,flush=True)
old_reading = reading
while True: # infinite loop
    time.sleep(4)
# rising means ambient light went from light to dark
    reading = GPIO.input(channel) # 1 => dark, D0 LED turns off; 0 if light
    if reading == old_reading: continue

# else section where the state has changed
    print('This is a change in state on channel',channel,'at ',datetime.datetime.now(),flush=True)
    print('Reading',reading)
    if reading == 1:
        print('Turning off the HDMI display...',flush=True)
        os.system("vcgencmd display_power 0")
    else:
        time.sleep(6)
        print('Turn on HDMI display...',flush=True)
        os.system("vcgencmd display_power 1")
    old_reading = reading

Now to play with it, in another window get into python and run these commands:

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
channel=4
GPIO.setup(channel, GPIO.IN)
GPIO.input(channel)
#GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#or
#GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

Those commented out lines at the end are the key ones. By executing them you should see the display turn off or on, and your other program should output some verbiage. Now hopefully the sensor will work something like that!

Wiring

Don’t know if this will pan out. I envision wiring (RPi pin #’s on the left):

  • 1 – Vcc (+ 3.3 V voltage)
  • 6 – Gnd (ground)
  • 7 – D0 (digital out)

At this point I don’t see the point of wiring the fourth lead on the diode sensor (which is A0, analog out – the RPi cannot read analog out), but having only three of them wired doesn’t quite seem right either. My electronics knowledge is weak!

So maybe I’ve wasted my money on these sensors, or I need to read them with a microcontroller and use i2c to talk to the RPi (too much effort and too much expense for my taste), but I hope not. Will know soon…

My first sensor, the photodiode, works! But its threshold is near one end of the control, which isn’t so great. But it’s fun to play with. In other words, its low light sensitivity may not be adequate for my purposes where I need to distinguish low ambient light (in a room with only a glowing TV screen, for instance) from even lower ambient light (lights off). Turns out our human eyes are the best measuring devices! Actually this photo diode, properly tuned, is quite good! I believe there is some jitter in the measurements however. So it can jump around during low light a bit. I have to consider how much of a problem that is.

The photodiode has a power led and a light sensor led. They are both way too bright. I suspect they could even create a feedback loop. I covered both with masking tape, leaving room for the adjustment screw.

But much, much worse than the the photodiode is the photoresistor. That at best distinguishes between a decent amount of light, and quite dark. But the transition between the two is sticky (I believe that would be called hysteresis). It will not work at all for my purposes based on my initial testing. It cannot distinguish between low light and very low light no matter where the dial is set.

Since this is all working, we just need to make it permanent by starting at boot time. So in my crontab file I added this line:

# Turn monitor off and on depending on ambien light! - DrJ 1/9/24
@reboot sleep 42; python3 gpio_basic.py > gpio_basic.log 2>&1
RPi4 shown with the slick metal case and the photodiode during daytime
Measure temperature of the CPU and why it matters

vcgencmd measure_temp

With my new fancy aluminum, heat-dissipating case I get around 40.4° C. On my RPi 3, air-cooled it is around 49° C. Why the sudden concern around heat? I’m just beginning to suspect that you know those times when you use the command line and things just seem to freeze? I always just assumed it was a glitch in the WiFi. But maybe it was actually the cpu getting too hot and having to pause itself to avoid burning up. I would see this when transferring files on my RPi 4. so the RPi 4 probably really does run hot unless you take steps to cool it, and the aluminum case in the equipment list above is really cool, ha , ha.

Tips

The command pinout is very useful. Pinout docs here: https://www.raspberrypi.com/documentation/computers/raspberry-pi.html

References and related

This guide talks about explicit support for generic digital input devices, not just a button: https://randomnerdtutorials.com/raspberry-pi-digital-inputs-python/

This talks about built-in pull-up pull-down resistors configurable via software! Who knew?

This might be useful for simple GPIO stuff: https://tutorials-raspberrypi.com/raspberry-pi-gpio-explanation-for-beginners-programming-part-2/

Gory details with gory circuit diagram: https://www.circuits.dk/everything-about-raspberry-gpio/

Running multiple RPi slideshows

How to deal with th GPIO pins using python: https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs

This project used the RPi GPIO OUTPUT pins to control a power relay device

Appendix A

I started with this code, gpio_callback.py, but the one condition kept getting called when the GPIO pin was reading 1. So I wrtoe gpio_basic.py and use that instead.

import RPi.GPIO as GPIO
import time
import os

GPIO.setmode(GPIO.BCM)
channel=4
GPIO.setup(channel, GPIO.IN)
reading = GPIO.input(channel)
print('Initial Reading',reading)
def my_callback(channel):
# rising means ambient light went from light to dark
    print('This is a edge event callback function!')
    print('Edge detected on channel %s'%channel)
    print('This is run in a different thread to your main program')
    print('Gonna stop that slideshow now...')
    reading = GPIO.input(channel) # 1 => dark, D0 LED turns off; 0 if light
    print('Reading',reading)
    if reading == 1:
        time.sleep(1)
        print('Turning off the HDMI display...')
        os.system("vcgencmd display_power 0")
    else:
        time.sleep(1)
        print('Turn on HDMI display...')
        os.system("vcgencmd display_power 1")

# RISING,FALLING or BOTH. https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/
GPIO.add_event_detect(channel, GPIO.BOTH, callback=my_callback)  # add edge detection on a channel
# for testing, use:
#GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# or
#GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
time.sleep(31415927) # one year

Leave a Reply

Your email address will not be published. Required fields are marked *