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).
Related
i have a thread running on the background checking every 5 sec and print a msg after 5 secs passes.
in loop1 the msg should appear at specific point. (in this case, its above print('test')).
the thread can wait longer than 5 secs when loop1 is running (like a few sec delay is fine) but it have not to appear at the same time as loop1 is running so i put queue to for blocking.
when loop2 is running, the messsage in the multithread should appear while loop2 is running at the same time unlike loop no1.
so i didnt put queue.get in loop2 since theres no need for blocking but the problem is when going into loop3. if we go into loop3 while we are on time.sleep(5) in multithread, thats fine but if we are on print ("thread working2") in multithread, i want to make sure it waits until it does all the work in print ("thread working2") part. there are more codes there but i just put a simple print for better readability. before going into loop3. is there any way i can accomplish this? and is the method im using right now is suitable for my intention?
sorry for my bad english!
import threading
import time
from queue import Queue
queue = Queue()
queue2 = Queue()
switch = False
def func0():
while True:
global switch
global queue
global queue2
time.sleep(5)
switch = True
print ("switch on")
a = queue.get()
if a == 1:
print("thread working")
time.sleep(0.5)
print("thread working")
time.sleep(0.5)
switch = False
queue2.put(True)
if a == 2:
print("thread working2")
time.sleep(0.5)
print("thread working2")
time.sleep(0.5)
switch = False
if __name__ == "__main__":
t1 = threading.Thread(target=func0)
t1.start()
testnumber = 0
testnumber2 = 0
testnumber3 = 0
while True: #loop no.1
if switch:
queue.put(1)
queue2.get()
print ("loop1")
time.sleep(0.5)
testnumber = testnumber +1
if testnumber == 200:
break
while True: #loop no.2
if switch:
queue.put(2)
print ("loop2")
time.sleep(0.5)
testnumber2 = testnumber2 + 1
if testnumber2 == 200:
break
while True: #loop no.3
print ("loop3")
time.sleep(0.5)
testnumber3 = testnumber3 + 1
if testnumber3 == 200:
break
t1.join()
As a new programmer, I'm trying to create a Python3 script that creates a Countdown timer based on the KeyCombination used which is then written to a text file used by StreamlabsOBS. The idea is that when a KeyCombo is pressed (e.g ctrl+alt+z) a function starts a timer, and at the same time, another function writes the current time in the countdown to a txt file. This script would ideally be running during the entire stream.
So far, I can get the countdown working and writing to the file exactly how I want it to. But it seems the Thread is still alive after finishing the countdown. I'm not sure if this is a problem or not. Another thing is that I want to implement some kind of pause feature, that would pause the timer function. I'm not sure how to even start on that part.
The print statements are for me to know what part of the function I am at.
from pynput import keyboard
from pathlib import Path
from threading import Thread
import queue
from time import sleep
script_location = Path(__file__).absolute().parent
timer_queue = queue.Queue()
def storeInQueue(function):
print("Sent Start Thread msg")
def storer(*args):
for time in function(*args):
timer_queue.put(time)
print(f"stored {time}")
return storer
#storeInQueue
def timer(t):
print("Iterating Timer Loop")
while t > -1:
yield t
sleep(1)
t -= 1
def speakKorean():
print("starting Thread")
timer_thread = Thread(target=timer, args=(5,))
timer_thread.start()
ctime = timer_queue.get()
while ctime >-1:
with open(script_location / 'ChronoDown.txt', "w") as timer_file:
timer_file.write(f"Speak Korean for {ctime}s")
timer_file.flush()
sleep(1)
ctime = timer_queue.get()
if ctime == 0: break
print('Speak Korean done!')
with open(script_location / 'ChronoDown.txt', "w") as timer_file:
timer_file.write(f"Done!")
timer_file.flush()
while timer_thread.is_alive:
print("timer thread still running?")
timer_thread.join()
break
if timer_thread.is_alive:
print("didn't work")
def on_activate_z():
timer_file = open(script_location / 'ChronoDown.txt', "w")
timer_file.write("other keywords")
timer_file.close()
def on_activate_c():
korean_thread = Thread(target=speakKorean,)
korean_thread.start()
print("Working")
def on_activate_x():
timer_file = open(script_location / 'ChronoDown.txt', "w")
timer_file.write("No cursing for time")
timer_file.close()
with keyboard.GlobalHotKeys({
'<ctrl>+<alt>+z': on_activate_z,'<ctrl>+<alt>+c': on_activate_c,
'<ctrl>+<alt>+x': on_activate_x}) as h:
h.join()
My console output looks like this after I run it. I'm not sure why "Sent Start Thread msg" sends before I start thread too.
Sent Start Thread msg
starting Thread
Working
Iterating Timer Loop
stored 5
stored 4
stored 3
stored 2
stored 1
stored 0
Speak Korean done!
timer thread still running?
didn't work
Also if you have any optimization tips that would be appreciated. Thank you in advance for any help.
Thanks to #furas , I've now implemented a pause function that properly resumes as well. This is my updated code :
from pynput import keyboard
from pathlib import Path
from threading import Thread
import queue
from time import sleep
script_location = Path(__file__).absolute().parent
timer_queue = queue.Queue()
paused = False
while paused == False:
def storeInQueue(function):
print("Sent Start Thread msg")
def storer(*args):
for time in function(*args):
timer_queue.put(time)
print(f"stored {time}")
return storer
#storeInQueue
def timer(t):
print("Iterating Timer Loop")
while t > -1:
if paused == False:
yield t
sleep(1)
t -= 1
else: continue
def speakKorean():
print("starting Thread")
timer_thread = Thread(target=timer, args=(5,))
timer_thread.start()
ctime = timer_queue.get()
while ctime >-1:
with open(script_location / 'ChronoDown.txt', "w") as timer_file:
timer_file.write(f"Speak Korean for {ctime}s")
timer_file.flush()
sleep(1)
ctime = timer_queue.get()
if ctime == 0: break
print('Speak Korean done!')
with open(script_location / 'ChronoDown.txt', "w") as timer_file:
timer_file.write(f"Done!")
timer_file.flush()
timer_thread.join()
if timer_thread.is_alive():
print("didn't work")
else: print("its dead")
def on_activate_z():
global paused
timer_file = open(script_location / 'ChronoDown.txt', "w")
timer_file.write("Paused")
timer_file.close()
if paused == True:
paused = False
print(f'Paused = {paused}')
else:
paused =True
print(f'Paused = {paused}')
def on_activate_c():
korean_thread = Thread(target=speakKorean,)
korean_thread.start()
print("Working")
def on_activate_x():
timer_file = open(script_location / 'ChronoDown.txt', "w")
timer_file.write("No cursing for time")
timer_file.close()
with keyboard.GlobalHotKeys({
'<ctrl>+<alt>+z': on_activate_z,'<ctrl>+<alt>+c': on_activate_c,
'<ctrl>+<alt>+x': on_activate_x}) as h:
h.join()
The main differences:
My entire code is now encapsulated in a While paused == False loop, which allows me to pause my timer function based on the state of paused using an if statement
I've added the missing ( ) to timer_thread.is_alive() which allowed me to properly end the timer Thread
I have made a thread that is supposed to show the seconds passing. Unfortunately, when I use getstr from the curses module the whole script stops, including the thread. I have to use a thread lock to stop random characters being printed out because of overlapping orders.
Any suggestions on how to fix this or an alternative would be great!
In the below example window and window2 are already set-up...
lock = threaing.Lock()
def main_function():
#starts thread
t1 = threading.Thread(target=time_calc,args=(window2,))
t1.start()
#Gets user input
while True:
data = window1.addstr(y,x,"Type something in!")
data = window1.getstr(y,x,5)
lock.acquire()
window1.erase()
txt = "You said: "+data
window1.addstr(y,x,txt)
lock.release()
def time_calc(window2):
current_count = 0
while True:
time += 1
text = "Time Count: "+str(time)
lock.acquire()
window2.erase()
window2.addstr(y,x,text)
lock.release()
time.sleep(1)
The problem with my code
I figured out the problem with my code. You can't run a thread inside a thread for some reason and I originally had my main function called to be considered a thread. I guess I should have stated this in my question. Sorry
There is probably a way to run a thread in a thread, but this did not work for me.
My Updated Code
lock = threading.Lock()
def call_threads():
t1 = threading.Thread(target=main_function,args=(window1,))
t1.start()
t2 = threading.Thread(target=time_calc,args=(window2,))
t1.start()
def main_function(window1):
#Gets user input
while True:
data = window1.addstr(y,x,"Type something in!")
data = window1.getstr(y,x,5)
lock.acquire()
window1.erase()
txt = "You said: "+data
window1.addstr(y,x,txt)
lock.release()
def time_calc(window2):
current_count = 0
while True:
time += 1
text = "Time Count: "+str(time)
lock.acquire()
window2.erase()
window2.addstr(y,x,text)
lock.release()
time.sleep(1)
If there is anything else that may have caused this error, please comment it!
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
Hi guys i don't know why the only block runs is my first function.
i am trying to pass my coin_counter last value to the 2nd function but my first function is not passing the value after it's release.
and also it doesn't print to the console
import RPi.GPIO as GPIO
import time
import threading
GPIO.setmode(GPIO.BCM)
GPIO.setup(27,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
lock = threading.Lock()
counter = 1
pulse = 0
def coin_counter():
global counter
lock.acquire()
try:
while True:
time.sleep(.1)
GPIO.wait_for_edge(27, GPIO.RISING)
#print("Pulse comming ! (%s)") %counter
counter += 1
return counter
finally:
lock.release()
print(coin_counter())
def get_pulse_count():
while True:
print('Hello World!')
try:
coincounter = threading.Thread(target=coin_counter)
getpulse = threading.Thread(target=get_pulse_count)
coincounter.start()
getpulse.start()
except KeyboardInterrupt:
coincounter.stop()
getpulse.stop()
GPIO.cleanup()
I think the problem in line print(coin_counter()). Its should be removed because we have infinite loop in main thread (coin_counter() call). No any code will be executed after this line. If we remove this line and add sleep into get_pulse_count() then it works. Also return counter does not required if you passing value through global variable counter.
I think this resolve the problem. or?
import RPi.GPIO as GPIO
import time
import threading
GPIO.setmode(GPIO.BCM)
GPIO.setup(27,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
lock = threading.Lock()
counter = 1
pulse = 0
def coin_counter():
global counter
global pulse
lock.acquire()
try:
time.sleep(.1)
GPIO.wait_for_edge(27, GPIO.RISING)
print("Pulse comming ! ", counter)
counter += 1
pulse = counter
finally:
lock.release()
def get_pulse_count():
global pulse
lock.acquire()
try:
print(pulse)
finally:
lock.release()
while True:
time.sleep(.1)
try:
coincounter = threading.Thread(target=coin_counter)
coincounter.start()
getpulse = threading.Thread(target=get_pulse_count)
getpulse.start()
except KeyboardInterrupt:
coincounter.stop()
getpulse.stop()
GPIO.cleanup()