How Can I Get Data Without Blocking?
Solution 1:
You don't need to use 2 Timers to periodically save data. And you do not need to use Threads either. Just keep a counter variable in your main Frame class (or the class with the Timer and collecting the data -- your example is simple enough that it may not need splitting) and use that to determine when to write data. Also: keep the data read from the serial port in an array in the same class so you can plot it or save it or whatever else you might want:
in MyFrame1.__init__()
add
self.last_saved_time = 0self.plotting = Trueself.data = []
Then in MyFrame1.timer1()
do
# read and save data
t1 = next_data()
self.data.append(t1) # (or do more parsing, convert to numpy arrays, etc# send to plotting if it is enabledifself.plotting:
self.plot_data()
# save if needed
now = time.time()
if (now - self.last_saved_time) > 15:
self.save_data_to_file()
Again, you do not necessarily need two timers or threads. You could do the plotting or the i/o in a separate thread, but you're going relatively slowly.
It would probably be wiser to eventually split up the code as "data collector" class with its own event loop and then transfer that to the GUI frame to plot as needed. But the example is small enough that such a refactoring is not needed yet.
Solution 2:
For non blocking operations with Gui / wxpython you need to use threads, you can use wx.lib.delayedresult
or you can use "threading" python module which i prefer
also if you need to get text data from a serial port you should decode them in utf-8, example:
ser = serial.Serial('COM9',9600)
try:
line = ser.readline()
line = line.decode("utf-8")
except UnicodeDecodeError:
line = "\ncan't decode from serial, choose different baudrate\n"print(line) # or do whatever you want with line
also this is an example for reading serial port using threading you can use it as an idea of what you want to do
i added explanation comments in the code
from threading import Thread
from time import sleep
# you can define a class inherited from Thread class or simply use a function classReadData(Thread):
def__init__(self):
super().__init__()
self.running = True# used as signal to kill the thread
self.ser = serial.Serial('COM9',9600) # open serialdefrun(self): # run method need to be defined for threading to workwhile self.running:
print('running')
sleep(1)
self.ser.close()
defread(self): # reading data from portif ser.is_open:
try:
line = ser.readline()
line = line.decode("utf-8") # decode data except UnicodeDecodeError:
line = "\ncan't decode from serial, choose different baudrate\n"
display(line)
line = ""defkill(self): # terminate thread safely
self.running = False
read_data = ReadData() # define new thread object
read_data.start() # start the thread
sleep(5)
# in case you want to kill the running threadprint('killing running thread')
read_data.kill()
Edit:
to communicate between your thread and main GUI i.e. you want to pass the serial data safely you should avoid using global variable and use queues instead, you can check this answer for how to use them
Post a Comment for "How Can I Get Data Without Blocking?"