pythontkinterarduinopyserial

pyserial doesnt read full line


I want to read data from my arduino and show it on a tkinter window, it works nicely but when I sent the Data on the arduino faster then every 10ms it resevieses many lines that are not full like this:

 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']
⚠️ Invalid line, skipped: ['0', '0', '0', '0', '0', '0', '0', '0', '0', 'Malik']

The weird thing is when i sent it at 10ms speed it works, just sometimes not when i move the window. Hope somebody can help me here is my code:

    def read_Serial_Values(self):
        read_Line = ReadLine(ser)
        self.raw_Input = read_Line.readline().decode('utf-8').strip()
        # if self.is_Data_Here():
        #     print("!Overload!")
        #     self.trash = ser.read_all()
        self.raw_Listet_Input = [x for x in self.raw_Input.split(",") if x]
        if len(self.raw_Listet_Input) < 21:
            print("⚠️ Invalid line, skipped:", self.raw_Listet_Input)
            return
        self.Inp_manager.save_Repeating_Input(self.raw_Listet_Input)

    def is_Data_Here(self):
        if ser.in_waiting >0:
            return True
        return False
               

class ReadLine:
    def __init__(self, s):
        self.buf = bytearray()
        self.s = s
    
    def readline(self):
        i = self.buf.find(b"\n")
        if i >= 0:
            r = self.buf[:i+1]
            self.buf = self.buf[i+1:]
            return r
        while True:
            i = max(1, min(2048, self.s.in_waiting))
            data = self.s.read(i)
            i = data.find(b"\n")
            if i >= 0:
                r = self.buf + data[:i+1]
                self.buf[0:] = data[i+1:]
                return r
            else:
                self.buf.extend(data)

I have tried changing the timeout but that didnt changed anything and I also changed the way the programm recevies the lines.


Solution

  • You're reading data too fast, and the serial input is not guaranteed to end cleanly with \n before your code tries to process it, and that’s why you are getting incomplete or "corrupted" lines.

    1. Use a dedicated thread for serial reading

    Tkinter is single-threaded. If you read from a serial in the same thread as the GUI, the GUI slows down (and vice versa), especially when you move the window.

    Run the serial reading in a separate thread, and put the valid data into a queue.Queue() which the GUI can safely read from.

    import threading
    import queue
    
    data_queue = queue.Queue()
    
    def serial_read_thread():
        read_Line = ReadLine(ser)
        while True:
            try:
                line = read_Line.readline().decode('utf-8').strip()
                parts = [x for x in line.split(",") if x]
                if len(parts) >= 21:
                    data_queue.put(parts)
                else:
                    print("⚠️ Invalid line, skipped:", parts)
            except Exception as e:
                print(f"Read error: {e}")
    

    Start this thread once at the beginning:

    t = threading.Thread(target=serial_read_thread, daemon=True)
    
    t.start()
    

    2. In your Tkinter loop, check the queue

    Use after() in Tkinter to periodically fetch from the queue and update the UI:

    def update_gui_from_serial():
        try:
            while not data_queue.empty():
                data = data_queue.get_nowait()
                print(data)
        except queue.Empty:
            pass
        root.after(50, update_gui_from_serial)  
    

    Please let me know if this works and if you need any further help! :)