Airfix
Airfix

Reputation: 127

Raspberry PI Button Push Listener

Is it possible to have button push listener in Python for the Raspberry Pi. I have a non-latching button going to a GPIO. I want to run some python code the first time the button is pushed. Then I want the code to stop on the second button push no matter where it is in the first line of code.

I've used a toggle bit variable called "flag" to register button pushes but obviously there is no listener to determine when the second push is made.

#!/usr/bin/env python
import RPi.GPIO as GPIO
import time

Button = 16    # pin16

def setup():

    GPIO.setmode(GPIO.BOARD)          # Numbers GPIOs by physical location
    GPIO.setup(Button, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)   # Button Input

def motorcontrol():
    flag=0
    while True:
        j=GPIO.input(16)
        if j==1: #Robot is activated when button is pressed
            flag=1
            print "Robot Activated",j
        while flag==1:    
            time.sleep(5)
            print "Robot Activated for 5 seconds"
            time.sleep(5)
            print "Robot Activated for 10 seconds"
            time.sleep(5)
            print "Robot Activated for 15 seconds"

            j=GPIO.input(16)
            if j==1: #De activate robot on pushing the button
                flag=0
                print "Robot DeActivated",j
                destroy()

def destroy():
    GPIO.cleanup()                     # Release resource               

if __name__ == '__main__':     # Program start from here
    setup()
    try:
        motorcontrol()
    except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
        destroy()

Upvotes: 0

Views: 1900

Answers (1)

furas
furas

Reputation: 142631

You can't use sleep() this way because your while loop can't check your botton. You have to loop all time and check if it is time to display text.

You can use small sleep() to use lees CPU.

import time

current_time = time.time()

text_1 = current_time + 5
text_2 = current_time + 10
text_3 = current_time + 15

flag = True

while flag:

    # TODO: check your button and change `flag`

    current_time = time.time()

    if text_1 and current_time >= text_1:
        print("5 seconds")
        text_1 = None #  to stop displaying
        # or show again after 5 seconds
        #text_1 = current_time + 5

    if text_2 and current_time >= text_2:
        print("10 seconds")
        text_2 = None #  to stop displaying

    if text_3 and current_time >= text_3:
        print("15 seconds")
        text_3 = None #  to stop displaying
        flag = False

    #time.sleep(0.1)

Or more like in most GUI

import time

# --- functions ---

def callback_1():
    print("5 seconds")

    # add new task to list
    tasks.append( (current_time + 5, callback_1) )

def callback_2():
    print("10 seconds")

def callback_3():
    print("15 seconds")

def callback_4():
    global flag
    flag = False

# --- main ---

current_time = time.time()

tasks = []

tasks.append( (current_time + 5, callback_1) )
tasks.append( (current_time + 10, callback_2) )
tasks.append( (current_time + 15, callback_3) )
tasks.append( (current_time + 17, callback_4) )

flag = True

while flag:

    # TODO: check your button

    current_time = time.time()

    # this way I execute task and remove from list
    new_tasks = []

    for t, c in tasks:
        if current_time >= t:
            c()
        else:
            new_tasks.append( (t,c) )

    tasks = new_tasks

    #time.sleep(0.1)

EDIT: I don't have RPi so I try to simulate it using own class GPIO - but maybe it will work on your computer. It shows where you should put code.

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time

'''
#
# for test only - instead of `import RPi.GPIO as GPIO`
#

# simulate button press
current_time = time.time()
button_1 = current_time + 2
button_2 = current_time + 10

class GPIO:
    BOARD = None
    IN = None
    PUD_DOWN = None

    @staticmethod
    def setmode(a):
        pass

    @staticmethod
    def setup(a, b, pull_up_down=None):
        pass

    @staticmethod
    def input(a):
        global button_1, button_2

        current_time = time.time()

        if button_1 and current_time >= button_1:
            button_1 = None
            return 1

        if button_2 and current_time >= button_2:
            button_2 = None
            return 1

        return 0

    @staticmethod
    def cleanup():
        pass
'''

Button = 16    # pin16

def setup():
    GPIO.setmode(GPIO.BOARD)          # Numbers GPIOs by physical location
    GPIO.setup(Button, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)   # Button Input

def motorcontrol():
    flag = False

    while True:
        j = GPIO.input(16)
        if j == 1:
            flag = True

            print "Robot Activated", j
            current_time = time.time()

            text_1 = current_time + 5
            text_2 = current_time + 10
            text_3 = current_time + 15

        while flag:    
            j = GPIO.input(16)
            if j == 1:
                flag = False
                print "Robot DeActivated", j
                destroy()

            current_time = time.time()

            if text_1 and current_time >= text_1:
                print "5 seconds"
                text_1 = None #  to stop displaying
                # or show again after 5 seconds
                #text_1 = current_time + 5

            if text_2 and current_time >= text_2:
                print "10 seconds"
                text_2 = None #  to stop displaying

            if text_3 and current_time >= text_3:
                print "15 seconds"
                text_3 = None #  to stop displaying
                flag = False

            time.sleep(0.1)

def destroy():
    GPIO.cleanup()      

if __name__ == '__main__':
    setup()
    try:
        motorcontrol()
    except KeyboardInterrupt:  
        destroy()

Upvotes: 1

Related Questions