r4d1um
r4d1um

Reputation: 548

Trigger Function when Button is pressed like a keydown trigger in python on rasperry pi 3

I am using an rasperry pi with latest raspian jessie installed.

I want to react to an keydown event, then a function should be called and executed exactly once and a parameter should be incremented.

what I currently have is

# Import Libraries
from gpiozero import LED,Button
from signal import pause
from time import sleep 

# LED Declaration
LED1 = LED(21)
LED2 = LED(16)
LED3 = LED(20)

# Button declaration
button = Button(19)

LED1.off()
LED2.off()
LED3.off()

current = 0

# Function for setting Outputs
def output(current):
    print(current)
    if current == 0:
        LED1.off()
        LED2.off()
        LED3.off()
    if current == 1:
        LED1.on()
        LED2.off()
        LED3.off()
    if current == 2:
        LED1.off()
        LED2.on()
        LED3.off()
    if current == 3:
        LED1.on()
        LED2.on()
        LED3.off()
    if current == 4:
        LED1.off()
        LED2.off()
        LED3.on()
    if current == 5:
        LED1.on()
        LED2.off()
        LED3.on()
    if current == 6:
        LED1.off()
        LED2.on()
        LED3.on()
    if current == 7:
        LED1.on()
        LED2.on()
        LED3.on()

def increment(current):
    print(current)
    if current < 7:
        current += 1
        output(current)
        return
    if current == 7:
        current = 0
        output(current)
        return


# Check for pressed button
while True:
    if button.when_pressed True:
        increment(current)

How can i keep sure that my function is just called once and my current variable is incremented correctly and not being reset to 0 when function is triggered once?

Upvotes: 0

Views: 722

Answers (2)

Maarten Fabr&#233;
Maarten Fabr&#233;

Reputation: 7058

At this moment, you try to use current to keep track of the state of the incrementor. But the current within the increment is not the same as the current in the global (module) namespace. Easiest way to circumvent this is to declare current as global in the increment function, but I think it is best to create a class to keep this state

class MyLeds()

    def __init__(self, *leds, current=0):
        self._leds = leds
        self._current = current

    def increment():
        self._current = (self._current + 1) % (2 ** len(self._leds) - 1)
        self._output()

    def _output():
        for i, led in enumerate(leds):
            on = self._current & 2**i
            led.on() if on else led.off()
            # print('led %i is %s' % (i+1, on))

I made the code also more flexible for more leds using bitwise &.

The rest of your script would look like this, then:

if __name__ == '__main__':
    from gpiozero
    from signal import pause
    from time import sleep 

    # LED Declaration
    led_ports = (21, 16, 20)
    leds = tuple(gpiozero.LED(led) for led in led_ports)

    for led in leds:
        led.off()
    my_leds = MyLeds(leds)
    # Button declaration
    button = gpiozero.Button(19)

    while True:
        if button.when_pressed:
            my_leds.increment()

Upvotes: 1

Ron Norris
Ron Norris

Reputation: 2690

You while loop will block the GUI from working. So try using the button's command option to call a function. Also, it is best practice to use a class to create the GUI. It helps avoid using global variables, etc.

from tkinter import *

class Counter:

    def __init__(self, master):
        self.current = 0
        # Button declaration
        button = Button(master, text='+', command=self.increment)
        button.grid()

    def increment(self):
        self.current += 1
        print(self.current)

root = Tk()
app = Counter(root)
root.mainloop()

Upvotes: 1

Related Questions