Issue
What I'm trying to accomplish: if the room lights go off, the monitor should dim. If the room lights go back on, the monitor should get brighter.
On a Rpi4B, I'm trying to use ddcutil in combination with a photoresistor and capacitor to automatically adjust monitor brightness depending on ambient light in the room. I really only need 3 brightness settings; one each for bright, average, and dim light conditions.
I've been editing some code I found and I have the code responding to three different levels of brightness (just text verification telling me the if the light is dim, medium, or bright.) The issue is that it keeps printing the result over and over and I only need it to print (or eventually run my ddcutil routine) once, but STILL continue to check the ambient light level and react accordingly. How do I continually check input from the sensor without continually passing an instruction to ddcutil? I know very little about writing code and I suspect a Boolean flag may be the answer that I don't understand. Thanks for any help.
#!/usr/local/bin/python
import RPi.GPIO as GPIO
import time
__author__ = 'Gus (Adapted from Adafruit)'
__license__ = "GPL"
__maintainer__ = "pimylifeup.com"
GPIO.setmode(GPIO.BOARD)
#define the pin that goes to the circuit
pin_to_circuit = 3
def rc_time (pin_to_circuit):
count = 0
#Output on the pin for
GPIO.setup(pin_to_circuit, GPIO.OUT)
GPIO.output(pin_to_circuit, GPIO.LOW)
time.sleep(.2)
#Change the pin back to input
GPIO.setup(pin_to_circuit, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_to_circuit) == GPIO.LOW):
count += 1
return count
#Catch when script is interupted, cleanup correctly
try:
# Main loop
while True:
if(rc_time(pin_to_circuit)) > 4000:
print("Too dark. Frame off.")
if(rc_time(pin_to_circuit)) < 4000 and (rc_time(pin_to_circuit)) > 1000:
print("Good light. Medium brightness.")
if(rc_time(pin_to_circuit)) < 1000:
print("Bright day. Maximum brightness set.")
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
Solution
I would store the last light value in a variable and in your loop compare that to the current value. I would also move the checking logic to it's own method so it can be re-used elsewhere if required.
def get_light_value():
pin_rc_time = rc_time(pin_to_circuit)
if pin_rc_time > 4000:
return "low"
elif pin_rc_time <= 4000 and pin_rc_time > 1000:
return "medium"
else:
return "high"
Notice here that we also only call rc_time
once per loop. That will avoid any weirdness if the value changes while the conditions are being determined. I changed the logic to check for <= 4000
which will cover the missing condition in your code where the value is exactly 4000. And I also used elif
/else
to ensure only one branch is evaluated.
Using this in the main loop:
last_light_value = None
curr_light_value = None
while True:
last_light_value = curr_light_value
curr_light_value = get_light_value()
# Do nothing if the value did not change
if last_light_value == curr_light_value:
time.sleep(1)
continue
if curr_light_value == "low":
print("Too dark. Frame off.")
elif curr_light_value == "medium":
print("Good light. Medium brightness.")
else: # Value must be high.
print("Bright day. Maximum brightness set.")
Homework for you:
To take this further, you might also want to think about what will happen if the pin value is very close to the threshold of the cutoffs. This will most likely cause the value to flip back and between categories, as some sensors are not extremely precise, and things like florescent lighting can oscillate in intensity.
To combat this, you could implement a filter that to only change the value if it is in a different category and has at least changed some delta of value since the last check. You can use a similar trick to the while loop which takes into account the last value seen before making a determination on if a value should be changed.
Answered By - flakes Answer Checked By - David Marino (WPSolving Volunteer)