Here is script (/shutdown.py). It monitors button press and if button is pressed more than 3 seconds, it runs poweroff command.
#!/usr/bin/python
# Import the modules to send commands to the system and access GPIO pins
from subprocess import call
from time import sleep
import RPi.GPIO as gpio
import time
# Define a function to keep script running
def loop():
raw_input()
# Define a function to run when an interrupt is called
def shutdown(pin):
button_press_timer = 0
while True:
if (gpio.input(17) == False) : # while button is still pressed down
button_press_timer += 1 # keep counting until button is released
if button_press_timer == 3:
#print "powering off"
call('poweroff', shell=True)
sleep(1)
else: # button is released, figure out for how long
#print "Poga atlaista. nospiesta bija " + str(button_press_timer) + " sekundes"
#button_press_timer = 0
return
# sleep(1) # 1 sec delay so we can count seconds
# print "powering off"
gpio.setmode(gpio.BCM) # Use BCM GPIO numbers
gpio.setup(17, gpio.IN, pull_up_down=gpio.PUD_UP) # Set up GPIO 17 as an input
gpio.add_event_detect(17, gpio.FALLING, callback=shutdown, bouncetime=200) # Set up an interrupt to look for button presses
loop() # Run the loop function to keep script running
If I run script from console like /shutdown.py all is fine. Button press is detected and system shutdown is initialed. But if i add that script to /etc/rc.local (/shutdown.py &), then it fails at startup with this error:
Traceback (most recent call last):
File "/shutdown.py", line 35, in <module>
loop() # Run the loop function to keep script running
File "/shutdown.py", line 11, in loop
raw_input()
EOFError: EOF when reading a line
If I comment out loop() line, then there is no error and script does not run in background. I just start and exit and button press not detected. So, how i can run that script at startup and keep running in background?
EDIT
I am not python guru and i think that loop() is python internal function. Now i seen that it is defined function which calls raw_input(). That script I found and modified to fit my needs.
Thanks.
What you really need is a Python daemon which runs in the background. The raw_input method you are trying to use looks like an ugly hack to me.
Have a look at python-daemon package, which is meant exactly for your use case and is quite simple to use. There is also an updated fork with Python 3 support.
After installing python-daemon, add this line to the beginning of your script
import daemon
Then substitute the loop() call at the end of your script with this code:
with daemon.DaemonContext():
while True:
time.sleep(10)
This code is untested, but you get the idea.
Related
I'm trying to create a program that spams your screen with terminal windows using threading and would like to create a failsafe button that force quits python when a certain parameter is met. I've tried "os._exit()" and that does not work. I am looking for a way to destroy all threads and force quit python as if my program runs for too long it will crash my computer.
def spam():
for i in range(30):
if i % 10 == 0: # if i is divisible by 10, it pauses for comedic timing
time.sleep(2)
os.system('open -a Terminal .') # opens terminal window
playsound('/Users/omar/Downloads/boom.wav') # plays comical 'vine' funny meme audio
thread = multiprocessing.Process(target=spam) # creates a thread
thread.start()
if pyautogui.failSafeCheck() == True or pynput.keyboard.Controller().type == 'Keyboard':
os._exit() and thread.terminate()
spam() # function call
I want to run a program using the subprocess module. While running the program, there are cases where it waits for a button press to continue. It is not waiting for this input to the stdin input. The input sent to stdin is ignored by the program. Only when I press a button on the console will the program continue running.
I tried it like this:
proc = Popen("festival.exe level.sok", stdin=PIPE, text=True)
proc.stdin.write('.')
proc.stdin.flush()
It this case nothing happened.
and like this:
proc = Popen...
proc.communicate('.')
In this case, the python code will not continue running until I press a button on the console. If I set a timeout then the python code continues to run but festival.exe does not continue to run.
What should I do to make festival.exe continue running?
P.S.: festival.exe is a solver for sokoban. This case occurs when the given level cannot be solved. E.g.:
########
#.. $ $#
# # #
########
assuming you have the festival program like this:
from random import getrandbits
solved = getrandbits(1)
if solved:
print("executed correctly")
else:
print('a error ocurred')
input('press a button to continue')
exit(1)
you can solve with:
from subprocess import Popen, PIPE
p = Popen(['python3','festival.py'],stdin=PIPE)
p.communicate(input=b'any\n')
I'm working on a little Raspberry Pi security project that has LEDs, a piezoelectric buzzer, a 9 digit keypad, and an LCD screen (Full Source Here: https://github.com/kevbo423/RPHSP/blob/master/Keypad.py).
In short, when a user enters an incorrect password with the keypad, I want the LEDs to flash and the buzzer to go off at the same time. I can't for the life of me figure out how to make that happen. I have the functions for the LEDs and the Buzzer created and individually working, but can't get them to go off simultaneously.
# Function for error LED feedback
def errorLED():
for i in range(3):
GPIO.output(6,1)
time.sleep(0.2)
GPIO.output(6,0)
GPIO.output(12,1)
time.sleep(0.2)
GPIO.output(12,0)
# Function for Buzzer Alarm Output
def buzzerAlarm():
for i in range(3):
GPIO.output(21,1)
time.sleep(0.5)
GPIO.output(21,0)
time.sleep(0.5)
I looked into using the Threading module, but ran into issues when I tried to execute the thread for the Buzzer beeping multiple times. Below is the test code I created to try and run the Buzzer thread multiple times...
# Buzzer Test
buzzerSound = threading.Thread(target=buzzerAlarm())
buzzerSound.start()
time.sleep(3)
buzzerSound.start()
time.sleep(3)
buzzerSound.start()
time.sleep(3)
...and the error message I received.
Traceback (most recent call last):
File "Keypad.py", line 277, in <module>
buzzerSound.start()
File "/usr/lib/python2.7/threading.py", line 730, in start
raise RuntimeError("threads can only be started once")
RuntimeError: threads can only be started once
Am I on the right track with the threading module? If so, should I be killing the Buzzer thread inside of the BuzzerAlarm() function or should I not be using .start() to run the function? Or do I need to be doing something else entirely? If threading isn't the best way to go, I'm open to suggestions.
From the documentation:
start()
It must be called at most once per thread object.
Therefore you should create a new Thread object if you want to start it again. For example:
buzzer_thread = threading.Thread(target=buzzerAlarm())
led_thread = threading.Thread(target=errorLED())
led_thread.start()
buzzer_thread.start()
time.sleep(3)
# Second time:
buzzer_thread = threading.Thread(target=buzzerAlarm())
led_thread = threading.Thread(target=errorLED())
led_thread.start()
buzzer_thread.start()
You may consider refactoring this into a function:
def buzzer_and_led():
buzzer_thread = threading.Thread(target=buzzerAlarm())
led_thread = threading.Thread(target=errorLED())
led_thread.start()
buzzer_thread.start()
# Wait until both the buzzer and the LED stop
while led_thread.is_alive() or buzzer_thread.is_alive():
pass
Firstly not a multi-threading answer, this answer should still work either way.
Okay, quick answer. What you could do is combine the two functions
# Function for error LED feedback
def errorLED():
for i in range(3):
GPIO.output(6,1)
time.sleep(0.2)
GPIO.output(6,0)
GPIO.output(12,1)
time.sleep(0.2)
GPIO.output(12,0)
# Function for Buzzer Alarm Output
def buzzerAlarm():
for i in range(3):
GPIO.output(21,1)
time.sleep(0.5)
GPIO.output(21,0)
time.sleep(0.5)
This would become
#Combined function
def combined():
for i in range(3):
GPIO.output(6,1) #Error LED
GPIO.output(21,1) #Alarm Buzzer
time.sleep(0.25) #Notice times changed by 0.05 so it can do the combination easyer
GPIO.output(6,0)
GPIO.output(12,1)
time.sleep(0.25)
GPIO.output(12,0)
#Repeats Code
GPIO.output(6,1)
GPIO.output(21,0) #Only difference is turning off the buzzer/alarm
time.sleep(0.25)
GPIO.output(6,0)
GPIO.output(12,1)
time.sleep(0.25)
GPIO.output(12,0)
Tell me if this works, I have not used my Raspberry PI in a while
I have a python script in my Raspberry Pi that is connected to a rain gauge. When the rain gauge detects rain, the script shows 0.2 and write it to file. This is the code:
#!/usr/bin/env python3
import time
import RPi.GPIO as GPIO
BUTTON_GPIO = 16
if __name__ == '__main__':
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
pressed = False
while True:
# button is pressed when pin is LOW
if not GPIO.input(BUTTON_GPIO):
if not pressed:
print("0.2")
pressed = True
# button not pressed (or released)
else:
pressed = False
time.sleep(0.1)
My idea is to use a code like that to save the total amount of rain. When the python script show 0.2 > write it to file.
python3 rain.py >> rain.txt
The code creates a file but doesn't write anything until execution is finished by Ctrl + C.
I need to execute it on boot. I have tried to add it to crontab and rc.local but doesn't work.
I tried to execute it with sudo and pi. The permissions are 755.
Thank you!
try this
import time
import RPi.GPIO as GPIO
BUTTON_GPIO = 16
if __name__ == '__main__':
outputfile=open("/var/log/rain.txt","a",0)
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
pressed = False
while True:
# button is pressed when pin is LOW
if not GPIO.input(BUTTON_GPIO):
if not pressed:
openputfile.write("0.2\n")
pressed = True
# button not pressed (or released)
else:
pressed = False
time.sleep(0.1)
open a file in append mode with non buffered write.
Then when an event occurs, write to that file.
Do not use shell redirect as it will (in this case) buffer all the program output until exit and then write to a file. Of course, the exit never happens as you have a "while True" with no break
Indeed, this construct command >> file takes the whole of stdout and flushes into the file. It's done only when command execution is over. You must write to the file as soon as your intermediate result is ready:
#!/usr/bin/env python3
import sys
import time
import RPi.GPIO as GPIO
BUTTON_GPIO = 16
if __name__ == '__main__':
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
pressed = False
# command line arguments
if len(sys.argv) > 1: ## file name was passed
fname = sys.argv[1]
else: ## standard output
fname = None
## this will clear the file with name `fname`
## exchange 'w' for 'a' to keep older data into it
outfile = open(fname, 'w')
outfile.close()
try:
while True:
# button is pressed when pin is LOW
if not GPIO.input(BUTTON_GPIO):
if not pressed:
if fname is None: ## default print
print("0.2")
else:
outfile = open(fname, 'a')
print("0.2", file=outfile)
outfile.close()
pressed = True
# button not pressed (or released)
else:
pressed = False
time.sleep(0.1)
except (Exception, KeyboardInterrupt):
outfile.close()
In this approach you should run python3 rain.py rain.txt and everything will be fine. The try except pattern ensures the file will be properly closed when execution is interrupted by errors or keyboard events.
Notice the file keyword argument in call to print. It selects an open file object to write printed stuff. It defaults to sys.stdout.
I am using python 3.8 on windows 10. I am able to run threading programs succesfully on IDLE but, the same programs do not start on command line or when I double click them. The shell pops up and exits quickly even when threads are not started. I even tried to catch any runtime errors and any errors using except but I got neither on IDLE and the program was still terminating abruptly on shell.
Here is an example -
import threading
import time
try:
def func():
for i in range(10):
print(i)
time.sleep(0.1)
t1 = threading.Thread(target = func)
t1.start()
#t1.join() # i tried this also
while t1.is_alive():
time.sleep(0.1) #trying to return back, i added this when the threads were not working
input() #waiting for the user to press any key before exit
except RuntimeError:
print('runtime error')
input()
except: # any error
print('Some error')
input()
I found that I had made a file by the name 'threading.py' in the directory. This file was causing Attribute Error of python because it has the same name as the 'threading' module of python. I renamed it and my programs are working jolly good!