@ -168,19 +168,161 @@ En primer lugar, se importan todas las librerías o módulos necesarios, previam
```
```
from threading import Thread
from threading import Thread
import collections
import collections
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
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
import serial
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
from matplotlib.lines import Line2Ds
```
```
Aquí se encuentran las funcionaes necesarias para: crear hilos con *threading*, hacer una colección o lista con los datos a graficar con *collections*, dibujar los datos en una gráfica animada con líneas 2D y visualizarla en la interfaz utilizando los módulos de la librería de *matplotlib*, establecer la comunicación serial con Arduino usando *serial*, el diseño de la interfaz se hace con el paquete *tkinter* y finalmente, se importa *time* para ocupar algunos retardos de tiempo.
Aquí se encuentran las funcionaes necesarias para: crear hilos con `threading`, hacer una colección o lista con los datos a graficar con `collections`, dibujar los datos en una gráfica animada con líneas 2D y visualizarla en la interfaz utilizando los módulos de la librería de `matplotlib`, establecer la comunicación serial con Arduino usando `serial`, el diseño de la interfaz se hace con el paquete `tkinter` y finalmente, se importa `time` para ocupar algunos retardos de tiempo.
A continuación, el código dispone de una serie de funciones que son llamadas entre sí y se utilizan también en los distintos objetivos de la interfaz para mostrar la información recibida de Arduino y mantener la interacción con el usuario:
A continuación, el código dispone de una serie de funciones que son llamadas entre sí y se utilizan también en los distintos objetivos de la interfaz para mostrar la información recibida de Arduino y mantener la interacción con el usuario:
Para comenzar, se declaran ciertas variables, aquellas cuyo valor es modificado dentro de alguna función se definen como globales, el resto se inicializan de manera normal.
```
global isRun
global on1
global on2
global conected
conected = False
on1 = False
on2 = False
isReceiving = False
isRun = False
numData = 2 #Número de datos a recibir de Arduino
datos = 0.0 #Variable de dato a leer desde Arduino
dato = 0.0 #Variable del dato convertido a float
serialPort = 'COM3' #Puerto al que está conectado el Arduino
baudRate = 9600 #Baudios configurados en Arduino
estado = "off" #Variable de estado que se enviará al serial
```
La variable `isRun` representa si la función de lectura y graficación de datos está corriendo, `on1` y `on2` son los estados de encendido o apagado en que se encuentran los transistores, mientras que `isReceiving` confirma que se han recibido datos correctamente. `numData` hace referencia a que se recibirán 2 datos desde Arduino, correspondientes al sensor 1 y 2, `datos` es la información leída desde Arduino en forma de string, `dato` es la variable dato leído convertido a flotante, `serialPort` es el puerto al que se encuentra conectado el micrcontrolador, `baudRate` es la velocidad de comunicación a la que está trabajando el monitor serial de Arduino, `estado` representa el dato que se envía a Arduino para encender o apagar alguno de los transistores.
Ahora bien, la función `conectar_serial` se utliza para entablar la comunicación con el monitor serial de Arduino.
```
def conectar_serial():
global arduino
global conected
try:
arduino = serial.Serial(serialPort, baudRate)
arduino.timeout = 0.2
time.sleep(0.5)
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")
```
`arduino` es el objeto encargado de establecer la conexión, sus atributos son el puerto serie y la tasa de baudios, `timeout` es el tiempo en que se están leyendo los datos constantemente, además se requiere de un pequeño retardo para lograr correctamente la comunicación de datos en primera instancia. Posterior a ello, únicamente se habilitan y deshabilitan botones para su uso en la interfaz.
La siguiente función `leer_datos` se usa para comenzar a recibir los datos de Arduino una vez lista la comunicación.
```
def leer_datos():
time.sleep(1.0)
arduino.reset_input_buffer()
print("leyendo")
while(conected):
if(isRun == True):
global isReceiving
global dato
global data
for i in range(numData):
datos = arduino.readline().decode("utf-8").strip()
print(datos)
if(datos != ''):
print("RECIBIENDO..." + str(i))
dato = float(datos)
data[i].append(dato)
if(i == 0):
var.set("TEMPERATURE 1: " + str(dato) + " °C")
else:
var2.set("TEMPERATURE 2: " + str(dato) + " °C")
else:
break;
isReceiving = True
```
Esta, a partir de un ciclo while al que se puede entrar una vez iniciada la conexión con Arduino, se encarga de leer y guardar en una variable `datos` la información decodificada en forma de cadena desde el monitor serie para, una vez asegurado que se ha leído un dato y no es información vacía, hacer su conversión a flotante y agregar este dato a la colección que se graficará posteriormente, además de poder visualizar el valor de la temperatura en la interfaz mediante una etiqueta ya sea que se trate del sensor 1 o 2. Cabe mencionar que cada que se muestra un `print` es para poder visualizar en la consola de python algún error o la parte del código donde nos encontramos.
Puesto que la lectura de datos se debe efectuar simultaneamente a la graficación de los mismos, es necesario correr la función de `leer_datos` en un hilo a parte:
```
def iniciar_hilo():
global thread
global isRun
btnStart.config(state = "disabled")
isRun = True
thread = Thread(target=leer_datos)
thread.start() #Inicio de la lectura
btnStart.config(state = "disabled")
btnPause.config(state = "normal")
```
Ahora, la siguiente función `iniciarGrafica` es la que se va a encargar de graficar mediante líeas 2D la colección de datos que recibe, pero para ello ocupa ser llamada posteriomente.
```
def iniciarGrafica(self, muestras,lines):
global dato
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])
```
Para poder guardar la gráfica que se muestra actualmente en la interfaz se utiliza la función:
```
def guardarGrafica():
plt.savefig('miFigura.png')
```
En control de los transistores se efectua a partir de las siguientes dos funciones:
```
def control1():
global on1
global estado
global arduino
if on1 == False:
on1 = True
btnManual.config(bg = "#55DE1E", text = "ON")
estado = "on1"
arduino.write(estado.encode())
else:
on1 = False
btnManual.config(bg = "red", text = "OFF")
estado = "off1"
arduino.write(estado.encode())
```
```
def control2():
global on2
global estado
global arduino
if on2 == False:
on2 = True
btnManual2.config(bg = "#55DE1E", text = "ON")
estado = "on2"
arduino.write(estado.encode())
else:
on2 = False
btnManual2.config(bg = "red", text = "OFF")
estado = "off2"
arduino.write(estado.encode())
```
Según sea el botón de la interfaz con el que se interactúa, se hace la función de on/off de los transistores, para ello se hace uso de las variables `on1` y `on2` que indican el estado actual de estos dispositivos, de manera que si se presiona algún botón se ingresa a la función y se comprueba su estado actual, si el valor booleano actual de la variable `on` es *False* se enciende el transistor y se envía este cambio de estado al serial de Arduino, de lo contrario si el valor actual es *True* se apaga el transistor correspondiente e igualmente se envía la información a Arduino. El botón cambia de color y texto según el estado en que se encuentre el dispositivo, además se modifica el valor booleano de la variable `on1` u `on2`.