Garvan
Posts: 41
Joined: Sun Jan 05, 2020 9:59 am

how to exit signal.pause() in code [SOLVED]

Wed Mar 25, 2020 1:18 pm

The BlueDot documentation https://bluedot.readthedocs.io/en/latest/recipes.html uses pause() to pause program flow while threads are waiting for signals. You can "exit" pause() by pressing Ctrl-C to terminate the program. How do I cause pause() to exit in code? For example, if I want a double-press to clean-up and exit the program.

An example of the use of pause()

Code: Select all

from bluedot import BlueDot
from signal import pause

def say_hello():
    print("Hello World")

def say_bye():
    print("Exit")
    
bd = BlueDot()
bd.when_pressed = say_hello
bd.when_double_pressed = say_bye

pause()
Last edited by Garvan on Thu Mar 26, 2020 8:09 am, edited 1 time in total.

User avatar
B.Goode
Posts: 9819
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: how to exit signal.pause() in code

Wed Mar 25, 2020 1:36 pm

Documentation for the library you are using is here: https://docs.python.org/3/library/signal.html

Depending on the behaviour you want, maybe sigtimedwait() is what you need.

If this is just for cleanup at the end of the script do you need to take any particular action?

Garvan
Posts: 41
Joined: Sun Jan 05, 2020 9:59 am

Re: how to exit signal.pause() in code

Wed Mar 25, 2020 2:32 pm

I want to exit the program when a button is pressed in BlueDot. Is there a way to exit signal.pause()? Or an alternative to signal.pause()?

I can exit the program using Ctrl-C, but I will not have a keyboard attached in the finished project.

scotty101
Posts: 3928
Joined: Fri Jun 08, 2012 6:03 pm

Re: how to exit signal.pause() in code

Wed Mar 25, 2020 2:45 pm

You could just have a small while loop with a time.sleep in it.

Code: Select all

running = True

def say_bye():
    global running
    print("Exit")
    running = False

while running:
    time.sleep(0.1)
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

Garvan
Posts: 41
Joined: Sun Jan 05, 2020 9:59 am

Re: how to exit signal.pause() in code

Wed Mar 25, 2020 3:06 pm

scotty101 wrote:
Wed Mar 25, 2020 2:45 pm
You could just have a small while loop with a time.sleep in it.

Code: Select all

running = True

def say_bye():
    global running
    print("Exit")
    running = False

while running:
    time.sleep(0.1)
Thanks, I will try this.

RobCranfill
Posts: 5
Joined: Sat Aug 18, 2018 4:47 pm
Location: Seattle, WA, USA
Contact: Website YouTube

Re: how to exit signal.pause() in code [SOLVED]

Sun May 24, 2020 12:02 am

I see that someone - the OP? - marked this as "[SOLVED]", but at best what I see here is a workaround. Does anyone know how to actually solve it? I have the same problem.

I have a headless Pi running some software for a MIDI project of mine. I attached a button (to GPIO pin 7) so that I can issue a shutdown command so as to take the system down nicely. When running for real, the shutdown command kills the program, fine, but when I run in test mode (see below) I *have* to <ctrl>C the program, I can't just exit nicely. (Which is OK, but bugs me.)

Anyone have a real solution?

Code: Select all

#!/usr/bin/env python3

# Wait for GPIO pin 7 to get grounded, then shut the machine down.
# args: [--test]

from datetime import datetime
from gpiozero import Button
import os
import signal
import sys
import time


testing_ = False
if len(sys.argv) == 2 and sys.argv[1] == '--test':
  testing_ = True
  print('Setting test mode')


def doShutdown():
  msg = '{} POWERING OFF! at {}'.format(sys.argv[0], datetime.now())
  if testing_:
    msg = '(Testing) ' + msg

  os.system('sudo logger -p emerg "{}"'.format(msg))

  if testing_:
    print('Testing - NOT shutting down')
# why doesn't this work?
#    sys.exit(1)
    print('You have to hit <ctrl>C, I don''t know why!')
  else:
    os.system('sudo poweroff')


button = Button(7)
button.when_held = doShutdown

print('Waiting for button hold....')

# This waits, but we can't get out of it - sys.exit() doesn't!
# But it's OK in our real world use, cuz the poweroff command *does* kill everything.
#
signal.pause()


RobCranfill
Posts: 5
Joined: Sat Aug 18, 2018 4:47 pm
Location: Seattle, WA, USA
Contact: Website YouTube

Re: how to exit signal.pause() in code [SOLVED]

Sun May 24, 2020 12:32 am

OK, I think I found the answer. According to the docs https://docs.python.org/3/library/signal.html
signal.pause()
Cause the process to sleep until a signal is received; the appropriate handler will then be called. Returns nothing.
So all you have to do is ... send yourself a signal. You don't even really need to do anything with it, just receiving the signal seems to break out of signal.pause().

Here's a somewhat-minimal example:

Code: Select all

#!/usr/bin/env python3

# Minimal example of how to break out of signal.pause().
# This waits for a GPIO button to be held (for 1 second), and then exits.
#
# @see https://docs.python.org/3/library/signal.html
#
# [email protected]

from gpiozero import Button
import os
import signal
import sys


# Handler for SIGUSER1
def handleSignal(num, stack):
  print('Got signal! And now we mysteriously will exit....')


def doShutdown():
  print('In Button.when_held handler...')

  # If this worked, all I really want is this. Or return, or whatever. Done.
  #  Why doesn't this work?
#  sys.exit(1)

  # Send a SIGUSER1; this seems to cause signal.pause() to return.
  os.kill(os.getpid(), signal.SIGUSR1)


button = Button(7)
button.when_held = doShutdown

# Install a handler for SIGUSER1 .... which seems to entirly fix our problem. Why?!?!
signal.signal(signal.SIGUSR1, handleSignal)

# This waits.
# According to the docs,
#  "Cause the process to sleep until a signal is received; the appropriate handler will then be called."
# so I guess this makes sense.
#
print('Waiting for button hold....')
signal.pause()


RobCranfill
Posts: 5
Joined: Sat Aug 18, 2018 4:47 pm
Location: Seattle, WA, USA
Contact: Website YouTube

Re: how to exit signal.pause() in code [SOLVED]

Sun May 24, 2020 12:44 am

One final comment: If you want to do even less coding, you don't really need to define and hook up a handler for the signal. Just send it, and signal.pause() still exits. In my test code, above, I did that and it works, but I do get a message on screen that
User defined signal 1
was received.

/rob

Return to “Python”