So Im reading a serial device that sends data every couple of seconds, I have my timer running on the screen and the goal is that every time it updates the serial read it restarts the timer to zero.. This allows me to visually see if Ive lost contact with the device. Ive spent alot of time searching to no avail. Not real good with python so any help would be appreciated.
from tkinter import *
from serial import Serial
import time
from serial.threaded import ReaderThread, Protocol
import threading
import tkinter as tk
#Input ED Number
ed_num = 0
def tkinter_input(prompt=""):
global ed_num
root = tk.Tk()
root.wm_attributes('-fullscreen',1)
root.configure(background='black')
tk.Label(root, font=('Ariel', 100), foreground='Green',
background='Black', text=prompt).pack()
entry = tk.Entry(root, font=('Ariel', 100),justify='center', foreground='Black',
background='white')
entry.focus()
entry.pack()
result = None
def callback(event):
nonlocal result
result = entry.get()
root.destroy()
entry.bind("<Return>", callback)
root.mainloop()
return result
result = tkinter_input("Scan Dosimeter")
ed_num = result
print(ed_num)
#Start Loop
root = Tk()
#Sets Main Window
root.wm_attributes('-fullscreen',1)
root.configure(background='black')
'''Shuts Down App will need to remove'''
button_quit = Button(root, text = 'QUIT', command = root.destroy).pack(anchor=NE)
#Container Frame
mainframe= Frame(root, bd=4, bg='Black')
mainframe.pack(anchor=CENTER, expand=True, fill=BOTH, padx=(20,20), pady=(20,20))
mainframe.grid_columnconfigure(0, weight=1)
mainframe.grid_rowconfigure(0, weight=1)
mainframe.grid_rowconfigure(1, weight=1)
mainframe.grid_rowconfigure(2, weight=1)
#ID Label
ed_id_label = Label(mainframe,
font=('Ariel', 50), foreground='Green',
background='Black', anchor='w')
ed_id_label.grid(row=0, column=0, sticky='ew', padx=(100,100), pady=(100,100))
#Dose Label
doselabel = Label(mainframe,
font=('Ariel', 130), foreground='Green',
background='Black', anchor='w')
doselabel.grid(row=1, column=0, sticky='ew', padx=(100,100), pady=(100,100))
# Rate Label
ratelabel = Label(mainframe,
font=('Ariel', 130), foreground='Green',
background='Black', anchor='w')
ratelabel.grid(row=2, column=0, sticky='ew', padx=(100,100), pady=(100,100))
#Timer Label
timelabel = Label(mainframe,
font=('Ariel', 20), foreground='Green',
background='Black', anchor='w')
timelabel.grid(row=3, column=0, sticky='se')
#Data Timer
seconds = 0
def countup(seconds):
seconds = 1
timelabel['text'] = str(seconds) "s"
root.after(1000, countup, seconds)
#Serial Reader Thread
class SerialReaderProtocolRaw(Protocol):
def data_received(self, data):
"""Called with snippets received from the serial port"""
updateLabelData(data)
def updateLabelData(data):
data = data.decode("utf-8")
if data[0:6] == ed_num:
ed_id_label['text']='Ed id: ' data[0:6]
doselabel['text']='Dose: ' data[11:14] '.' data[14:15]
if data[21:22] == '0':
ratelabel['text']='Rate: ' data[18:19]
if data[21:22] == '1':
ratelabel['text']='Rate: ' data[18:20]
if data[21:22] == '2':
ratelabel['text']='Rate: ' data[18:21]
if data[21:22] == '3':
ratelabel['text']='Rate: ' data[18:22]
if data[6:7] =='1':
doselabel.config(bg= "red")
if data[6:7] =='2':
ratelabel.config(bg= "red")
root.update_idletasks()
# Initiate serial port
serial_port = Serial('COM3', baudrate = 57600)
# Initiate ReaderThread
reader = ReaderThread(serial_port, SerialReaderProtocolRaw)
# Initiate Counter Thread
countupthread = threading.Thread(target=countup, args = (seconds,))
# Start reader/counter
countupthread.start()
reader.start()
# Join Threads
countupthread.join()
root.after(1, countup, seconds)
root.mainloop()
CodePudding user response:
There are at least two solutions I can think of off the top of my head: cancel and restart the counter, or make seconds
global.
Stop and restart the counter
When you schedule something with after
, it returns an identifier. You can pass this identifier to after_cancel
to prevent that function from running. Since you're not using classes, you can use a global variable to track this identifier.
Example:
def countup(seconds):
global after_id
seconds = 1
timelabel['text'] = str(seconds) "s"
after_id = root.after(1000, countup, seconds)
Then, whenever you need to reset the timer you can use the following two lines to cancel and restart countup
:
root.after_cancel(after_id)
countup(0)
Make seconds
global
Instead of passing seconds
to the countup
function, have it use a global variable. You can then just reset this variable whenever you want.
seconds = 0
def countup():
global seconds
seconds = 1
timelabel['text'] = str(seconds) "s"
after_id = root.after(1000, countup, seconds)
With that, whenever you want to reset the counter you simply need to reset seconds
:
global seconds
seconds = 0