My question is how to thread a function that needs time to execute , then return a value , whilst I can do other stuff at the same time.
I saw others similar questions and solutions but I don't get how to apply them here.
import speech_recognition as sr
r = sr.Recognizer()
import threading
from queue import Queue
queue = Queue()
def mySpeechRecognizer():
print("START SPEECH INPUT\n") #
with sr.Microphone() as source:
r.adjust_for_ambient_noise(source)
try:
audio = r.listen(source)#, timeout = 5) #####
userInput = r.recognize_google(audio)
if any(userInput) == True:
print("Text Input :", userInput) #
# do sth here
print("END SPEECH INPUT NORMAL") #
return userInput #
except Exception as e:
print("Exception In Function mySpeechRecognizer() :", e)
print("END SPEECH INPUT EXCEPTION") #
return #
recognize = threading.Thread(target = lambda q: q.put(mySpeechRecognizer()), args = (queue, ))
recognize.start()
print('do sth')
recognize.join()
print('do sth')
print(queue.get())
print('do sth')
My expectation is that it will print 3 times "do sth" while recognizing. Once it finishes , it will print the return value without blocking the print , i.e. getting queue.get() while print
How can I accomplish this , and what's wrong with my attempt ?
I think I have finally came up with a solution . . .
We can use queue.empty() to check whether the func has a return value or not ( True --> is empty i.e. no return val ; False --> not empty i.e. has return val ) so when queue.empty() remains True , I can do other stuff like print. With the while loop , it will be something like this :
...
while queue.empty(): # don't have return val
print("do sth") # do stuff
else: # --> have return val
print(queue.get()) # print the return val of the func
recognize.join() # join the thread
Correct me if I am wrong ?
Here is my problem:
I have a text file (settings.txt) with some variables:
dataLogging=0
bootDelay=10
shutdownDelay=30
decimal1=5
...etc
I change the values of these variables from a web page. This is working fine.
I run a script (test.py) which imports and uses these variables:
import MySQLdb
from gps import *
import threading
from datetime import datetime
import sys
import os
import imp
f = open('/var/www/html/scripts/settings.txt')
global data
data = imp.load_source('data', '', f)
f.close()
global dataLogging, bootDelay, shutdownDelay, decimal1, ...
# variables
dataLogging = data.dataLogging
bootDelay = data.bootDelay
shutdownDelay = data.shutdownDelay
decimal1 = data.decimal1
...
Now, the rest of the script runs a class:
class GpsPoller(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
global gpsd, lonvalue, latvalue, oldlon, oldlat, newlon, newlat, maxtrip
gpsd=gps(mode=WATCH_ENABLE)
self.current_value = None
self.running = True
def run(self):
global gpsd, lonvalue, latvalue, oldlon, oldlat, newlon, newlat, maxtrip
oldlon = ("%0.*f" % (int(decimal1), float(gpsd.fix.longitude))) <---- here is my second problem
oldlat = ("%0.*f" % (int(decimal1), float(gpsd.fix.latitude)))
etc...
which is being called with ...
if __name__ == '__main__':
if (int(float(dataLogging)) == 1): <---- here is my first problem
gpsp=GpsPoller()
try:
gpsp.start()
while True:
print "Loop running success"
time.sleep(int(sleep))
except(KeyboardInterrupt,SystemExit):
# Close the database object
db.close()
gpsp.running = False
gpsp.join()
The problem is that when I change the variables in the settings file via my web page, the changes are not being reflected in the test.py script until the script is stopped and then restarted.
For example, 'if (int(float(dataLogging)) == 1):' should start the script, but when the variable dataLogging is changed to '0', the script should stop. Basically, the variables should update after a predefined number of seconds.
Hope anyone can help!
Many thanks.
UPDATE:
This is what I have in the 'if(int(float(dataLogging)) == 1) block:
if(int(float(dataLogging)) == 1):
# more variables
lonvalue = "0.00"
latvalue = "0.00"
gpsd = None
class GpsPoller(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
global gpsd, lonvalue, latvalue, oldlon, oldlat, newlon, newlat, maxtrip, dataLogging
print "hello 1"
gpsd=gps(mode=WATCH_ENABLE)
self.current_value = None
self.running = True
def run(self):
global gpsd, lonvalue, latvalue, oldlon, oldlat, newlon, newlat, maxtrip
print "hello 2"
#########
#
# If I commment out everything from here to...
#
#########
oldlon = ("%0.*f" % (int(decimal1), float(gpsd.fix.longitude)))
oldlat = ("%0.*f" % (int(decimal1), float(gpsd.fix.latitude)))
while gpsp.running:
gpsd.next()
# set new latitude/longitude to 4 decimal accuracy
newlon = ("%0.*f" % (int(decimal2), float(gpsd.fix.longitude)))
newlat = ("%0.*f" % (int(decimal2), float(gpsd.fix.latitude)))
# compare old settings with new settings
if ((oldlon != newlon) or (oldlat != newlat) or (dataLogging != 0)):
# set old latitude/longitude to 4 decimal accuracy
oldlon = ("%0.*f" % (int(decimal2), float(gpsd.fix.longitude)))
oldlat = ("%0.*f" % (int(decimal2), float(gpsd.fix.latitude)))
# set latitude/longitude to 7 decimal accuracy to enter into db
lonvalue = ("%0.*f" % (int(decimal3), float(gpsd.fix.longitude)))
latvalue = ("%0.*f" % (int(decimal3), float(gpsd.fix.latitude)))
# datetime object containing current date and time
now = datetime.now()
dt = now.strftime("%Y-%m-%d %H:%M:%S")
try:
if ((int(float(latvalue)) != 0) or (latvalue != nan) or (dataLogging != 0)):
# Write data to GPSData.txt
f = open("/var/www/html/scripts/GPSData.txt", "a+")
f.write("%s" % maxtrip + "|" + lonvalue + "|" + latvalue + "|" + dt + "\n")
f.flush()
f.close()
print "lonvalue: ",lonvalue,"latvalue: ",latvalue, " maxtrip: ",maxtrip," time: ",dt
# Write to the database
cursor.execute("INSERT INTO gps_data VALUES(null,%s,%s,%s,%s)", (maxtrip,latvalue,lonvalue,dt))
# Commit the changes
db.commit()
# Snap-to-roads recommends an interval of 1-10 sec
#time.sleep(int(sleepTime))
time.sleep(10)
# Unless there is a problem
except:
print "Loop running fail"
gpsp=GpsPoller()
try:
gpsp.start()
while True:
print "Loop running success"
time.sleep(5)
except(KeyboardInterrupt,SystemExit):
# Close the database object
db.close()
gpsp.running = False
gpsp.join()
#########
#
# ...here, then the block stops executing if 'dataLogging = 0'
# and restarts when 'dataLogging = 1'
#
#########
def testing():
updateSettings()
global dataLogging
print "datalogging: ",dataLogging
if (int(float(dataLogging)) == 1):
gpsp=GpsPoller()
try:
gpsp.start()
while True:
print "Loop running success"
time.sleep(int(sleep))
testing()
except(KeyboardInterrupt,SystemExit):
# Close the database object
db.close()
gpsp.running = False
gpsp.join()
testing()
Basically, I need the code within the commented out section to react to the change in the variable 'dataLogging'.
Many thanks
===================================
So, I've simplyfied the code. The object of the exercise is to take the 'dataLogging' value from the settings.txt file and, if the value is '1' get the lon/lat coordinates and if the value is '0' do nothing.
The code below correctly reacts to the change in the settings.txt file.
It prints 'dataLogging ON' if the value is '1' and changes to 'dataLogging OFF' if the value is changed to '0'. I can change the value at will and it always works.
The problem lies with the commented out code. If I uncomment the code, and the value is set to '1', then the logging of the coordinates does not stop even when the value is returned to '0'.
Sorry, my ignorance, but I am used to coding in php.
UPDATE 2:
# loop settings.txt file every 5 seconds and declare global variables
def updateSettings():
f = open('/var/www/html/scripts/settings.txt')
global data
data = imp.load_source('data', '', f)
f.close()
# variables
global dataLogging
dataLogging = data.dataLogging
print "New datalogging from settings.txt ", dataLogging
if dataLogging == 1:
getGPSon()
else:
getGPSoff()
def getGPSon():
print "dataLogging ON"
"""
gpsd = gps(mode=WATCH_ENABLE|WATCH_NEWSTYLE)
print 'latitude\tlongitude\ttime utc\t\t\taltitude\tepv\tept\tspeed\tclimb\tdataLogging' # '\t' = TAB to try and output the data in columns.
try:
while True:
report = gpsd.next()
if report['class'] == 'TPV':
print getattr(report,'lat',0.0),"\t",
print getattr(report,'lon',0.0),"\t",
print getattr(report,'time',''),"\t",
print getattr(report,'alt','nan'),"\t\t",
print getattr(report,'epv','nan'),"\t",
print getattr(report,'ept','nan'),"\t",
print getattr(report,'speed','nan'),"\t",
print getattr(report,'climb','nan'),"\t",
print dataLogging,"\t"
time.sleep(2)
#update()
except (KeyboardInterrupt, SystemExit): #when you press ctrl+c
print "Done.\nExiting."
"""
def getGPSoff():
print "dataLogging OFF"
def update():
while True:
updateSettings()
time.sleep(5)
update()
I am developing a program to produce an event whenever a speed is reached on a gps. The code I am currently trying to modify is below:
from gps import *
import time
import threading
import math
class GpsController(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info
self.running = False
def run(self):
self.running = True
while self.running:
# grab EACH set of gpsd info to clear the buffer
self.gpsd.next()
def stopController(self):
self.running = False
#property
def fix(self):
return self.gpsd.fix
#property
def utc(self):
return self.gpsd.utc
#property
def satellites(self):
return self.gpsd.satellites
if __name__ == '__main__':
# create the controller
gpsc = GpsController()
try:
# start controller
gpsc.start()
while True:
#print "latitude ", gpsc.fix.laif
#print "longitude ", gpsc.fix.longitude
#print "time utc ", gpsc.utc, " + ", gpsc.fix.time
#print "altitude (m)", gpsc.fix.altitude
#print "eps ", gpsc.fix.eps
#print "epx ", gpsc.fix.epx
#print "epv ", gpsc.fix.epv
#print "ept ", gpsc.gpsd.fix.ept
print "speed (m/s) ", gpsc.fix.speed
#print "climb ", gpsc.fix.climb
#print "track ", gpsc.fix.track
#print "mode ", gpsc.fix.mode
#print "sats ", gpsc.satellites
time.sleep(1)
#Error
#except:
# print "Unexpected error:", sys.exc_info()[0]
# raise
#Ctrl C
except KeyboardInterrupt:
print "User cancelled"
finally:
print "Stopping gps controller"
gpsc.stopController()
#wait for the thread to finish
gpsc.join()
print "Done"
I am wanting to add an "if" statement to the program to first look at the speed being transmitted and printing or enabling an event whenever the speed reaches a certain number.
I am not sure where and when to add the "if" code.
In the while loop would make the most sense. There was no specification as to whether the event should happen once or multiple times when hitting the 'certain amount'.
from gps import *
import time
import threading
import math
class GpsController(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info
self.running = False
def run(self):
self.running = True
while self.running:
# grab EACH set of gpsd info to clear the buffer
self.gpsd.next()
def stopController(self):
self.running = False
#property
def fix(self):
return self.gpsd.fix
#property
def utc(self):
return self.gpsd.utc
#property
def satellites(self):
return self.gpsd.satellites
if __name__ == '__main__':
# create the controller
gpsc = GpsController()
try:
# start controller
gpsc.start()
while True:
if gspc.fix.speed > event_trigger_amt:
print "speed (m/s) ", gpsc.fix.speed
doEvent()
time.sleep(1)
#Ctrl C
except KeyboardInterrupt:
print "User cancelled"
finally:
print "Stopping gps controller"
gpsc.stopController()
#wait for the thread to finish
gpsc.join()
from brisa.core.reactors import install_default_reactor
reactor = install_default_reactor()
print reactor
from brisa.core.threaded_call import run_async_function
from brisa.upnp.control_point.control_point import ControlPoint
from datetime import datetime
service = ('u', 'urn:schemas-upnp-org:service:SwitchPower:1')
binary_light_type = 'urn:schemas-upnp-org:device:BinaryLight:1'
def on_new_device(dev):
print 'Got new device:', dev.udn
print "Type 'list' to see the whole list"
if not dev:
return
def get_switch_service(device):
return device.services[service[1]]
def create_control_point():
c = ControlPoint()
print "hello"
c.subscribe('new_device_event', on_new_device)
print "c"
return c
def main():
""" Main loop iteration receiving input commands.
"""
print "hell"
c = create_control_point()
print "helllo"
c.start()
run_async_function(_handle_cmds, (c, ))
reactor.add_after_stop_func(c.stop)
reactor.main()
def _exit(c):
""" Stops the _handle_cmds loop
"""
global running_handle_cmds
running_handle_cmds = False
def _search(c):
""" Start searching for devices of type upnp:rootdevice and repeat
search every 600 seconds (UPnP default)
"""
c.start_search(600, 'upnp:rootdevice')
def _get_status(c):
""" Gets the binary light status and print if it's on or off.
"""
try:
service = get_switch_service(c.current_server)
status_response = service.GetStatus()
if status_response['ResultStatus'] == '1':
print 'Binary light status is on'
else:
print 'Binary light status is off'
except Exception, e:
if not hasattr(c, 'current_server') or not c.current_server:
print 'BinaryLight device not set.Please use set_light <n>'
else:
print 'Error in get_status():', e
def _get_target(c):
""" Gets the binary light target and print if it's on or off.
"""
try:
service = get_switch_service(c.current_server)
status_response = service.GetTarget()
if status_response['RetTargetValue'] == '1':
print 'Binary light target is on'
else:
print 'Binary light target is off'
except Exception, e:
if not hasattr(c, 'current_server') or not c.current_server:
print 'BinaryLight device not set.Please use set_light <n>'
else:
print 'Error in get_target():', e
def _stop(c):
""" Stop searching
"""
c.stop_search()
def _list_devices(c):
""" Lists the devices that are in network.
"""
k = 0
for d in c.get_devices().values():
print 'Device no.:', k
print 'UDN:', d.udn
print 'Name:', d.friendly_name
print 'Device type:', d.device_type
print 'Services:', d.services.keys() # Only print services name
print
k += 1
if __name__ == '__main__':
print "hello"
main()
I am getting the output:
ankit#ubuntu:~/Desktop$ python controlpt.py
<brisa.core.reactors.glib2.GLib2Reactor object at 0x88c3e0c>
hello
hell
It is not going to the line c = create_control_point. why is that? please guide me in removing this error.
I am not familiar with this 'brisa' library. I would gather that, for some reason, the ControlPoint constructor is exiting the entire program using sys.exit() (or is calling some equivalent C code).
Run the program on the command-line, like this:
$ python
>>> import controlpt
>>> controlpt.main()
Then you should be able to see if it is actually quitting the whole process. If it dumps you back to the >>> prompt, then I don't know what's going on. But if it quits Python entirely, it means that that ControlPoint constructor is quitting.
The error is given at the end:
from brisa.core.reactors import install_default_reactor
reactor = install_default_reactor()
print reactor
from brisa.upnp.control_point.control_point import ControlPoint
def on_new_device(dev):
print 'Got new device:', dev.udn
print "Type 'list' to see the whole list"
if not dev:
return
def create_control_point():
c = ControlPoint()
print "hello"
c.subscribe('new_device_event', on_new_device)
print "c"
return c
def main():
print "Inside main"
c = create_control_point()
print "Inside create control point"
c.start()
reactor.add_after_stop_func(c.stop)
reactor.main()
def _search(c):
""" Start searching for devices of type upnp:rootdevice and repeat
search every 600 seconds (UPnP default)
"""
c.start_search(600, 'upnp:rootdevice')
def _stop(c):
""" Stop searching
"""
c.stop_search()
def _list_devices(c):
""" Lists the devices that are in network.
"""
k = 0
for d in c.get_devices().values():
print 'Device no.:', k
print 'UDN:', d.udn
print 'Name:', d.friendly_name
print 'Device type:', d.device_type
print 'Services:', d.services.keys() # Only print services name
print
k += 1
# Control the loop at _handle_cmds function
running_handle_cmds = True
commands = {
'search': _search,
'stop': _stop,
'list': _list_devices,
}
def _handle_cmds(c):
while running_handle_cmds:
try:
input = raw_input('>>> ').strip()
if len(input.split(" ")) > 0:
try:
if len(input.split(" ")) > 1:
commands[input.split(" ")[0]](c, input.split(" ")[1])
else:
commands[input.split(" ")[0]](c)
except KeyError, IndexError:
print 'Invalid command, try help'
except TypeError:
print 'Wrong usage, try help to see'
except KeyboardInterrupt, EOFError:
c.stop()
break
# Stops the main loop
reactor.main_quit()
if __name__ == '__main__':
print "hello"
main()
Error:
ankit#ubuntu:~/Desktop$ python controlpt.py
<brisa.core.reactors.glib2.GLib2Reactor object at 0x965bdcc>
hello
Inside main
After that I know understand, it is not initialising the control point. The Information about the libraries(Control point) is available at http://brisa.garage.maemo.org/apidoc/index.html
If this is anything like some other event-based libraries such as Twisted, you want to get the reactor's main running before you do much of anything else.
Drop the call to reactor.main in your main function. Then, instead of just calling main in your if at the bottom, do this:
if __name__ == "__main__":
run_async_function(main)
reactor.main()
See if things behave more like what you expect then.
(run_async_function is in the threaded_call module.)