Invernadero – GreenHouse

Vamos a monitorizar nuestras plantas. Se podría aplica a los jardines urbanos que cada vez más personas tienden a tener en el hogar y en los espacios públicos.

Controlaremos la humedad del suelo, la humedad y la temperatura del medioambiente para controlar y cuidar de manera más eficiente nuestras plantas. Haremos un pequeño invernadero con un techo abierto que puedes abrir y cerrar.

La idea es que a través de un sitio web podemos ver y controlar gráficamente los tres o cuatro parámetros antes mencionados, temperatura, humedad del aire, suelo húmedo y si la puerta está abierta o cerrada.

Podría mejorarse el proyecto, permitiendo abrir y cerrar la puerta y regar desde el sitio web.

Incluso se podrían recibir notificaciones por correo electrónico si ocurren ciertas circunstancias.

Lista de materiales.

Este proyecto tiene dos tipos de materiales, electrónicos y no electrónicos.

Electronic components:

  • Raspberry Pi 3 (RPi3) Model B Quad-Core 1.2 GHz 1 GB RAM.
  • 32 GB MicroSD clase 10.
  • Fuente de alimentación para la Raspberry.
  • HDMI Cable
  • Arduino UNO R3
  • Sensor DHT22 (temperatura y humedad)
  • Sensor humedad del suelo.
  • Control del motor paso a paso con L298N
  • Motor paso a paso 17HS2408 4-lead Nema 17
  • Bomba de agua.
  • relé

 

Componentes no electrónicos:

  • Listón de madera(2,7 cm X 2,7 cm x 240 cm). 10 metros , para la estructura del invernadero
  • Maceta (50cmx20cm{+-})
  • Botella grande de agua.
  • Manguera (2metros)
  • Cable(7 metros +-)
  • 2 bisagras
  • Plástico duro para cubrir el invernadero.
  • Tornillos para construir el invernadero

Construyendo el invernadero.

Primer test del sensor de temperatura y humedad.

El sensor DHT22 tiene 4 pines pero solo utilizaremos tres, 2 para la alimentación y uno para leer la información.

Fijaros bien en los nombres de los pines, pueden cambiar según el fabricante.

Y ahora el programa, aunque en el esquema aparece el sensor pinchado en el pin 3, nosotros lo colocaremos en el 13.

Necesitarás la librería para el sensor: DHT-sensor-library-master

#include <DHT.h>
#include <DHT_U.h>
#define DHTTYPE DHT22

const int DHTPin = 13;
DHT dht(DHTPin, DHTTYPE);

void setup() {
 Serial.begin(9600);
 Serial.println("DHTxx test!");
 dht.begin();
 }

void loop() {
 //Esperamos algunos segundos para medir.
 delay(2000);
 // Leemos temperatura y humedad
 float h = dht.readHumidity();
 float t = dht.readTemperature();
 if (isnan(h) || isnan(t)) {
 Serial.println("Falló la lectura sensor!");
 }
 else
 {
 Serial.print("{\"humedad\":");
 Serial.print(h);
 Serial.print(",");
 Serial.print("\"temperatura\":");
 Serial.print(t);
 Serial.println("}\n");
 }
}

Y ahora el sensor de humedad de la tierra:

Es muy sencillo, al igual que el anterior lleva 4 pines, dos de alimentación y dos de lectura, uno  digital y otro analógico. Este último será el que utilizaremos nosotros:

Lo conectaremos al pin analógico A0.

Y el programa de test:

#define sensor A0
 
void setup(){
 pinMode(sensor, INPUT);
 Serial.begin(9600);
}
 
void loop(){
 //Se hace la lectura del pin A0 
 //map() para ajustar los valores leídos a los porcentajes que queremos utilizar 
 int valorHumedad = map(analogRead(sensor), 0, 1023, 100, 0);
 
 Serial.print("{\"humedadSuelo\":");
 Serial.print(valorHumedad);
 Serial.println("}\n");
 delay(1000);
}

Y los dos sensores juntos:

#include <DHT.h>
#include <DHT_U.h>
#define DHTTYPE DHT22
#define sensor A0

const int DHTPin = 13;
const int sensorPin = A0;

DHT dht(DHTPin, DHTTYPE);

void setup() {
 pinMode(sensorPin, INPUT);
 Serial.begin(9600);
 Serial.println("DHTxx test!");
 dht.begin();
}
void loop() {
 //Esperamos algunos segundos para medir.
 delay(5000);
 // Leemos temperatura y humedad 
 float h = dht.readHumidity();
 float t = dht.readTemperature();
 //Se hace la lectura analoga del pin A0 
 //map() para ajustar los valores leidos
 int valorHumedad = map(analogRead(sensor), 0, 1023, 100, 0);
 
 if (isnan(h) || isnan(t)) {
 Serial.println("Falló la lectura sensor!");
 }
 else
 {
 Serial.print("{\"humedad\":"); 
 Serial.print(h); 
 Serial.print(",");
 Serial.print("\"temperatura\":");
 Serial.print(t);
 Serial.print(",");
 Serial.print("\"humedadSuelo\":");
 Serial.print(valorHumedad);
 Serial.println("}\n");
 }
}

Abrir y cerrar la puerta del invernadero.

Para abrir y cerrar la puerta superior vamos a utilizar un motor paso a paso, por tener un mayor control de las vueltas realizadas, así podremos abrir y cerrar con precisión.

Utilizaremos un driver L298N para realizar ese movimiento, la conexión será la siguiente:

El esquema de conexión muestra la conexión utilizada entre el modulo L298N y el motor paso a paso. Cada una de las bobinas del motor esta conectada a una salida del módulo. Para identificar las bobinas de un motor paso a paso utilizamos un multímetro en modo de continuidad. Los cables que dan continuidad son los extremos de cada bobina.

En este caso, como el motor paso a paso es de 12 VDC y 2 Amparios (OJO, si no le damos el amperaje correcto el motor hará cosas extrañas), utilizamos el jumper de selección de +5V, para activar el regulador interno del módulo y solo hacer uso de una fuente de 12 VDC para alimentar el motor.

Los jumper de activación ENA y ENB los hemos activado de igual manera.

Código de Arduino

El código de Arduino hace girar el motor paso a paso una vuelta en un sentido y luego ejecuta otra vuelta en sentido opuesto. Este código hace uso de la librería ‘Stepper.h‘, que se instala por defecto en las ultimas versiones del IDE de Arduino.

El valor de la variable stepsPerRevolution depende del número de pasos del motor paso a paso. Este valor se encuentra en las especificaciones de la hoja de datos del motor. En nuestro caso el motor paso a paso utilizado es de 200 pasos/vuelta.

/* El motor está conectado a los pines digitales 8 - 11 de la Arduino. 
El motor debe girar una paso en una dirección, a continuación, una paso en la otra dirección. 
 */

#include <Stepper.h>
// cambia el valor por num. de pasos de tu motor
// Motor Nema 17 (200 pasos 1.8 º por paso)
const int stepsPerRevolution = 200;  

// inicializa la libreria 'stepper' en los pines 8 a 11
Stepper myStepper(stepsPerRevolution, 8,9,10,11);            

void setup() {
  // establece la velocidad en 60rpm
  myStepper.setSpeed(60);
  // inicializa el puerto serial
  Serial.begin(9600);
}

void loop() {
  // gira una vuelta en una dirección
  myStepper.step(stepsPerRevolution);
  delay(500);
  
  // gira uns vuelta en la otra dirección
  myStepper.step(-stepsPerRevolution);
  delay(500); 
}

Continuamos construyendo el invernadero.

Encendido y apagado de la bomba de agua.

Para esto utilizaremos un relé. Un relé es un dispositivo electromecánico que permite a un procesador como Arduino controlar cargas a un nivel tensión o intensidad muy superior a las que su electrónica puede soportar.

Por ejemplo, con una salida por relé podemos encender o apagar cargas de corriente alterna a 220V e intensidades de 10A, lo cual cubre la mayoría de dispositivos domésticos que conectamos en casa a la red eléctrica.

La conexión es muy sencilla, en el esquema aparece una bombilla, pero sería lo mismo para una bomba de agua. De la misma forma aparece conectado al pin 10, como lo tendremos ocupado nosotros lo conectaremos al pin 6.

Código

El código es realmente muy sencillo, es apagar y encender el pin 6, que en este caso envía un pulso de 5v al relé y le permite manejar voltajes más altos y encender cualquier aparato electrónico común en casa.

const int control = 6 ;

void setup()
    {
         pinMode(control,  OUTPUT) ;
    }
void loop()
    {
         digitalWrite(control, HIGH);
         delay(1000);
         digitalWrite(control, LOW);
         delay(1000);
    }

Uniendo programas.

Vamos a unir los programas que gestionan el sensor de temperatura, el de humedad y el control del motor paso a paso.

Si la temperatura sobrepasa lo 20 grados abriremos la puerta superior (6 vueltas de motor paso a paso) y encenderemos un ventilador que hemos conectado al pin 12. Utilizaremos una variable boolean para saber si la puerta está abierta o no, así evitaremos abrir la puerta más de una vez.

#include <DHT_U.h>
#include <DHT.h>
#include <Stepper.h>

#define DHTTYPE DHT22
#define sensor A0

const int pinVentilador = 12;
const int DHTPin = 13;
const int sensorPin = A0;
const int stepsPerRevolution = 200;
const int pinBomba = 5;

int cont;
boolean abierta = false;

DHT dht(DHTPin, DHTTYPE);
Stepper myStepper(stepsPerRevolution, 6, 7, 8, 9);

void setup() {
pinMode(sensorPin, INPUT);
pinMode(pinVentilador, OUTPUT);
pinMode(pinBomba, OUTPUT);
Serial.begin(9600);
Serial.println(«DHTxx test!»);
dht.begin();
// velocidad a 60 rpm:
myStepper.setSpeed(60);
}
void loop() {
//Esperamos algunos segundos para medir.
delay(100000);
// Leemos temperatura y humedad
float h = dht.readHumidity();
float t = dht.readTemperature();
//Se hace la lectura analoga del pin A0
//map() para ajustar los valores leidos
int valorHumedad = map(analogRead(sensor), 0, 1023, 100, 0);

if (isnan(h) || isnan(t)) {
Serial.println(«Falló la lectura sensor!»);
}
else
{
Serial.print(«{\»humedad\»:»);
Serial.print(h);
Serial.print(«,»);
Serial.print(«\»temperatura\»:»);
Serial.print(t);
Serial.print(«,»);
Serial.print(«\»humedadSuelo\»:»);
Serial.print(valorHumedad);
Serial.print(«,»);
Serial.print(«\»puerta\»:»);
if (abierta)
Serial.print(15);
else
Serial.print(0);
Serial.println(«}\n»);
}

if ((t >= 20) && (abierta == false)) {
digitalWrite(pinVentilador,HIGH);
abrirpuerta();
abierta = true;
}
if ((t <= 18) && (abierta == true)) {
cerrarpuerta();
digitalWrite(pinVentilador,LOW);
abierta = false;
}
if ((valorHumedad<= 50)) {
digitalWrite(pinBomba, LOW);
delay(10000);
}
else{
digitalWrite(pinBomba, HIGH);
delay(100);
}
}
void abrirpuerta() {
for (cont = 0; cont < 6; cont++) { //6 será el máximo
// Serial.println(«clockwise»);
myStepper.step(stepsPerRevolution);
delay(500);
}
}
void cerrarpuerta() {
for (cont = 0; cont < 6; cont++) {
// Serial.println(«clockwise»);
myStepper.step(-stepsPerRevolution);
delay(500);
}
}

Conectando la Raspberry PI

Veamos el software que vamos a utilizar, por una parte una base de datos Mysql para guardar los datos y mostrarlos posteriormente con servidor web Apache.

Seguiremos el siguiente esquema:

En primer lugar, los sensores envían los datos al Arduino, este manda una cadena en formato JSON, a la Raspberry Pi por medio del puerto serie a un proceso Python que se ejecuta en segundo plano. Este proceso recibe la información y lo envía a una base de datos Mysql.

Cuando un usuario accede a la web, se recoge la información de la base de datos y se muestra al usuario por medio de una gráfica.

Una vez preparado nuestro Arduino, vamos a crear la base de datos; para ello, necesitaremos el motor de base de datos Mysql (MariaDB también nos sirve); por lo que usaremos el comando correspondiente para instalarlo. Para instalar Mysql en Raspbian, usaremos el siguiente comando:

#apt-get install mysql-server

Con el servidor ya instalado, vamos a pasar a crear una base de datos y a crear una tabla; para ello usaremos el siguiente comando para conectarnos a nuestra base de datos:

#sudo su
#mysql -u root -p

Introducimos la contraseña del usuario root que hemos tenido que crear al instalar Mysql. Ahora estamos dentro del interprete de Mysql y vamos a crear la base de datos. El siguiente comando creará una base de datos y crearemos una tabla dentro de dicha base de datos.

>CREATE DATABASE Invernadero;
>USE Invernadero;
>CREATE TABLE Datos(id BIGINT(20) PRIMARY KEY AUTO_INCREMENT , fecha datetime, temp DECIMAL, hum DECIMAL, humSuelo DECIMAL, puerta TINYINT);
>exit

Tras crear la tabla correctamente, ya estamos preparados para pasar a crear el proceso en segundo plano que inserte en la base de datos; para ello recurriremos a python.

Verificar que el sistema cuente con Python instalado:

root@devuan:~# python --version
Python 2.7.9

Si no se encuentra instalado, ejecutar:

# apt-get install python

Y por lo tanto tenemos que instalar una serie de librerías necesarias para poder conectarnos en primer lugar al puerto serie USB y por otro lado poder guardar la información en la base de datos.

Instalar la librería Pyserial para conectarnos por puerto serie a nuestro Arduino. Para instalar esta librería utilizaremos la utilidad Pip para Python.

#pip install pyserial

Ya hemos terminado de configurar todo lo necesario para crear el proceso en segundo plano. Seguidamente crearemos un fichero al que llamaremos leeDatos.py y añadiremos el siguiente código donde se recoge la información y la graba a la base de datos.

#!/usr/bin/env python

import serial 
import json 
import mysql.connector

# Variable con la configuracion de la conexion
config_mysql = {
    'user': 'mypywebapp',
    'password': '123456',
    'host': 'localhost',
    'database': 'Invernadero',
}


arduino = serial.Serial('/dev/ttyUSB0', baudrate=9600, timeout=1.0)
while True: 
    character= arduino.readline()
    MyJson = character 
    db = mysql.connector.connect(**config_mysql)
    if character != '\n': 
      try:
        print (character)
        data=json.loads(character) 
        print ("222")
        curs = db.cursor()
        # Creamos la consulta SQL
        query = ("INSERT INTO Datos(fecha,temp,hum,humSuelo,puerta) values(now(),"+str(data['temperatura'])+","+str(data['humedad'])+","+str(data['humedadSuelo'])+","+str(data['puerta'])+")")    
        # Ejecutamos la consula SQL
        print (query)
        curs.execute(query)   
        printº
        db.commit() 
      except ValueError: 
        print ("Error")  
arduino.close()
# Cerramos cursor
curs.close()

# Cerramos la conexion
db.close()

El Script anterior se conecta al Arduino por puerto serie y cada vez que recibe los datos en JSON, los analiza y después lo inserta en la base de datos por medio de una sentencia SQL into.

Podemos comprobar que todo se ha hecho correctamente por medio de una consulta SQL; conectándonos a nuestra Raspberry Pi y entrando de nuevo al interprete SQL. En el interprete ejecutamos la siguiente sentencia.

SELECT * FROM Datos;

Una vez que tenemos este proceso listo, vamos a pasar a crear la web. para ello vamos a crear un script CGI para Python. Para lo cual necesitaremos instalar el servidor web apache. Para instalarlo, usaremos el siguiente comando.

#apt-get install apache2

Si falla la instalación podemos actualizar el sistema con:

#apt-get update
#apt-get upgrade

Configuración de Apache

Para poder ejecutar scripts Python, es necesario habilitar el módulo cgi (Common Gateway Interface). Sin embargo, cuando se utiliza un servidor multihilado se debe reemplazar por cgid. Así que, dependiendo del tipo de instalación, se deberán ejecutar los siguientes comandos para que Apache tenga la capacidad de ejecuar scripts Python.

Si se utiliza prefork:

# a2enmod mpm_prefork cgi

Si en cambio se utiliza event (por defecto):

# a2enmod mpm_event cgid

O si se utiliza worker:

# a2enmod mpm_worker cgid

Luego será necesario reiniciar Apache.

A continuación, crear un directorio de trabajo donde alojar la aplicación Web que contiene scripts Python:

# mkdir /var/www/mypyweb

Editar el archivo de configuración del sitio Web por defecto (/etc/apache2/sites-available/000-default.conf) para que este directorio sea la raíz del servidor, y sea posible ejecutar scripts Python:

        DocumentRoot /var/www/mypyweb

        <Directory /var/www/mypyweb>
                Options +ExecCGI
                DirectoryIndex index.py
        </Directory>
        AddHandler cgi-script .py
        AddDefaultCharset utf-8

Notar que se ha indicado en la configuración del directorio /var/www/mypyweb que el archivo por defecto es index.py.

Ahora sí, reiniciar Apache para que tome todos los cambios:

# service apache2 restart

Creación de un script Python para verificar el acceso mediante HTTP

Cambiar al directorio de la aplicación para crear el archivo índice:

# cd /var/www/mypyweb/

Crear el archivo por defecto index.py:

# nano index.py

Agregar el siguiente contenido a modo de prueba simple de ejecución de código Python:

#!/usr/bin/python
# coding=utf-8

# Imprimir los headers HTTP
print("Content-Type: text/html")
print("")

# Imprimir el contenido de la página
print("<h2>Hola mundo</h2>")
print("<p>Prueba de ejecución de script Python en modo CGI.</p>")

Luego ajustar los permisos adecuadamente:

# chown root:www-data index.py 
# chmod +x index.py 

Se cambia el grupo para que Apache tenga acceso de lectura y se otorga ejecución para todo el mundo. El dueño puede cambiarse según sea necesario (en este ejemplo se deja «root» para que Apache no pueda alterar el contenido del script).

Es posible verificar el script desde línea de comandos:

# ./index.py 
Content-Type: text/html

<h2>Hola mundo</h2>
<p>Prueba de ejecución de script Python en modo CGI.</p>

Habiendo comprobado que no posee errores, acceder nuevamente al sitio desde un navegador.

Acceso a una base de datos MySQL desde Python

Por último, resta verificar el acceso a una base de datos MySQL desde Pyhton. Para ello se requiere instalar el paquete pymysql provisto por Python (no por la distribución). Estos paquetes se gestionan con la herramienta pip:

# apt-get install python-pip

Luego de instalar pip, es posible instalar el paquete pymysql que provee acceso a bases de datos MySQL desde scripts Python:

# pip install pymysql
Downloading/unpacking pymysql
  Downloading PyMySQL-0.7.2-py2.py3-none-any.whl (76kB): 76kB downloaded
Installing collected packages: pymysql
Successfully installed pymysql
Cleaning up...

A continuación, es recomendable crear un usuario MySQL para la aplicación Web (jamás utilizar el usuario «root» de MySQL). Conectarse al servidor y ejecutar la consulta create user 'mypyweb'@'localhost' identified by '123456'; para crear al usuario «mypyweb» con contraseña «123456» que tiene restringido el acceso sólo desde localhost:

# mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  ....

mysql> create user 'mypywebapp'@'localhost' identified by '123456';
Query OK, 0 rows affected (0.00 sec)

mysql> quit
Bye

Editar nuevamente el archivo index.py:

# nano index.py

Y agregar las siguientes líneas al final del mismo:

# Mostrar la versión de MySQL
import pymysql
con = pymysql.connect(db='', user='mypyweb', passwd='123456', host='localhost')
c = con.cursor()
c.execute("select @@version")
v = c.fetchall()[0]
print("<p>La versión de MySQL es: <b>%s</b></p>" % v)

Guardar los cambios y verificar el correcto funcionamiento del circuito Apache-Python-MySQL.

Nuestra página para mostrar los datos guardados en la BBDD.

#!/usr/bin/python
# coding=utf-8

import pymysql

print("Content-Type: text/html")
print("")
print "<html>"
print "<head>"
print "  <script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>"
print "  <script type=\"text/javascript\">" 
print "        google.charts.load('current', {'packages':['corechart']});"
print "        google.charts.setOnLoadCallback(drawChart);"
con = pymysql.connect(user='mypywebapp', passwd='123456', host='localhost', db='Invernadero')
c = con.cursor()
c.execute("SELECT * FROM Datos Order by fecha LIMIT 15")
print "function drawChart() {"
print "var data = google.visualization.arrayToDataTable(["
print          "['Fecha', 'Temperatura', 'Humedad Aire', 'Humedad Tierra']"
for data in c.fetchall():
    print ",\n['"+str(data[1])+"',"+str(data[2])+","+str(data[3])+","+str(data[4])+"]"
print        "]);"
con.close() 
print "var options = {"
print          "title: 'Invernadero',"
print          "curveType: 'function',"
print          "legend: { position: 'bottom' }"
print        "};"
 
print        "var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));"
 
print        "chart.draw(data, options);"
print      "}"
print    "</script>"
print "</head>"
print "<body>"
print "    <div id=\"curve_chart\" style=\"width: 900px; height: 500px\"></div>"
print "</body>"
print "</html>"

Este script muestra la página web, como una gráfica a partir de los datos obtenidos de la base de datos.

Una vez todo listo, vamos a pasar a encender el sistema; en primer lugar encenderemos el proceso en segundo plano con el siguiente comando.

#python leeDatos.py &;

y por último, si todo va bien, solo tenemos que acceder a la dirección web: http://localhost/ desde nuestra Raspberry Pi y aparecerá en pantalla la información de temperatura, humedad,….