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()
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.)
My code seems to be failing after the constructor is called.
Here is my code - it is failing on the c = create_control_point() line in main():
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
Why isn't it getting to the c = create_control_point() line? Also, the controlpoint constructor is quitting the whole program.
When I tried
$ python
>>> import controlpt
>>> controlpt.main()
I got the output:
>>> controlpt.main()
hell
ankit#ubuntu:~/Desktop$
Help?
Since it's dying on the ControlPoint initialization, have you tried the following in the interpreter?
from brisa.upnp.control_point.control_point import ControlPoint
c = ControlPoint()
If that works, then there's something else at play.
I wrote this simple Munin plugin to graph average fan speed and I want to redo it to OOP - strictly as a learning exercise. Don't have a clue where to start though. Anyone feel like offering some guidance or even an example of what this script should look like when done. I will use it to redo some other scripts into an OOP style as well; again for learning purposes.
import sys
import subprocess
CMD = "/usr/sbin/omreport chassis fans".split()
# Munin populates sys.argv[1] with "" (an empty argument), lets remove it.
sys.argv = [x for x in sys.argv if x]
if len(sys.argv) > 1:
if sys.argv[1].lower() == "autoconfig":
print "autoconfig"
elif sys.argv[1].lower() == "config":
print "graph_title Average Fan Speed"
print "graph_args --base 1000 -l 0"
print "graph_vlabel speed (RPM)"
print "graph_category Chassis"
print "graph_info This graph shows the average speed of all fans"
print "graph_period second"
print "speed.label speed"
print "speed.info Average fan speed for the five minutes."
else:
try:
data = subprocess.Popen(CMD,stdout=subprocess.PIPE).stdout.readlines()
except OSError, e:
print >> sys.stderr, "Error running '%s', %s" % (" ".join(cmd), e)
sys.exit(1)
count = total = 0
for item in data:
if "Reading" in item:
# Extract variable length fan speed, without regex.
total += int(item.split(":")[1].split()[0])
count += 1
# Sometimes omreport returns zero output if omsa services aren't started.
if not count or not total:
print >> sys.stderr, 'Error: "omreport chassis fans" returned 0 output.'
print >> sys.stderr, 'OMSA running? Try: "srvadmin-services.sh status".'
sys.exit(1)
avg = (total / count)
print "speed.value %s" % avg
You remake it in OOP by identifying code and data that goes together. These you then merge into "classes".
You actual data above seems to be the output of a process.
The code is iterating over it. I guess you can make a class out of that if you want to, but it's a bit silly. :)
So, something like this (obviously completely untested code):
import sys
import subprocess
class Fanspeed(object):
def __init__(self, command):
self.command = command.split()
def average_fan_speed(self):
data = subprocess.Popen(CMD,stdout=subprocess.PIPE).stdout.readlines()
count = total = 0
for item in data:
if "Reading" in item:
# Extract variable length fan speed, without regex.
total += int(item.split(":")[1].split()[0])
count += 1
# Sometimes omreport returns zero output if omsa services aren't started.
if not count or not total:
raise ValueError("I found no fans. Is OMSA services started?"
avg = (total / count)
return % avg
if __main__ == '__main__':
# Munin populates sys.argv[1] with "" (an empty argument), lets remove it.
sys.argv = [x for x in sys.argv if x]
if len(sys.argv) > 1:
if sys.argv[1].lower() == "autoconfig":
print "autoconfig"
elif sys.argv[1].lower() == "config":
print "graph_title Average Fan Speed"
print "graph_args --base 1000 -l 0"
print "graph_vlabel speed (RPM)"
print "graph_category Chassis"
print "graph_info This graph shows the average speed of all fans"
print "graph_period second"
print "speed.label speed"
print "speed.info Average fan speed for the five minutes."
else:
try:
cmd = "/usr/sbin/omreport chassis fans"
fanspeed = Fanspeed(cmd)
average = fanspeed.average_fan_speed()
except OSError, e:
print >> sys.stderr, "Error running '%s', %s" % (cmd, e)
sys.exit(1)
except ValueError, e:
# Sometimes omreport returns zero output if omsa services aren't started.
print >> sys.stderr, 'Error: "omreport chassis fans" returned 0 output.'
print >> sys.stderr, 'OMSA running? Try: "srvadmin-services.sh status".'
sys.exit(1)
But YMMV. It's perhaps a bit clearer.