HackXIt
HackXIt

Reputation: 542

How do I create a dynamic callback functions in Python? (RPi 3 GPIO)

I'm programming an alarm system from the ground up for my project in python3-6, using an raspberry pi 3 and some alarm components (PIR, REED, etc) To recieve alarms from the components I use the RPi.GPIO library which already has inbuilt Interrupt functionality. Here is the code I wrote so far: UPDATED 31.10.2017 15:44

#Library Imports
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)
time_stamp = time.time()

def PIRcallback(channel):
    print ('Alarm detected: ' + PIR.Name + '\nMotion!')
def REEDcallback(channel):
    print ('Alarm detected: ' + REED.Name + '\nDoor!')
def VIBRcallback(channel):
    print ('Alarm detected: ' + VIBR.Name + '\nWindow!')

class Alarm:
    def __init__(self, IO, pin, Name, cb_var):
        self.IO = IO
        self.pin = pin
        self.Name = Name
        self.callback_func = cb_var
        if (IO == 'input'):
            GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
        elif (IO == 'output'):
            GPIO.setup(pin, GPIO.OUT)
        else:
            print ('Error: No input/output declared')
        self.addEvent('Up', 500)
    def addEvent(self, UpDown, btime):
        if (UpDown == 'Up'):
            UpDown = GPIO.RISING
        elif (UpDown == 'Down'):
            UpDown = GPIO.FALLING
        GPIO.add_event_detect(self.pin, UpDown, callback=self.cb, bouncetime=btime)
    def getPin(self):
        return self.pin
    def cb(self):
        global time_stamp
        time_now = time.time()
        print (time_now)
        if (time_now - time_stamp) >= 0.4:
            print (time_stamp)
            time_stamp = time_now
            self.callback_func()

#Testing Class Init     
REED = Alarm('input', 37, "REED", REEDcallback)
PIR = Alarm('input', 36, "PIR", PIRcallback)
VIBR = Alarm('input', 38, "VIBR", VIBRcallback)

try:
    while True:
        time.sleep(0.5)
except KeyboardInterrupt:
    print ("Terminating program...")
    time.sleep(1)
finally:
    GPIO.cleanup()
    print ("Cleaned GPIO!")

Thanks for helping!

Upvotes: 2

Views: 1781

Answers (1)

lxop
lxop

Reputation: 8605

In Python, functions are first-class variables themselves, and can be passed around like any other variable. In this case, you should simply pass the callback function directly to your Alarm constructor, rather than the name:

class Alarm:
    def __init__(self, IO, pin, callback):
        self.IO = IO
        self.pin = pin
        self.callback_func = callback
        if (IO == 'input'):
            GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
        elif (IO == 'output'):
            GPIO.setup(pin, GPIO.OUT)
        else:
            print ('Error: No input/output declared')
        self.addEvent('Up', self.callback, 500)

    [...]

    def callback(self):
        global time_stamp
        time_now = time.time()
        if (time_now - time_stamp) >= 0.3:
            time_stamp = time_now
            return self.callback_func()  # <- Don't forget the parentheses here


#Testing Class Init    
REED = Alarm('input', 37, REEDcallback)
PIR = Alarm('input', 36, PIRcallback)
VIBR = Alarm('input', 38, VIBRcallback)
# This bit is now done in the constructor:
# VIBR.addEvent('Up', VIBR.callback, 500)
# PIR.addEvent('Up', PIR.callback, 500)
# REED.addEvent('Up', REED.callback, 500)

Upvotes: 1

Related Questions