Tkinter GUI to be able to change variables of an separate continuous process

Question:

I have designed an marine engine simulator – it’s a program that sends some serial DATA using a certain protocol called "BlueVision". The data is encoded based on a header, a block number, a block type, actual data (indexed), a checksum and a footer. Due to the fact that if you want to change a value in the actual data – then the checksum changes – I designed an recalculation of the block with the correct checksum when the data is changed. I made a GUI that allows me to change the value of 2 data points in order to be able to test live. The problem is that I don’t know how to use threads or subprocesses correctly and the window keeps on freezing. The application works – but works badly and I kept on searching for a similar issue – and did find some suggestions but I haven’t been able to implement it. Can someone help? PS: the code is awkward at best – please don’t judge – I know I could of made it way better – but this is the best I could do with the time I had. The issue might not be clear to you if you don’t have a COM port where the program writes to.

# Blue Vision is a MTU serial communication protocol - based on HEX values grouped in BLOCKS
import tkinter as tk
from tkinter import ttk
import time
import serial

def split_by_n(seq, n):
    while seq:
        yield seq[:n]
        seq= seq[n:]

def after(self, ms, func=None, *args):
    """Call function once after given time.

    MS specifies the time in milliseconds. FUNC gives the
    function which shall be called. Additional parameters
    are given as parameters to the function call.  Return
    identifier to cancel scheduling with after_cancel."""

win = tk.Tk()
win.title("GUI - TEST VERSION")
win.geometry("750x250")


label = tk.Label(win, text = "Main Engine Overspeed")
label.pack()

v = tk.StringVar()
v.set('00')

c = tk.StringVar()
c.set("00")

def setText(word):
    v.set(word)

a = ttk.Button(win, text ="01", command =lambda:setText("01"))
a.pack()
b = ttk.Button(win, text="00", command = lambda:setText("00"))
b.pack()

label1 = tk.Label(win, text ="Main Engine Speed")
label1.pack()

name_entry = tk.Entry(win, textvariable=c)
name_entry.pack()


def task():
    MyVar = v.get()
    priEngSp =c.get()
    if len(priEngSp) == 0:
        priEngSp = '00'
    
    block_3 = 'FAF500030002000000290100000001000100000001000001000000000000000000000000000222AF5F'
    block_4 = 'FAF500040003000001A000004650000047E00000000000000000000000000007EF4000083D6000000000000000000000000000000000000000000000012C000006D600000000000000000000278D00000000000000007FFFFFFF000000000001991500000000000000000016E36000000000000923D8000971F8000001F40000059F000026AC00002774000005800000251C00000580000027740000283C0000056200001D4C00001F400000061800000000000060FB00004650000036B000007D0000008CA0000006180000251C0000000000000000000000000000284800192D500017A6B00000051B0000251CFFFFFFA8000002580000044C000000FA0000000000000000000006770000CB200000D6D8000006770000CB200000D6D80000060600005DC000000000000027100000000000000000000000000000000000000000000003C2000061A8000000000000000000000000000000000000000000000000000000000000000000000000000000000000363300000EA6000249F0FFFFFB1E000F42400000000000000000000000000000000000000000000032D9AF5F'
    block_5 = 'FAF5000500020000005600000000000000000000000000000000000000000000007F7F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034AAF5F'
    block_6 = 'FAF5000600020000003D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000234AF5F'
    block_7 = 'FAF5000700030000008C000006280000064A0000064A0000068D0000066B0000068D0000068D000006AE0000000000000000000006AE000006070000060700000607000005E5000005A2000006070000064A00000000000000000000062A000006AE000005A20000350EFFFFF07C00003CDEFFFFE8AC00000000000000000000000000000000000012DEAF5F'
    block_8 = 'FAF50008000300000070000000000000112900000000000000000000059C000027740000283C000047E000000000000000000000000000000000000000000000000000000000000000007FFFFFFF7FFFFFFF0000055100002CEC0000000000000000000000000000000000000DD1AF5F'
    block_9 = 'FAF50009000200000020000000000000000000000000000000000000021AAF5F'
    block_10 = 'FAF5000A0002000000260000000000000000000000000000000000000000000000000221AF5F'
    block_11 = 'FAF5000B0003000000EC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E9AF5F'
    block_12 = 'FAF5000C000200000045000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000242AF5F'
    
    
    block_2 = 'FAF50002000200000074010001000000000000000000000000000000000000000000007F0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E9AF5F'
    checksum = hex(0x00)

    block_2split = list(split_by_n(block_2,2))
    block_2split[10] = MyVar.upper() #Overspeed Alarm Position

    for i in range(len(block_2split)-6):
        checksum = hex(int(checksum, 16) + int(block_2split[i], 16)) 

    checksum_string = str(checksum)
    checksum_actvalue = checksum_string[2:]
    checksum_long = checksum_actvalue.rjust(8,'0').upper()
    checksum_split = list(split_by_n(checksum_long,2))

    block_2split[len(block_2split)-3] = checksum_split[3]
    block_2split[len(block_2split)-4] = checksum_split[2]
    block_2split[len(block_2split)-5] = checksum_split[1]
    block_2split[len(block_2split)-6] = checksum_split[0]

    Block_2Output = ''.join(str(item) for item in block_2split)

    iEngineSpeed = int(priEngSp,10)
    hEngineSpeed = hex(iEngineSpeed * 10)
    sEngineSpeed = str(hEngineSpeed)[2:].upper()

    while (len(sEngineSpeed)<8):
        sEngineSpeed = '0' + sEngineSpeed


    block_4split = list(split_by_n(block_4,4))
    sEngineSpeed_split = list(split_by_n(sEngineSpeed,4))

    block_4split[5] = sEngineSpeed_split[0]
    block_4split[6] = sEngineSpeed_split[1]

    Block_4joint = ''.join(str(item) for item in block_4split)
    Block_4joint_sp = list(split_by_n(Block_4joint,2))
    checksumb4 = hex(0x00)

    for i in range(len(Block_4joint_sp)-6):
        checksumb4 = hex(int(checksumb4, 16) + int(Block_4joint_sp[i], 16))

    checksumb4_string = str(checksumb4)
    checksumb4_actvalue = checksumb4_string[2:]
    checksumb4_long = checksumb4_actvalue.rjust(8,'0').upper()
    checksumb4_split = list(split_by_n(checksumb4_long,2))

    Block_4joint_sp[len(Block_4joint_sp)-3] = checksumb4_split[3]
    Block_4joint_sp[len(Block_4joint_sp)-4] = checksumb4_split[2]
    Block_4joint_sp[len(Block_4joint_sp)-5] = checksumb4_split[1]
    Block_4joint_sp[len(Block_4joint_sp)-6] = checksumb4_split[0]

    Block_4Output = ''.join(str(item) for item in Block_4joint_sp)

    blocks = [Block_2Output, block_3, Block_4Output, block_5, block_6, block_7, block_8, block_9, block_10, block_11, block_12]
    with serial.Serial('COM5', '9600') as ser: #you might wanna comment this part out
        for block in blocks:
            print(block)
            ser.write(bytes.fromhex(block.strip())) #you might wanna comment this part out
            time.sleep(1)

    win.after(200, task)

win.after(200, task)
win.mainloop()
Asked By: Mihai

||

Answers:

To avoid freezing, one of the way is to use thread:

from threading import Thread
...

def task():
    while True:
        MyVar = v.get()
        ...
        blocks = [Block_2Output, block_3, Block_4Output, block_5, block_6, block_7, block_8, block_9, block_10, block_11, block_12]
        with serial.Serial('COM5', '9600') as ser: #you might wanna comment this part out
            for block in blocks:
                print(block)
                ser.write(bytes.fromhex(block.strip())) #you might wanna comment this part out
                time.sleep(1)

        time.sleep(0.2)

# run task() in a thread
Thread(target=task, daemon=1).start()
win.mainloop()
Answered By: acw1668
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.