Using thread in while loop causes problems with LED blink - python

I've been hung up on a problem for a couple of days, now. I've spent hours searching message boards and have come up empty.
I have a program that pulls data from an API, parses it with JSON, and displays it on an LCD screen. I want an LED light to blink when data meets a certain condition. I have been fairly successful so far. The issue I am running into is when a thread is called to start the blink from my main while loop, and the main while loop restarts, it appears that the thread is then called again. This causes my LEDs to start acting wacky after each subsequent while loop restart. Any suggestions?
I tried using v.isAlive() == False" in hopes that the thread wouldn't restart but that wasn't helpful. I just want the thread to start once if the condition is met and then continue blinking the LED until the condition is not met. Since I use an LCD screen, the data is on a continuous loop.
Here is a very simplified snippet of my program:
def partCloudBlink():
while True:
allLEDon()
time.sleep(2.5)
yellowLEDon()
time.sleep(1)
allLEDoff()
def partCloudBlink_start():
v = threading.Thread(target=partCloudBlink)
if v.isAlive() == False:
v.daemon = True
v.start()
RUNNING = True
try:
while RUNNING:
if weather in ("Partly Cloudy"):
partCloudBlink_start()
print "Current conditions: %s" % (conditions) #unrelated to the question, just program filler
except KeyboardInterrupt:
RUNNING = False
Thank you very much!

It's because a new thread object is created every time partCloudBlink_start is called. v.isAlive() is always False since it's a new thread.
You can create a global variable or something similar to store the thread object depending on your code structure.

Related

Send flag to python program to exit, in its own time. Windows

I am writing a long-term prime search program, that can be closed and reopened with a system of writing out found primes to file. I do not want help with the algs, but I need a method of killing the program only when it gets to the end of the main loop i.e. it has fully found a prime. The relevant parts of code are below.
check = 7
def isprime(n):
#do...
while True:
if isprime(check):
print(check, "is prime")
else:
print(check, "isn't prime")
check += 2
This code will not work, but it is a good template as my question is not specific to my program. I want to break out of the main while True loop, only when at the end of it. The only solution I could think of, which is not practical at all, is at the end of while True I read in a file and if it is "stop" I break. However, I don't want to have to type into a file when I want to stop, and reading a file is a time-waster.
I am sorry if this question appears opinion based, but I tried my best.
Threading is a good option as suggested by others. However, you can have a lighter option of using a try/except catching a keyboard interrupt and using an end flag. If the kill signal is sent during the isprime() calculation, the current calculation for isprime() will be killed, check will not be incremented by 2, the except block will execute to switch the end flag to True, and then you will re-start the isprime calculation for the previous check until you are done, increment, then break. The advantage of this method is that it is lighter than having the overhead of creating a new thread (which is small compared to creating a new process) and that it is easier to debug than a multithreaded script. However, the multithreaded option is fine to debug if the code will not get much bigger and you won't be needing other threads as a part of the same script.
end = False
while True:
try:
if isprime(check):
print(check, "is prime")
else:
print(check, "isn't prime")
check += 2
if end:
break
except KeyboardInterrupt:
print('end signal received')
end = True
You can define a function to create a prime and another function to listen to KeyboardInterrupt signals as Ralf commented. In your prime function at the end do a
if not Keyboard_thread.is_alive():
break
This will have your code check that it has not been stopped only at the end of the cycle, thereby avoiding terminating your program mid calculation. Threading documentation is at https://docs.python.org/2/library/threading.html for more depth! essentially though you want to do something like
t = threading.Thread(target=your_function, args=[your_list_of_parameters](arguments are optional))
t.start()
Sorry if you already know threads, but it wasn't part of your post so I will assume you do not.
You can call t.join() to end your thread that is waiting for keyboard interrupts (specifying a timeout), or have your function come to an end by breaking. Doing so will then flag your other thread (the one checking if keyboard_thread.is_alive() that it should also break out of its loop. Note: threads only run until the end of the function you assign them, so for instance if your function is:
def new_function():
print("hey")
If you assign a thread to this function, the thread will print "hey" once and then terminate itself upon reaching the end of the function. Feel free to leave a comment if something I said is unclear!

Wait for directory (Windows) to exist to continue code? (2.7)

I am trying to have my code detect when a flashdrive is plugged in and then continue the code. I am currently using "os.path.exists". When I start the code with the flashdrive plugged in, the code functions fine, however, if I start when the flashdrive is unplugged, and attempt to plug it in while the code is running, the code never checks to see if the flashdrive is plugged in and keeps forcing the code to sleep. How can I get the code to work?
import os
import sys
import datetime
from datetime import datetime
import shutil
import time
#Wait for FlashDrive to be connected
if os.path.exists("F:\"):
connected = 1
else:
connected = 0
while connected == 0:
print "..."
time.sleep(10)
#Get current date
currentdate=datetime.now().strftime("%m-%d-%Y")
print "Photos saved: " + currentdate
#Copy and rename DCIM
src = "F:/Pictures"
dst = "C:/Users/Josh/Desktop/photos/" + currentdate
shutil.copytree(src, dst)
The code is supposed to be a loop and execute every time an iPhone connects and never stop running, but I cannot get the code to work if it does not really check for the flashdrive.
Cycle with some arbitrary sleeps isn't a good idea (at all). It makes your program less responsive to the event, because it will take at least N ms to catch an event fired at the start of the iteration*. Also it wastes CPU due to a large amount of API calls.
Create a window.
Listen to WM_DEVICECHANGE message in your message loop. It will fire every time your device configuration changed, but won't tell you, how.
On such event, ask for current configuration.
You can find a tutorial here. Also, take a look at the similar answer on SO.
(*) Actually sleep will test on each next system tick if time_passed >= sleep_timeout. If so, it will return to the program. Problem is that system tick could be 1/18 of second on an old PC (56 ms), so you'll never have 10 ms delay.
Your problem is htat you set the connected variable outside the loop so it's never updated.
Try:
while not os.path.exists('F:\'):
print("...")
time.sleep(10)
--edit---
Then, wait for it to be removed at the end:
while os.path.exists('F:\'):
print("...")
time.sleep(10)
And, finally, wrap the entire thing in a big while True: so that the whole program repeats.
(Again, I do agree this is a 'hackish' and inefficent way to do this task)

Multitask to update the file contept every second with python

Im trying to write a chat logic, so here what I want to do
def chatlogic():
talk=True
while talk:
if __name__ == '__main__':
Thread(target = fluse).start()
message = raw_input('enter a message: ')
if not message: #Ending Conversation if empty message was sent
talk=False
conv_file.write('[%s]%s: %s\n' %(msgtime,user,message))
#conv_file.flush()
return 'Conversation Ended'
def fluse():
while True:
time.sleep(1)
conv_file.fluse()
the file must update every second, nomatter what you are doing.
What am i doing wrong?
note: I have never used multitasking before
There are many problems in this code, but the one you seem to be asking about is here:
while talk:
if __name__ == '__main__':
Thread(target = fluse).start()
This means that each time through the loop—that is, once per message—you're going to fire off a new fluse thread. And that thread loops forever, calling conv_file.fluse() every second until the end of time.
So, if you type messages at 0.3, 2.7, and 5.1 seconds after app startup, you're going to get a fluse at 5.3 seconds, another at 5.7, another at 6.1, and so on.
If you want this to only happen once/second, just start a single thread, instead of starting a new one each time through the loop. For example:
if __name__ == '__main__':
Thread(target = fluse).start()
while talk:
# etc.
If, instead, you want it to happen a second after each write, but not every second again after that, just take the loop out of the function:
def fluse():
time.sleep(1)
conv_file.fluse()
Although in this case, threading.Timer is an easier way to do the same thing.
Anyway, even with this fix, as I said, there are a number of other problems:
You're calling a file method that doesn't exist—presumably you meant flush instead of fluse?
The file doesn't exist either. Maybe you meant it to be a global, created outside the functions? Or an argument to them?
You're trying to loop forever until an empty message, but you call return each time through the loop, which means you're only going to loop once.
There's no way to exit your program, because you fire off a non-daemon background thread that runs forever.
You never call the chatlogic function anyway, so the program just exits immediately without doing any work.
If I fix all of the other errors in your program, and add something that shows me whether the fluse thread is doing its job, it does something… and maybe you can tell us whether it's the thing you wanted.
from threading import Thread
import time
def chatlogic(conv_file):
user = 'Nobody'
t = Thread(target=flusher, args=[conv_file])
t.daemon=True
t.start()
while True:
message = raw_input('enter a message: ')
if not message: #Ending Conversation if empty message was sent
break
msgtime = time.asctime()
conv_file.write('[%s]%s: %s\n' %(msgtime,user,message))
return 'Conversation Ended'
def flusher(conv_file):
while True:
time.sleep(1)
print 'Flushing the file now'
conv_file.flush()
if __name__ == '__main__':
conv_file = open('convfile.txt', 'w')
chatlogic(conv_file)
This is still a strange design. The file is being flushed once/second even if you didn't write anything, and that there's no guarantee it actually gets flushed at the end, and so on. But this is what it sounds like you were attempting to do.

Continuing a Loop and Moving On (Python)

I have a 'while' loop in my Python app (v2.7) which basically communicates with a Bluetooth GPS device and the loop continues for as long as there is data being received. In essence, the while loop looks like this:-
> data = ""
>
> if data == None:
> print "Connection Failed" else:
> print "Connection Established"
>
> while True:
> data = socket.recv(1024)
Now what I want to do is leave this while loop running continually throughout the life of the program until the bluetooth device is switched off which in turn will end the loop as no data will be being received. Nonetheless, as this while loop continues, I then want to move onto another method which will parse the data.
How can I leave the loop running and move on to the next command? Is threading required? I'm new to the concept of threading and so please be patient with me :)
Thanks
Yeah, because you're essentially going to be doing two things at the same time, you'll have to create a new thread (using threading) or perhaps more simply a new process (using multiprocessing or just os.fork)
The easiest thing to do is to put this part in a function, and use multiprocessing or threading to start the function in a different process. Typically you'll have less weirdness with multiple processes than multiple threads, just FYI.
received = ""
while True:
data = socket.recv(1024)
if not data:
break # ends the while loop
received+=data
do_stuff(received)

When while loop placed in wxPython events

I'm trying to write a GUI program grabbing specific contents from a webpage. The idea is when I hit the start button, the program should start extracting information from that page. And I want to add some code to check if connected to the Internet. If not, continue trying until connected.
So I just added the following code in the event, but found it didn't work. Also the whole program has to be closed in a forced way. Here's my code:
import urllib2
import time
InternetNotOn = True
while InternetNotOn:
try:
urllib2.urlopen("http://google.com")
InternetNotOn = False
print "Everyting is fine!"
except urllib2.URLError, e:
print "Error!"
time.sleep(10)
What could the problem be?
When you have an event based program, the overall flow of the program is this:
while the-program-is-running:
wait-for-an-event
service-the-event
exit
Now, lets see what happens when service-the-event calls something with a (potentially) infinite loop:
while the-program-is-running:
wait-for-an-event
while the-internet-is-on:
do-something
exit
Do you see the problem? In the worse case your program may never call wait-for-an-event again because your loop is running.
Remember: the event loop is already an infinite loop, you don't need to add another infinite loop inside of it. Instead, take advantage of the existing loop. You can use wx.CallAfter or wx.CallLater to call a method which will cause your function to be called at the next iteration of the event loop.
Then, within your function you call wx.CallAfter or wx.CallLater again to cause it to again be called on the next iteration of the event loop.
Instead of time.sleep(10) you can call wxApp::Yield and time.sleep(1) ten times.
Beware of reentrancy problems (e.g. pressing the start button again.). The start button could be dimmed while in the event handler.
But Bryan Oakley's solution is probably the better way.

Categories