0

I was hoping someone could help me with this issue. I'm hoping it's fairly simple to fix, but I have been trying for a while to figure this out. I have trimmed my larger code to this, as I believe the issue here is the crux of the problem.

I have a raspberry pi and an external button. This is on python3 on Linux. I am using GPIOZero for the button. The code below I believe is simple to understand, but basically, I want a function to loop at all times. When I press a button I want another function to run, but only if a variable is a certain number. I describe what I ultimately want to happen in a comment below, but my code is unfinished and simplified just for this problem.

I only want button.when_pressed to work when timer = 0. The problem is, once the code naturally gets into the button.when_pressed function, it never "lets go" of the function again. When I successfully redefine the variable to timer = 1, it still prints button is pressed when I press the button. I don't know why. To me, it seems like it should only work once timer = 0.

Any suggestions? I think I have a misunderstanding of global variables I will plan on researching. I'm not sure if that's the issue. I have also tried using break and continue to try to get it "back on its loop" but that hasn't worked either. Also I want to use button.when_pressed instead of btn.is_pressed, because I want the program to only do something when I'm holding the button down once, and not loop when I'm holding it down. In this case, I want button is pressed to print a single time. If I did btn.is_pressed it would print button is pressed every two seconds, which I dont want.

Thanks for any help. I'm happy to learn.

#!/usr/bin/python3

from gpiozero import Button
from time import sleep
import time

button = Button(4)
timer = 0

def press():
    print("Button is pressed")
    global timer
    timer = 1
   
def loop():
    global timer
    timer =  1
   
while True:
       
    if timer == 0:
        button.when_pressed = press
   
    else:
        loop()

    sleep(2)
  • 2
    All your `if timer == 0` condition does is rebind the button's `when_pressed` callback function. That has no influence over what happens when the callback is actually invoked, or how many times you are "allowed" to execute it. You're just saying "this is the function I want to call at a later point in time when I press the button". I'm surprised this prints anything at all, because in order for `press` to trigger, you'd have to bind it first, which you only do when `timer == 0`, which can only happen when you call `press` or when `timer != 0`... – Paul M. Dec 20 '21 at 23:49
  • You should describe the expected behavior. Aside from the issue with the callback function, right now once timer is 1, there is no mechanism to make it back 0. Is this expected? – mozway Dec 20 '21 at 23:51
  • @mozway This is part of a larger code that is a work in progress and unfinished. Ultimately, the code will play a very long video when the button is pressed. As long as the button is held down, the video will continue. When no button is pressed. I want the first video to close and a second short video to open, play, then close on a loop. I only want the first video to open when the button is pressed AND the second video is closed. When the second video is playing, I want any button press to open the first video until after the second one has finished playing. – domerwannabe Dec 21 '21 at 00:14
  • Looks like you only need to set a flag when your second video is playing and remove it when done. Or make the playing blocking so that your loop won't run in the meantime – mozway Dec 21 '21 at 00:24
  • @PaulM I only want that callback function to work when the variable ```timer = 0```. If I were to set that initial line to ```if timer == 999``` then indeed it never works. It only works due to an initial variable of ```timer = 0``` at the top. However, it seems that if ```timer``` ever equals 0, the callback will trigger anytime a button is pressed afterwards, no matter what happens to the code/variable later in the loop. – domerwannabe Dec 21 '21 at 00:27
  • @mozway I agree, except nothing seems to stop the ```button.when_press``` callback, no matter what. I could add ```sleep()``` after ```loop()``` but when I press the button it does the ```press()``` function no matter what . – domerwannabe Dec 21 '21 at 00:30

2 Answers2

0

If you want to disable the callback you had set to button.when_pressed, you need to do another assignment with button.when_pressed = None. This is listed in the documentation:

when_released:

[...] Set this property to None (the default) to disable the event.

It's not exactly clear what behavior you want from your current code. If you want the button to be active for 2 seconds, then be deactivated indefinitely, you can use:

button.when_pressed = press
sleep(2)
button.when_pressed = None

There's no need for a loop, since you don't want to repeat anything.

If you only want the button to be active for a single button press, that needs to happen within 2 seconds, you could instead call button.wait_for_press(2). I hesitate to write a full block of code for that though, as the docs don't specify how a timeout is signaled (it might be by return value, or via an exception). I don't have a Raspberry Pi so I can't test myself, but you could try it out and see what happens.

Blckknght
  • 100,903
  • 11
  • 120
  • 169
  • I will look into this. Thank you. I describe my ultimate goal in a comment above. I want a loop because I want to short video to play every X amount of seconds. It will open, play, close, repeat. When I press the button, I want another video to play except when the looping video is initiated. I want the button triggered video only to play when the button is pressed (and held) when the other video is done playing. – domerwannabe Dec 21 '21 at 00:34
0

Treat your whole piece of code as one "black box", ask yourself, what is the input/output? button press or timer mode? (because I don't quite understand what does timer variable mean in your code)

Your code implies timer mode is the top level input to control the flow,

while True:
    if timer == 0:
        button.when_pressed = press
    else:
        loop()
    sleep(2)

Is it expected?

If you allow user to press the button at any time, suggest you make button press to be your top level input, change the logic to keep when_pressed callback always on, set flag once triggered, and then check if the button has been pressed and still is_pressed in your while loop.

pressed = False

def play_video_1():
    pass

def play_video_2():
    pass

def press():
    print("Button is pressed")
    global pressed
    pressed = True


button.when_pressed = press

while True:
       
    if pressed and not_playing_video2:
        if is_pressed:
            play_video_1()
        else:
            pressed = False
            play_video_2()
    else:
        play_video_2()

balun
  • 1,191
  • 1
  • 7
  • 12