|
# -*- 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
|
|
from matplotlib.lines import Line2D #Para hacer las líneas de las gráficas
|
|
|
|
#Variables a utilizar
|
|
global isRun #Valor booleano de programa corriendo
|
|
global on1 #Valor booleano del estatus del transistor
|
|
global on2
|
|
global conected
|
|
conected = False
|
|
on1 = False #Inicializa transistor 1 apagado
|
|
on2 = False #Inicializa transistor 2 apagado
|
|
isReceiving = False #Valor booleano de recibiendo datos
|
|
isRun = False
|
|
dato = 0.0 #Variable del dato convertido a float
|
|
serialPort = 'COM3' #Puerto al que está conectado el Arduino
|
|
baudRate = 9600 #Baudios configurados en Arduino
|
|
datos = 0.0 #Variable de dato a leer desde Arduino
|
|
estado = "off" #Variable de estado que se enviará al serial
|
|
numData = 2 #Número de datos a recibir de 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(conected):
|
|
if(isRun == True):
|
|
global isReceiving #valor booleano de recibiendo datos
|
|
global dato #dato a recibir desde Arduino
|
|
global data #Colección de datos a graficar
|
|
for i in range(numData):
|
|
datos = arduino.readline().decode("utf-8").strip() #Lectura del dato
|
|
print(datos)
|
|
if(datos != ''): #Asegurar que se haya leído un dato
|
|
print("RECIBIENDO..." + str(i))
|
|
dato = float(datos) #Conversión del dato en float
|
|
data[i].append(dato) #Agrega el dato a la colección
|
|
if(i == 0):
|
|
var.set("TEMPERATURA 1: " + str(dato) + " °C") #impresión del dato numérico en la interfaz
|
|
else:
|
|
var2.set("TEMPERATURE 2: " + str(dato) + " °C") #impresión del dato numérico en la interfaz
|
|
else:
|
|
break;
|
|
isReceiving = True #Confirmación de que se ha recibido el dato
|
|
|
|
#Función para iniciar la gráfica
|
|
def iniciarGrafica(self, muestras,lines):
|
|
global dato
|
|
#if(datos != ''):
|
|
lines[0].set_data(range(muestras), data[0]) #Se grafica en la línea la colección de datos
|
|
lines[1].set_data(range(muestras), data[1])
|
|
|
|
#Establecer conexión con Arduino
|
|
def conectar_serial():
|
|
global arduino #Variable que va aguardar la conexión
|
|
global conected
|
|
try:
|
|
arduino = serial.Serial(serialPort, baudRate) #Asignación del objeto a la variable
|
|
arduino.timeout = 0.2 #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")
|
|
btnManual.config(state = "normal")
|
|
btnManual2.config(state = "normal")
|
|
conected = True
|
|
except:
|
|
print("Error de conexión")
|
|
|
|
#Hilo para la lectura de datos constante
|
|
def iniciar_hilo():
|
|
global thread #Variable donde guardar el hilo
|
|
global isRun
|
|
btnStart.config(state = "disabled")
|
|
isRun = True
|
|
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')
|
|
|
|
#Función de control Manual (ON/OFF controlado por el usuario)
|
|
def control1():
|
|
global on
|
|
global estado
|
|
global arduino
|
|
if on1 == False: #Cuando el transistor está apagado
|
|
on1 = True #Cambia la variable de condición
|
|
btnManual.config(bg = "#55DE1E", text = "ON") #Cambia color y texto del botón
|
|
estado = "on1" #cambia la variable de estado
|
|
arduino.write(estado.encode()) #Se envía encender al serial de Arduino
|
|
else: #Cuando el transistor está encendido
|
|
on1 = False #Cambia la variable de condición
|
|
btnManual.config(bg = "red", text = "OFF") #Cambia color y texto del botón
|
|
estado = "off1" #Cambia la variable de estado
|
|
arduino.write(estado.encode()) #Se envía apagar al serial de Arduino
|
|
|
|
def control2():
|
|
global on2
|
|
global estado
|
|
global arduino
|
|
if on2 == False: #Cuando el transistor está apagado
|
|
on2 = True #Cambia la variable de condición
|
|
btnManual2.config(bg = "#55DE1E", text = "ON") #Cambia color y texto del botón
|
|
estado = "on2" #cambia la variable de estado
|
|
arduino.write(estado.encode()) #Se envía encender al serial de Arduino
|
|
else: #Cuando el transistor está encendido
|
|
on2 = False #Cambia la variable de condición
|
|
btnManual2.config(bg = "red", text = "OFF") #Cambia color y texto del botón
|
|
estado = "off2" #Cambia la variable de estado
|
|
arduino.write(estado.encode()) #Se envía apagar al serial de Arduino
|
|
|
|
#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():
|
|
global isRun
|
|
global arduino
|
|
isRun = False
|
|
anim.event_source.stop()
|
|
arduino.close()
|
|
btnResume.config(state = "normal")
|
|
btnPause.config(state = "disabled")
|
|
|
|
#Función para continuar graficando
|
|
def reanudar():
|
|
global arduino
|
|
global isRun
|
|
conectar_serial()
|
|
arduino.reset_input_buffer() #limpia el buffer de datos
|
|
isRun = True
|
|
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
|
|
global conected
|
|
anim.event_source.stop()
|
|
isRun = False
|
|
conected = False
|
|
arduino.close()
|
|
btnPause.config(state = "disabled")
|
|
btnResume.config(state = "disabled")
|
|
btnManual.config(state = "disabled")
|
|
btnManual2.config(state = "disabled")
|
|
|
|
#Variables a graficar
|
|
muestras = 100 #Número de datos a visualizar
|
|
tiempoMuestreo = 100
|
|
data = []
|
|
lines = []
|
|
for i in range(numData):
|
|
data.append(collections.deque([0] * muestras, maxlen = muestras)) #Rango de datos
|
|
lines.append(Line2D([], [], color = "blue"))
|
|
|
|
fig = plt.figure(facecolor = '0.94') #creación de la gráfica (figura)
|
|
ax1 = fig.add_subplot(2, 1, 1, xlim=(0,100), ylim=(0, 150)) #Rango de ejes
|
|
ax1.title.set_text("Sensor 1 - Arduino")
|
|
ax1.set_ylabel("Voltaje")
|
|
ax1.add_line(lines[0])
|
|
|
|
ax2 = fig.add_subplot(2, 1, 2, xlim=(0,100), ylim=(0, 150)) #Rango de ejes
|
|
ax2.title.set_text("Sensor 2 - Arduino")
|
|
ax2.set_xlabel("Muestras")
|
|
ax2.set_ylabel("Voltaje")
|
|
ax2.add_line(lines[1])
|
|
|
|
root= tk.Tk()
|
|
root.title("Sistema de calentamiento")
|
|
|
|
var = tk.StringVar()
|
|
var2 = 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')
|
|
labelBlank = tk.Label(frame1, text="")
|
|
labelBlank.grid(row=0, column=4, pady=2, padx=25)
|
|
btnManual = tk.Button(frame1, text = "OFF", command = control1, bg = "red", state = "disabled")
|
|
btnManual.grid(row=0, column=6, pady=2, padx=10)
|
|
labelState = tk.Label(frame1, text="Transistor 1 State:")
|
|
labelState.grid(row=0, column=5, pady=2, padx=5)
|
|
labelBlank2 = tk.Label(frame1, text="")
|
|
labelBlank2.grid(row=0, column=7, pady=2, padx=125)
|
|
btnManual2 = tk.Button(frame1, text = "OFF", command = control2, bg = "red", state = "disabled")
|
|
btnManual2.grid(row=0, column=9, pady=2, padx=10)
|
|
labelState2 = tk.Label(frame1, text="Transistor 2 State:")
|
|
labelState2.grid(row=0, column=8, pady=2, padx=5)
|
|
#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=0, pady=2, padx=10)
|
|
labelData = tk.Label(frame2, textvariable=var, font="Helvetica 10 bold")
|
|
labelData.grid(row=1, column=1, pady=2, padx=230)
|
|
labelData2 = tk.Label(frame2, textvariable=var2, font="Helvetica 10 bold")
|
|
labelData2.grid(row=1, column=2, pady=2, padx=1)
|
|
|
|
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, cache_frame_data=False)
|
|
|
|
root.geometry('1000x600')
|
|
root.mainloop()
|