Monitor inteligente de Calidad del aire


En esta etapa de la historia que nos hemos visto abocados a vivir, dadas las vías de contagio del coronavirus, se hace necesario evaluar la calidad del aire que respiramos para intentar minimizar las vías de contagio dado que ha quedado demostrado por la comunidad científica que el aire es precisamente una de las principales vías de propagación.

Toser, cantar, hablar o incluso respirar envía aerosoles y otras sustancias en suspensión en una variedad de tamaños de modo que cuanto más cerca esté del origen, mayor será la posibilidad de exposición a esas cotícelas  potencialmente  cargadas de virus que podrían inhalarse o caer en sus ojos, es por eso que muchos científicos también se están preocupado por los riesgos potenciales de los aerosoles, ya que la más pequeña de estas partículas pueden flotar a través de las habitaciones y causar infecciones. Por todo ello, es una preocupación mayor cuando la ventilación es deficiente porque se pueden acumular partículas en el aire y con ello potencialmente contagiar a las personas que se expongan, si bien la Organización Mundial de la Salud reconoció recientemente que no se puede descartar la transmisión por aerosol en algunas situaciones, enfatizando que se necesita más investigación para demostrar de manera concluyente su papel en la propagación del virus, aunque en todo caso tal y como han demostrado las estadísticas   haciendo uso generalizado de mascarillas reducimos el riesgo.

No obstante, a pesar de usar medios de protección, los riesgos de transmisión de COVID-19 en habitaciones abarrotadas y condiciones de mala ventilación, y en cualquiera de estos entornos, el tiempo es clave, por lo que cuanto más tiempo pase alguien en un espacio mal ventilado o lleno de gente, mayor será el riesgo previsto de enfermarse.  

Además, si algún día logramos la ansiada inmunidad de rebaño, existen además evidencias de que los altos niveles de CO2 influyen sobre el rendimiento de los alumnos en el aula o en los espacios de trabajo, así que aun así deberíamos estar pendientes de este valor simplemente por mejorar nuestra salud.

Para evaluar la calidad de aire, uno de los principales indicadores es la cantidad de material particulado (PM), que a menudo se clasifica además por sus tamaños, por ejemplo, PM2.5 y PM10, pero, sin embargo, se vuelve más complejo medir compuestos orgánicos volátiles (COV) u otros componentes como el formaldehído(HCHO) y los pesticidas. Asimismo, tanto el CO2 como CO son otros contaminantes potencialmente mortales pues sirve como un indicador de las personas que han estado en una estancia

Investigaciones de este tipo pues nos pueden motivar a elaborar un pequeño dispositivo de bajo coste que permita monitorizar los niveles de CO2 en espacios cerrados con el objeto de poder medir la concentración de dicho gas y de esta forma saber cuándo tenemos que renovar el aire de un aula o espacio cerrado (o incluso en nuestra casa) para prevenir posibles contagios

En un reciente informe del 03/11/2020 [9] nos habla con datos de la importancia de la ventilación y de la necesidad de ventilar en las aulas más allá de lo que indican muchos de los protocolos vigentes en muchas comunidades autónomas: El muestreo de mediciones realizado en centros educativos por el Comité de Expertos en Ventilación del COGITI, confirma la necesidad de contar con medidores de CO2

Con un simple NodeMCU, y al menos un sensor de CO2 con una plataforma de IOT vamos a ver como es muy fácil construir un sistema simplificado que permita indicar cuando los niveles de CO2 están dentro de unos determinados umbrales, monitorizar por ejemplo los datos de distintas aulas de forma centralizada, almacenar datos estadísticos en una base de datos o realizar otras muchas tareas que podrían sernos útiles sin incrementar prácticamente el coste del dispositivo.

Las partes del proyecto: Cayenne,sensores y ESP32

Una de las plataformas alejadas de las grandes multinacionales que más se ha mantenido en el tiempo es la plataforma Cayenne de myDevices ofreciendo un amplio abanico de posibilidades.

Además, cuenta con apoyos de grandes empresas de la industria tecnológica como Microchip y Smetch y del hardware libre como Arduino permitiéndonos crear paneles de control de una forma muy sencilla arrastrando y soltando widgets para visualizar, gestionar y controlar dispositivos conectados del IoT o domóticas todo a través de un broker MQTT.

Entre todos los servicios que nos ofrece la plataforma caben destacar el control y monitorización remoto, alertas, avisos, programación de eventos, tratamientos de datos, seguimiento de dispositivos, código personalizado, una API MQTT y compatibilidad con redes LoRaWAN.

Soporta varios tipos de placas y hardware: Raspberry Pi, Arduino, ESP8266 y varias redes y dispositivos LoRaWan.  También cabe destacar las cajas del IoT o IoT in a Box donde básicamente “paquetizan” una solución incluyendo en este paquete todo el hardware necesario incluyendo además los paneles de control personalizados para monitorizar ese hardware.

Gracias pues a esta veterana plataforma de Cayenne, es bastante sencillo monitorizar cualquier variable física de un modo realmente bastante sencillo simplemente haciendo casi un “drug &drop” desde el panel de control de Cayenne como vamos a ver en este trabajo donde vamos a presentar un complejo monitor de calidad de inalámbrico y de bajo coste gracias la potencia del software de esta plataforma y por supuesto la electrónica que lo hace posible.

En efecto   gracias a un framework genérico desarrollado por myDevices IO Project Builder llamado Cayenne, desarrolladores, fabricantes también aficionados pueden construir rápidamente prototipos y proyectos que requieran controlar o monitorizar   cualquier cosa conectada a diferentes placas con conectividad, permitiendo con una sola cuenta gratuita de Cayenne, crear un número ilimitado de proyectos mediante una solución bastante intuitiva   basada en arrastrar y soltar. 

Obviamente el punto fuerte de Cayenne son las capacidades de IO para que pueda controlar de forma remota sensores, motores, actuadores, incluidas los puertos de GPIO con almacenamiento ilimitado de datos recogidos por los componentes de hardware, triggers y alertas, que proporcionan las herramientas necesarias para la automatización y la capacidad de configurar alertas. Además, también puede crear cuadros de mando personalizados para mostrar su proyecto con arrastrar y soltar widgets que también son totalmente personalizables.

Resumidamente algunas de estas características clave de esta ya veterana plataforma son las siguientes:

  • Fácil instalación que conecta rápidamente los dispositivos, sensores, actuadores, y las extensiones en cuestión de minutos.
  • Motor de reglas para desencadenar acciones a través de dispositivos.
  • Panel personalizable con widgets de visualización de arrastrar y soltar.
  • Para construir un proyecto de la IO a partir de cero se ha logrado el objetivo de proporcionar un Proyecto Generador de IO que reduce el tiempo de desarrollo de horas en lugar de meses.
  • Control de puertos que se pueden configurar desde una aplicación móvil o desde un navegador
  • Acceso remoto instantáneo desde su smartphone o con un ordenador
  • Una aplicación móvil tanto para IOS como para Android para configurar, el monitor y los dispositivos de control y sensores desde cualquier lugar.

Este proyecto obviamente no serviría para nada si no contara con los sensores correspondientes que nos va a ofrecer las mediciones físicas 

  • Un sensor MQ: suelen proporcionarse con una placa de medición estándar con el comparador LMC662 o similar, que permite obtener la lectura tanto como un valor analógico, como un valor digital cuando se supera un cierto umbral regulado a través de un potenciómetro ubicado en la placa. Los sensores de gases deben ser calibrados antes de obtener una medida precisa, pero también ofrecen una señal analógica que podemos usar en nuestras medidas.
  • Un sensor DHT11: El DHT11 puede medir temperaturas entre 0 a 50, con una precisión de 2ºC, humedad entre 20 a 80%, con precisión del 5% y con una a frecuencia de muestreo de 1 muestras por segundo (1 Hz) usando un interfaz de un hilo para comunicarse con el microcontrolador
  • Un sensor CCS811: Constituye el   elemento más importante de este proyecto. Este sensor de calidad del aire de dióxido de carbono está fabricado por múltiples empresas como Keyestudio, AMS, Adafruit, etc. utilizando principalmente el chip CCS811.  Este sensor de gas digital en miniatura de potencia ultrabaja, es de “bajo coste” y puede detectar una amplia gama de compuestos orgánicos volátiles (TVOC), incluidos niveles equivalentes de dióxido de carbono (eCO2) y óxido metálico (MOX). Incluye un conversor ADC interno, un procesador interno para realizar los cálculos y comunicación a través de a través de bus I2C por lo que es muy sencillo conectarlo a un microcontrolador.

Finalmente, como microcontrolador usaremos el sucesor del veterano SoC ESP8266(Node) que ha dado paso al ESP32 (Node MCU) la cual es la denominación de una familia de chips SoC de bajo costo y consumo de energía, con Wi-Fi y Bluetooth de modo dual integrada empleando el microprocesador Tensilica Xtensa LX6 (creado y desarrollado por Espressif Systems y fabricado por TSMC utilizando su proceso de 40 nm). Tiene variantes de simple y doble núcleo e incluye interruptores de antena, balun de radiofrecuencia, amplificador de potencia, amplificador receptor de bajo ruido, filtros, y módulos de administración de energía.

Con todos estos elementos, gracias a Cayenne, veremos cómo es posible construir un potente medidor de calidad de aire que sin duda nos va poder ayudar a comprender las vías de transmisión de este grave virus que está paralizando de una forma tan extrema nuestro mundo.

La plataforma Cayenne

Si entramos en la web de Cayenne myDevices podemos que no encuentras ninguna opción donde se vean los planes disponibles, no hay mucha información. Sin embargo, nos podemos dar de alta y comenzar a utilizar su servicio puesto que el modelo de negocio de esta plataforma se sustenta en su Marketplaces con soluciones terminadas para los clientes, así que investigadores, aficionados, estudiantes, etc.  podemos utilizar esta plataforma para crear nuestros proyectos sin pagar un solo euro (o dólar).

Todo se comunica a través de una API MQTT y la única limitación podría venir a la hora de hacer llamadas a la API.

  • Cada cliente sólo puede enviar 60 mensajes por minuto por IP.
  • Cada cliente sólo puede intentar 50 conexiones cada 10 minutos por IP.

Estas limitaciones no hacen referencia al número de dispositivos, pero si al cómputo global de mensajes enviados y de intentos de conexión.

En teoría, además al contrario de lo que sucede en otras plataformas, no hay problemas a la hora de descargar los datos almacenados en la plataforma, tan solo los intrínsecos provocados por tamaños excesivos en los ficheros a de descargar por su gran tamaño o por posibles problemas de red

Dentro de la plataforma hay dos componentes que nos permitirán controlar y manejar nuestros dispositivos hardware:

  • Aplicaciones móviles para iOS y Android para control remoto de los dispositivos.
  • Panel de control online para la gestión total de nuestros dispositivos.

Para crear un proyecto del IoT o domótica con Cayenne sólo necesitaremos una placa o hardware compatible (Raspberry Pi, Arduino, ESP8266, etc), lo cual en nuestro caso por su gran versatilidad y potencia lo vamos a centrar en la mencionada placa ESP32

Respecto al software, necesitaremos instalar la librería de Cayenne además no solo podemos manejar el interfaz desde su página web pues también tenemos disponible una APP en Android o iOS.

Para empezar necesitamos  irnos  a Log in to Cayenne (mydevices.com)   creando una cuenta gratuita en Cayenne myDevices  donde  sólo necesitamos nombre y apellidos, un email y una contraseña. Una vez que nos hemos dado de alta, nos tendremos que volver a validar y desde este momento ya podremos acceder al panel de control de la cuenta que acabamos de crear.

 Antes de continuar necesitaremos instalar la librería Cayenne MQTT con el IDE de Arduino Esta librería nos va a permitir conectar nuestras placas, ya sean Arduino MKR1000 o cualquier placa ESP8266, a la plataforma del IoT en la nube Cayenne myDevices. Lo haremos a través del gestor de librerías.

Entre en la opción del menú Programar>Incluir Librería>Gestionar Librerías y buscar cayennemqtt. Esto instalará tanto el código como los ejemplos de esta librería. Con esto ya tenemos todo preparado para empezar a configura nuestro proyecto ya que Cayenne myDevices es totalmente compatible con Arduino y todas sus variantes de modo que es muy sencillo de configurar. Si no ha añadido ningún dispositivo o placa a Cayenne myDevices, la primera pantalla que sale es esta.

Seleccionaremos Generic ESP8266 en el caso de que vayamos a configurar incluso si ESp32) y en la siguiente pantalla nos está indicando que debemos hacer los siguinte:

  • Nos aseguráremos que el ESP32 está conectada al PC o Mac con el cable USB.
  • Instale el IDE de Arduino.
  • Instale la librería Cayenne MQTT.
  • Seleccione la placa y el puerto correctos en el IDE de Arduino.

Todo esto ya está hecho y si no lo está, tendría que hacerlo para poder proseguir. Una vez esté configurado haga clic en Next, apareciéndonos nada más seleccionar la placa, una ventana donde muestra un código. Copiar y pegar ese código en un nuevo programa en el IDE de Arduino (se puede copiar haciendo clic en el botón superior derecha una pantalla similar a la siguiente).

En este código ya viene configurado el username, password y el clientID necesarios para conectar a Cayenne myDevices. Sin embargo, nos queda rellenar el nombre de la red WiFi (ssid) y la contraseña (wifiPassword).

Ahora sólo nos queda cargar el código a la placa. Abra el monitor serie y tendrá algo parecido a esto.

Si todo ha ido bien, aparecerá el Generic ESp32 a la izquierda dentro de la plataforma Cayenne myDevices.

Configurar dispositivo en Cayenne myDevices

Si hacemos clic en el engranaje de la derecha, podemos entrar en la configuración del dispositivo

En esa pantalla podremos modificar el nombre, pero sobre todo es aquí donde obtendremos todos los parámetros del dispositivo   que necesitaremos configurar en ESP32 para que se pueda conectar y enviar o recibir datos de la plataforma Cayenne.

Configurada esta parte ya podremos añadir los sensores, así como programar acciones interactivas al satisfacer alguna condición, pero esa parte la vamos a comentar más adelante cuando comentemos que tipo de sensores vamos a emplear, así como su característica más importante.

Sensores DHTXX

Dado que es interesante correlacionar temperatura y humedad con la calidad del aire (de hecho, hay sensores de alta precisión y coste elevado que incluyen estas medidas) en este proyecto se ha optado por un usar un sensor de precisión como es el DHT11 con objeto que complete el resto de medidas que se realicen.

DHT11 y DHT22 son dos modelos de una misma familia de sensores, que permiten realizar la medición simultánea de temperatura y humedad usando además un único hilo para comunicar los datos vía serie, para lo cual ambos disponen de un procesador interno que realiza el proceso de medición, proporcionando la medición mediante una señal digital, por lo que resulta muy sencillo obtener la medición desde un microprocesador como Arduino, ESP8266 o el Node MCU que usaremos.

Ambos son similares pero el DHT11 presenta una carcasa azul (es el que usaremos en la práctica), mientras que el sensor DHT22 es blanco, compartiendo además los mismos pines disponiendo de 4 patillas, de las cuales usaremos sólo 3: Vcc, Output y GND.  Como peculiaridad, la salida la conectaremos a una entrada digital, pero necesitaremos poner una resistencia de 10K entre Vic y el Pin Output, pero existen unos módulos que integran esta junto con los pines VCC, OUT y GND.

El DHT11 puede medir temperaturas entre 0 a 50, con una precisión de 2ºC, humedad entre 20 a 80%, con precisión del 5% y con una a frecuencia de muestreo de 1 muestras por segundo (1 Hz)

En clara superioridad con el dHT11, el modelo DHT22 tiene unas características mucho más profesionales.

  • Medición de temperatura entre -40 a 125, con una precisión de 0.5ºC
  • Medición de humedad entre 0 a 100%, con precisión del 2-5%.
  • Frecuencia de muestreo de 2 muestras por segundo (2 Hz)

Destacar que este tipo de sensores de temperatura (y, aún más, los sensores de humedad), son sensores con elevada inercia y tiempos de respuesta elevados. Es decir, al “lentos” para reflejar los cambios en la medición.

Conectar el DHT11   o el DHT22 a un Arduino o al Node MCU es sencillo, simplemente alimentamos desde Arduino al sensor a través de los pines GND y Vcc del mismo. Por otro lado, conectamos la salida Output a una entrada digital de Arduino. Según la composición que adquiramos necesitaremos poner una resistencia de 10K entre Vcc y el Pin Output, aunque actualmente se venden módulos con el sensor montado con la resistencia ya integrada e incluso con un orificio para poder fijarlo a un soporte (es la razón por la que solo tienen tres pines).

El esquema eléctrico quedaría como la siguiente imagen:

Los sensores DHT11 y DHT22 usan su propio sistema de comunicación bidireccional mediante un único hilo, empleando señales temporizadas por lo que en general, lo normal es que empleemos una librería existente para simplificar el proceso. Por ejemplo podemos usar la librería de Adafruit disponible  en https://github.com/adafruit/DHT-sensor-library

 Como vemos el circuito para conectar al Node MCU   el sensor de temperatura y humedad DHT11 no puede ser más sencillo, pues simplemente alimentaremos con 3.3v DC tanto el DHT11 como el Node MCU   en sus pines correspondiente     sin olvidar que la salida de datos del DH11pin datos) tenemos que conectarla al pin 5 del GPIO.

Para esta parte del proyecto al usar el ESP32, vamos a usar en resumen los siguientes pines del ESP32 al DHT11:

  • GPIO23 (pin15): conexión al DHT11
  • VCC(pin1): conexión +5V al DHT11
  • GND(pin2): conexión GND al DHT11

SENSOR DE GASES MQ

Los sensores de gases MQ son una familia de dispositivos diseñados para detectar la presencia de distintos componentes químicos en el aire. Podemos conectar estos dispositivos a un autómata o procesador como Arduino. Existe una gran variedad de sensores MQ y cada modelo está diseñado para detectar una o más sustancias, pensadas para un uso específico, como por ejemplo detección gases inflamables, calidad del aire o detección de alcohol en aire respirado.

Los sensores de gases MQ suelen proporcionarse con una placa de medición estándar con el comparador LMC662 o similar, que permite obtener la lectura tanto como un valor analógico, como un valor digital cuando se supera un cierto umbral regulado a través de un potenciómetro ubicado en la placa. Los sensores de gases deben ser calibrados antes de obtener una medida precisa. Aun calibrados estos sensores no disponen de la garantía necesaria para formar parte de un sistema de seguridad.

Pese a sus limitaciones, los sensores de gases tipo MQ son muy usados en proyectos de electrónica casera con Arduino. Por ejemplo, podemos hacer encender o apagar un ventilador en función de la calidad del aire, hacer un pequeño detector de alcoholemia, o una alama que suene al detectar humos.

Los sensores MQ están compuestos por un sensor electro-químico que varía su resistencia al estar en contacto con las sustancias. Estos s sensores de gases son dispositivos con alta inercia, es decir, la respuesta necesita tiempos largos para estabilizarse tras un cambio de concentración de los gases medidos. Ello es debido a la necesidad física de que el gas abandone el material sensible, lo cual es un proceso lento.

Todos los modelos MQ disponen de un calentador necesario para elevar la temperatura del sensor, y que sus materiales adquieran la sensibilidad. Mientras el calentador no alcance la temperatura de funcionamiento, la lectura del sensor no será fiable. El tiempo de calentamiento depende de cada modelo de sensor. En la mayoría de modelos es suficiente para con unos pocos minutos, pero algunos modelos requieren hasta 12 y 48 horas hasta obtener mediciones estables.

Por otro lado, cada modelo necesita su propia tensión para alimentar el calentador. En muchos modelos esta tensión es de 5V, pero algunos modelos tienen condicionantes especiales para la alimentación.

El consumo de los sensores MQ puede ser elevado debido al calor necesario para funcionar el calentador, que puede llegar hasta 800 mW en algunos modelos. Esto es superior a la potencia que puede suministrar el regulador de Arduino, por lo que será necesario proporcionar una fuente de alimentación externa.

A continuación, podemos ver una tabla de resumen con los distintos modelos de sensores disponibles, los gases a los que son sensibles, y algunos datos sobre el calentador, aunque no obstante deberíamos consultar detalladamente el Datasheet de cada sensor MQ particular antes de emplearlo para detallar sus especificaciones técnicas, especialmente la tensión de alimentación del calentador, el tiempo de calentamiento, y la curva de sensibilidad del sensor.

ModeloSustancias detectadasCalentador
MQ-2Metano, butano, GLP, humo5V
MQ-3Alcohol, Etanol, humo5V
MQ-303AAlcohol, etanol, humo0.9V
MQ-4Metano, gas natural comprimido (GNP)5V
MQ-5Gas natural, GLP5V
MQ-6Butano, GLP5V
MQ-306AButano, GLP0.9V
MQ-7Monóxido de carbonoAlternado 5V y 1.4V
MQ-307AMonóxido de carbonoAlternado 0.2 y 0.9V
MQ-8Hidrógeno5V
MQ-9Monóxido de carbono, gases inflamablesAlternado 5V y 1.5V
MQ-309AMonóxido de carbono, gases inflamablesAlternado 0.2 y 0.9V
MQ-131Ozono6V
MQ-135Benceno, alcohol, humo, calidad del aire5V
MQ-136Ácido sulfhídrico5V
MQ-137Amoniaco5V
MQ-138Benceno, tolueno, alcohol, acetona,5V
propano, formaldehído, hidrógeno
MQ-214Metano, gas natural5V
MQ-216Gas natural, gas carbón6V
MG-811Dióxido de carbono6V
AQ-104Calidad del aire * 
AQ-2Gases inflamables, humo 
AQ-3Alcohol, Benceno 
AQ-7Monóxido de carbono 

* Conviene amplificación

SENSOR MQ2

El módulo del sensor de gas MQ-2 es un dispositivo que se utiliza para detectar y medir la concentración de gases en el aire. Puede detectar tales gases como: GLP, propano, metano, hidrógeno, alcohol, humo y carbono monóxido. Aunque puede detectar esos gases, no es capaz de distinguir diferencia entre ellos.

El MQ-2 es un semiconductor de óxido metálico (MOS), también conocido como quimiorresistor. El sensor contiene un material sensor cuya resistencia cambios con diferentes concentraciones de gas. Este cambio de resistencia es utilizado para la detección de gas. El sensor también tiene un potenciómetro incorporado, con que podemos ajustar su sensibilidad.

El sensor está encerrado dentro de dos capas de malla fina de acero inoxidable llamada Red anti-explosión. Como resultado de eso, es capaz de detectar inflamables gases sin incidencias. Asimismo, brinda protección al sensor, y filtra las partículas en suspensión. De esa manera, solo los gases pueden pasar dentro de la cámara de detección.

El módulo tiene un chip comparador LM393 integrado que convierte las lecturas en señales digitales y analógicas. También hay un potenciómetro que se utiliza para calibrar la sensibilidad de detección

Estas son las especificaciones del sensor:

Para obtener los mejores resultados de detección, el sensor de gas debe precalentarse. El mejor tiempo de precalentamiento del sensor es superior a 24 horas. Para obtener información detallada sobre las especificaciones del sensor, consulte la hoja de datos.

La sensibilidad del módulo se puede ajustar con un potenciómetro integrado. Mover el eje del potenciómetro en el sentido de las agujas del reloj aumenta la sensibilidad. Mover el eje del potenciómetro en sentido anti horario disminuye la sensibilidad del módulo.

Conexiones del MQ2

El módulo del sensor de gas tiene cuatro pines cuyo pinout se muestra en la siguiente imagen:

El esquema eléctrico es sencillo pues solo tenemos que alimentar módulo conectando GND y 5V a los pines correspondientes de Arduino y bien podemos usar la lectura digital, conectamos la salida DO a una de las entradas digitales. (Opcionalmente, podemos calibrar el umbral de disparo de la salida digital con el potenciómetro instalado en el módulo) o bien como en nuestro caso usar una entrada analógica AO conectada a una entrada analógica de nuestro ESP32.

LECTURA DIGITAL

El siguiente código muestra la lectura digital del sensor MQT2. El código es muy sencillo pues simplemente utilizamos una entrada digital para comprobar el estado del sensor, empleando el puerto serie para informar de la detección.

#define DIGITAL_PIN 2

#define ANALOG_PIN 0

uint16_t gasVal;

boolean isgas = false;

String gas;

void setup() {

Serial.begin(9600);

pinMode(DIGITAL_PIN, INPUT);

}

void loop() {

gasVal = analogRead(ANALOG_PIN);

isgas = digitalRead(DIGITAL_PIN);

if (isgas) {

gas = "No";

}

else {

gas = "Yes";

}

gasVal = map(gasVal, 0, 1023, 0, 100);

Serial.print("Gas detected: ");

Serial.println(gas);

Serial.print("Gas percentage: ");

Serial.print(gasVal);

Serial.print("%\n");

delay(2000);

}

El sketch comienza con la definición y creación de dos macros llamadas DIGITAL_PIN, ANALOG_PIN.El DIGITAL_PIN representa el pin digital de Uno que se utiliza para conectar el pin de salida digital del sensor. ANALOG_PIN representa el pin de entrada analógica de Uno que se utiliza para conectar el pin de salida analógica del sensor.

Los datos del módulo se pueden leer de dos formas. Uno es leyendo el pin de salida analógica del módulo y el otro es leyendo el pin de salida digital del módulo. Para leer el pin de salida analógica del módulo, la variable llamada gasVal se usa para almacenar el valor de retorno de la función analogRead (). El valor de retorno es un número entero en el rango de 0 a 1023. Para convertirlo en un porcentaje, se usa la función map (). Esta es una función incorporada del Arduino IDE. Tiene cinco argumentos y devuelve un valor como, por ejemplo:

gasVal = map (entrada, in_min, in_max, out_min, out_max)

El primer argumento es el valor de entrada, que está en el rango de in_min a in_max. El valor de retorno es un número entero en el rango de out_min a out_max. Esta función asigna un número en el rango de entrada a otro número que está en el rango diferente.Para leer el pin de salida digital del módulo, la variable isGas se usa para almacenar el valor de retorno de la función digitalRead ().Al final de la función loop (), los datos se muestran en Serial Monitor. Entre dos mediciones hay una pausa de 2 segundos: delay(2000);

LECTURA ANALÓGICA

En el siguiente código realizamos la lectura analógica del sensor. Al igual que el anterior, es código es muy sencillo. Simplemente empleamos una entrada analógica cualquiera para leer la salida analógica del sensor, y mostramos el resultado por puerto serie.

const int MQ_PIN = A0;

const int MQ_DELAY = 2000;

void setup()

{

Serial.begin(9600);

}

void loop()

{

int raw_adc = analogRead(MQ_PIN);

float value_adc = raw_adc * (5.0 / 1023.0);

Serial.print("Raw:");

Serial.print(raw_adc);

Serial.print(" Tension:");

Serial.println(value_adc);

delay(MQ_DELAY);

}

LEER LA CONCENTRACIÓN DE UN GAS

Es posible discriminar el nivel de un gas determinado empleando la lectura analógica para determinar la concentración del gas normalmente en ppm (partes por millón), pero algunos sensores usan otras unidades como mg/L o bpm (partes por billón)

El Datasheet de cada sensor proporciona unas gráficas que permiten obtener la concentración del gas a partir de la relación entre la resistencia del sensor R0 y la resistencia medida Rs. También es necesario conocer la resistencia Rl empleada en el módulo para realizar la lectura del sensor MQ.

En la siguiente imagen muestra las curvas de concentración de cada gas medido en un sensor MQ-2 que es el que emplearemos en este proyecto.

Las gráficas se disponen en escala logarítmica para ambos ejes y, en general, son aproximadamente rectas bajo estas escalas. Por lo que la concentración resultará según la siguiente formula:

Para determinar la concentración necesitaremos la recta que la aproxima, para lo cuál debemos coger dos puntos cuales cualquiera de las gráficas P0 = {X0, Y0} y P1 = {X1, Y1}, resultando la ecuación de la recta:

Para obtener A y B simplemente    sustituimos P0 = {X0, Y0} y P1 = {X1, Y1}, en las dos ecuaciones siguientes:

Finalmente  con  todos estos datos podemos obtener a partir de los coeficientes obtenidos medidas más fiables de concentración de gases  usando el siguiente código que finalmente no usaremos en la versión final del proyecto dado que no estamos interesados en discriminar el nivel de un gas en concreto:

const int MQ_PIN = A0; // Pin del sensor

const int RL_VALUE = 5; // Resistencia RL del modulo en Kilo ohms

const int R0 = 10; // Resistencia R0 del sensor en Kilo ohms

// Datos para lectura multiple

const int READ_SAMPLE_INTERVAL = 100; // Tiempo entre muestras

const int READ_SAMPLE_TIMES = 5; // Numero muestras

// Ajustar estos valores para vuestro sensor según el Datasheet

// (opcionalmente, según la calibración que hayáis realizado)

const float X0 = 200;

const float Y0 = 1.7;

const float X1 = 10000;

const float Y1 = 0.28;

// Puntos de la curva de concentración {X, Y}

const float punto0[] = { log10(X0), log10(Y0) };

const float punto1[] = { log10(X1), log10(Y1) };

// Calcular pendiente y coordenada abscisas

const float scope = (punto1[1] - punto0[1]) / (punto1[0] - punto0[0]);

const float coord = punto0[1] - punto0[0] * scope;

void setup()

{

Serial.begin(9600);

}

void loop()

{

float rs_med = readMQ(MQ_PIN); // Obtener la Rs promedio

float concentration = getConcentration(rs_med/R0); // Obtener la concentración

// Mostrar el valor de la concentración por serial

Serial.println("Concentración: ");

Serial.println(concentration);

}

// Obtener la resistencia promedio en N muestras

float readMQ(int mq_pin)

{

float rs = 0;

for (int i = 0;i<READ_SAMPLE_TIMES;i++) {

rs += getMQResistance(analogRead(mq_pin));

delay(READ_SAMPLE_INTERVAL);

}

return rs / READ_SAMPLE_TIMES;

}

// Obtener resistencia a partir de la lectura analogica

float getMQResistance(int raw_adc)

{

return (((float)RL_VALUE / 1000.0*(1023 - raw_adc) / raw_adc));

}

// Obtener concentracion 10^(coord + scope * log (rs/r0)

float getConcentration(float rs_ro_ratio)

{

return pow(10, coord + scope * log(rs_ro_ratio));

}

Finalmente, dado que estamos interesados en la detección global de gases y no en el de un gas particular, usaremos un esquema mixto   como podemos ver en las siguientes líneas, que es el que usaremos en la implementación final:

// Obtener la resistencia promedio en N muestras

float readMQ1(into mq_pin)

{

   float rs = 0;

   for (int i = 0;i<READ_SAMPLE_TIMES;i++) {

      rs += analogRead(analogPin);

      delay(READ_SAMPLE_INTERVAL);

   }

   return rs / READ_SAMPLE_TIMES;

}

//todas las medidas

gasVal=readMQ1(analogPin);  

gasVal = map(gasVal, 0, 1023, 0, 100); 

Serial.print("La conentracion  de gases es :");

Serial.println(gasVal);

Cayenne.virtualWrite(V3, gasVal); //virtual pin

delay(10000);

//lectura digital sensor MQ2

isgas=digitalRead(15);

if (isgas) { 

gas = "No"; 

else { 

gas = "Yes"; 

Serial.print("Valor seensor gas:");

Serial.println(gas);

 Cayenne.virtualWrite(V6, isgas); //virtual pin

Dado que el sensor MQT2 lo vamos a montar sobre un ESP32, las conexiones que realizaremos son las siguientes:

  1. GPIO36 (pin14): conexión A0 al MQT2
  2. VCC ( pin1) : conexión VCC del MQT2
  3. GND(pin2): conexión GND del MQT2
  4. GPIO04(pin5): conexión D0 al MQT2

SENSOR CCS811

El CCS811 es un sensor construido por diferentes fabricantes para la medición calidad del aire interior, que podemos usar fácilmente junto con un procesador como Arduino y todas sus variantes como puede ser un ESP32

Este sensor de calidad del aire de dióxido de carbono está fabricado por múltiples empresas como Keyestudio, AMS, Adafruit, etc., pero en todo caso así marcado básicamente porque utiliza principalmente el chip CCS811. 

Este sensor de gas digital en miniatura de potencia ultrabaja, es de bajo coste y que puede detectar una amplia gama de compuestos orgánicos volátiles (TVOC), incluidos niveles equivalentes de dióxido de carbono (eCO2) y óxido metálico (MOX). Al igual que la mayoría de sensores químicos, el CCS811 necesita un precalentador por lo que la mayoría de fabricantes recomiendan que el sensor funcione durante 20 minutos para que las mediciones se estabilicen, y durante 48 horas si se cambia de ubicación.

El CCS811 incluye un conversor ADC interno, un procesador interno para realizar los cálculos y comunicación a través de a través de bus I2C por lo que es muy sencillo conectarlo a un ESP32.

Dispone de 5 modos de medición (medición continua, o medición cada 0.250, 1, 10, 60 segundos) y que permiten adaptarlo a aplicaciones de bajo consumo alimentadas por batería, pero cuidado porque según el fabricante puede o no implantar esa funcionalidad.

La tensión del CCS811 es de 1.8 a 3.3V, aunque en muchos módulos se incorpora un adaptador de nivel que permite hacerlo funcionar directamente con 5V como es el caso del módulo de KeyStudio.

Para determinar la calidad del aire interior, el CCS811 es un sensor multi-gas MOX(Metal-Oxide) que incluye medición de monóxido de carbono (CO) y compuestos volátiles (VOCs) como etanol, aminas, o hidrocarburos aromáticos. Las dos medidas que nos ofrece son las siguientes:

  • Con ambos datos (CO y VOC) el CCS811 puede determinar la cantidad de dióxido de carbono equivalente (eCO2) que se mide en el rango de 400 a 29206 ppm (partes por millón). El datasheet no proporciona datos sobre precisión en la medición
  • Varios compuestos orgánicos volátiles (TVOC) varían de 0 a 32768 ppbo (partes por billón) en el caso del fabricante Keystudio (pero otros fabricantes como AMS ofrecen rangos de 0 a 1187 ppb en TVOC)

Como curiosidad el orificio de posición de 3 mm de diámetro en el sensor contribuye a fijarlo a otro dispositivo (al igual que ocurre con la familia DHTXX).

Parámetros técnicos

  • Voltaje de funcionamiento: DC 5 V
  • Corriente de trabajo: 30 mA
  • Potencia máxima: 60 mW
  • Rango de medición de eCO2: 400-29206 ppm
  • Rango de medición de TVOC: 0 a 32768ppb
  • Interfaz: 7 pines (paso de 2,54 mm)
  • Diámetro del orificio de posicionamiento: 3 mm
  • Dimensiones: 30 * 20 mm
  • Atributos ambientales: ROHS

PINOUTS


TVOC

Los compuestos orgánicos son sustancias químicas que contienen carbono y se encuentran en todos los elementos vivos. Los compuestos orgánicos volátiles, a veces llamados VOC, o COV, se convierten fácilmente en vapores o gases que  contribuyen a la mala calidad del aire interior, siendo omnipresentes tanto en interiores como en exteriores.

Los COV son sustancias químicas orgánicas emitidas como gases por productos o procesos que  en su mayor parte, se puede oler su presencia. Las fuentes típicas de COV en interiores incluyen cosas como agentes de limpieza, desinfectantes, ambientadores, deshumidificadores y más. Incluso algo tan aparentemente “inocuo “como una alfombra nueva es probable que emita gas de formaldehído. Las fuentes de contaminación de COV del exterior podrían incluir sustancias químicas volátiles en el agua subterránea contaminada que se introducen durante el uso del agua.

Para medir la contaminación del aire en interiores, debe realizar pruebas para detectar todos los contaminantes posibles o probables. Una excepción a esto son los sensores de compuestos orgánicos volátiles (COV), que analiza múltiples contaminantes y brinda un valor / nivel agregado:

  • Intervalo de concentraciones para una situación de confort: 0.2 mg/m3
  • Intervalo de concentraciones con inicio de situaciones de di confort: 0,2–0,3 mg/m3
  • Intervalo de concentraciones para una situación de des confort: 0,3 – 250 mg/m3
  • Intervalo de situación tóxica > 250 mg/m3

Por tanto, el TVOC que nos dé debería ser menor o igual a 0. 6mg / m 3

CO2

 La concentración de CO2 en el aire es un gran “gas trazador” para controlar qué tan mal están las cosas. Por supuesto, los humanos producimos CO2 al respirar, y cuanto más trabajamos, más CO2 producimos.

El dióxido de carbono (CO2) puede no ser el factor más pernicioso que impacta la calidad del aire interior, pero a menudo se usa como sustituto de la calidad del aire y el nivel de ocupación del edificio. Cuantos más ocupantes haya en una habitación o edificio, más CO2 se libera al aire. Para evitar que los niveles de CO2 aumenten demasiado, lo que puede tener un impacto negativo en los ocupantes, el aire exterior debe introducirse deliberadamente en el edificio a través de un sistema de ventilación.

A menudo, sin embargo, esos esfuerzos sobrecargan innecesariamente el sistema de ventilación, desperdiciando energía. Al monitorear los niveles de CO2 y proporcionar ventilación según sea necesario, lo que se denomina ventilación de control de demanda, puede mantener una calidad de aire saludable y reducir el uso de energía

Mirando la medida de CO2 es un buen indicador de la calidad del aire que respiramos. Típicamente, el aire exterior es de aproximadamente 400. Si el medidor pasa de 1000 ppm, en general, debe hacer algo con el aire que hay allí.

ESQUEMA DE MONTAJE

La conexión con el CCS811 es sencilla, ya que la comunicación se realiza a través de I2C. La tensión de funcionamiento es de 1.8 a 3.3V, pero como se ha comentado   muchos módulos incorporan adaptación a 5V, por tanto, para alimentar el módulo conectaremos los pines del módulo GND y Vin, respectivamente, y GND y 5V en Arduino.

Por otro lado, para la comunicación por I2C deberemos conectar los pines SCK y SDA con los pines correspondientes de nuestro modelo de Arduino.

El pin WakeUp activa el sensor cuando este se pone a GND. Por otro lado, el pin RST reinicia el sensor cuando se pone a GND. Ambos están pulled Up, así que, para que funcione, deberemos poner explícitamente WAKE a GND.

Finalmente, el pin INT se emplea en algunos modos de funcionamiento, para detectar cuando el sensor tiene una nueva medición o esta sobrepasa un umbral.

La conexión, vista desde Arduino, sería la siguiente:


 

Aunque el fabricante keystudio recomienda la versión Arduino 1.8.7, como veremos más adelante funciona perfectamente con versiones no oficiales de Arduino y por supuesto con el ESP32, pero es cierto que otras versiones podrían no ser compatible.

#include <CCS811.h>

// Sensor CCS811 (& Cable, / * IIC_ADDRESS = * / 0x5A);
CCS811 sensor;
void setup(void)
{
Serial.begin (115200);
/ * Espere a que el chip se inicialice por completo y luego salga * /
while (sensor.begin ()! = 0) {
Serial.println ("no se pudo iniciar el chip, verifique si la conexión del chip está bien");
retraso (1000);
}
/ **
* @brief Establecer ciclo de medición
* @param cycle: en typedef enum {
* eClosed, // Inactivo (las medidas están deshabilitadas en este modo)
* eCycle_1s, // Modo de potencia constante, medición IAQ cada segundo
* eCycle_10s, // Medición IAQ del modo de calentamiento por pulsos cada 10 segundos
* eCycle_60s, // Medición IAQ del modo de calentamiento por pulsos de baja potencia cada 60 segundos
* eCycle_250ms // Modo de potencia constante, medición del sensor cada 250ms
*} eCycle_t;
* /
sensor.setMeasCycle (sensor.eCycle_250ms);
}
void loop() {
delay(1000);
if(sensor.checkDataReady() == true){
Serial.print("CO2: ");
Serial.print(sensor.getCO2PPM());
Serial.print("ppm, TVOC: ");
Serial.print(sensor.getTVOCPPB());
Serial.println("ppb");
} else {
Serial.println ("¡Los datos no están listos!");
}
/ *!
* @brief Establecer línea de base
* @param obtener de getBaseline.ino
* /
sensor.writeBaseLine (0x847B);
// el retraso no puede ser menor que el ciclo de medición
// delay (1000);
}

Cuando una persona exhala delante del sensor, los datos cambian rápidamente, como se muestra a continuación donde en una situación previa sin personas había el nivel de 400ppm de CO2  y 0 ppb de TVOC y pasamos a 475ppm de CO2 y 11ppb de TVOC.

A la hora de conectar el CCS811 al ESP32   deberemos hacer las siguientes conexiones:

  • GPIO 22 (pin14): conexión SCL al CCS811
  • GPIO21(oin11): conexión SDA al CCS811
  • +5V (pin1): conexión VCC del CCS811
  • GND(pin2): conexión GND y WAKE

 

PLACA NODE MCU

Respecto a la placa de desarrollo usada es la NodeMCU-32S basada en ESP32, placa que cuenta con conectividad WiFi + Bluetooth, CP2102 a bordo y llaves. Además, todos los pines de E / S del módulo ESP-WROOM-32 son accesibles a través de los encabezados de extensión. Gracias a los ricos recursos de código abierto, admite el desarrollo de varias formas, como los comandos Lua / AT / MicroPython / Arduino / IOT, etc., lo que le ayuda a crear prototipos rápidos de aplicaciones de IoT.

Algunas características de esta placa:

  • Módulo ESP-WROOM-32 integrado
  • CP2102 integrado, convertidor de USB a UART
  • Puerto USB para entrada de energía, programación de firmware o depuración UART
  • Cabezales de extensión de 2×19 pines, rompen todos los pines de E / S del módulo
  • 2x teclas, utilizadas como reinicio o definidas por el usuario
  • Especificaciones
  • Módulo WIFI: ESP-WROOM-32
  • Procesador: ESP32-D0WDQ6
  • Flash incorporado: 32 Mbit
  • Antena: antena PCB integrada
  • Interfaz periférica: UART / GPIO / ADC / DAC / SDIO / PWM / I2C / I2S
  • Protocolo WiFi: IEEE 802.11 b / g / n
  • Bluetooth: Bluetooth 4.2
  • Rango de frecuencia: 2.4G ~ 2.5G (2400M ~ 2483.5M)
  • Modo WIFI: Estación / SoftAP / SoftAP + Station
  • Fuente de alimentación: 5 V
  • Nivel lógico: 3,3 V
  • Dimensiones: 48,26 mm x 25,4 mm

Respecto a esta placa, es muy relevante tener muy claro la función de   todos los pines de los que contamos como podemos ver en la siguiente imagen:

Para este proyecto vamos a usar los siguientes pines:

  • GPIO23 (pin15): conexión al DHT11
  • GPIO36 (pin14): conexión A0 al MQT2
  • GPIO04(pin5): conexión D0 al MQT2
  • GPIO 22 (pin14): conexión SCL al CCS811
  • GOUI21(oin11): conexión SDA al CCS811
  • +5V(pin1): a todas las líneas de VCC de los tres sensores
  • GND(pin2): a todas las líneas de 0V, GND o masa de los sensores, así como al terminal WAKE del CCS811

Programación final del Node MCU-32S

Para instalar el firmware en el node MCU32S   lo primero es descargar e instalar el IDE de Arduino (Arduino IDE.).Para instalar el paquete de la placa en Archivo -> Preferencias, agregue http://arduino.esp8266.com/stable/package_esp8266com_index.json al campo URL del Administrador de tableros adicionales. Después instalaremos la plataforma esp8266 desde Tools -> Board -> Boards Manage (en caso de que la placa fuese un ESP32, habría que instalar manualmente el paquete de la placa siguiendo las instrucciones aquí: https://github.com/espressif/arduino-esp32/blob/master/README.md#installation-instructions).

Lo siguiente es descargar esta biblioteca como un archivo zip  e instalar la biblioteca zip descargada desde Sketch -> Incluir biblioteca -> Agregar biblioteca .ZIP.

Ahora ya podemos conectar el módulo ESP a su pc a usando un USB y seleccionado su puerto (y obviamente el módulo NodeMCU en el IDE de Arduino) en el menú Herramientas.

El interfaz de Cayenne como hemos visto en líneas anteriores ,en realidad está concebido para que su manejo sea realmente sencillo   de configurar   así que nos iremos a  su   url :   https://cayenne.mydevices.com/   y tras registrarnos nos iremos al panel de control  , clicamos en  Add new   y seleccionamos Generic ESP8266

A continuación, nos ofrece la API key que deberemos añadir al sw del   ESP12E      y tras reiniciarlo ya debería poderse comunicar con el node de Cayenne.

Si la placa pues   está configurada con el MQTT (username /pwd) así como con conectividad wifi, ya   debería de poder conectarse al framework de Cayenne   y podemos seguir hacia adelante añadiendo sensores que deberán estar de acuerdo con el software que vamos instalando en el Node MCU.

Envío de temperatura y humedad

En este caso como hemos definido dos puertos virtuales para temperatura y humedad el firmware del Node MCU, por lo necesitamos añadir dos widgets asociados a esos dos canales:

Para la temperatura no podemos olvidar que habíamos asignado el primer puerto virtual (canal 1), el cual debemos asignar al widget

Respecto a la humedad   habíamos asignado el segundo puerto virtual (canal 2), el cual debemos asignar al widget:

Para probar Cayenne con el Node MCU y un sensor como el DHT11     necesitamos programar el ESP32 para conectarse a su punto de acceso wifi por lo que pasamos a describir el programa que desplegaremos en el Node MCU.  

Básicamente el código a subir al    NodeMCU  para empezar monitorizando la temperatura y humedad solo  usa 5 librerías: 

  • Tres de Cayenne donde tendremos que definir el SSID y la pwd de la red wifi, así como las credenciales de Cayenne,
  • Una cuarta de temporización para enviar muestras a intervalos prefijados (que obviamente podemos cambiar)
  • Por último, la mencionada para la gestión del DTHXX.

//#define CAYENNE_DEBUG

#define CAYENNE_PRINT Serial

#include <CayenneMQTTESP32.h>

#include <SimpleTimer.h>

Necesitaremos actualizar en el código anterior cambiando el valor de SSID, contraseña configurándola para la red wifi de su hogar y también no olvidar   registrar el token de Cayenne que previamente habrá solicitado desde la propia web de Cayenne  MyDevices  en la pestaña Ajustes del proyecto.

// WiFi network info.

char ssid[] ="MOVISTAR_C0D5";

char  wifiPassword[]= "3HgLtpyGsTCjJBntvTCt";

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.

char username[]="d5bb49f0-a6c8-11e6-839f-8bfd46afe676";

char password[]="59306795b26873b288e497f9dea8ce3a3d8c25d6";

char clientID[]="59e0f4b0-f38e-11e7-939f-b354e6d68235";

El token, user y pwd de Cayenne se pueden ver como citamos anteriormente desde la propia web de Cayenne en la pestaña Ajustes del proyecto:

Como nosotros vamos a usar el DHT11 como sensor de humedad y temperatura, al cual conectaremos al pin D5 del Node MCU. Para su gestión usaremos la librería DHT.h, definiremos el puerto y crearemos el objeto dht para acceder a este:

#include “DHT.h”

#define DHTTYPE DHT11   // DHT 11

const int DHTPin = 23;     // por defect  el 5  what digital pin we’re connected to

DHT dht(DHTPin, DHTTYPE);

Asimismo, es importante en la función setup del sketch de Arduino, inicializar el objeto dht, tarea que realizaremos una vez inicialicemos el objeto Cayenne al que le pasaremos todas las credenciales:  username, password, clientID, ssid, wifiPassword.

void setup() {

    Serial.begin(115200);

    Cayenne.begin(username, password, clientID, ssid, wifiPassword);

   Serial.println(“DHT11 test!”);

  dht.begin();

}

Es de destacar la creación de dos puertos virtuales para capturar los valores en tiempo real de la temperatura y la humedad tomadas ambas del DHT11 lo cual nos van a permitir comunicarnos con el API de Cayenne. Además, en esta primera parte mostraremos por consola del ESP32 ambos valores de temperatura y humedad antes de enviarla a la plataforma.

Cayenne.virtualWrite(0, millis());

  float t = dht.readTemperature();

  Serial.print("La  temperatura es de:");

  Serial.print(t);

  Serial.println(" *C ");

  Cayenne.virtualWrite(1, t); //virtual pin

 delay(10000);

  float h = dht.readHumidity();

  Serial.print("La Humedad es de :");

  Serial.print(h);

  Serial.println(" %\t");

  Cayenne.virtualWrite(V2, h); //virtual pin

delay(10000);

El código fuente para probar sólo el DHT11 antes de continuar añadiendo más sensores  es el siguiente:

//#define CAYENNE_DEBUG

#define CAYENNE_PRINT Serial

#include <CayenneMQTTESP32.h>

#include <SimpleTimer.h>

#include "DHT.h"

#define DHTTYPE DHT11   // DHT 11

const int DHTPin = 5;     // what digital pin we're connected to

DHT dht(DHTPin, DHTTYPE);

// WiFi network info.

char ssid[] = “";

char wifiPassword[] = "";

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.

char username[] = "";

char password[] = "";

char clientID[] = "";

unsigned long lastMillis = 0;

void setup() {

                Serial.begin(9600);

                Cayenne.begin(username, password, clientID, ssid, wifiPassword);

   Serial.println("DHT11 test!");

  dht.begin();

}

void loop() {

                Cayenne.loop();

}

CAYENNE_OUT_DEFAULT()

{

  Cayenne.virtualWrite(0, millis());

   float t = dht.readTemperature();

  Serial.print("Temperatura:");

  Serial.print(t);

  Serial.println(" *C ");

  Cayenne.virtualWrite(1, t); //virtual pin

  float h = dht.readHumidity();

  Serial.print("Humedad:");

  Serial.print(h);

  Serial.println(" %\t");

  Cayenne.virtualWrite(V2, h); //virtual pin

   }

CAYENNE_IN_DEFAULT()

{

  CAYENNE_LOG("Channel %u, value %s", request.channel, getValue.asString());

  getValue.setError("Error message");

}

En la siguiente imagen podemos verlo ejecutándose la parte del sensor DHT11 conectado al ESP32:

Finalmente, al haber asignado los dos widgets, si esta Node MCU está conectada a Internet, debería mostrar un panel similar al siguiente en el que se ha añadido un widget nuevo asociado al valor analógico.

Pinchando en la esquina podemos hacer un seguimiento estadístico según criterios temporales (tiempo real, últimos 10 minutos, ultima hora, últimos 7 días, últimos 30 días, últimos tres meses, ultimo 6 meses y el último año.

En el ejemplo vemos la opción “h” que corresponde a los últimos 60 minutos:

Y también podemos acceder al histórico de todas las medidas:

Estos datos debidamente filtrados según nuestra necesidad también los podemos descargar en formato csv para utilizarlos a nuestra conveniencia.

La demora entre él envió de datos y su reflejo en el interfaz es muy pequeño como podemos apreciar en la siguiente imagen:

Envío del nivel de gases

En este caso dadas las características del sensor MQ 2 , vamos  a enviar dos tipos de medidas a la plataforma Cayenne , dado que la familia de sensores MQ XX nos ofrece  tanto una señal digital que indica o no presencia de gasee  (y que podemos ajustar mediante un trimmer), así como una salida analógica genérica que también podemos ajustar según nuestras necesidades específicas de detección  tal y como hemos comentado en el apartado del sensor MQ2 , pero que en este caso, dado que nos interesa abarcar el máximo abanico posible de gases  lo vamos  hacer global.

En el firmware del ESP32 definiremos el puerto analógico (GPIO36) y   una función para tomar un numero de muestras significativas llamada readMQ1:

//sensor mQ

uint16_t gasVal;

boolean isgas = false;

String gas;

int analogPin = 36;

// Obtener  promedio en N muestras

float readMQ1(int mq_pin)

{

   float rs = 0;

   for (int i = 0;i<READ_SAMPLE_TIMES;i++) {

      rs += analogRead(analogPin);

      delay(READ_SAMPLE_INTERVAL);

   }

   return rs / READ_SAMPLE_TIMES;

}

Ahora definidas las funciones , solo tenemos que tomar la muestra de las medidas analógicas  para enviarlas por el puerto virtual 3 a la plataforma Cayenne

//todas las medidas

gasVal=readMQ1(analogPin);  

gasVal = map(gasVal, 0, 1023, 0, 100); 

Serial.print("La concentración  de gases es :");

Serial.println(gasVal);

Cayenne.virtualWrite(V3, gasVal); //virtual pin

delay(10000);

Respecto al umbral de detección de gases ajustable con el trimmer del propio sensor MQ2, leeremos el valor binario del puerto 4.

Como la señal binaria está en lógica inversa desde el propio programa cambiaremos invirtiendo su valor para enviarlo así a la plataforma de modo que intente ser fiel a la realidad (un “cero” si no hay presencia excesiva de gas y un “uno” en caso de exceso de gases)

//lectura digital sensor MQ2

isgas=digitalRead(4);

if (isgas) { 

gas = "No";

isgas=0; 

else { 

gas = "Si"; 

isgas=1;

Serial.print("Valor sensor gas:");

Serial.println(gas);

Cayenne.virtualWrite(V6, isgas); //virtual pin

delay(10000);

Ya en la plataforma de Cayenne, para el caso de alta concentración de gases usaremos el canal 6. Como el sensor funciona de modo inverso según hemos visto en el código (enviando un “1” lógico cuando no hay presencia de gases y un “0” lógico cuando no lo hay), hemos invertido en el sw de Arduino por lo que finalmente enviaremos un cero (sin nivel de gases) o un uno (cuando haya presencia según hayamos ajustado el trimmer).

En la imagen vemos el sensor con el led verde apagado (sin presencia de gases) enviando un uno lógico por el puerto digital D4.

Y en la siguiente imagen, hemos expuesto al sensor a gases de combustión, encendiéndose el led verde de la derecha, enviando el MQ un nivel bajo por el puerto D4.

En el panel de Cayenne, para intentar representar esta misma información seleccionaremos el canal 6 con un valor decimal, indicando el umbral de 0 a 0.5, es decir un “0” lógico como verde (es decir sin presencia de gases) y el umbral de 0.5 a 1, es decir un “1” lógico indicándolo como rojo.

Respecto al valor analógico de la salida de gases del sensor MQ 2 que conectaremos al Gpio 36 del ESP32, vamos a usar el canal 3 de Cayenne   y que configuraremos con tres umbrales:

  • Del 0 al 300: nivel verde
  • De 301 al 600: nivel amarillo
  • De 601 al 1023: nivel rojo

Envío de nivel de calidad de aire

Hemos visto que el sensor CCS811 es el componente más importante del montaje, destacando que la comunicación por I2C se realiza mediante los pines SCK y SDA al ESP32 conectando el pin WakeUp (el que activa el sensor) a GND y el por otro lado, el pin RST, que reinicia el sensor cuando se pone a GND. Ambos están pulled Up, así que funcione, deberemos poner explícitamente WAKE a GND y finalmente, el pin INT se emplea en algunos modos de funcionamiento, para detectar cuando el sensor tiene una nueva medición o esta sobrepasa un umbral.

En el firmware del ESP32   para definir el CCS811 necesitamos incluir la librería CCS811.h definiendo además la variable sensor que será del tipo CCS811.

#include <CCS811.h>

/*

 * IIC address default 0x5A, the address becomes 0x5B if the ADDR_SEL is soldered.

 */

//CCS811 sensor(&Wire, /*IIC_ADDRESS=*/0x5A);

CCS811 sensor;

Ahora una vez definido el objeto sensor en la función setup, tras la inicialización de Cayenne y del sensor DHT   necesitamos tras asegurarnos de que el sensor es funcional inicializar el sensor con el modo de funcionamiento.

Para este sensor hay cinco modos posibles

  • eClosed : Inactivo (las medidas están deshabilitadas en este modo)
  • eCycle_1s: Modo de potencia constante, medición IAQ cada segundo
  • eCycle_10s: Medición IAQ del modo de calentamiento por pulsos cada 10 segundos
  •  eCycle_60s: Medición IAQ del modo de calentamiento por pulsos de baja potencia cada 60 segundos
  • eCycle_250ms : Modo de potencia constante, medición del sensor cada 250m

En este proyecto usaremos el modo de potencia constante, es decir con posibles mediciones del sensor cada 250 ms

void setup() {

    Serial.begin(115200);

    Cayenne.begin(username, password, clientID, ssid, wifiPassword);

   Serial.println("DHT11 test!");

  dht.begin();

   while(sensor.begin() != 0){

        Serial.println("failed to init chip, please check if the chip connection is fine");

        delay(1000);

    }

    /**

     * @brief Set measurement cycle

     * @param cycle:in typedef enum{

     *                  eClosed,      //Idle (Measurements are disabled in this mode)

     *                  eCycle_1s,    //Constant power mode, IAQ measurement every second

     *                  eCycle_10s,   //Pulse heating mode IAQ measurement every 10 seconds

     *                  eCycle_60s,   //Low power pulse heating mode IAQ measurement every 60 seconds

     *                  eCycle_250ms  //Constant power mode, sensor measurement every 250ms

     *                  }eCycle_t;

     */

    sensor.setMeasCycle(sensor.eCycle_250ms);

}

Y ya tan solo nos queda recuperar los valores de CO2   con el método sensor. getCO2PPM () o el valor de TVOC con el método getTVOCPPB () y enviar ambos datos a Cayenne por los puertos virtuales V4 y V5 respectivamente.

Ya definido el firmware en el ESP32 para este último sensor en la plataforma de Cayenne, para el caso de C02 definiremos un nuevo widget asociado al canal 4 con tres rangos posibles de valores:

De un modo análogo en el canal 5 también definiremos un nuevo widget para el caso del TVOC   asociándolo al canal 4 con tres rangos posibles de valores:

Con esto ya habríamos terminado de añadir los widget básicos para mostrar en el panel de Cayenne  todas las medidas enviadas.

Configuración de un trigger

Los triggers o disparadores en Cayenne son una forma de hacer que su placa reaccione a un cambio de un sensor conectado a él. Esto podría ser algo tan simple como un valor de temperatura superior a un cierto valor o incluso sólo si el ESP32 pierde la conexión, lo cual como se podría imaginar puede ser muy potente en la creación de dispositivos inteligentes que reaccionan a los alrededores (como, por ejemplo, si la habitación se pone demasiado fría, encienda un calefactor, etc.).

El proceso de agregar un disparador es muy sencillo como vamos a ver a continuación:

  1. Ir a añadir en la esquina superior izquierda del tablero de instrumentos.
  2. Seleccionar un trigger desde el cuadro de abajo.
  3. El nombre de su trigger, voy a llamar a la mía “demasiado caliente”.
  4. Ahora arrastrar y soltar su Node MCU desde la esquina izquierda en el caso de la caja.
  5. Por debajo de esto seleccionar el sensor de temperatura y tienen casilla junto a “por encima de la temperatura” seleccionado. (Si las opciones del dispositivo no se muestran simplemente actualizar la página)
  6. Ahora en el cuadro de selección a continuación, notificación y agregar una dirección de correo electrónico o número de teléfono de un mensaje de texto (puede agregar ambos).Asegúrese de marcar las casillas de verificación también.
  7. Ahora haga clic en “Save trigger”.
  8. Ahora se debe guardar y le enviará una alerta cada vez que el sensor de temperatura es más de 40 grados Celsius.
  9. También puede arrastrar el ESP12E en el cuadro a continuación, y tienen que hacer muchas cosas, incluyendo el control de los dispositivos de salida. Por ejemplo, puede añadir un LED que se activará cuando la temperatura supere los 40 grados Celsius.
  10. Para hacer clic en el gatillo de disparo LED de nueva situada en la parte superior de la página. Nombre esta activar el gatillo LED.
  11. Ahora arrastrar el Pi en el caso de la caja y luego seleccione el sensor de temperatura de nuevo con 40 grados centígrados por encima.
  12. Ahora arrastrar el Node MCU en cuadro a continuación. Seleccione nuestra salida digital y marque la casilla de verificación activada.
  13. Ahora haga clic en Save trigger.
  14. Ahora, cada vez que nuestro sensor de temperatura conectado al Pi informe una temperatura superior a 40 grados Celsius, enviará un correo electrónico y encenderá el LED. También necesitará agregar otro disparador para apagar el LED cuando caiga por debajo de los 40 

 Sin duda hay infinitas posibilidades como nos podemos imaginar.

Aplicación móvil

Hay un valor añadido extra dentro de la plataforma Cayenne, que no todas las plataformas cuentan, y es precisamente el hecho de contar con una aplicación móvil tanto para Android como para IoS.

Teóricamente no solo sirve para visualizar los datos pues también es posible modificar widgets, añadir dispositivos, activar trigger, etc.  tal y como lo podemos hacer desde el interfaz web

En las siguientes imágenes vemos capturas de pantalla del interfaz definido para este proyecto corriendo en tiempo real desde la aplicación Android.

La configuración final

En este proyecto hemos usado los siguientes pines del ESP32:

  • GPIO23 (pin15): conexión al DHT11
  • GPIO36 (pin14): conexión A0 al MQT2
  • GPIO04(pin5): conexión D0 al MQT2
  • GPIO 22 (pin14): conexión SCL al CCS811
  • GPIO21(oin11): conexión SDA al CCS811
  • +5V(pin1): a todas las líneas de VCC de los tres sensores
  • GND(pin2): a todas las líneas de 0V, GND o masa de los sensores, así como al terminal WAKE del CCS811

Las conexiones anteriormente citadas, cuyo detalle se ha especificado a lo largo de todo este trabajo, finalmente quedaría configurado de la siguiente forma:

Y este es aspecto de todo el montaje sobre una placa protoboard:

Una vez compilado el firmware explicado a lo largo de este texto desde la consola serie del IDE de Arduino podemos ir comprobando las diferentes medidas que se van tomando para enviar a la plataforma Cayenne.

Y estos datos tienen su reflejo en la interfaz de Cayenne:

Pruebas

Veamos a continuación como varían las condiciones según el número de personas, temperatura, humedad o estado de las ventanas

Niveles con dos personas a las 9:05AM próximas a la distancia de 2mt sin mascarillas.

Después de una hora y media el nivel de CO2 con una   única persona siendo destacable como baja tanto el nivel de gases como el nivel de CO2

Ahora veamos la evolución de concentración de gases al bajar de dos personas a una sola.

Y la concentración de Co2.

Respecto a la temperatura y humedad apenas sufren variaciones

Easy Auto Refresh

Esta extensión para Chrome permite recargar la página a intervalos definidos para refrescar los datos y poder mostrar los cambios, lo cual es muy útil para no tener que estar constantemente refrescando la página desde obtenemos la información del Cayenne

Por ejemplo, si establecemos que se envíen datos cada 5 minutos, podemos ajustar el valor de refresco en 300 segundos y de este modo podemos estar seguros que la información que hay en pantalla es la última enviada.

Código completo con comentarios

 //*****************************************************************

// Proyecto   para la medición de la calidad de aire

// Por Carlos Rodriguez Navarro  

// **************************************************************

//

//Para este proyecto vamos a usar los siguientes pines:

// GPIO23  (pin15):conexión al DHT11

// GPIO36 (pin14): conexión al MQT4

// GPIO04(pin5): conexión D0 al MQT2

// GPIO 22 (pin14) : conexión SCL al CCS811

// GOUI21(oin11): conexión SDA al CCS811 

// +5V(pin1) : a todas las líneas de VCC de los tres sensores

// GND(pin2) : a todos las líneas de 0V ,GNDo masa  de los sensores , así como al terminal WAKE del CCS811

//

// Este proyecto usa Cayenne mediante un ESP32 para enviar / recibir datos de muestra.

// Asegúrese de instalar el paquete de placa ESP32 y seleccione la placa ESP32 correcta antes de compilar.

// Para instalar el paquete de placa ESP32, siga las instrucciones aquí: https://github.com/espressif/arduino-esp32/blob/master/README.md#installation-instructions.

//#define CAYENNE_DEBUG

#define CAYENNE_PRINT Serial

#include <CayenneMQTTESP32.h>

#include <SimpleTimer.h>

#include "DHT.h"

#define DHTTYPE DHT11   // DHT 11

#include <CCS811.h>

/*

 * IIC address default 0x5A, the address becomes 0x5B if the ADDR_SEL is soldered.

 */

//CCS811 sensor(&Wire, /*IIC_ADDRESS=*/0x5A);

CCS811 sensor;

const int DHTPin = 23;     // por defect  el 5  what digital pin we're connected to

DHT dht(DHTPin, DHTTYPE);

// WiFi network info.

Char ssid[] ="sssssssss";

char  wifiPassword[]= "gsssssssssssssssssssssssssss";

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.

char username[]="dsssssssssssssssssssssssssssssssssssssssssss";

char password[]="5sssssssssssssssssssssssssssssssss";

char clientID[]="5ssssssssssssssssssssssssssssssssssss";


unsigned long lastMillis = 0;

//sensor mQ

uint16_t gasVal;

boolean isgas = false;

String gas;

int analogPin = 36;

//const int MQ_PIN =13;//  );      // Pin del sensor


const int RL_VALUE = 5;      // Resistencia RL del modulo en Kilo ohms

const int R0 = 10;          // Resistencia R0 del sensor en Kilo ohms

// Datos para lectura multiple

const int READ_SAMPLE_INTERVAL = 100;    // Tiempo entre muestras

const int READ_SAMPLE_TIMES = 5;       // Numero muestras

// Ajustar estos valores para vuestro sensor según el Datasheet

// (opcionalmente, según la calibración que hayáis realizado)

const float X0 = 200;

const float Y0 = 1.7;

const float X1 = 10000;

const float Y1 = 0.28;

// Puntos de la curva de concentración {X, Y}

const float punto0[] = { log10(X0), log10(Y0) };

const float punto1[] = { log10(X1), log10(Y1) };

// Calcular pendiente y coordenada abscisas

const float scope = (punto1[1] - punto0[1]) / (punto1[0] - punto0[0]);

const float coord = punto0[1] - punto0[0] * scope;

// Obtener la resistencia promedio en N muestras

float readMQ(int mq_pin)

{

   float rs = 0;

   for (int i = 0;i<READ_SAMPLE_TIMES;i++) {

      rs += getMQResistance(analogRead(analogPin));

      delay(READ_SAMPLE_INTERVAL);

   }

   return rs / READ_SAMPLE_TIMES;

}

// Obtener la resistencia promedio en N muestras

float readMQ1(int mq_pin)

{

   float rs = 0;

   for (int i = 0;i<READ_SAMPLE_TIMES;i++) {

      rs += analogRead(analogPin);

      delay(READ_SAMPLE_INTERVAL);

   }

   return rs / READ_SAMPLE_TIMES;

}

// Obtener resistencia a partir de la lectura analogica

float getMQResistance(int raw_adc)

{

   return (((float)RL_VALUE / 1000.0*(1023 - raw_adc) / raw_adc));

}

// Obtener concentracion 10^(coord + scope * log (rs/r0)

float getConcentration(float rs_ro_ratio)

{

   return pow(10, coord + scope * log(rs_ro_ratio));

}

void setup() {

    Serial.begin(115200);

    Cayenne.begin(username, password, clientID, ssid, wifiPassword);

   Serial.println("DHT11 test!");

  dht.begin();

   while(sensor.begin() != 0){

        Serial.println("failed to init chip, please check if the chip connection is fine");

        delay(1000);

    }

    /**

     * @brief Set measurement cycle

     * @param cycle:in typedef enum{

     *                  eClosed,      //Idle (Measurements are disabled in this mode)

     *                  eCycle_1s,    //Constant power mode, IAQ measurement every second

     *                  eCycle_10s,   //Pulse heating mode IAQ measurement every 10 seconds

     *                  eCycle_60s,   //Low power pulse heating mode IAQ measurement every 60 seconds

     *                  eCycle_250ms  //Constant power mode, sensor measurement every 250ms

     *                  }eCycle_t;

     */

    sensor.setMeasCycle(sensor.eCycle_250ms);

}

void loop() {

    Cayenne.loop();

}

CAYENNE_OUT_DEFAULT()

{

  Cayenne.virtualWrite(0, millis());

  float t = dht.readTemperature();

  Serial.print("La  temperatura es de:");

  Serial.print(t);

  Serial.println(" *C ");

  Cayenne.virtualWrite(1, t); //virtual pin

 delay(10000);

  float h = dht.readHumidity();

  Serial.print("La Humedad es de :");

  Serial.print(h);

  Serial.println(" %\t");

  Cayenne.virtualWrite(V2, h); //virtual pin

delay(10000);

 //leer sensor MQ segun la grafica de medidas

// float rs_med = readMQ(analogPin);      // Obtener la Rs promedio

// float concentration = getConcentration(rs_med/R0);   // Obtener la concentración

//  Serial.print("La conentracion rs_med:");

//  Serial.println(rs_med);

// Mostrar el valor de la concentración por serial

//  Serial.print("La conentracion es de :");

//   Serial.println(concentration);

//todas las medidas

gasVal=readMQ1(analogPin);  

gasVal = map(gasVal, 0, 1023, 0, 100); 

Serial.print("La concentracion  de gases es :");

Serial.println(gasVal);

Cayenne.virtualWrite(V3, gasVal); //virtual pin

delay(10000);

 // int raw_adc = analogRead(analogPin );

 // float value_adc = raw_adc * (5.0 / 1023.0);

 // Serial.print("Valor digital :");

 // Serial.println(raw_adc);

 // Cayenne.virtualWrite(V6, raw_adc); //virtual pin

//lectura digital sensor MQ2

isgas=digitalRead(4);

if (isgas) { 

gas = "No"; 

else { 

gas = "Yes"; 

Serial.print("Valor sensor gas:");

Serial.println(gas);

 Cayenne.virtualWrite(V6, isgas); //virtual pin

delay(10000);

//sensor de ccs811

 if(sensor.checkDataReady() == true){

        Serial.print("Valor de CO2: ");

        Serial.print(sensor.getCO2PPM());

        Cayenne.virtualWrite(V4, sensor.getCO2PPM()); //virtual pin

        Serial.println("ppm");

        Serial.print("Valor de TVOC: ");

        Serial.print(sensor.getTVOCPPB());

        Serial.println("ppb");

        Cayenne.virtualWrite(V5,sensor.getTVOCPPB( )); //virtual pin

    } else {

        Serial.println("Data is not ready!");

    }

    /*!

     * @brief Set baseline

     * @param get from getBaseline.ino

     */

    sensor.writeBaseLine(0x847B);

delay(10000); 

//ALMCENAMOS EL LUGAR DONDE SE HACEN LAS MEDIDAS 

//Cayenne.virtualWrite(V6,1);

//1 : estudio

//2: dormitorios

//3: salon

//delay(10000);

//ALMACENAMOS EL NUMERO DE PERSONAS

//Cayenne.virtualWrite(V7,1);

 //delay(10000);

 //pausa entre medidas

  for (int i = 0;i<300;i++)  //pausa de 5 minutos

  {

  delay(1000);

  }

 }

// Default function for processing actuator commands from the Cayenne Dashboard.

// You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.

CAYENNE_IN_DEFAULT()

{

  CAYENNE_LOG("Channel %u, value %s", request.channel, getValue.asString());

  //Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");

}

Regresión lineal

Con los datos salvados en la plataforma Cayenne    de los 6 sensores vamos a intentar analizar la correlación   entre las diferentes magnitudes físicas para intentar obtener un modelo predictivo usando Machine Learning.

En primer lugar, desde el interfaz de Cayenne en “Data” seleccionaremos dos días   y descargaremos en un fichero csv los datos pertenecientes a los 6 sensores.

Recordemos que los algoritmos de Machine Learning Supervisados, aprenden por sí mismos y -en este caso- a obtener automáticamente esa “recta” que buscamos con la tendencia de predicción. Para hacerlo se mide el error con respecto a los puntos de entrada y el valor “Y” de salida real. El algoritmo deberá minimizar el coste de una función de error cuadrático y esos coeficientes corresponderán con la recta óptima. Hay diversos métodos para conseguir minimizar el coste, pero lo más común es utilizar una versión vectorial y la llamada Ecuación Normal que nos dará un resultado directo.

Este es un ejemplo de la salida de un csv exportado a Excel correspondiente lo datos de dos días:

Desgraciadamente con esa salida directa que nos proporciona Cayenne debemos configurarla para poder ser procesados de forma inversa, es decir cambiando filas por columnas y eliminando la información que no es relevante

Los diferentes tipos de datos obtenidos delas medidas descargadas son los siguientes:

Por ejemplo, tanto el identificador del dispositivo, el canal y el identificador del sensor podemos eliminarlos ya que van unívocamente asociadas al nombre del sensor

Y este es el formato finalmente que adoptaremos con los datos relevantes que vamos a necesitar:

 A continuación, vamos a realizar la representación gráfica a lo largo de 239 muestras tomadas casa cinco minutos desde el 16/5/2021 a las 6:38 al día 17/517 06:20.

Podemos como tanto el nivel de co2 en ppm, como el nivel de gases como incluso el TVOC están bastantes relacionados entre sí, no quedando además clara la relación de estas con la temperatura o la humedad

Una vez obtenido este formato de salida, lo podemos exportar nuevamente a csv con delimitador “coma” y no “punto y coma” para que no haya problemas en la importación desde el notebook.

En la simulación vamos a usar el entorno Anaconda con Jupiter Notebook sobre una maquina con Windows 10 con Intel core i5 cuyo nombre será modelo_regresion.ypnv

Comencemos por importar las librerías que utilizaremos:

import numpy as np

import pandas as pd

import seaborn as sb

import matplotlib.pyplot as plt

%matplotlib inline

from mpl_toolkits.mplot3d import Axes3D

from matplotlib import cm

plt.rcParams['figure.figsize'] = (16, 9)

plt.style.use('ggplot')

from sklearn import linear_model

from sklearn.metrics import mean_squared_error, r2_score

Ahora ya podemos leer el archivo csv y lo cargamos como un datasheet de Pandas. Y vemos su tamaño:

#cargamos los datos de entrada

data = pd.read_csv("./articulos_ml.csv")

#veamos cuantas dimensiones y registros contiene

data.shape

Nos devuelve este valor:

(243,5)

Ahora veamos las cabeceras:

#son 243 registros con 5 columnas. Veamos los primeros registros

data.head()

Es muy importante analizar la estadística de todas las medidas, lo cual en Python es bastante sencillo

# Ahora veamos algunas estadísticas de nuestros datos

data.describe()

Ahora vamos a ver la distribución de los datos:

# Visualizamos rápidamente las características de entrada

data.drop(['temperatura'],1).hist()

plt.show()

# Visualizamos rápidamente las características de entrada

data.drop(['humedad'],1).hist()

plt.show()

En estas gráficas anteriores vemos entre qué valores se concentran la mayoría de registros (gases y C02).

Vamos a filtrar los datos de cantidad de gases y co2 con los registros concentración de gases de menos de 762 y también con los que tengan de Co2 de menos de 11.000ppm. Lo gratificaremos pintando en azul los puntos con menos de 1808 (la media) y en naranja los que tengan más.

# Vamos a RECORTAR los datos en la zona donde se concentran más los puntos

# esto es en el eje X: entre 0 y 220

# y en el eje Y: entre 0 y 1400

filtered_data = data[(data['gases'] <= 220) & (data['c02ppm'] <= 11000)]

colores=['orange','blue']

tamanios=[30,60]

f1 = filtered_data['c02ppm'].values

f2 = filtered_data['gases'].values

# Vamos a pintar en colores los puntos por debajo y por encima de la media de co2

asignar=[]

for index, row in filtered_data.iterrows():

    if(row['c02ppm']>762):

        asignar.append(colores[0])

    else:

        asignar.append(colores[1])

plt.scatter(f1, f2, c=asignar, s=tamanios[0])

plt.show()

Y en la siguiente imagen podemos ver la representación de los puntos:

Vamos a crear nuestros datos de entrada por el momento sólo concentración de gases  y como etiquetas la concentración de CO2. Creamos el objeto LinearRegression y lo hacemos “encajar” (entrenar) con el método fit().

 Finalmente imprimimos los coeficientes y puntajes obtenidos.

# Asignamos nuestra variable de entrada X para entrenamiento y las etiquetas Y.

dataX =filtered_data[["c02ppm"]]

X_train = np.array(dataX)

y_train = filtered_data['gases'].values

# Creamos el objeto de Regresión Linear

regr = linear_model.LinearRegression()

# Entrenamos nuestro modelo

regr.fit(X_train, y_train)

# Hacemos las predicciones que en definitiva una línea (en este caso, al ser 2D)

y_pred = regr.predict(X_train)

# Veamos los coeficientes obtenidos, En nuestro caso, serán la Tangente

print('Coefficients: \n', regr.coef_)

# Este es el valor donde corta el eje Y (en X=0)

print('Independent term: \n', regr.intercept_)

# Error Cuadrado Medio

print("Mean squared error: %.2f" % mean_squared_error(y_train, y_pred))

# Puntaje de Varianza. El mejor puntaje es un 1.0

print('Variance score: %.2f' % r2_score(y_train, y_pred))

Y este es el resultado obtenido:

De la ecuación de la recta y = mX + b nuestra pendiente “m” es el coeficiente 0,05 y el término independiente “b” es 159,7843466   asi que la ecuación de la recta sería:   y= 0.0504829*x +159.78434668080695;

Tenemos un Error Cuadrático de 103,38 que no es muy malo como se ve reflejado en el puntaje de Varianza que debería ser cercano a 1.0 (el valor obtenido es 0.60).

Veamos a continuación los datos   de regresión lineal con la recta que obtuvimos:

# Vamos a RECORTAR los datos en la zona donde se concentran más los puntos

# esto es en el eje X: entre 0 y 220

# y en el eje Y: entre 0 y 1400

filtered_data = data[(data['gases'] <= 220) & (data['c02ppm'] <= 11000)]

colores=['orange','blue']

tamanios=[30,60]

f1 = filtered_data['c02ppm'].values

f2 = filtered_data['gases'].values

# Vamos a pintar en colores los puntos por debajo y por encima de la media de co2

asignar=[]

for index, row in filtered_data.iterrows():

    if(row['c02ppm']>762):

        asignar.append(colores[0])

    else:

        asignar.append(colores[1])

plt.scatter(f1, f2, c=asignar, s=tamanios[0])

#plt.show()

from matplotlib import pyplot

#definimos la ecuación de la recta usando los datos calculados en el apartado anterior

# y=mx+n donde m es el coeficiente   y n el termino independiente

# y con esto definimos f(x)

def f(x):

    return  0.0504829*x +159.78434668080695;

#En esta variable se genera una lista con valores del -10 al 10.

#Todos estos valores serán los que tomara x.

x = range(0, 1400)

#Con el método plot especificamos que función graficaremos.

#El primer argumento es la variable con los valores de x.

#El segundo argumento le pasamos todos estos valares a la función con ayuda de un bucle.

pyplot.plot(x, [f(i) for i in x])

# Mostramos el gráfico.

pyplot.show()

Y esta es la recta final que hemos obtenido de regresión lineal:

Predicción en regresión lineal simple

Vamos a intentar probar nuestro algoritmo, suponiendo que quisiéramos predecir para una concentración de Co2de 800   cuál es el nivel de gases

#Vamos a comprobar:

# Quiero predecir el nivel de gases  para un nivel de CO2 de 800 ,

# según nuestro modelo, hacemos:

y_Dosmil = regr.predict([[800]])

print(int(y_Dosmil))

Nos arroja el siguiente resultado

200
 
 

Este dato puede ser una trivialidad, pero pues ser claramente útil, porque en caso de una lectura anómala o incluso ante un posible fallo del sensor de nivel de aire, podemos usar este valor como referencia para que se dispare una alarma desde Cayenne.

Regresión Lineal Múltiple o “Regresión con Múltiples Variables”)

Vamos a extender los cálculos utilizando más de una variable de entrada para el modelo pues le dará mayor poder al algoritmo de Machine Learning, ya que de esta manera podremos obtener predicciones más complejas de modo que nuestra “ecuación de la Recta”, pase a ser:   Y = b + m1 X1 + m2 X2 + … + m(n) X(n)

Utilizaremos ahora dos “variables predictivas” para poder graficar en 3D.

Vamos a crear nuestros datos de entrada por el momento sólo con los datos de Tvoc y como etiquetas la temperatura y humedad Creamos además el objeto LinearRegression y lo hacemos “encajar” (entrenar) con el método fit ().

Finalmente imprimimos los coeficientes y puntajes obtenidos.

Vamos a intentar mejorar el Modelo, con una dimensión más:

# Para poder graficar en 3D, haremos una variable nueva.

suma = ( filtered_data["tvoc"])

dataX2 =  pd.DataFrame()

dataX2["temperatura"] = filtered_data["temperatura"]

dataX2["humedad"] = filtered_data["humedad"]

XY_train = np.array(dataX2)

z_train = filtered_data['c02ppm'].values

#Creamos un nuevo objeto de Regresión lineal  que  tendrá  dos dimensiones

#para  entrenar: las que contiene XY_train

regr2 = linear_model.LinearRegression()

# Entrenamos el modelo, esta vez, con 2 dimensiones

# obtendremos 2 coeficientes, para graficar un plano

regr2.fit(XY_train, z_train)

# Hacemos la predicción con la que tendremos puntos sobre el plano hallado

z_pred = regr2.predict(XY_train)

# Los coeficientes

print('Coeficientes: \n', regr2.coef_)

# Error cuadrático medio

print("Error cuadratico medio: %.2f" % mean_squared_error(z_train, z_pred))

# Evaluamos la varianza (siendo 1.0 el mejor posible)

print('Varaianza: %.2f' % r2_score(z_train, z_pred))

Cuya salida es la siguiente:

Coeficientes: 
 [23.5745229  29.52613494]
Error cuadratico medio: 50913.69
Varaianza: 0.17

Ya tenemos nuestras 2 variables de entrada en XY_train y nuestra variable de salida pasa de ser “Y” a ser el eje “Z”.

Creamos un nuevo objeto de Regresión lineal con SKLearn pero esta vez tendrá las dos dimensiones que entrenar: las que contiene XY_train. Al igual que antes, imprimimos los coeficientes y puntajes obtenidos:

fig = plt.figure()

ax = Axes3D(fig)

 # Creamos una malla, sobre la cual graficaremos el plano

xx, yy = np.meshgrid(np.linspace(0, 3500, num=10), np.linspace(0, 60, num=10))

# calculamos los valores del plano para los puntos x e y

nuevoX = (regr2.coef_[0] * xx)

nuevoY = (regr2.coef_[1] * yy)

# calculamos los correspondientes valores para z. Debemos sumar el punto de

#intercepción

z = (nuevoX + nuevoY + regr2.intercept_)

# Graficamos el plano

ax.plot_surface(xx, yy, z, alpha=0.2, cmap='hot')

# Graficamos en azul los puntos en 3D

ax.scatter(XY_train[:, 0], XY_train[:, 1], z_train, c='blue',s=30)

# Graficamos en rojo, los puntos que

ax.scatter(XY_train[:, 0], XY_train[:, 1], z_pred, c='red',s=40)

# con azim podremos visualizar el grafico entre 0 y 360 grados.

ax.view_init(elev=30., azim= 65)

ax.set_xlabel('Nivel  de Co2')

ax.set_ylabel('Gases')

ax.set_zlabel('TVOC,temp y humedad')

ax.set_title('Regresión Lineal con Múltiples Variables')

#Vamos a intentar probar nuestro modelo, suponiendo que quisiéramos predecir el nivel de C02

# con los valores de temperatura y humedad

print('Predicción: \n')

z_Effort= regr2.predict([[30, 30]])

print(int(z_Effort))

Y la salida es

Prediccion: 
 
165

Podemos rotar el gráfico para apreciar el plano desde diversos ángulos modificando el valor del parámetro azim en view_init con números de 0 a 360.