I have a Tkinter app which connects to a proprietary sensor over serial and controls it with Python. I am trying to have a thread which always runs in the background to detect if the connection dies, shows an alert, and allows the user to press a button to re-establish the serial connection (reconnect is also done in another thread). For some reason, the COM monitor thread works fine, and when I unplug the serial cable, it shows a popup and enables the reconnect button as expected, but when I reconnect one or twice, the reconnect thread just stops releasing the lock. I've checked this with print statements.
Here is the code which spawns the thread that does the actual reconnect over serial. This thread is spawned when the reconnect button is pressed.
def spawn_reconnect_to_mote_thread(self):
self.reconnect_thread = threading.Thread(target=self.reconnect_to_mote)
self.reconnect_thread.daemon = True
self.reconnect_thread.name = 'reconnect'
self.reconnect_thread.start()
Here is the reconnect function. We also use a proprietary control software written in python which is why the syntax may look weird. This software has its own thread that is spawned when a connection is made. MOTE_MODEL_MAP just maps the correct control functions to the correct model ID which allows this to be easily extended to different hardware models.
def reconnect_to_mote(self):
with self.lock:
self.connection.close()
self.connection = MOTE_MODEL_MAP[self.mote_model_str ['mote_transport'].Connection({'serial': [self.com_port]})
self.com_model_label['text'] = MOTE_MODEL_MAP[self.mote_model_str]['name']
self.reconnect_button['state'] = 'disabled'
self.scan_button['state'] = 'active'
self.monitor_com = True
This spawns the thread to monitor the COM port. This thread is spawned pretty early on in the app's __init__
once the initial connection is made and the hardware is prepped with some commands.
def spawn_com_monitor_thread(self):
self.com_monitor_thread = threading.Thread(target=self.com_monitor)
self.com_monitor_thread.daemon = True
self.com_monitor_thread.name = 'com monitor'
self.com_monitor_thread.start()
Lastly, this is the actual function running in the thread which monitors the COM port. It just constantly grabs open COM ports and checks if the one we're using exists. If not, it should show a popup, set a flag, and allow the user to click the reconnect button. The reconnect function should then set the flag again. This is to prevent infinite popups while a user reconnects.
def com_monitor(self):
while True:
ports = [port[0] for port in list(list_ports.comports())]
if (self.com_port not in ports) and (self.monitor_com == True):
with self.lock:
self.monitor_com = False
self.scan_button['state'] = 'disabled'
msg.showerror(title='Serial connection died', message='The serial cable has become disconnected. Scanning has been stopped. Please reconnect the cable and reconnect to the mote.')
self.reconnect_button['state'] = 'active'
self.monitor_com = False
I've been banging my head on this for a couple days now with no solution. I haven't done much threading before and would like to do this in a threaded way to allow for maximum responsiveness.
I am running Python 3.6.13.