0

I am running a piece of python code on a raspberry pi.
The function of the code is that GPIO 5 is set as a pull up resistor with a momentary switch attached. When the switch is pressed it grounds the pull up resistor. I am attempting to use the button push to trigger a callback.
The callback works like this:
If the button is pressed and detected as still pressed it defines a variable called "t1" as the current time.
If the button is detected as no longer pressed it defines a variable called "t2" then subtracts "t1" from "t2" to find the time difference (amount of time button was held down for). It then converts that value to an integer defined as variable "deltaseconds". Then it takes action based on the length the button was held for. If more than 7 seconds, reboot the raspberry pi, if more than 1 second but less than 7 it toggles output GPIO(12) between high and low.

The issue I am experiencing is like this:
The code runs
When the button is pressed I see the print of "Button 5 pressed"
When the button is released I see the print "Button 5 released"
Then an error is display as "UnboundLocalError: local variable 't1' referenced before assignment"
The error is in reference to line 21 delta = t2-t1

The full code looks like this:

import os
import RPi.GPIO as GPIO
import webiopi
import time
import datetime
from datetime import datetime
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)
BUTTON_5 = 5
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(12,GPIO.OUT)
GPIO.output(12,1)
#Just to visually distinguish between setup steps and main program
def pressed(BUTTON_5):
    if GPIO.input(5) == False:
        t1 = datetime.now()
        print "Button 5 pressed"
    elif GPIO.input(5) == True:
        print "Button 5 released"
        t2 = datetime.now()
        delta = t2-t1
        deltaseconds = delta.total_seconds()
        if (deltaseconds > 7) : # pressed for > 7 seconds
            print "Restarting System"
            subprocess.call(['shutdown -r now "System halted by GPIO action" &'], shell=True)
        elif (deltaseconds > 1) : # press for > 1 < 7 seconds
            print "Toggling GPIO 12"
            GPIO.output(12, not GPIO.input(12))
GPIO.add_event_detect(BUTTON_5, GPIO.BOTH, bouncetime=200)
GPIO.add_event_callback(BUTTON_5, pressed)
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    GPIO.cleanup()       # clean up GPIO on CTRL+C exit
3
  • You set t1 to datetime.now() in the above if statement, then you try to access it in the following elif statement. Commented Oct 2, 2015 at 3:26
  • Yes! @dursk is right! your elif condtion is running where t1 variable is undefined. Commented Oct 2, 2015 at 3:33
  • That makes sense, Thank you. That being said, I've tried moving it and I guess I've reached the limit of my knowhow on this one because I can't find a place to put it where it works. Can you advise where I can define the variable so the value holds? Commented Oct 2, 2015 at 3:42

3 Answers 3

0

Check the scope of your variables. t1 is defined in the == False block. Line 21 is in the elif block. When a block ends, all local variables are destroyed (or at least inaccessible).

To correct this, add a line to see if t1 is defined at the beginning of your loop, and if it is not defined, define it to something unreasonable (that you may decide to check against later).

Sign up to request clarification or add additional context in comments.

Comments

0

t1 should be defined outsidepressed(BUTTON_5). You want to preserve the value from one call of this function to the next. While it is possible to possible to have static variables in a python function (by making them attributes of the function), it's generally clearer to make them global (in python 2). So, just put global t1 at the start of your function.

I should mention that global variables can quickly get out of hand, but if the variable is only being accessed in one function, there's no problem.

2 Comments

So if I define t1 outside of the callback it will have a set value and if the == False block runs it will change the value of t1. Will the new value be stored after that block finishes or will it revert?
The value doesn't revert when the block finishes. The global statement creates or modifies a global variable. Once the global variable is create, it remains in existence until the program finishes running, unless you explicitly delete it, and its value doesn't change unless you explicitly modify it.
0

After a substantial amount of investigating and learning I was able to achieve the desired result with the following code:

import os
import RPi.GPIO as GPIO
import webiopi
import time  
import subprocess
import datetime
from datetime import datetime
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)
BUTTON_5 = 5
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(12,GPIO.OUT)
GPIO.output(12,1)
#Just to visually distinguish between setup steps and main program
t1 = 999999999999999999999
def pressed(BUTTON_5):
    if GPIO.input(5) == False:
        global t1 
        t1 = datetime.now()
        print "Button 5 pressed"
    elif GPIO.input(5) == True:
        print "Button 5 released"
        t2 = datetime.now()
        delta = t2-t1
        deltaseconds = delta.total_seconds()
        if (deltaseconds > 7) : # pressed for > 7 seconds
            print "Restarting System"
            subprocess.call(['shutdown -r now "System halted by GPIO action" &'], shell=True)
        elif (deltaseconds > 1) : # press for > 1 < 7 seconds
            print "Toggling GPIO 12"
            GPIO.output(12, not GPIO.input(12))
GPIO.add_event_detect(BUTTON_5, GPIO.BOTH, bouncetime=200)
GPIO.add_event_callback(BUTTON_5, pressed)
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    GPIO.cleanup()       # clean up GPIO on CTRL+C exit  

This code seems to run smoothly and I have tested it thoroughly. I had to define "t1" as a global variable, once I learned what they were and how they work it all started to fall into place.

Thank you to everyone who contributed to me getting to this answer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.