En esta nueva entrada del curso de programación con Protocoder vamos a partir de la entrada anterior, donde aprendiamos cómo leer datos de un sensor de temperatura y humedad y representarlos en Protocoder, para seguir trabajando sobre este proyecto.
En esta nueva entrada añadiremos dos nuevas características: Modificaremos el intervalo en el que Arduino envía datos a Protocoder, y fijaremos una alarma que nos avisará en caso de que la temperatura sobrepase el límite marcado.
Código Arduino
En el código Arduino, con respecto al código de la entrada anterior, se ha movido el contenido del loop a una nueva función, que se encargaba de tomar medidas y enviarlo a través de Bluetooth a Protocoder. También se ha creado una nueva función que comprueba si hay datos y modifica el valor del tiempo que tarda Arduino en enviar nuevos datos a Protocoder. Esta última función se ha preparado para soportar la recepción de otros datos y decodificarlos fácilmente, añadiendo unas líneas de código.
El código que estaba en loop en la entrada anterior, ahora se ha incluido en la función getTH:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void getTH(){ float aux; h = hts221.getHumidity(); t = hts221.getTemperature(); if (debug){ Serial.println(h); Serial.println(t); } h = int(h*100); t = int(t*100); aux = h *10000 + t; Serial.println(aux); delay(sampleTime); } |
Las variables h, t y sampleTime de esta función son variables globales, por lo que podremos acceder y modificar sus valores desde cualquier punto del programa. La variable aux es una variable que se necesita solo de manera interna en la función getTH, por lo que se inicializa dentro de la función de manera local.
La función checkIncomming se encarga de recibir datos y procesarlos. Espera recibir desde Protocoder dos números enteros, el primero lo utilizaremos como flag, es decir, es una variable de control que “decidirá” que hacer con los datos que se han recibido y, el segundo número entero, será el dato que vayamos a modificar. Por ejemplo, para modificar el valor de la variable sampleTime, desde Protocoder enviaremos primero el flag, que en este caso valdrá 1 y, después, separados por una coma, el número que queramos asignar a la variable, por ejemplo 2000, y finalizando con el carácter de salto de linea “\n”, quedando el paquete de datos: 1,2000\n.
El carácter “\n” se utiliza para determinar cuando se ha terminado de recibir el mensaje, asegurandonos así de que se ha recibido de manera completa.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void checkIncomming(){ int data,flag; if (Serial.available()>0){ flag = Serial.parseInt(); data = Serial.parseInt(); if (Serial.read() == '\n'){ switch (flag) { case 1: //1 for changing sample time sampleTime = data; break; } } } } |
Para añadir nuevas funciones dentro de la función checkIncomming, bastará con añadir un nuevo case dentro del switch y programar el envío desde Protocoder utilizando un nuevo flag. En la próxima entrada de este curso se añadirá una nueva funcionalidad a esta función, pero podéis ir probando a añadir nuevas funciones.
Código Protocoder
Dentro del código de Protocoder, se ha centrado y cambiado el tamaño del texto que mostraba los datos de la temperatura y humedad y se han añadido dos cuadros de texto, un botón para enviar datos a través de la conexión Bluetooth a Arduino y un toggle, para activar una alarma, que se activará si se sobrepasa la temperatura marcada.
En primer lugar, modificamos el tamaño y posición del texto que muestra los datos de temperatura y humedad para centrarlos en pantalla:
1 2 3 4 5 6 |
var textH = ui.addText("Hum", margin +w/5, 2*y,w,2*h); textH.textSize(50); textH.color("#000000"); var textT = ui.addText("Temp", margin +w/5, 3*y,w,2*h); textT.textSize(50); textT.color("#000000"); |
Vamos a dotar de nuevas funcionalidades a nuestra aplicación. En primer lugar vamos a añadir la posibilidad de poder modificar la velocidad a la que se envían los datos desde Arduino a Protocoder y también configuraremos una alarma que se activará si la temperatura leída en Arduino es mayor que la temperatura que introduzcamos en pantalla. Si la alarma se activa se mostrará una notificación en pantalla, además de hacer vibrar el dispositivo y reproducir un sonido.
Para configurar la velocidad del envío de datos usaremos la función checkIncomming, que hemos creado en Arduino. Esta función espera recibir dos números enteros separados por comas y para cerrar el paquete de datos, el símbolo “\n”. Configuramos la función de envío para que los datos se formateen como se ha explicado:
1 2 3 4 5 6 7 |
function send(flag,value) { if (btStatus) { btClient.send(flag+","+value+"\n"); }else{ ui.toast("Not Connected"); } } |
Cuando se quieran enviar datos, basta con llamar a la función e incluir los datos flag y value como argumentos, la función en sí se encarga de formatear los datos.
Para cambiar el intervalo, incluiremos un cuadro de texto, o input, en el que se podrán escribir los datos a enviar. Se ha configurado el cuadro de texto para introducir el tiempo en segundos y convertirlos de manera interna a milisegundos, la unidad de tiempo en la que se trabaja en Arduino. Para incluir un cuadro de texto utilizamos la siguiente orden:
1 2 3 |
ui.addButton("Text",posX,posY,width,height).onClick(function(){ //Code }); |
Se van a utilizar dos variables para modificar el tiempo que Arduino espera para enviar los datos, la variable timeToSend, que almacenará el tiempo a enviar, y flag, que se igualará a 1 para que corresponda al case del switch en la función checkIncomming del código Arduino en el que se cambia el tiempo.
1 2 3 |
var setIntervale = ui.addInput("Set intervale (s)", margin, 5*y, w/2, h).onChange(function(val){ timeToSend = val * 1000; // From seconds to miliseconds }); |
También incluimos un botón para que se envíen los datos una vez que se ha pulsado:
1 2 3 4 |
var setIntervaleBtn = ui.addButton("Set Intervale",margin +w/2,5*y,w/2,h).onClick(function(){ flag = 1; // set flag to 1 to set intervale on Arduino send(flag,timeToSend); }); |
Para crear la alarma de temperatura, utilizaremos otro cuadro de texto y un toggle, un interruptor que tiene un valor asignado según se haya pulsado o no. Además utilizamos dos variables tempAlarm, que almacenará la temperatura que queremos como límite para que se active la alarma, y isAlarmSet, que tomará el valor del toggle, que puede ser true o false. Para crear el cuadro de texto y las variables utilizamos las siguientes órdenes:
1 2 3 4 5 |
var tempAlarm = 0; var isAlarmSet = false; var setAlarm = ui.addInput("Set Alarm (ºC)",margin,6*y,w/2,h).onChange(function(val){ tempAlarm = val; }); |
La sintaxis para generar un toggle es:
1 2 3 |
ui.addToggle("text",posX,posY,width,height,estado_inicial[true o false]).onChange(function(val){ //Code }); |
Para crear el toggle utilizamos las siguientes ordenes:
1 2 3 4 5 6 7 |
var notification = false; // change to true if a notification has been shown var setAlarmCheck = ui.addToggle("Alarm",margin + w/2,6*y,w/2,h,false).onChange(function(val){ isAlarmSet = val; if(!val){ notification=false; // Change state to false when toggle is unchecked } }); |
Dentro del toggle, asignamos el valor que tenga, true o false, a la variable isAlarmSet y modificamos el valor de la variable notification a false si el valor del toggle es false, que utilizaremos a continuación para evitar que no se repita la notificación más de una vez, es decir, es necesario desactivar el toggle para que el sonido y la vibración de la notificación vuelvan a enviarse.
Dentro del botón btnConnect y la función onNewData, incluimos el código responsable de comprobar si la temperatura leída es mayor que la temperatura que se ha fijado como alarma, en caso de que el toggle esté activado. Para ello, utilizamos las siguientes ordenes:
1 2 3 4 5 6 7 8 |
if(isAlarmSet && temperature>=tempAlarm){ app.notification(01,"Temperature Alarm","Temperature is "+temperature+"ºC"); if (!notification){ device.vibrate(1000); media.playSound("glass_ping.mp3"); } notification = true; } |
En primer lugar, comprobamos con un condicional if si la variable isAlarmSet es true, es decir, si el toggle está activado, y si temperature es mayor que tempAlarm. Si ambas condiciones son true, se mostrará una notificación con la orden:
1 |
app.notification(01,"Temperature Alarm","Temperature is "+temperature+"ºC"); |
La sintaxis de la notificación es:
1 |
app.notification(id(int),"title","description"); |
A continuación si la variable notification es false, es decir, no se ha producido notificación o se ha desactivado el toggle, se hace que el dispositivo vibre durante 1 segundo y se reproduce un sonido de notificación con las órdenes:
1 2 |
device.vibrate(1000); media.playSound("glass_ping.mp3"); |
Por último, se cambia el valor de la variable notification a true para indicar que se ha reproducido una notificación.