Can't quit a running python script

2.2k views Asked by At

I just started learning Raspberry Pi development with python and have a simple RGB LED circuit setup on my breadboard, I then connected this to Pubnub to control it from a little web interface I built which just sends a method name and RGB values over Pubnub where the python script has subscribed to the particular channel.

from pubnub import Pubnub
import RPi.GPIO as G
import time

pubnub = Pubnub(publish_key="****", subscribe_key="****")
def callback(message, channel):
    globals()[message['method']](message['data'])
def error(message):
    print("ERROR: " + str(message))
def connect(message):
    print("CONNECTED")
def reconnect(message):
    print("RECONNECTED")
def disconnect(message):
    print("DISCONNECTED")

G.setmode(G.BCM)

red_channel_pin = 18
green_channel_pin = 23
blue_channel_pin = 24

G.setup(red_channel_pin, G.OUT)
G.setup(green_channel_pin, G.OUT)
G.setup(blue_channel_pin, G.OUT)

pwm_red = G.PWM(red_channel_pin,500)
pwm_red.start(100)

pwm_green = G.PWM(green_channel_pin,500)
pwm_green.start(100)

pwm_blue = G.PWM(blue_channel_pin,500)
pwm_blue.start(100)

def set_rgb_values(data):
    pwm_red.ChangeDutyCycle(float(data['red']))
    pwm_green.ChangeDutyCycle(float(data['green']))
    pwm_blue.ChangeDutyCycle(float(data['blue']))

try:
    pubnub.subscribe(channels="rasprgb",callback=callback, error=error, connect=connect, reconnect=reconnect, disconnect=disconnect) 
except KeyboardInterrupt:
    print('Cleaning Up')
    G.cleanup()
    pubnub.unsubscribe(channel='rasprgb')

All of this works except for trying to close the program and clean up the GPIO pins, unsubscribe from the channel, etc.

In the past I've used a while True: loop and that has worked, but since I don't want to do something in a loop here, I just want to open a connection and leave it open until I terminate it a loop doesn't make sense here

Hitting Ctrl + C just outputs KeyboardInterrupt but it doesn't seem to be calling the except block

How can I get this to be able to terminate and clean up GPIO pins?

UPDATE

After refactoring to use signal here is what I have now replacing the try...except (assuming I have imported them at the top of the file)

def sig_handler(signal,frame):
    print('Cleaning Up')
    G.cleanup()
    pubnub.unsubscribe(channel='rasprgb')
    sys.exit(0)

pubnub.subscribe(channels="rasprgb",callback=callback, error=error, connect=connect, reconnect=reconnect, disconnect=disconnect)
signal.signal(signal.SIGINT, sig_handler)

However, pressing ctrl + c still does not close out the program and run the cleanup code

2

There are 2 answers

4
stevieb On

Using the signal module, you can create a global interrupt handler:

import signal
import sys

def sig_handler(signal, frame):
    print('Cleaning Up')
    G.cleanup()
    pubnub.unsubscribe(channel='rasprgb')
    sys.exit(0)

signal.signal(signal.SIGINT, sig_handler)

Now, when you CTRL-C, your cleanup code will run, and the program will exit. I use Perl mostly on my Pis, but I do the same thing to ensure that all pins are reset before a re-run of the same application, or a run of a different app.

0
Evan Levy On

You can exit a script using any key press with this function. I also don't see a problem with a while loop but if I really needed an alternative method, I would use this:

import sys, os

def wait_key():
  ''' Wait for a key press on the console and return it. '''
  result = None

  import termios
  fd = sys.stdin.fileno()

  oldterm = termios.tcgetattr(fd)
  newattr = termios.tcgetattr(fd)
  newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
  termios.tcsetattr(fd, termios.TCSANOW, newattr)

  try:
      result = sys.stdin.read(1)
  except IOError:
      pass
  finally:
      termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)

  return result

print('Press any key to quit: ')
wait_key()

Another similar method can be utilized by using the curses module like so:

import curses
stdscr = curses.initscr()
c = stdscr.getch()
print 'you entered', chr(c)
curses.endwin()

Also if you are using Windows, you can use the msvcrt module:

import msvcrt
c = msvcrt.getch()
print 'you entered', c