TL;DR: Since this is a long question I have the following problems:
- I'm looking for a good way to use gpiozero Button to raise SystemExit upon button press
- I have an imported module to drive an E-Ink display (Waveshare 2.7in). To shut down the display, the shutdown function of this module does besides other things also call GPIO.cleanup(), which clashes with gpiozeros automated cleanup
- Depending on whether I place GPIO.cleanup() and raise SystemExit within the button press callback function or the main loop of my dummy program below, I either get errors or I don't and I don't understand why
I have a Waveshare E-Ink Display (https://github.com/waveshare/e-Paper) and a button connected to my Raspberry Pi. My main program should run some code, check whether the display needs to be updated and then sleep for a set amount of time before checking again. When the button is pressed, the E-Ink Display should be cleared and turned off and then, the python program should quit. I'm using gpiozero to control the Button. The Waveshare E-Ink module to drive the display calls GPIO.cleanup() among other things when it is turned off. So I realize there is already some conflict between GPIO.cleanup() and gpiozero. My first code looked like this
from gpiozero import Button from time import sleep import RPi.GPIO as GPIO btn1 = Button(5) def handleBtnPress(): GPIO.cleanup() #simulates the E-Ink Display shut down which also calls GPIO.cleanup() raise SystemExit btn1.when_pressed = handleBtnPress while True: #run main program stuff sleep(1)
Now when I run this code in Thonny on the Raspberry Pi, I get the following Error:
Error in atexit._run_exitfuncs: Traceback (most recent call last): File "/usr/lib/python3/dist-packages/gpiozero/pins/pi.py", line 302, in _set_when_changed self._disable_event_detect() File "/usr/lib/python3/dist-packages/gpiozero/pins/rpigpio.py", line 253, in _disable_event_detect GPIO.remove_event_detect(self.number) RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM) Exception ignored in: <function GPIOBase.__del__ at 0xb5e39300> Traceback (most recent call last): File "/usr/lib/python3/dist-packages/gpiozero/devices.py", line 151, in __del__ File "/usr/lib/python3/dist-packages/gpiozero/mixins.py", line 394, in close File "/usr/lib/python3/dist-packages/gpiozero/devices.py", line 540, in close File "/usr/lib/python3/dist-packages/gpiozero/pins/rpigpio.py", line 136, in close File "/usr/lib/python3/dist-packages/gpiozero/pins/__init__.py", line 450, in <lambda> File "/usr/lib/python3/dist-packages/gpiozero/pins/pi.py", line 302, in _set_when_changed File "/usr/lib/python3/dist-packages/gpiozero/pins/rpigpio.py", line 253, in _disable_event_detect RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)
I realize this is because of GPIO.cleanup() being called in this case directly or later by the E-Ink module shutdown function. The second weird thing is that Thonny displays
Backend terminated or disconnected. Use 'Stop/Restart' to restart.
I then have to restart the backend manually.
I designed another way to shutdown the progam using the button. In this case, pressing the button does not call GPIO.cleanup() and raises SystemExit but rather sets an exitflag and the main program listens for that flag and shuts down when it sees it.
from gpiozero import Button from time import sleep import RPi.GPIO as GPIO exitflag=False btn1 = Button(5) def handleBtnPress(): global exitflag print("set exitflag") exitflag=True btn1.when_pressed = handleBtnPress while True: if exitflag==True: print("exitflag set") GPIO.cleanup() #simulates the E-Ink Display shut down which also calls GPIO.cleanup() print("E-Ink display off. Raising SystemExit") raise SystemExit else: print("exitflag not set") #run main program stuff sleep(1)
Now when I run this program, neither do I get errors from gpiozero because of the called GPIO.cleanup() nor do I get an error from Thonny about the backend being terminated. I realize the reason must be because I'm calling these functions not inside the function that is called upon button press.
I don't understand why this callback function behaves so differently from the main while loop, could somebody explain that?
While I could just use the exitflag strategy, depending on the sleep time in the loop, the program might continue some operations or take a long time before it checks the flag again and I don't want that.
Are there alternative ways to design the program beside my two suggestions. Any help is welcome