7
\$\begingroup\$

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)
\$\endgroup\$
  • \$\begingroup\$ Unfortunately, updating the code in your questions after receiving answers is against site policy. See What do after receiving answers for more information. \$\endgroup\$ – Quill Dec 11 '15 at 13:44
  • \$\begingroup\$ Just to state that, the purpose of creating this context manager is not just to ensure cleanup on exit, but to ensure cleanup when program exits the with block. We might need to use cleanupmultiple times. Whereas at_exit only run once on program exit. \$\endgroup\$ – rabbit.aaron Dec 11 '15 at 13:58
  • \$\begingroup\$ I have also created a decorator for this purpose, available here \$\endgroup\$ – rabbit.aaron Dec 11 '15 at 14:05
3
\$\begingroup\$

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.

| improve this answer | |
\$\endgroup\$
  • 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 Dec 11 '15 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 in SafeGPIO(). 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 Dec 11 '15 at 3:07
  • \$\begingroup\$ Are you sure this is as safe as using with? There are exceptions listed there where at_exit isn't being called, though admittedly I'm not sure when with doesn't call __exit__ correctly. \$\endgroup\$ – SuperBiasedMan Dec 11 '15 at 10:15
  • \$\begingroup\$ Unless python crashes, otherwise with catches all exceptions. That's why they use with open(...) to read / write files. \$\endgroup\$ – rabbit.aaron Dec 11 '15 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 Dec 11 '15 at 20:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.