Construye un sensor de calidad del aire con un sensor MQ135 para detectar humo y otros gases nocivos con Alexa

En esta sección te explicamos cómo crear un sensor de calidad del aire con un ESP32 o ESP8266. Después podrás consultar la calidad del aire con Amazon Alexa y recibir una notificación push en la app Sinric Pro cuando la calidad del aire baje de un determinado umbral.

Requisitos previos :

  1. ESP32, ESP8266 x 1.
  2. MQ135 x 1.
  3. Cables puente (jumper).

Sinric Pro MQ135 air quality

Breve introducción al MQ135

El MQ135 es un sensor de gas semiconductor que se usa habitualmente en equipos de control de la calidad del aire. Es sensible a una amplia variedad de gases, como amoníaco, sulfuros, benceno y humo. El sensor tiene dos salidas: una salida digital que pasa a nivel alto cuando la concentración de gas supera un determinado umbral, y una salida analógica que proporciona una tensión proporcional a la concentración de gas.

El sensor MQ135 necesita una alimentación de 5V y consume unos 150mA de corriente. La salida digital se puede conectar a un ESP32, ESP8266 o Pico W para medir la concentración de gas.

Cómo calibrar el sensor MQ135

El MQ135 no da directamente un valor en ppm. Su resistencia (Rs) cambia con la concentración de gas, y el valor en ppm se calcula a partir de la relación entre Rs y R0, la resistencia del sensor en aire limpio. R0 es distinta en cada sensor, así que hay que calibrar cada uno.

1. Rodaje inicial (una sola vez): coloca el sensor en el exterior, donde haya suficiente aire fresco (lo ideal, según la hoja de datos, es a 20°C y 33% de humedad), y déjalo encendido entre 12 y 24 horas para completar el rodaje y que se estabilice.

2. Calentamiento (en cada encendido): el sensor tiene un calentador. Las lecturas son demasiado altas durante los primeros minutos tras el encendido, así que espera a que se estabilicen antes de usarlas.

3. Mide R0 en aire limpio: con el sensor todavía al aire fresco, deja que la librería TroykaMQ que se usa en este tutorial calcule R0 y lo muestre:

#include <TroykaMQ.h>

#define PIN_MQ135 34 // ESP32. Use A0 on ESP8266

MQ135 mq135(PIN_MQ135);

void setup() {
  Serial.begin(115200);
  mq135.calibrate();               // run this in clean air
  Serial.print("Ro = ");
  Serial.println(mq135.getRo());
}

4. Reutiliza el valor: anota el R0 mostrado y pásalo a calibrate(). Así el sensor no necesita aire fresco cada vez que se reinicia:

mq135.calibrate(YOUR_RO_VALUE);

La temperatura y la humedad alteran la lectura, así que calibra en condiciones parecidas a las del lugar donde se va a usar el sensor. El MQ135 sirve para detectar que la calidad del aire ha cambiado, pero no es un instrumento de precisión.

¿La lectura del MQ135 se queda atascada en valores altos (entre 3800 y 4095)?

En un ESP32, analogRead() devuelve valores de 0 a 4095. Una lectura que se mantiene en la parte alta de ese rango, o cerca de ella, suele deberse a una de estas causas:

Hoja de especificaciones: SNS-MQ135

Cableado

Sinric Pro ESP32 ESP8266 MQ135 air quality sensor wiring diagram

MCU Pin A0 Pin VCC
ESP32 34 (Analog ADC1_CH6) 5V
ESP8266 A0 5V/VIN
Pico W GP26 (ADC0) 5V

Nota: en el ESP32, el ADC2 (GPIO04, GPIO02, GPIO15) es inestable cuando se usa el Wi-Fi.

Vamos a comprobar que el sensor de movimiento está bien cableado y funciona.

#include <TroykaMQ.h> // https://github.com/amperka/TroykaMQ

#if defined(ESP8266)
  #define SENSOR_PIN        A0
#elif defined(ESP32) 
  #define SENSOR_PIN        34
#endif

MQ135 mq135(SENSOR_PIN);

void setup() {
   Serial.begin(9600);
   // before calibrating the sensor, warm it up for 60 seconds calibrate the sensor in clean air
   mq135.calibrate();
   // if you know the resistance of the sensor in clean air
   // you can specify it manually, eg: 160 mq135.calibrate(160);   
   Serial.print("Ro = ");
   Serial.println(mq135.getRo());
}

void loop() {
   // display gas values in ppm
   Serial.print(mq135.readCO2());
   Serial.println("ppm");
   delay(1000);
}

Ver este código en GitHub Gist

El Monitor serie de Arduino IDE mostrará las detecciones de movimiento de esta forma:

Sinric Pro mq135 test reading

Detectar una mala calidad del aire

#include <TroykaMQ.h> // https://github.com/amperka/TroykaMQ

#if defined(ESP8266)
  #define SENSOR_PIN        A0
#elif defined(ESP32) 
  #define SENSOR_PIN        34
#endif

MQ135 mq135(SENSOR_PIN);

const int AQI_THRESHOLD_SEVERE = 700;
const int AQI_THRESHOLD_VERY_POOR = 600;
const int AQI_THRESHOLD_POOR = 500;
const int AQI_THRESHOLD_MODERATE = 400;

int ppm = 0;

void setup() {
   Serial.begin(9600);
   // before calibrating the sensor, warm it up for 60 seconds calibrate the sensor in clean air
   mq135.calibrate();
   // if you know the resistance of the sensor in clean air
   // you can specify it manually, eg: 160 mq135.calibrate(160);   
   Serial.print("Ro = ");
   Serial.println(mq135.getRo());
}

void loop() {
   ppm = mq135.readCO2();
   
   if (ppm > AQI_THRESHOLD_SEVERE) {
    Serial.print("Air quality is SEVERE!");
   } else if (ppm > AQI_THRESHOLD_VERY_POOR) {
    Serial.print("Air quality is VERY POOR!");
   } else if (ppm > AQI_THRESHOLD_POOR) {
    Serial.print("Air quality is VERY POOR!");
   } else if (ppm > AQI_THRESHOLD_MODERATE) {
    Serial.print("Air quality is MODERATE");
   } else {
    Serial.print("Air quality is GOOD");
   }

   delay(1000);
}

Ver este código en GitHub Gist

Paso 1 : Conéctate a Sinric Pro

Paso 1.1 : Crea un tipo de dispositivo personalizado para el sensor de calidad del aire.

Sinric Pro no tiene un tipo de dispositivo integrado para un sensor de calidad del aire con PPM, así que vamos a crear un tipo de dispositivo personalizado para el sensor de agua con la función Device Template para obtener:

  1. El valor en PPM

  2. Si la calidad del aire es Severe, Very Poor, Poor, Moderate o Good.

Nota: puedes usar la función de importación de plantillas de dispositivo que se describe más abajo para no tener que crear la plantilla completa.

Sinric Pro air quality ensor device template

Aquí tenemos que seleccionar las funciones de nuestro sensor de calidad del aire. Queremos saber si la calidad del aire es Severe, Very Poor, Poor, Moderate o Good. Así que arrastra una capacidad Range, una Mode y una Push Notification.

Sinric Pro custom device type for MQ135 air quality sensor with range and mode capabilities

Haz clic en el botón Configure y configura las dos capacidades como se muestra a continuación.

Sinric Pro moisture sensor template mode and range settings

Haz clic en Save para guardar.

Sinric Pro moisture sensor template mode and range settings

Haz clic en Save para guardar la plantilla.

Ahora puedes ver la plantilla que acabamos de crear.

¿Importar una plantilla existente?

Si te da pereza configurar todos los valores de Mode y Range, puedes usar la función de importación.

Sinric Pro capacitive soil moisture sensor import template

Pega esta plantilla:

{
  "name": "Air Quality Sensor",
  "description": "Air Quality Sensor",
  "deviceTypeId": "5ff0b112994fd31b7d5e8065",
  "capabilities": [
    {
      "id": "5ff0b41b994fd31b7d5e8961",
      "mode": {
        "instanceId": "modeInstance1",
        "locale": "en-US",
        "modeName": "Air Quality",
        "nonControllable": true,
        "modeValues": [
          "SEVERE",
          "VERY POOR",
          "POOR",
          "MODERATE",
          "GOOD"
        ]
      }
    },
    {
      "id": "5ff0b45f994fd31b7d5e89c2",
      "range": {
        "instanceId": "rangeInstance1",
        "locale": "en-US",
        "rangeName": "ppm",
        "minimumValue": 1,
        "maximumValue": 1024,
        "precision": 1,
        "unitOfMeasure": "600e7986a7a09c3f3230f8fb",
        "presets": [],
        "nonControllable": true
      }
    },
    {
      "id": "62a707bd9e2f39090569e2d3"
    }
  ]
}

Ver este código en GitHub Gist

Sinric Pro create device alexa

Sinric Pro create device alexa

Sinric Pro copy device id

Sinric Pro copy device id

Paso 2 : Conéctate a Sinric Pro

Paso 2.1 Instala la librería Sinric Pro

Sinric Pro install SinricPro library

Paso 2.2 Instala TroykaMQ

TroykaMQ no está disponible en el Gestor de bibliotecas de Arduino. Tienes que descargarla de https://github.com/amperka/TroykaMQ y copiarla en C:\Users\<your username>\Documents\Arduino\libraries

2.2 Código completo

AirQualitySensor.h

#ifndef _AIRQUALITYSENSOR_H_
#define _AIRQUALITYSENSOR_H_

#include <SinricProDevice.h>
#include <Capabilities/ModeController.h>
#include <Capabilities/RangeController.h>
#include <Capabilities/PushNotification.h>

class AirQualitySensor 
: public SinricProDevice
, public ModeController<AirQualitySensor>
, public RangeController<AirQualitySensor>
, public PushNotification<AirQualitySensor> {
  friend class ModeController<AirQualitySensor>;
  friend class RangeController<AirQualitySensor>;
  friend class PushNotification<AirQualitySensor>;
public:
  AirQualitySensor(const String &deviceId) : SinricProDevice(deviceId, "AirQualitySensor") {};
};

#endif

sinricpro-air-quality-sensor.ino


// Uncomment the following line to enable serial debug output
//#define ENABLE_DEBUG

#ifdef ENABLE_DEBUG
  #define DEBUG_ESP_PORT Serial
  #define NODEBUG_WEBSOCKETS
  #define NDEBUG
#endif

#include <Arduino.h>
#ifdef ESP8266
  #include <ESP8266WiFi.h>
#endif
#ifdef ESP32
  #include <WiFi.h>
#endif

#include <TroykaMQ.h> // https://github.com/amperka/TroykaMQ
#include <SinricPro.h>
#include "AirQualitySensor.h"

#define WIFI_SSID         ""   // Your WiFI SSID name 
#define WIFI_PASS         ""   // Your WiFi Password.

#define APP_KEY           ""   // Should look like "de0bxxxx-1x3x-4x3x-ax2x-5dabxxxxxxxx" (Get it from Portal -> Secrets)
#define APP_SECRET        ""   // Should look like "5f36xxxx-x3x7-4x3x-xexe-e86724a9xxxx-4c4axxxx-3x3x-x5xe-x9x3-333d65xxxxxx" (Get it from Portal -> Secrets)
#define DEVICE_ID         ""   // Should look like "5dc1564130xxxxxxxxxxxxxx" (Get it from Portal -> Devices)

#define BAUD_RATE         115200              // Change baudrate to your need (used for serial monitor)
#define EVENT_WAIT_TIME   60000               // send event every 60 seconds


#define BAUD_RATE         115200
#define EVENT_WAIT_TIME   60000               // send event every 60 seconds

#if defined(ESP8266)
  #define SENSOR_PIN        A0
#elif defined(ESP32) 
  #define SENSOR_PIN        34
#endif

MQ135 mq135(SENSOR_PIN);

const int AQI_THRESHOLD_SEVERE = 700;
const int AQI_THRESHOLD_VERY_POOR = 600;
const int AQI_THRESHOLD_POOR = 500;
const int AQI_THRESHOLD_MODERATE = 400;

int ppm = 0;
int lastPPM = 0;
String lastAirQualityLevelStr = "";

AirQualitySensor &airQualitySensor = SinricPro[DEVICE_ID];
 
// ModeController
void updateMode(String mode) {
  airQualitySensor.sendModeEvent("modeInstance1", mode, "PHYSICAL_INTERACTION");
}

// RangeController
void updateRangeValue(int value) {
  airQualitySensor.sendRangeValueEvent("rangeInstance1", value);
}

// PushNotificationController
void sendPushNotification(String notification) {
  airQualitySensor.sendPushNotification(notification);
}

/********* 
 * Setup *
 *********/

void setupAirQualitySensor() {
   // before calibrating the sensor, warm it up for 60 seconds calibrate the sensor in clean air
   mq135.calibrate();
   // if you know the resistance of the sensor in clean air
   // you can specify it manually, eg: 160 mq135.calibrate(160);   
   Serial.print("Ro = ");
   Serial.println(mq135.getRo());
}

void setupSinricPro() {
  SinricPro.onConnected([]{ Serial.printf("[SinricPro]: Connected\r\n"); });
  SinricPro.onDisconnected([]{ Serial.printf("[SinricPro]: Disconnected\r\n"); });
  SinricPro.begin(APP_KEY, APP_SECRET);
};

void setupWiFi() {
  #if defined(ESP8266)
    WiFi.setSleepMode(WIFI_NONE_SLEEP); 
    WiFi.setAutoReconnect(true);
  #elif defined(ESP32)
    WiFi.setSleep(false); 
    WiFi.setAutoReconnect(true);
  #endif

  WiFi.begin(SSID, PASS);
  Serial.printf("[WiFi]: Connecting to %s", SSID);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.printf(".");
    delay(250);
  }
  Serial.printf("connected\r\n");
}

void setup() {
  Serial.begin(BAUD_RATE);
  setupAirQualitySensor();
  setupWiFi();
  setupSinricPro();
}

/********
 * Loop *
 ********/

 void handleAirQualitySensor() {
  if (SinricPro.isConnected() == false) {
    return; 
  }

  static unsigned long last_millis;
  unsigned long        current_millis = millis();
  if (last_millis && current_millis - last_millis < EVENT_WAIT_TIME) return;
  last_millis = current_millis;
    
  ppm = mq135.readCO2();

  Serial.printf("Present ppm: %d\r\n", ppm); 
  
  if (ppm == lastPPM) {
    Serial.printf("PPM did not changed. do nothing...!\r\n");
    return; 
  }

  /* determine air quality level */
  String airQualityLevelStr = "";

  if (ppm > AQI_THRESHOLD_SEVERE) {
    airQualityLevelStr = "SEVERE";
   } else if (ppm > AQI_THRESHOLD_VERY_POOR) {
    airQualityLevelStr = "VERY POOR";
   } else if (ppm > AQI_THRESHOLD_POOR) {
    airQualityLevelStr = "POOR";
   } else if (ppm > AQI_THRESHOLD_MODERATE) {
    airQualityLevelStr = "MODERATE";
   } else {
    airQualityLevelStr = "GOOD";
   }

  /* Update air quality level label if changed */
  if(lastAirQualityLevelStr != airQualityLevelStr) {
    lastAirQualityLevelStr = airQualityLevelStr;
    updateMode(lastAirQualityLevelStr);
  }
  
  delay(500);

  /* update PPM label */
  updateRangeValue(ppm);

  /* send a push notification when air quality level is bad! */
  if (ppm > AQI_THRESHOLD_SEVERE) {
    sendPushNotification("Air quality is SEVERE!");
  } else if (ppm > AQI_THRESHOLD_VERY_POOR) {
    sendPushNotification("Air quality is VERY POOR!");
  } else if (ppm > AQI_THRESHOLD_POOR) {
    sendPushNotification("Air quality is VERY POOR!");
  }

  lastPPM = ppm;  // save to compare next time.
}

void loop() {
  handleAirQualitySensor();
  SinricPro.handle();
}

Ver este código en GitHub Gist

Ahora deberías poder ver el estado de la calidad del aire y el nivel de agua con Alexa y la app Sinric Pro

Alexa, ¿cuál es la calidad del aire (nombre del modo) en Air Quality Sensor (nombre del dispositivo)?

Alexa, ¿cuál es el ppm (nombre del rango) en Air Quality Sensor (nombre del dispositivo)?

Sinric Pro MQ135 air quality sensor in the Alexa app

Sinric Pro MQ135 air quality sensor in the Portal

Paso 3 : ¡Anuncios de voz!

✅ Cómo funciona:

1️⃣ Añade un Switch en SinricPro (¡tu activador secreto!)

2️⃣ Crea una rutina de Alexa que diga tu mensaje, por ejemplo “¡La calidad del aire es mala!”, cuando se encienda el Switch

3️⃣ Envía desde tu código un evento de estado de encendido para poner ese Switch en ON

void triggerVoiceAnnouncement() {
    SinricProSwitch& mySwitch = SinricPro[SWITCH_ID];
    mySwitch.sendPowerStateEvent(true);
}

Solución de problemas

  1. Google Home y SmartThings no son compatibles.

  2. Consulta nuestra página de Solución de problemas para más detalles.

Tutoriales relacionados

Este documento es de código abierto. ¿Has visto una errata? Crea una issue