Вы находитесь на странице: 1из 20

AQSENSORS

PROYECTO DE LABORATORIO DE MICROCONTROLADORES 2017 TII


INTEGRANTES: JORGE BRAVO, VALERIA TAMA Y SEBASTIAN FUENZALIDA PARALELO: 3
1. Planteamiento del Problema

La visión principal del proyecto es crear un Gateway que permita monitorear una red de
sensores inalámbricos, ya sea de manera local o en la Nube.

La primera meta que alcanzar era poder conectar inalámbricamente los sensores con el
concentrador que sería el encargado de procesar los datos, luego de esto, el cómo crear el
Gateway y como conectar este a la Nube.

Se usaran 3 sensores: Temperatura, humedad, CO y módulos XBEE para la comunicación


inalámbrica.

2. Solución del Problema

La realización del proyecto se dividió en partes separadas, para luego unir todo en un solo
conjunto. Los sub-problemas a resolver fueron los siguientes:

• Configuración Inalámbrica de los módulos XBEE S2.


• Sensores
• Recibir la data inalámbricamente
• Diseñar el Gateway
• Tener Acceso a la nube
2.1. Configuración inalámbrica de los módulos XBEE S2.

Materiales:

• 2 módulos XBEE S2 (ZIGBEE antena de 2mW)


• 1 XBEE Explorer Stick (o arduino + shield XBEE)

Para poder configurar estos módulos, es necesario conocer sus modos de funcionamiento
básicos:

• Coordinator: Este es el módulo central de la red, por esto, solo es posible tener uno
en toda la red. En este modo el modulo es capaz de recibir toda la información de la
Red, e incluso manejar las configuraciones, de las demás antenas.
• Router: Se utiliza para redirigir las señales provenientes de otros router y enviar esta
información al Coordinator.
• End Point: Es el punto final de la red.

En este caso se usará 2 módulos XBEE uno será el coordinador y otro un Router.

Para realizar esas configuraciones sobre las antenas es necesario el programa XCTU de Digi, el
link de descarga puede ser encontrado en Anexos (1).

Figura 2.1 : Grafico de la red básica de Zigbee realizada en este Proyecto. C : coordinator, R: Router.
Se conecta el módulo XBEE al XBEE Explorer Stick y este conjunto se conecta a un puerto USB
del computador.

Abrir XCTU y en este se mostrará todos los puertos COM conectados, aquí se escoge el puerto y
ahora hay que dirigirse a la ventana Modem Configuración, allí es donde se configurara la
antena. La configuración es la siguiente:

Figura 2.1.1: Configuración de una antena como router. Los cambios a realizar son los marcados con Azul.

Como se puede ver en la Figura 2.1.1 la primera parte es la configuración de la Red, se debe
escoger en la pestaña Function Set la configuración ZNET 2.5 Router/End Device AT. Que indica
que el módulo trabajara como router. En la primera parte de la configuración, se debe setear un
PAN ID, identificación de la red, en este caso se escogió 17. Y activa la verificación del canal JV-
Channel Verification.

En la segunda parte de la Figura 2.1.1 se realiza la configuración de los pines de entrada y salida.
Al ser 3 sensores se elige usar los pines D1, D2, D3 de la antena y se los configura como ADC.
Luego se configura una frecuencia de muestreo en el apartado I/O Sampling, en este caso se
puso 3E8, es decir, 1000ms o 1 segundo.
Figura 2.1.2: Configuración de antena como Coordinator.

En el caso de la figura 2.1.2 en la pestaña de selección Function Set se escoge ZNET 2.5
COORDINATOR API, que indica que la antena funcionara como Coordinator. En este caso solo se
necesita configurar el PAN ID para que pueda conectarse con la otra antena (Ambas antenas
deben tener el mismo PAN ID).

2.2. Sensores

Materiales:

• 1 sensor MQ7 (sensor de monóxido de carbono)


• 1 sensor Capacitive Moisture Sensor V1.0 (Sensor de Humedad)
• 1 sensor LM35 (sensor de temperatura)
• 1 arduino

Para el uso del sensor MQ7 se debe remitir a la hoja de datos, allí se encuentra una gráfica, con
la cual se puede sacar una ecuación con ayuda de Excel.

Figura 2.2: Ecuación para el uso del sensor MQ7


Para el uso del Sensor Capacitivo de Humedad, la hoja de datos, nos indica que se debe medir
el valor máximo y mínimo de voltaje, ya que se trabajara en porcentajes. Este tendrá su valor
máximo en ambiente seco, y valor mínimo en un ambiente totalmente húmedo (Insertarlo en
un vaso de agua).

En el caso del sensor LM35 este simplemente trabaja a 10mV por cada grado centígrado.

2.3. Recibir la data inalámbricamente

Materiales:

• 1 sensor MQ7 (sensor de monóxido de carbono)


• 1 sensor Capacitive Moisture Sensor V1.0 (Sensor de Humedad)
• 1 sensor LM35 (sensor de temperatura)
• 1 arduino
• 2 LM358
• 1 XBEE Xplorer Stick
• 2 Módulos Xbee S2
• 2 resistencias de 330 ohmios
• 3 resistencias de 1kohmios.
• 1 tft LCD táctil de MCUFRIEND

Para esto en la planta se debe conectar los sensores y la antena con ayuda del XBEE EXPLORER
STICK, que ayudara a alimentar todos los sensores, de la siguiente manera:

vcc

J5
1 U1:A
2 U1:B
4

3
4

4 3
1
R1 5
Sensor de CO 2 1k 7
6
8

LM358 R2
8

330 LM358
vcc
vcc

R3
330
5
4
3
2
1

6
5
4
3
2
1

vcc
J3 J1
J6 CONN-H5 CONN-H6
1 U2:A U2:B
2
4

3
3 5 Xbee Xplorer Stick
Sensor de Humedad 1
R4 7
2 6 J4 J2
10k
CONN-H5 CONN-H6
8

LM358 LM358

vcc R5
5
4
3
2
1

6
5
4
3
2
1

10k

1 U3

vcc 27.0

2
VOUT

3 LM35

Figura 2.3.1: Conexión de los sensores a la antena configurada como router

Se debe trabajar con opamps ya que la entrada máxima de voltaje análoga del módulo XBEE S2
es de 1.2V. Una vez conectado todo de esta manera se está listo para trabajar con el
coordinador.
El módulo Xbee configurado como Coordinator se conecta al arduino usando los pines de 3.3V,
gnd, DataOut de la antena con el Rx de arduino, Datainput de la antena con el Tx de arduino.

Figura 2.3.2: Conexión del modulo Xbee S2 al Arduino.

Una vez conectado esto, se debe saber que los módulos XBEE se comunican de acuerdo a la
siguiente codificación:

Figura 2.3.3: Comunicación entre módulos Xbee

Dado esto se usa el siguiente código para obtener las lecturas análogas de los sensores, se
maneja estos datos para mostrarlos de acuerdo con su unidad (grados C, ppm, %) y se usa una
tft LCD Táctil, para mostrar estos datos en una gráfica.
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin

#define TOUCH_ORIENTATION LANDSCAPE


#define USE_UTOUCH 0

#include <SPI.h> // f.k. for Arduino-1.5.2


#include "Adafruit_GFX.h"// Hardware-specific library
#include <MCUFRIEND_kbv.h>
#include <TouchScreen.h>
MCUFRIEND_kbv tft;

// MCUFRIEND UNO shield shares pins with the TFT. Due does NOT work
#define YP A1 //A3 for ILI9320
#define YM 7 //9
#define XM A2
#define XP 6 //8

TouchScreen myTouch(XP, YP, XM, YM, 300);


TSPoint tp; // Almacena el punto donde el tactil fue presionado

//Funciones de ayuda para el manejo del Tactil


void readResistiveTouch(void) //Lee las coordenadas del touch
{
tp = myTouch.getPoint();
pinMode(YP, OUTPUT); //restore shared pins
pinMode(XM, OUTPUT);
digitalWrite(YP, HIGH);
digitalWrite(XM, HIGH);
}

bool ISPRESSED(void) // Booleano que es True si la pantalla tactil esta siendo


presionada
{
readResistiveTouch();
return tp.z > 20 && tp.z < 1000;
}

void waitForTouch() //Ayuda a mantener una pantalla mientras no se haya


presionado el touch
{
while (ISPRESSED() == true) {}
while (ISPRESSED() == false) {}
while (ISPRESSED() == true) {}
}

void showpoint(void) // Muestra el punto presionado en el serial


{
Serial.print("\r\nx="); Serial.print(tp.x);
Serial.print(" y="); Serial.print(tp.y);
Serial.print(" z="); Serial.print(tp.z);
}

#define BLACK 0x0000


#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF

void ventana(int N1, int N2, int N3, int N4,int N5,String tittle){ //
Construye la ventana principal
tft.drawRect(0, 0, 70, 239, BLACK);
tft.fillRect(0,0,70,239, tft.color565(58,122,148));
tft.fillRect(71,0, 248, 239, WHITE);
tft.drawLine(90, 0, 90, 239, BLACK); // Linea Vertical
tft.drawLine(90, 0, 95, 5, BLACK); //Flecha
tft.drawLine(90, 0, 85, 5, BLACK); //Flecha
tft.drawLine(85, 234, 319, 234, BLACK); // Linea Horizontal
tft.drawLine(314, 229, 319, 234, BLACK); //Flecha Horizontal
tft.drawLine(314, 239, 319, 234, BLACK); //Flecha Horizontal
for(int j = 3; j< 234; j += 3){
tft.drawLine(85, j, 95, j, BLACK);
}
tft.setTextColor(BLACK);
tft.setTextSize(0.5);
tft.setCursor(72, 39); //Nivel1
tft.println(N1);
tft.setCursor(72, 78); //Nivel2
tft.println(N2);
tft.setCursor(72, 117); //Nivel3
tft.println(N3);
tft.setCursor(72, 156); //Nivel4
tft.println(N4);
tft.setCursor(72, 195); //Nivel5
tft.println(N5);

tft.setCursor(95, 0);
tft.println(tittle);
tft.setCursor(314, 224);
tft.println("t");
}

short estado = 0;
int analogMSB1 = 0;
int analogLSB1 = 0;
int analogMSB2 = 0;
int analogLSB2 = 0;
int analogMSB3 = 0;
int analogLSB3 = 0;
int analogRead1 = 0;
int analogRead2 = 0;
int analogRead3 = 0;
int buf[227];
int buf2[227];
int buf3[227];
int i;
int cont;
int x = 0;
int tam=0;
float vin1 = 0;
float vin2 = 0;
float vin3 = 0;
void setup() { //Inicializacion de coponentes
Serial.begin(9600);
uint16_t ID = tft.readID();
tft.begin(ID);
tft.invertDisplay(true);
tft.setRotation(1);
tft.fillScreen(WHITE);
tft.setTextColor(tft.color565(135,193,220));
tft.setTextSize(4);
tft.setTextColor(tft.color565(195,196,196));
tft.setCursor(70,70);
tft.println("AQSensors");
tft.setTextSize(1);
tft.setCursor(70,130);
tft.println("Red de Sensores");
tft.setTextSize(1);
tft.setCursor(70,145);
tft.println("Grupo 1");
waitForTouch();
tft.fillScreen(WHITE);
ventana(125, 100, 75, 50, 25, "Temp [C]");
}

void loop() {
if(ISPRESSED() == true){ //Pregunta en que parte esta siendo presionado el
tactil
readResistiveTouch();
if(tp.x < 950 && tp.x > 820){
if(tp.y > 206 && tp.y < 440){
while(ISPRESSED() == true){}
ventana(125, 100, 75, 50, 25, "Temp [C]");
for(i = x; i< x+tam; i++){
tft.drawPixel((i-x) + 91, buf[(i)%tam], tft.color565(136,204,227));
}
estado = 0;
}else if(tp.y > 445 && tp.y < 690){
while(ISPRESSED() == true){}
ventana(2500, 2000, 1500, 1000, 500, "CO [ppm]");
for(i = x; i< x+tam; i++){
tft.drawPixel((i-x) + 91, buf2[(i)%tam], tft.color565(136,204,227));
}
estado = 1;
}else if(tp.y > 695 && tp.y < 960){
while(ISPRESSED() == true){}
ventana(83, 67, 50, 33, 17, "Hum [%]");
for(i = x; i< x+tam; i++){
tft.drawPixel((i-x) + 91, buf3[(i)%tam], tft.color565(136,204,227));
}
estado = 2;
}
}
}
tft.setTextColor(BLACK);
if(Serial.available()>21){ //lEctura del serial, de acuerdo al protocolo de
counicacion entre XBEE's
if(Serial.read()==0x7E){
for(int i=1; i<19; i++){
byte discardByte = Serial.read();
Serial.println(discardByte, HEX);
}
analogMSB1 = Serial.read();
Serial.println(analogMSB1);
analogLSB1 = Serial.read();
Serial.println(analogLSB1);
analogMSB2 = Serial.read();
Serial.println(analogMSB2);
analogLSB2 = Serial.read();
Serial.println(analogLSB2);
analogMSB3 = Serial.read();
Serial.println(analogMSB3);
analogLSB3 = Serial.read();
Serial.println(analogLSB3);
analogRead1 = analogLSB1 + (analogMSB1*256);
analogRead2 = analogLSB2 + (analogMSB2*256);
analogRead3 = analogLSB3 + (analogMSB3*256);
vin1 = (analogRead1/1023.0*1.15); //COnvertir un ADC to vin
vin2 = ((analogRead2/1023.0*1.15)-0.07)/660.0*1590.0; //se resta 0.07
por la diferencia de potencial entre la tierra del sensor, y la de la antena
vin3 = (1023.0-((float)analogRead3))/437.0*100.0; //Voltaje maximo *100
ya que es solo un porcentaje
float RS = 1000.0*((5.0-(float)vin2)/((float)vin2));
float CO = 106.92*pow((RS/5677.0),(-1.458));
tft.fillRect(0,0,70,240, tft.color565(58,122,148));
tft.drawLine(0, 78, 70, 78, tft.color565(41,61,102)); // Division1
tft.drawLine(0, 156, 70, 156, tft.color565(41,61,102)); // Division2
tft.setTextSize(1);
tft.setTextColor(BLACK);
tft.setCursor(5,29);
tft.println("temp:");
tft.print(" ");
tft.print(vin1*100);
tft.println(" C");
tft.setCursor(5, 107);
tft.println("CO:");
tft.print(" ");
tft.print(CO);
tft.println(" ppm");
tft.setCursor(5, 185);
tft.println("Humedad:");
tft.print(" ");
tft.print(vin3);
tft.println(" %");
int value = 234-vin1*100*233.0/150.0; //Para que la grafica no salga
alrevez
int value2 = 234 - CO*233.0/3000.0;
int value3 = 234 - vin3*233.0/100.0;
if (tam == 227){
x = (x+1)%tam;
buf[(x+tam-1)%tam] = value;
buf2[(x+tam-1)%tam] = value2;
buf3[(x+tam-1)%tam] = value3;
}else{
buf[tam] = value;
buf2[tam] = value2;
buf3[tam] = value3;
tam += 1;
}
if(estado == 0){
graph(buf, value);
}
if(estado == 1){
graph(buf2, value2);
}
if(estado == 2){
graph(buf3, value3);
}
}
}
}

void graph(int bf[227], int value){ //Grafica los puntos que se vayan
leyendo.
if (tam == 227){
for (i = x; i < x+tam; i++){
tft.drawLine((i-x) + 92, bf[(i-1)%tam],(i-x-1)+92,bf[(i-2)%tam],
WHITE);
if(i < (x + tam -1)){tft.drawLine(((i-x) + 92), bf[i%tam],(i-x-
1)+92,bf[(i-1)%tam],tft.color565(136,204,227));};
}
}else{
tft.drawLine(tam+92, value,tam+91,bf[tam-2],
tft.color565(136,204,227));
}
}

Con esto la planta queda construida, ya que manda valores al serial, este se leerá en la raspberry
para publicarse en el servidor.

2.4. Acceso a la Nube.

Materiales:

• Raspberry Pi
• Planta Construida anteriormente.

Para esta parte del proyecto se usan las siguientes librerías y paquetes.

• PythonSerial: Se obtiene con el siguiente comando:


sudo apt-get install python-serial
• Apache2 + Php5:
sudo apt-get install apache2 php5 libapache2-mod-php5
• MySQL server
sudo apt-get install mysql-server mysql client php5-mysql

• Python MySQLDB: Aquí se debe poner una contraseña


sudo apt-get install Python-mysqldb

El primer paso es crear la base de datos, esta tendrá la siguiente estructura.

Para esto primero se ingresa a MYSQL mediante terminal, usando el siguiente comando:

mysql -u root -p

Pedirá la contraseña ingresada anteriormente.

Para crear una base de datos se usa el siguiente comando:

CREATE DATABASE AQsensor;

Ahora se debe ingresar a la base de datos:

USE AQsensor;

Dentro de la base de datos se crea la tabla:

CREATE TABLE sensors(id INT NOT NULL, Temperatura INT NOT NULL, CO INT NOT NULL,
Humedad INT NOT NULL);

Con esto la tabla queda creada, para insertar valores a esta tabla se usa:

INSERT INTO sensors (datetime, temperatura, co, humedad) VALUES (ValorFecha, ValorTemp,
ValorCO, ValorHum);

Una vez creada la base de datos, se usa el siguiente código en Python, que lee los datos del
serial, los analiza y los guarda en la base de Datos.
#!/usr/bin/env python

import time
import datetime
import glob
import MySQLdb
import serial
from time import strftime

db = MySQLdb.connect(host="localhost", user="root",passwd="sensorproject",
db="AQsensor") #Aqui se configura el nombre de la base de datos y el password
cur = db.cursor()
db.commit()

ser = serial.Serial( #Configuracion del serial


port = '/dev/ttyACM0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 1
)

while True:
x = ser.readline()
y = str(x).replace("\n","")
if( y != ""):
for i in range(0, 17):
x = ser.readline()
try: #Lectura del serial de acuerdo al protocolo de comunicacion de
los XBEES
msb1 = int(str(ser.readline()).replace("\n",""))
lsb1 = int(str(ser.readline()).replace("\n",""))

msb2 = int(str(ser.readline()).replace("\n",""))
lsb2 = int(str(ser.readline()).replace("\n",""))

msb3 = int(str(ser.readline()).replace("\n",""))
lsb3 = int(str(ser.readline()).replace("\n",""))

analogRead1 = lsb1 + (256*msb1)


analogRead2 = lsb2 + (256*msb2)
analogRead3 = lsb3 + (256*msb3)
vin1 = (analogRead1/1023.0*1.15)
vin2 = (analogRead2/1023.0*1.15-0.07)/660.0*1590.0
vin3 = (1023.0-(analogRead3))/453.0*100.0
RS = 1000.0*(5.0-float(vin2))/float(vin2)
CO = 106.92*((RS/5677.0)**(-1.458))
datetimeWrite = (time.strftime("%Y-%m-%d ") +
time.strftime("%H:%M:%S"))
print datetimeWrite
#El comando usado para insertar datos en la base de datos
sql = ("""INSERT INTO sensors (datetime, temperatura, co, humedad)
VALUES(%s, %s, %s, %s)""", (datetimeWrite, vin1*100, CO, vin3))
try:
print "Writing to database..."
cur.execute(*sql)
db.commit()
print "write complete"
except:
db.rollback()
print "failed"
cont += 1
print(vin1*100)
print(CO)
print(vin3)
except:
continue

cur.close()
db.close()

Con la data insertándose en la base de datos, se usa un código en php del lado del servidor, para
esto se debe saber en qué parte está almacenado los archivos de nuestro servidor.

Los archivos que se muestran en el servidor están en la carpeta /var/www/html.

Aquí se debe poner la página web que se quiere mostrar en el servidor.

Dentro de esta carpeta se crea el siguiente código llamado Datajson.php, que lee la base de
datos y la retorna en un JSON(arreglo de objetos)
<?php

$username="root";
$password="sensorproject";
$database="AQsensor";
$numdata = 100;
mysql_connect(localhost,$username,$password);
@mysql_select_db($database) or die("Unable to select database");

$query="SELECT * FROM sensors";


$result = mysql_query($query);

$num = mysql_numrows($result);

mysql_close();

$sensValues = array();

if($num < $numdata){


$i = 0;
}else{
$i = $num-$numdata;
}

while($i < $num)


{
$dateAndDatas = array();
$dataTime = mysql_result($result, $i, "datetime");
$temp = mysql_result($result, $i, "temperatura");
$co = mysql_result($result, $i, "co");
$hum = mysql_result($result, $i, "humedad");

$dateAndDatas["Fecha"] = $dataTime;
$dateAndDatas["Temp"] = $temp;
$dateAndDatas["CO"] = $co;
$dateAndDatas["Hum"] = $hum;
if($num < $numdata){
$sensValues[$i] = $dateAndDatas;
}else{
$sensValues[$i+$numdata-$num] = $dateAndDatas;
}
$i++;
}

echo json_encode($sensValues);
?>
Ahora se crea el archivo principal llamado index.php, este es el que mostrara el servidor por
defecto.

Para generar la gráfica se usa la librería de javascript canvasjs, jquery, jquery.canvasjs, estas
pueden descargarse de sus páginas oficiales.
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Sensor</title>
<style type="text/css">
#temp{
visibility: hidden;
position: fixed;
}
</style>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="canvasjs.min.js"></script>
<script src="jquery.canvasjs.min.js"></script>
<script type="text/javascript">
var datos; //lee los datoscomo un string, los datos que estan en
Datajson.php
var objDat; //los datos transformados a un JSON
function cargaTemp(objDat){ //Genera un arreglo con par de puntos para
la grafica de temperatura
dataPoints = [];
for(i=0; i<objDat.length; i++){
if(objDat[i] != null){
dataPoints.push({x: new Date(objDat[i].Fecha), y:
Number(objDat[i].Temp)});
}
}
return dataPoints;
}
function cargaCO(objDat){ //Genera un arreglo con par de puntos para
la grafica de CO
dataPoints = [];
for(i=0; i<objDat.length; i++){
if(objDat[i] != null){
dataPoints.push({x: new Date(objDat[i].Fecha), y:
Number(objDat[i].CO)});
}
}
return dataPoints;
}
function cargaHum(objDat){ //Genera un arreglo con par de puntos para
la grafica de Humedad
dataPoints = [];
for(i=0; i<objDat.length; i++){
if(objDat[i] != null){
dataPoints.push({x: new Date(objDat[i].Fecha), y:
Number(objDat[i].Hum)});
}
}
return dataPoints;
}
$(document).ready(function(){ //Nada de lo anterior se ejecuta ya que
son funciones, la ejecucion comienza cuando toda la pagina fue descargada por
el navegador
//Para eso es la funcion ready
$("#temp").load("Datajson.php"); //Se carga en un div invisible los
datos que leyo el archivo Datajson.php de la base de datos
datos = JSON.stringify(<?php include 'Datajson.php';?>);
objDat = JSON.parse(datos);
var chartTemp = new CanvasJS.Chart("chartContainerTemp", { //Crea el
grafico
animationEnabled:true,
theme: "light2",
title: {
text: "Temperatura"
},
axisX:{
valueFormatString: "DD/MMM/YY hh:mm:ss"
},
axisY:{
title: "ยบC",
titleFontSize: 15,
maximum: 150
},
legend:{
cursor:"pointer",
fontsize:16
},
data: [{
type: "spline",
yValueFormatString: "#0.##",
xValueFormatString:"DD/MMM/YY hh:mm:ss",
dataPoints: cargaTemp(objDat)
}]
});
var chartCO = new CanvasJS.Chart("chartContainerCO", {
animationEnabled:true,
theme: "light2",
title: {
text: "Monoxido de Carbono"
},
axisX:{
valueFormatString: "DD/MMM/YY hh:mm:ss"
},
axisY:{
title: "ppm",
titleFontSize: 15,
maximum: 3000
},
legend:{
cursor:"pointer",
fontsize:16
},
data: [{
type: "spline",
yValueFormatString: "#0.##",
xValueFormatString:"DD/MMM/YY hh:mm:ss",
dataPoints: cargaCO(objDat)
}]
});
var chartHum = new CanvasJS.Chart("chartContainerHum", {
animationEnabled:true,
theme: "light2",
title: {
text: "Humedad"
},
axisX:{
valueFormatString: "DD/MMM/YY hh:mm:ss"
},
axisY:{
title: "Porcentaje %",
titleFontSize: 15,
maximum: 100
},
legend:{
cursor:"pointer",
fontsize:16
},
data: [{
type: "spline",
yValueFormatString: "#0.##",
xValueFormatString:"DD/MMM/YY hh:mm:ss",
dataPoints: cargaHum(objDat)
}]
});
chartTemp.render();
chartCO.render();
chartHum.render();
window.setInterval(function(){
$("#temp").load("Datajson.php");
datos = document.getElementById("temp").innerHTML;
objDat = JSON.parse(datos);
chartTemp.options.data[0].dataPoints = cargaTemp(objDat);
chartTemp.render();
chartCO.options.data[0].dataPoints = cargaCO(objDat);
chartCO.render();
chartHum.options.data[0].dataPoints = cargaHum(objDat);
chartHum.render();
}, 1000);
});
</script>
</head>
<body>
<div id="temp"></div>
<div id="chartContainerTemp" style="height: 300px; width: 100%; border-
color: lightgrey;border-radius: 10px;border-style: double; margin-bottom:
25px;"></div>
<div id="chartContainerCO" style="height: 300px; width: 100%; border-color:
lightgrey;border-radius: 10px;border-style: double; margin-bottom:
25px;"></div>
<div id="chartContainerHum" style="height: 300px; width: 100%; border-color:
ligtgrey;border-radius: 10px;border-style: double; margin-bottom:
25px;"></div>
</body>
</html>

Con esto está todo listo, para que todo funcione se debe conectar el arduino a la raspberry, y
tener conectada la planta. Luego de esto, se ejecuta el código en Python, ahora al abrir el
navegador y poner la dirección ip local de la raspberry se mostrará en tiempo real la gráfica de
los valores de los sensores.

3. Adicional (Aplicación en Android)

Para la aplicación en Android se usa phonegap, esto crea una aplicación en Android por medio
de una página web codificada en html y javascript, así que el código es básicamente el mismo
que el anterior con unos pequeños cambios.

Para esto primero se descarga la aplicación phonegap, se crea un nuevo proyecto y en él, se
pega el siguiente código, además de las librerías en la carpeta correspondiente.

<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Sensor</title>
<style type="text/css">
#temp{
visibility: hidden;
position: fixed;
}
</style>
<script src="jquery-3.3.1.min.js"></script>
<script src="canvasjs.min.js"></script>
<script src="jquery.canvasjs.min.js"></script>
<script type="text/javascript">
var datos;
var objDat;
function cargaTemp(objDat){
dataPoints = [];
for(i=0; i<objDat.length; i++){
if(objDat[i] != null){
dataPoints.push({x: new Date(objDat[i].Fecha), y:
Number(objDat[i].Temp)});
}
}
return dataPoints;
}
function cargaCO(objDat){
dataPoints = [];
for(i=0; i<objDat.length; i++){
if(objDat[i] != null){
dataPoints.push({x: new Date(objDat[i].Fecha), y:
Number(objDat[i].CO)});
}
}
return dataPoints;
}
function cargaHum(objDat){
dataPoints = [];
for(i=0; i<objDat.length; i++){
if(objDat[i] != null){
dataPoints.push({x: new Date(objDat[i].Fecha), y:
Number(objDat[i].Hum)});
}
}
return dataPoints;
}

$(document).ready(function(){
$("#temp").load("http://192.168.100.54/Datajson.php"); //ip local de la
raspberry
var chartTemp = new CanvasJS.Chart("chartContainerTemp", {
animationEnabled:true,
theme: "light2",
title: {
text: "Temperatura"
},
axisX:{
valueFormatString: "DD/MMM/YY hh:mm:ss"
},
axisY:{
title: "C",
titleFontSize: 15,
maximum: 150
},
legend:{
cursor:"pointer",
fontsize:16
},
data: [{
type: "spline",
yValueFormatString: "#0.##",
xValueFormatString:"DD/MMM/YY hh:mm:ss",
dataPoints: []
}]
});
var chartCO = new CanvasJS.Chart("chartContainerCO", {
animationEnabled:true,
theme: "light2",
title: {
text: "Monoxido de Carbono"
},
axisX:{
valueFormatString: "DD/MMM/YY hh:mm:ss"
},
axisY:{
title: "ppm",
titleFontSize: 15,
maximum: 3000
},
legend:{
cursor:"pointer",
fontsize:16
},
data: [{
type: "spline",
yValueFormatString: "#0.##",
xValueFormatString:"DD/MMM/YY hh:mm:ss",
dataPoints: []
}]
});
var chartHum = new CanvasJS.Chart("chartContainerHum", {
animationEnabled:true,
theme: "light2",
title: {
text: "Humedad"
},
axisX:{
valueFormatString: "DD/MMM/YY hh:mm:ss"
},
axisY:{
title: "Porcentaje %",
titleFontSize: 15,
maximum: 100
},
legend:{
cursor:"pointer",
fontsize:16
},
data: [{
type: "spline",
yValueFormatString: "#0.##",
xValueFormatString:"DD/MMM/YY hh:mm:ss",
dataPoints: []
}]
});
chartTemp.render();
chartCO.render();
chartHum.render();
window.setInterval(function(){
$("#temp").load("http://192.168.100.54/Datajson.php");
datos = document.getElementById("temp").innerHTML;
objDat = JSON.parse(datos);
chartTemp.options.data[0].dataPoints = cargaTemp(objDat);
chartTemp.render();
chartCO.options.data[0].dataPoints = cargaCO(objDat);
chartCO.render();
chartHum.options.data[0].dataPoints = cargaHum(objDat);
chartHum.render();
}, 1000);
});
</script>
</head>
<body>
<div id="temp"></div>
<div id="chartContainerTemp" style="height: 300px; width: 100%; border-
color: lightgrey;border-radius: 10px;border-style: double; margin-bottom:
25px;"></div>
<div id="chartContainerCO" style="height: 300px; width: 100%; border-color:
lightgrey;border-radius: 10px;border-style: double; margin-bottom:
25px;"></div>
<div id="chartContainerHum" style="height: 300px; width: 100%; border-color:
ligtgrey;border-radius: 10px;border-style: double; margin-bottom:
25px;"></div>
</body>
</html>
Figura 3.1: Vista de Phonegap, dentro de la carpeta mostrada va la página web.

Ahora se crea un proyecto en github, subir toda esta carpeta, para luego en una cuenta de
PhoneGap Build se hace un pull del repositorio github, y automáticamente se empieza a
construir el apk de la aplicación.

4.- Conclusiones

 El uso de la raspberry es muy amplio ya que permite realizar operación avanzadas para
el IOT a un costo no muy alto, al ser una computadora básica y en miniatura.
 El uso de shields para arduino, como el caso de la TFT, puede dejar muchos pines
inhabilitados, una opción para la solución de este problema, es usar una pantalla i2c.
 En raspberry se puede hacer prácticamente cualquier cosa, ya que se tiene libertad de
escoger el lenguaje en el que se desee programar, como en este caso, se escogió,
Python, mysql, javascript, php, css, html.

5.- Recomendaciones

 Este proyecto se puede ampliar aún más, dando alarmas cuando ciertos valores límites
de calidad de aire se hayan alcanzado. Configurar los parámetros de los sensores
localmente. Realizar un análisis estadístico de todos los datos.
 Para el uso de librería y/o algún código nuevo, es mejor remitirse a la web oficial de la
misma, ya que es documentación verídica, aunque en algunos casos sea un poco más
difícil de comprender.
 En este caso se usa un solo punto de sensores, pero se puede ampliar la red XBEE para
agregar más de un sensor, es decir, sensar varios cuartos a la vez.
 Al leer los datos de las antenas, procurar siempre imprimir estos al serial una vez leídos,
como una especia de confirmación, sino se hace esto, se podría producir un error en la
toma de datos.
 Para que el servidor creado tenga salida a la web se debe configurar el router principal,
para que permita el tráfico de salida desde nuestro servidor, en la mayoría de casos, se
lo agrega como un dispositivo DMZ.

Anexos:

1.- Link de descarga del XCTU: https://www.digi.com/products/xbee-rf-solutions/xctu-


software/xctu

Вам также может понравиться