i am building a Phone with my Raspberry Pi and Twinkle.
In my example i am starting Twinkle with a subprocess and checking the output for my code.
Now i need to start a while-loop when someone is calling to check the "end-call button". This works well but i need to end the loop if the far end cancelled the call. How can i break the while loop from another if condition?
Here is my code for example:
#IMPORTS
import sys
import time
import RPi.GPIO as GPIO
from multiprocessing.pool import ThreadPool
import threading
#START TWINKLE
from subprocess import Popen, PIPE
proc = Popen(["twinkle", "-c"], stdin=PIPE, stdout=PIPE, bufsize=1)
for line in iter(proc.stdout.readline, b''):
print line
#BUTTON WATCHER
def button_watch():
input_state = GPIO.input(36)
while (input_state == False):
print "loop"
#END LOOP ON BUTTON PRESS
if (input_state == False):
print('Button Pressed')
input_state = GPIO.input(36)
GPIO.setup(32, GPIO.OUT)
GPIO.output(32, GPIO.LOW)
proc.stdin.write("answer\n")
time.sleep(0.2)
break
#INCOMING CALL
def main():
if (line.find("incoming call") > 0):
print "call is coming"
GPIO.setmode(GPIO.BOARD)
GPIO.setup(32, GPIO.OUT)
GPIO.output(32, GPIO.HIGH)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(36, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#START BUTTON WATCHER ON INCOMING CALL
t1 = threading.Thread(target=button_watch)
t1.start()
#CALL CANCELLED
if (line.find("far end cancelled call") > 0):
print "call was cancelled"
GPIO.setmode(GPIO.BOARD)
GPIO.setup(32, GPIO.OUT)
GPIO.output(32, GPIO.LOW)
##############################################
# NEED TO END WHILE LOOP FROM "button_watch" #
##############################################
tmain = threading.Thread(target=main)
tmain.start()
proc.communicate()
I added a comment seeking clarification because I am not sure I understand the intent completely. Now, eventually you will find better and more robust ways to do this but the simplest solution would be to check for a compound condition (assuming you still need input_condition == False).
So you could define a global flag called remote_disconnected, initialize it in a way that your while loop runs in the beginning, and compound it like:
while (input_condition == False and remote_disconnected == False):
make the button_watch depend on a global flag, so you can turn the flag to False
Related
I am using a simple code from PiMyLife tutorial to read from a Light Dependant Resistor using a capacitor. This works great..
I then added a 2nd LDR and capacitor, added it to pin 31 and then duplicated the code (the rc_time function and the fuction call) to add an additional Light Dependant Resistor but for some reason the second function call never happens.
#!/usr/local/bin/python
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
#define the pin that goes to the circuit
pin_ldr_one = 29
pin_ldr_two = 31
def rc_time_one (pin_ldr_one):
count_one = 0
#Output on the pin for
GPIO.setup(pin_ldr_one, GPIO.OUT)
GPIO.output(pin_ldr_one, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_ldr_one, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_ldr_one) == GPIO.LOW):
count_one += 1
return count_one
def rc_time_two (pin_ldr_two):
count_two = 0
#Output on the pin for
GPIO.setup(pin_ldr_two, GPIO.OUT)
GPIO.output(pin_ldr_two, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_ldr_two, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_ldr_two) == GPIO.LOW):
count_two += 1
return count_two
#Catch when script is interrupted, cleanup correctly
try:
# Main loop
while True:
print("LDR 1: ",rc_time_one(pin_ldr_one))
print("LDR 2: ",rc_time_two(pin_ldr_two))
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
So I thought I would try threading instead thinking that the 2 function calls were having issues.
So this is the threading code I came up with however this too fails to run the second (in this cask 2nd thread). Any ideas where I am going wrong. Thanks for all your help
#!/usr/local/bin/python
import RPi.GPIO as GPIO
import time
from time import sleep, perf_counter
from threading import Thread
GPIO.setmode(GPIO.BOARD)
#define the pin that goes to the circuit
pin_ldr_one = 29
pin_ldr_two = 31
def rc_time_one (pin_ldr_one = 29):
count_one = 0
#Output on the pin for
GPIO.setup(pin_ldr_one, GPIO.OUT)
GPIO.output(pin_ldr_one, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_ldr_one, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_ldr_one) == GPIO.LOW):
count_one += 1
print("LDR 1: ",count_one)
return count_one
def rc_time_two (pin_ldr_two = 31):
count_two = 0
#Output on the pin for
GPIO.setup(pin_ldr_two, GPIO.OUT)
GPIO.output(pin_ldr_two, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_ldr_two, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_ldr_two) == GPIO.LOW):
count_two += 1
print("LDR 2: ",count_two)
return count_two
#Catch when script is interrupted, cleanup correctly
try:
# Main loop
while True:
# create two new threads
t1 = Thread(target=rc_time_one)
t2 = Thread(target=rc_time_two)
# start the threads
t1.start()
t2.start()
t1.join()
t2.join()
#print("LDR 1: ",rc_time_one(pin_ldr_one))
#print("LDR 2: ",rc_time_two(pin_ldr_two))
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
Peter
In the if-else statement below, I want the condition GPIO,input(17) has to be different than 0 for at least 5 second until it prints out "COMMUNICATION IS LOST, PLEASE CHECK". Please help me on this issue
import RPi.GPIO as GPIO
from time import sleep
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)
try:
while True:
if GPIO.input(17):
print "GOOD COMMUNICATION"
else:
print "COMMUNICARION IS LOST, PLEASE CHECK"
sleep (0.1)
finally:
GPIO.cleanup()
try this
import RPi.GPIO as GPIO
from time import sleep
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)
try:
count = 0
while True:
if GPIO.input(17):
count = 0
print "GOOD COMMUNICATION"
else:
if count == 50:
print "COMMUNICATION IS LOST, PLEASE CHECK"
else:
count += 1
sleep(0.1)
finally:
GPIO.cleanup()
If you mean 17 needs to be 0 for 5 seconds that should work
While overkill for this project a thread can help here quite a bit so it's here for anyone interested.
from threading import Thread, Lock
import time
class ListenThread(Thread):
def __init__(self, lock):
Thread.__init__(self)
self._lock = lock # We lock when we work with our status
self._terminating = False
self._status = "CONNECTION NOT MADE"
def run(self):
self._seconds = 0
while True:
if self._terminating:
break
if self._seconds > 5:
self._lock.acquire()
self._status = "COMMUNICATION IS LOST, PLEASE CHECK"
self._lock.release()
elif GPIO.input(17):
self._seconds = 0
self._lock.acquire()
self._status = "GOOD COMMUNICATION"
self._lock.release()
time.sleep(0.5) #interval
self._seconds += 0.5
def status(self):
return self._status
def end(self):
self._lock.acquire()
self._terminating = True;
self._lock.release()
lock = Lock()
worker = ListenThread(lock)
worker.start()
for i in range(0, 25):
# Do other things! When we want to check on the status
# simply ask. Making sure to lock for safety.
lock.acquire()
print worker.status()
lock.release()
time.sleep(0.3)
worker.end() # Make sure to stop the thread!
This will have the same effect except has the usefulness of a thread so we can keep doing work on our main function. (I've replaced the while loop so that it ends but the same could be done as the OP).
I purchased a QTR-8RC Reflectance Sensor Array and now trying to configure it with Python. I am trying to determine the rate of decay of the voltage that is being read by my receivers (phototransistors) so that I know when a line is being detected. I don't know why my Python code isn't returning anything. Not even a warning statement. Additional information includes that by default the GPIO is an output and the LEDs are ON. Any help is appreciated!
import RPi.GPIO as GPIO
from time import sleep
def Read():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(5, GPIO.OUT)
sleep(0.01)
count = 0
GPIO.setup(5, GPIO.IN)
while GPIO.input(5) == True:
count = count + 1
return count
while True:
Read()
print(Read())
sleep(1)
I don't have any knowledge about QTR-8RC Reflectance Sensor Array.
But looking at your python code, the problem might be with
while GPIO.input(5) == True
If the value is always true then the line with the return statement is never reached.
You could use print statement after while block to check that. Something like
while GPIO.input(5) == True:
count = count + 1
print "while loop has ended"
return count
Instead of running the program continuously run it for some time and check the outputs.
And may be you need to increase the sleep time to see the output practically.
import RPi.GPIO as GPIO
from time import sleep
def Read():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(5, GPIO.OUT)
sleep(0.01)
count = 0
GPIO.setup(5, GPIO.IN)
while GPIO.input(5) == True:
count = count + 1
print "count :", count
return count
for _ in range(100):
print(Read())
sleep(2)
I am writing a python script, that will show the status of a raspberry pi's gpio input pins in a web browser. This script is just for the backend testing:
import RPi.GPIO as GPIO
import time
import os
os.system('clear')
GPIO.setmode(GPIO.BOARD)
GPIO.setup(29, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(32, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(37, GPIO.IN, pull_up_down=GPIO.PUD_UP)
while True:
input_state = GPIO.input(37)
if input_state == False:
print('One')
time.sleep(0.2)
input_state = GPIO.input(32)
if input_state == False:
print('Two')
time.sleep(0.2)
input_state = GPIO.input(29)
if input_state == False:
print('Three')
time.sleep(.02)
My output crazily spams the screen with the number until the input switch is turned off. How can I prevent the same consecutive line from repeating immediately?
Thanks!
How about printing only when the input states actually change? Something like this (untested):
# Your code to initialise everything:
import RPi.GPIO as GPIO
import time
import os
os.system('clear')
GPIO.setmode(GPIO.BOARD)
GPIO.setup(29, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(32, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(37, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# New loop keeping track of the previous ("old") input states:
old_input_states = [None] * 3
while True:
input_states = [GPIO.input(n) for n in (37, 32, 29)]
if input_states != old_input_states:
for n, name in enumerate(['One', 'Two', 'Three']):
if input_states[n] == False:
print name
old_input_states = input_states
So to explain what this new loop code is doing:
First, a list old_input_states is created which contains three None entries. This will be used to remember the last state of the three GPIOs.
Then at the beginning of the loop, the GPIO.input(n) function is called, for n being 37, 32 and 29 for the three GPIOs. The resulting list input_states now contains the three GPIO states.
Then this list is compared against the old_input_states list and if they differ, it will do the following:
For each name in 'One', 'Two' and 'Three' (which are enumerated by n, i.e. for 'One' it is 0, 1 for 'Two' and 2 for 'Three'), it checks the value of that input_states[n] to see if it is False and if it is, it prints the name which should match the corresponding GPIO.
Then it updates old_input_states to match input_states so in the next loop, it will only check (and potentially print) again if the input_states changed.
EDIT
Note that the code will output all GPIOs which are currently False at the point where a change is detected. To only print the ones going from True to False, you should be able to use the following code for the section starting with the # New loop comment:
# New loop keeping track of the previous ("old") input states:
old_input_states = [None] * 3
while True:
input_states = [GPIO.input(n) for n in (37, 32, 29)]
for n, name in enumerate(['One', 'Two', 'Three']):
if input_states[n] != old_input_states[n] and input_states[n] == False:
print name
old_input_states = input_states
EDIT 2
As indicated by the OP, the preferred output is in list-form anyway. Also there appeared to be some bouncing happening on the switch inputs to the GPIOs, which could be improved by using the time.sleep calls. Further, the output should be inverted. The final code of the while loop looks like this:
old_input_states = [None] * 3
while True:
input_states = [GPIO.input(n) for n in (37, 32, 29)]
if input_states != old_input_states:
inverted_input_states = [1 - i for i in input_states]
print inverted_input_states
time.sleep(0.2)
old_input_states = input_states
Disclaimer: For better debouncing reliability of switches I'd use different code, but that is beyond the scope of this question
You could modify your code to work with an 'on change' type logic:
import RPi.GPIO as GPIO
import time
import os
os.system('clear')
GPIO.setmode(GPIO.BOARD)
# allows you to rename the io ports
io_names = [ 'One', 'Two', 'Three' ]
class IOMonitor():
def __init__( self, num , io, pud ):
self.num = num
GPIO.setup(self.num, io, pull_up_down=pud)
self.last_state = GPIO.input(self.num)
def poll( self ):
# detect current state
current_state = GPIO.input(self.num)
# compare with old state
if( current_state != self.last_state ):
# set new last state
self.last_state = current_state
# print name of io that changed
print( io_names[self.num] )
ioMonitors = [
IOMonitor(29, GPIO.IN, GPIO.PUD_UP),
IOMonitor(32, GPIO.IN, GPIO.PUD_UP),
IOMonitor(37, GPIO.IN, GPIO.PUD_UP)
]
def main():
while True:
for io in ioMonitors:
io.poll()
time.sleep(0.2)
main()
I don't have access to your libraries so this code is untested but should be logically correct.
Using a Raspberry Pi and some push buttons I want to control video playback. When someone presses a button the corresponding video plays. The buttons work great. When you press a button the video plays, but when you press a different button or the same button it opens the video without closing the video that was currently playing. I've been searching a while to fix this. I'm pretty new to Python so please keep it as simple as possible. In the code below I'm trying to accomplish it using multithreading. I wasn't able to close the thread though when another thread starts. I am able to close the video after it plays for 10 seconds, but I can't move the quit command anywhere else to close other videos: playSippycup.stdin.write('q')
Here's are the errors I'm currently receiving:
Unhandled exception in thread started by <function shoppingcart at 0xb6c566f0>Playing Sippycup
Unhandled exception in thread started by <function dodgeballs at 0xb6c56670>
Traceback (most recent call last):
File "./labmural2.py", line 53, in dodgeballs
playDodgeballs.stdin.write('q')
NameError: global name 'playDodgeballs' is not defined
Traceback (most recent call last):
File "./labmural2.py", line 71, in shoppingcart
playShoppingcart.stdin.write('q')
NameError: global name 'playShoppingcart' is not defined
Thanks so much for any help you guys can offer!
#!/usr/bin/env python
import RPi.GPIO as GPIO
import subprocess
import time
import thread
GPIO.setmode (GPIO.BCM)
GPIO.setwarnings (False)
GPIO.setup(9, GPIO.IN)
GPIO.setup(10, GPIO.IN)
GPIO.setup(11, GPIO.IN)
GPIO.setup(17, GPIO.OUT)
GPIO.setup(22, GPIO.OUT)
GPIO.setup(27, GPIO.OUT)
def sippycup( name ):
global playSippycup
while True:
if GPIO.input(11) == True:
print name
time.sleep(1)
playSippycup=subprocess.Popen(['omxplayer','Desktop/videos/sippycup.mp4'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, close_fds=True)
time.sleep(10)
playSippycup.stdin.write('q')
if GPIO.input(9) == True:
playSippycup.stdin.write('q')
if GPIO.input(10) == True:
playSippycup.stdin.write('q')
def dodgeballs( name ):
global playDodgeballs
while True:
if GPIO.input(9) == True:
print name
time.sleep(1)
playDodgeballs=subprocess.Popen(['omxplayer','Desktop/videos/dodgeballs.mp4'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, close_fds=True)
time.sleep(10)
playDodgeballs.stdin.write('q')
if GPIO.input(10) == True:
playDodgeballs.stdin.write('q')
if GPIO.input(11) == True:
playDodgeballs.stdin.write('q')
def dodgeballs( name ):
global playDodgeballs
while True:
if GPIO.input(9) == True:
print name
time.sleep(1)
playDodgeballs=subprocess.Popen(['omxplayer','Desktop/videos/dodgeballs.mp4'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, close_fds=True)
time.sleep(10)
playDodgeballs.stdin.write('q')
if GPIO.input(10) == True:
playDodgeballs.stdin.write('q')
if GPIO.input(11) == True:
playDodgeballs.stdin.write('q')
def shoppingcart( name ):
global playShoppingcart
while True:
if GPIO.input(10) == True:
print name
time.sleep(1)
playShoppingcart=subprocess.Popen(['omxplayer','Desktop/videos/shoppingcart.mp4'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, close_fds=True)
time.sleep(10)
playShoppingcart.stdin.write('q')
if GPIO.input(9) == True:
playShoppingcart.stdin.write('q')
if GPIO.input(11) == True:
playShoppingcart.stdin.write('q')
thread.start_new_thread( sippycup, ("Playing Sippycup",) )
thread.start_new_thread( dodgeballs, ("Playing Dodgeballs",) )
thread.start_new_thread( shoppingcart, ("Playing Shoppingcart",) )
while True:
pass
GPIO.cleanup()
NEW EDIT:
#!/usr/bin/python
from time import sleep
import RPi.GPIO as GPIO
import subprocess
import time
import thread
GPIO.setmode (GPIO.BCM)
GPIO.setwarnings (False)
GPIO.setup(9, GPIO.IN)
GPIO.setup(10, GPIO.IN)
GPIO.setup(11, GPIO.IN)
GPIO.setup(17, GPIO.OUT)
GPIO.setup(22, GPIO.OUT)
GPIO.setup(27, GPIO.OUT)
def welcome_loop():
while True:
global playProcess
x = 1
print "LOOPING"
time.sleep(.5)
playProcess=subprocess.Popen(['omxplayer','-b','Desktop/videos/loop/loop.mp4'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, close_fds=True)
time.sleep(10)
playProcess.stdin.write('q')
x += 1
def videos():
while True:
if GPIO.input(9):
print "STOP LOOP"
time.sleep(.5)
playProcess.stdin.write('q')
time.sleep(.5)
print "Play Sippycup"
sippycup_video=subprocess.Popen(['omxplayer','-b','Desktop/videos/sippycup.mp4'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, close_fds=True)
time.sleep(10)
sippycup_video.stdin.write('q')
time.sleep(.5)
welcome_loop()
if GPIO.input(10):
print "STOP LOOP"
time.sleep(.5)
playProcess.stdin.write('q')
time.sleep(.5)
print "Play Dodgeballs"
dodgeballs_video=subprocess.Popen(['omxplayer','-b','Desktop/videos/dodgeballs.mp4'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, close_fds=True)
time.sleep(10)
dodgeballs_video.stdin.write('q')
time.sleep(.5)
welcome_loop()
if GPIO.input(11):
print "STOP LOOP"
time.sleep(.5)
playProcess.stdin.write('q')
time.sleep(.5)
print "Play Shoppingcart"
shoppingcart_video=subprocess.Popen(['omxplayer','-b','Desktop/videos/shoppingcart.mp4'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, close_fds=True)
time.sleep(10)
shoppingcart_video.stdin.write('q')
time.sleep(.5)
welcome_loop()
thread.start_new_thread( videos, () )
thread.start_new_thread( welcome_loop, () )
while True:
pass
GPIO.cleanup()
ERROR:
Unhandled exception in thread started by
Traceback (most recent call last):
File "./labmural2.py", line 28, in welcome_loop
playProcess.stdin.write('q')
IOError: [Errno 32] Broken pipe
NameError: global name 'playDodgeballs' is not defined means that you are trying to use playDodgeballs before it is defined playDodgeballs = ...
I would simplify your code by removing all globals and threads. subprocess.Popen runs a separate process; it doesn't block your main thread:
names = 'sippycup', 'dodgeballs', 'shoppingcart'
movies = ['Desktop/videos/{name}.mp4'.format(name=name) for name in names]
players = [Player(movie=movie) for movie in movies]
player = players[0]
setup_io() # GPIO setup
while True:
for key in get_key_events(): # get GPIO input
if key == '0':
player = players[0]
elif key == 'space':
player.toggle() # pause/unpause
elif key == 'enter':
player.start()
...
where Player is a simple wrapper around omxplayer subprocess:
import logging
from subprocess import Popen, PIPE, DEVNULL
logger = logging.getLogger(__name__)
class Player:
def __init__(self, movie):
self.movie = movie
self.process = None
def start(self):
self.stop()
self.process = Popen(['omxplayer', self.movie], stdin=PIPE,
stdout=DEVNULL, close_fds=True, bufsize=0)
self.process.stdin.write(start_command) # start playing
def stop(self):
p = self.process
if p is not None:
try:
p.stdin.write(quit_command) # send quit command
p.terminate()
p.wait() # -> move into background thread if necessary
except EnvironmentError as e:
logger.error("can't stop %s: %s", self.movie, e)
else:
self.process = None
def toggle(self):
p = self.process
if p is not None:
try:
p.stdin.write(toggle_command) # pause/unpause
except EnvironmentError as e:
logger.warning("can't toggle %s: %s", self.movie, e)
Specify appropriate start_command, quit_command, toggle_command. You could define different methods depending on what commands omxplayer understands and what commands you need.