Hello. I'm a complete Python beginner and I'd like to know how to add a fail-safe to your code so that the script is stopped after a certain phrase or key combination has been given as input.

To explain further, I'm playing around with a Raspberry Pi at work. I created a simple circuit with a LED, button and a few lines of code to control it all. I start the python script which can only be stopped manually (CTRL+C or CTRL+Z) in the terminal. The script waits for a user input, which in this case, is pressing the button, and when that happens the LED lights up and the output in the terminal is "Button pressed". The script continues to run until I press CTRL+C which is a terminal bound command I belive.

I'd like to do the following: The script runs for an infinite amount of time, but if I input "stop" or "close" or something like that instead of pressing the button, it should stop immediately (just like with CTRL+C).

I tried:

stop = raw_input("Phrase: ")

if stop == "stop":
    sys.exit(0)
else:
    MAIN

But that's not what I'm looking for because now the main script doesn't work like it's supposed to. I'd like the script to run as it did before I added the above lines, but when I input something from the keyboard instead of pressing the button it stops.

Just in case things are unclear here's the whole code:

import RPi.GPIO as GPIO
import sys

#set pin 8 as input, pin 10 as output
GPIO.setmode(GPIO.BOARD)
GPIO.setup(8, GPIO.IN)
GPIO.setup(10, GPIO.OUT)

#reset pins if CTRL+C or CTRL+Z is pressed
try:
    while True:

        #save value from pin 8
        input_value = GPIO.input(8)

        var = raw_input("Phrase: ")

        if var == "stop":
            sys.exit(0)
        else:

            #if value on pin 8 is false (button pressed)
            if input_value == False:

                #light up the LED
                GPIO.output(10, GPIO.HIGH)
                print("Button pressed")

                #check value on pin 8 again
                while input_value == False:
                    input_value = GPIO.input(8)
            else:

                #else LED is off
                GPIO.output(10, GPIO.LOW)

except KeyboardInterrupt:
    GPIO.cleanup()

Note: The code isn't mine completely. Most of it is copied from people who posted tutorials for controlling a LED with a switch through a Raspberry Pi.

Edited 3 Years Ago by syfr

Well the only reason sys.exit won't work is if var doesn't = 'stop', if var = anything else than 'stop', it will execute the rest of the code, also make sure input_value has a value of False if it doesn't it will just goto the else here and then turn off the LED:

else:
    #else LED is off
    GPIO.output(10, GPIO.LOW)

Edited 3 Years Ago by aVar++

I'm not sure if you understand what I want. The original code without the

    stop = raw_input("Phrase: ")
    if stop == "stop":
    sys.exit(0)
    else:
    MAIN

works perfectly fine, but with these few lines it doesn't anymore.

Here's what happens after I run the script:
- script waits for input (Phrase: ) and if I press the button the LED doesn't light up, but it should!
- I give anything except "stop" as input and the next step is executed (wait for button press)
- I press the button, but the LED doesn't light up AND I'm back to the first step
- I enter anything again and NOW the LED lights up (although I haven't pressed the button), and it doesn't turn off either
- so now the LED is on the whole time (button not pressed) and I'm at "Phrase: " again
- I enter anything again and the LED turns off (button not pressed)
- if I enter "stop" while it waits for "Phrase: " the script stops
- if I enter "stop" while it waits for button press it doesn't close, but if I also press the button afterwards the script stops

What I really want is this:
- script waits for button press
- I press the button, LED light up and stays lit for as long as the button is pressed
- I release the button and the LED turns off
- back to first step
- script runs in an infinite loop for as long as I don't stop it with CTRL+C
- this is the part I can't figure out: if at any point while the script waits for the button press I enter "stop" it should stop

Edited 3 Years Ago by syfr

So this is how it looks like when I start the ORIGINAL script WITHOUT the 4 lines of code I quoted above:

pi@raspberrypi ~ $ sudo python led.py

| <- linux terminal coursor

I press the button 3 times and I get:

Button pressed
Button pressed
Button pressed
| <- I can write anything I want here and the script just ignores it

So if I feel playful I can do this:

Button pressed
Button pressed
Button pressed
fdsfa
jhfttz
| <- I can even write "stop" here and it does nothing which is logical

Button pressed
Button pressed
Button pressed
fdsfa
jhfttz
stop
stop
| <- That's what I want. When I write "stop" here the script stops

raw_input just waits for keyboard input, but I want the script to wait for either keyboard input OR button press

Edited 3 Years Ago by syfr

I apologize for all the posts, but I'm analyzing different options and I can't edit the previous post anymore.

Here's a couple of ideas I have to solve it, but I don't know how to implement them:

  • A switch case, but I found out python doesn't have that. Instead I can define a 3 functions for 3 different scenarios (invalid input, button press & "stop"). The problem with this is I don't know how I can use strings instead of integers for calling the different functions.

An example of what I mean:

cases = {
    "error" : error,
    "False" : button,
    "stop" : exit
}

def error():
    print("Invalid input")

def button():
    CODE FOR CONTROLLING LED WITH BUTTON

def exit():
    sys.exit(0)
  • The second solution I thout of is time dependant. When the script has been idle for a certain period of time it stops by itself.

Something in the lines of:

if time.sleep() == 5:
    sys.exit(0)

I know there has to be a simple solution.

How about putting your validation code, and as a mesure of precaution, an echo form of your input, so that you can see what you actually type in.

while(True):
    ipt = raw_input("\\\\: ")
    print ipt
    if ipt == "stop": sys.exit(0);
    else:  #rest of the program

and than, post your results here, so we can see what it actually gets from the console as an input.

Edited 3 Years Ago by Lucaci Andrew

Andrew, the code works. I already tried it multiple times with multiple variations. Anything I input, that's what I get back. If I input "stop" the script stops. The thing is as soons as I use raw_input in my code the keyboard gets priority, and the button for controlling the LED doesn't work properly anymore (see my second post for further info). Maybe I'm implementing it wrong, maybe it's because there are two inputs (keyboard and GPIO8) and I'm missing something in my code so that's why both inputs are getting mixed up... I don't know.

Tony, could you explain further? Or point me in the right direction? I'm still a beginner at programming overall, and a complete python beginner (2 days experience). I just want to know what I'm doing wrong.

I have to point out again, that I don't want my script to wait for keyboard input at all. I want it to wait for button press, just like the original script does, but just in case I decide to stop the script with the keyboard, it should recognise the phrase "stop" and exit immediately.

At this point I think it would be easier to implement a timer which executes sys.exit(0) after, let's say, 5 minutes. How would I do that?

Edited 3 Years Ago by syfr

could the problem be in the raspberry pi and gpio pins? does manually editing the sys/class/gpio related files work correctly?

I as far as I understand, the Raspberry Pi is a tiny inexpensive ($35) computer board based on Linux and Python. It came out about a year ago in the UK and sold over one million units so far. Correct me if I am wrong. Sounds like an interesting project anyway!

They are awesome. I have two of them. The pi pins aren't protected as good as the arduino, so I set up my arduino to listen for commands on the serial port, and the pi sends commands to it using a python script and the serial library. I can change the whole behavior of the arduino by loading different python scripts on the pi. The possibilities are endless with the pi anyway, but I felt better testing stuff out through the arduino. (I waited months for my first pi to come, I can pick up an arduino less than a mile from my house.)

You could probably use a non blocking input with a call to select() like in this example (linux only):

#!/usr/bin/env python
# -*-coding: utf8-*-
from __future__ import unicode_literals, print_function, division
__doc__ = """ module: sandbox.pollinput -
"""

import select
import sys
import time

def opt_input():
    i, w, x = select.select([sys.stdin], [], [], 0)
    if i:
        return sys.stdin.readline()
    else:
        return ''

def prompt():
    sys.stdout.write('Phrase: ')
    sys.stdout.flush()

def main():
    prompt()
    while True:
        input_value = opt_input() # non blocking attempt
        if input_value.strip() == 'stop':
            sys.exit(0)
        else:
            if input_value:
                prompt()
            time.sleep(0.3) # <-- simulate program busy

if __name__ == "__main__":
    main()

Edited 3 Years Ago by Gribouillis

This article has been dead for over six months. Start a new discussion instead.