0

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.

Logan Crocker
  • 79
  • 1
  • 3
  • 8
  • `tkinter` does not support multithreading in the sense that only one thread in a multithreaded application can access it. – martineau Jun 02 '22 at 22:31
  • Is there any workaround for this or do I need to completely rethink my approach? I would really like to have a constant monitor of the COM port connection, but the main function of this app spawns a thread which loops until a flag is set and controls the hardware. I would like to be able to detect if the connection is disconnected while this is happening too. – Logan Crocker Jun 03 '22 at 19:46
  • A common workaround is to have the threads use a `Queue` to communicate with one another. See my answer to [Freezing/Hanging tkinter GUI in waiting for the thread to complete](https://stackoverflow.com/questions/53696888/freezing-hanging-tkinter-gui-in-waiting-for-the-thread-to-complete/53697547#53697547) for an example. – martineau Jun 03 '22 at 23:36

0 Answers0