We are always told to call GPIO.cleanup()
before we exit our Pi programs. I've seen people using try ... catch ... finally
to achieve this. But hey, we are doing python here, an elegant programming language. Do you guys think this is a more elegant solution?
# SafeGPIO.py
from RPi import GPIO
class SafeGPIO(object):
def __enter__(self):
return GPIO
def __exit__(self, *args, **kwargs):
GPIO.cleanup()
Use like this:
from SafeGPIO import SafeGPIO
import time
with SafeGPIO() as GPIO:
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.OUT)
GPIO.output(7, True)
GPIO.setup(8, GPIO.OUT)
GPIO.output(8, True)
val = 0
for i in xrange(10):
val = (val + 1) % 2
active_pin = 7 + val
inactive_pin = 7 + (val + 1) % 2
GPIO.output(active_pin,True)
GPIO.output(inactive_pin,False)
time.sleep(2)
1 Answer 1
Intuitively I think that I don't like to encapsulate all of my program in a with SafeGPIO() as GPIO
call, so I searched the library and found at_exit. Using this you should be able to have something like the following in SafeGPIO.py:
import at_exit
from RPi import GPIO as RPi_GPIO
# Something useful to re-export GPIO?! Possibly the following?
GPIO = RPi_GPIO
@atexit.register
def cleanup():
RPI_GPIO.cleanup()
Not sure on how to re-export the GPIO, but if this construct works you only need to do from SafeGPIO import GPIO
, and then when Python exits it will call the original GPIO.cleanup()
.
Now the real question is why don't the RPi
module automatically do this if this is a best practice when using RPi
? Sadly, I don't know the answer to that, but it could be a reason for it, which might affect whether this is actually a good solution or not.
PS! I've addressed some more variants related to how to do cleanup in this answer, where I also focus a little more on choosing different options related to use cases.
-
1\$\begingroup\$ Well, I'm a programmer, new to Raspberry Pi, but opening pins feels like opening files to me. And in python you use
with open('filename','rb') as myfile:
to wrap around your file read so you always close the file. \$\endgroup\$rabbit.aaron– rabbit.aaron2015年12月11日 03:00:47 +00:00Commented Dec 11, 2015 at 3:00 -
\$\begingroup\$ And also, my code is not limited to clean up pins on exit, also u can use it to clean up pins in a function or half way in your code. To avoid wrapping all your code in the
SafeGPIO
, you can have your code in a function, then wrap that function call inSafeGPIO()
. I like the idea of using a decorator. I will create a decorator version of it as well. Maybe put it up in github. \$\endgroup\$rabbit.aaron– rabbit.aaron2015年12月11日 03:07:02 +00:00Commented Dec 11, 2015 at 3:07 -
\$\begingroup\$ Are you sure this is as safe as using
with
? There are exceptions listed there whereat_exit
isn't being called, though admittedly I'm not sure whenwith
doesn't call__exit__
correctly. \$\endgroup\$SuperBiasedMan– SuperBiasedMan2015年12月11日 10:15:52 +00:00Commented Dec 11, 2015 at 10:15 -
\$\begingroup\$ Unless python crashes, otherwise
with
catches all exceptions. That's why they usewith open(...)
to read / write files. \$\endgroup\$rabbit.aaron– rabbit.aaron2015年12月11日 10:39:35 +00:00Commented Dec 11, 2015 at 10:39 -
\$\begingroup\$ @rabbit.aaron, I've written an extended version of this answer on your followup question, trying to highlight some of the different aspects of various alternatives. \$\endgroup\$holroy– holroy2015年12月11日 20:51:18 +00:00Commented Dec 11, 2015 at 20:51
cleanup
on exit, but to ensurecleanup
when program exits thewith
block. We might need to usecleanup
multiple times. Whereasat_exit
only run once on program exit. \$\endgroup\$