diff --git a/GUI.py b/GUI.py index 885b365..ac583bd 100644 --- a/GUI.py +++ b/GUI.py @@ -1,157 +1,168 @@ -# -*- coding: utf-8 -*- -""" -Created on Wed Feb 15 10:44:49 2023 - -@author: david -""" - -from threading import Thread -import collections #Colección de datos para graficarlos -import matplotlib.pyplot as plt #Gráficación de datos -import matplotlib.animation as animation #Animar la gráfica -import time -import serial -#import numpy as np -from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg #Crear una figura para insertar en tkinter -import tkinter as tk #Para la interfaz -#from matplotlib.lines import Line2D - - -def leer_datos(): - time.sleep(1.0) - arduino.reset_input_buffer() - print("leyendo") - while(isRun): - global isReceiving - global dato1 - print("RECIBIENDO...") - dato1 = float(arduino.readline().decode("utf-8").strip()) - print(dato1) - var.set("TEMPERATURA: " + str(dato1) + " °C") - isReceiving = True - -def iniciarGrafica(self, muestras,lines): - global dato1 - data.append(dato1) - lines.set_data(range(muestras), data) -global isRun -isReceiving = False -isRun = True -dato1 = 0.0 -serialPort = 'COM3' -baudRate = 9600 - -def conectar_serial(): - global arduino - try: - arduino = serial.Serial(serialPort, baudRate) - arduino.timeout = 0.5 - time.sleep(0.5) - print("CONECTADO") - btnStart.config(state = "normal") - btnConectar.config(state = "disabled") - except: - print("Error de conexión") - -def iniciar_hilo(): - global thread - thread = Thread(target=leer_datos) - thread.start() - btnStart.config(state = "disabled") - btnPause.config(state = "normal") - -def guardarGrafica(): - plt.savefig('miFigura.png') - -def control1(): - window2 = tk.Toplevel() - window2.resizable(width = 0, height = 0) - window2.title('Control Manual') - window2.geometry('500x300') - -def control2(): - window3 = tk.Toplevel() - window3.resizable(width = 0, height = 0) - window3.title('Control ON/OFF') - window3.geometry('500x300') - -def pausar(): - anim.event_source.stop() - btnResume.config(state = "normal") - btnPause.config(state = "disabled") - -def reanudar(): - anim.event_source.start() - btnResume.config(state = "disabled") - btnPause.config(state = "normal") - -def desconectar_serial(): - global isRun - anim.event_source.stop() - isRun = False - arduino.close() - btnPause.config(state = "disabled") - btnResume.config(state = "disabled") - - -muestras = 100 -data = collections.deque([0] * muestras, maxlen = muestras) -tiempoMuestreo = 100 - -fig = plt.figure(facecolor = '0.94') -ax = plt.axes(xlim=(0,100), ylim=(-40, 150)) -plt.title("Sensor 1 - Arduino") -ax.set_xlabel("Muestras") -ax.set_ylabel("Voltaje") -lines = ax.plot([], [])[0] - -root= tk.Tk() -root.title("Sistema de calentamiento") - -var = tk.StringVar() -frame = tk.Frame(root, bd=2) -frame.grid(column=0, row=3, columnspan=2, sticky="nsew") -frame1 = tk.Frame(root) -frame1.grid(column=0, row=1, columnspan=2, sticky="EW") -frame2 = tk.Frame(root) -frame2.grid(column=0, row=2, columnspan=2, sticky="EW") -frame0 = tk.Frame(root) -frame0.grid(column=0, row=0, columnspan=2, sticky="EW") - -root.columnconfigure(0, weight=1) -root.columnconfigure(1, weight=1) -#self.master.rowconfigure(0, weigh=1) -#self.master.rowconfigure(1, weigh=1) -#self.master.rowconfigure(2, weigh=1) -root.rowconfigure(3, weigh=5) - -canvas = FigureCanvasTkAgg(fig, master=frame) -canvas.get_tk_widget().pack(padx=0, pady=0, expand=True, fill='both') -btnManual = tk.Button(frame2, text = "Manual", command = control1) -btnManual.grid(row=0, column=0, pady=2, padx=10) -btnOnOff = tk.Button(frame2, text = "ON/OFF", command = control2) -btnOnOff.grid(row=0, column=1, pady=2, padx=10) -btnConectar = tk.Button(frame1, text = "Connect", command = conectar_serial, bg="#00F1FC") -btnConectar.grid(row=0, column=0, pady=2, padx=10) -btnStart = tk.Button(frame1, text = "Start", command = iniciar_hilo, bg="#008C17", state="disabled") -btnStart.grid(row=0, column=1, pady=2, padx=10) -btnPause = tk.Button(frame1, text = "Pause", command = pausar, bg="#E2E200", state="disabled") -btnPause.grid(row=0, column=2, pady=2, padx=10) -btnResume = tk.Button(frame1, text = "Resume", command = reanudar, bg="#00F428", state="disabled") -btnResume.grid(row=0, column=3, pady=2, padx=10) -btnDesconectar = tk.Button(frame2, text='Disconnect', command = desconectar_serial, bg="#FE5E5E") -btnDesconectar.grid(row=0, column=3, pady=2, padx=10) -labelData = tk.Label(frame2, textvariable=var) -labelData.grid(row=0, column=4, pady=2, padx=500) - -barraMenu = tk.Menu(frame0) -barra1 = tk.Menu(barraMenu) -barra1.add_command(label="Guardar gráfica", command=guardarGrafica) -barraMenu.add_cascade(label="Archivo", menu=barra1) -root.config(menu=barraMenu) - -anim = animation.FuncAnimation(fig, iniciarGrafica, fargs=(muestras, lines), interval = tiempoMuestreo) - -root.geometry('1000x600') -root.mainloop() - +# -*- coding: utf-8 -*- +""" +Created on Wed Feb 15 10:44:49 2023 + +@author: david +""" + +from threading import Thread #Funciones para hilos +import collections #Colección de datos para graficarlos +import matplotlib.pyplot as plt #Gráficación de datos +import matplotlib.animation as animation #Animar la gráfica +import time #Delays +import serial #comunicación con el monitor serial de Arduino +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg #Crear una figura para insertar en tkinter +import tkinter as tk #Para la interfaz + +#Variables a utilizar +global isRun #Valor booleano de programa corriendo +isReceiving = False #Valor booleano de recibiendo datos +isRun = True +dato1 = 0.0 #Variable del dato a leer desde Arduino +serialPort = 'COM3' #Puerto al que está conectado el Arduino +baudRate = 9600 #Baudios configurados en Arduino + + +#Función de lectura de datos en Arduino +def leer_datos(): + time.sleep(1.0) + arduino.reset_input_buffer() #limpia el buffer de datos + print("leyendo") + while(isRun): + global isReceiving #valor booleano de recibiendo datos + global dato1 #dato a recibir desde Arduino + print("RECIBIENDO...") + dato1 = float(arduino.readline().decode("utf-8").strip()) #Lectura del dato y conversión a float + print(dato1) + var.set("TEMPERATURA: " + str(dato1) + " °C") #impresión del dato numérico en la interfaz + isReceiving = True #Confirmación de que se ha recibido el dato + +#Función para iniciar la gráfica +def iniciarGrafica(self, muestras,lines): + global dato1 + data.append(dato1) #Agrega el dato a la colección + lines.set_data(range(muestras), data) #Se grafica en la línea la colección de datos + +#Establecer conexión con Arduino +def conectar_serial(): + global arduino #Variable que va aguardar la conexión + try: + arduino = serial.Serial(serialPort, baudRate) #Asignación del objeto a la variable + arduino.timeout = 0.5 #Tiempo a esperar para que haya datos disponibles en el puerto serie + time.sleep(0.5) #Tiempo muerto para permitir la conexión + print("CONECTADO") + btnStart.config(state = "normal") + btnConectar.config(state = "disabled") + except: + print("Error de conexión") + +#Hilo para la lectura de datos constante +def iniciar_hilo(): + global thread #Variable donde guardar el hilo + thread = Thread(target=leer_datos) #Creación del hilo con la función para leer los datos + thread.start() #Inicio de la lectura + btnStart.config(state = "disabled") + btnPause.config(state = "normal") + +#Pestaña para guardar la gráfica +def guardarGrafica(): + plt.savefig('miFigura.png') + +#Ventana de control Manual (ON/OFF controlado por el usuario) +def control1(): + window2 = tk.Toplevel() + window2.resizable(width = 0, height = 0) + window2.title('Control Manual') + window2.geometry('500x300') + +#Ventana para control según una temperatura dada (Automático) +def control2(): + window3 = tk.Toplevel() + window3.resizable(width = 0, height = 0) + window3.title('Control ON/OFF') + window3.geometry('500x300') + +#Función para pausar la gráfica +def pausar(): + anim.event_source.stop() + btnResume.config(state = "normal") + btnPause.config(state = "disabled") + +#Función para continuar graficando +def reanudar(): + anim.event_source.start() + btnResume.config(state = "disabled") + btnPause.config(state = "normal") + +#Función para finaliar la conexión con Arduino +def desconectar_serial(): + global isRun + anim.event_source.stop() + isRun = False + arduino.close() + btnPause.config(state = "disabled") + btnResume.config(state = "disabled") + +#Variables a graficar +muestras = 100 #Número de datos a visualizar +data = collections.deque([0] * muestras, maxlen = muestras) #Rango de datos +tiempoMuestreo = 100 + +fig = plt.figure(facecolor = '0.94') #creación de la gráfica (figura) +ax = plt.axes(xlim=(0,100), ylim=(-40, 150)) #Rango de ejes +plt.title("Sensor 1 - Arduino") +ax.set_xlabel("Muestras") +ax.set_ylabel("Voltaje") +lines = ax.plot([], [])[0] #Creación de la línea a graficar + +root= tk.Tk() +root.title("Sistema de calentamiento") + +var = tk.StringVar() +frame = tk.Frame(root, bd=2) +frame.grid(column=0, row=3, columnspan=2, sticky="nsew") +frame1 = tk.Frame(root) +frame1.grid(column=0, row=1, columnspan=2, sticky="EW") +frame2 = tk.Frame(root) +frame2.grid(column=0, row=2, columnspan=2, sticky="EW") +frame0 = tk.Frame(root) +frame0.grid(column=0, row=0, columnspan=2, sticky="EW") + +root.columnconfigure(0, weight=1) +root.columnconfigure(1, weight=1) +#self.master.rowconfigure(0, weigh=1) +#self.master.rowconfigure(1, weigh=1) +#self.master.rowconfigure(2, weigh=1) +root.rowconfigure(3, weigh=5) + +canvas = FigureCanvasTkAgg(fig, master=frame) +canvas.get_tk_widget().pack(padx=0, pady=0, expand=True, fill='both') +btnManual = tk.Button(frame2, text = "Manual", command = control1) +btnManual.grid(row=0, column=0, pady=2, padx=10) +btnOnOff = tk.Button(frame2, text = "ON/OFF", command = control2) +btnOnOff.grid(row=0, column=1, pady=2, padx=10) +btnConectar = tk.Button(frame1, text = "Connect", command = conectar_serial, bg="#00F1FC") +btnConectar.grid(row=0, column=0, pady=2, padx=10) +btnStart = tk.Button(frame1, text = "Start", command = iniciar_hilo, bg="#008C17", state="disabled") +btnStart.grid(row=0, column=1, pady=2, padx=10) +btnPause = tk.Button(frame1, text = "Pause", command = pausar, bg="#E2E200", state="disabled") +btnPause.grid(row=0, column=2, pady=2, padx=10) +btnResume = tk.Button(frame1, text = "Resume", command = reanudar, bg="#00F428", state="disabled") +btnResume.grid(row=0, column=3, pady=2, padx=10) +btnDesconectar = tk.Button(frame2, text='Disconnect', command = desconectar_serial, bg="#FE5E5E") +btnDesconectar.grid(row=0, column=3, pady=2, padx=10) +labelData = tk.Label(frame2, textvariable=var) +labelData.grid(row=0, column=4, pady=2, padx=500) + +barraMenu = tk.Menu(frame0) +barra1 = tk.Menu(barraMenu) +barra1.add_command(label="Guardar gráfica", command=guardarGrafica) +barraMenu.add_cascade(label="Archivo", menu=barra1) +root.config(menu=barraMenu) + +#Animación de la gráfica (figura, función que grafica la línea, argumentos para graficar, rango de la figura) +anim = animation.FuncAnimation(fig, iniciarGrafica, fargs=(muestras, lines), interval = tiempoMuestreo) + +root.geometry('1000x600') +root.mainloop() +