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 :
- ESP32, ESP8266 x 1.
- MQ135 x 1.
- Cables puente (jumper).

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:
- La tensión de salida supera el rango del ADC. El módulo se alimenta con 5V, de modo que su salida A0 puede superar el límite de 3.3 V del ADC del ESP32 y la lectura se satura. Añade un divisor de tensión entre A0 y el GPIO.
- El sensor todavía se está calentando, o es un sensor nuevo al que aún no se le ha hecho el rodaje.
- Se usa un pin del ADC2 con el Wi-Fi activado. Usa un pin del ADC1, como el GPIO 34.
- El sensor se calibró en aire contaminado, así que R0 es incorrecto. Vuelve a calibrarlo al aire fresco.
Hoja de especificaciones: SNS-MQ135
Cableado

| 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:

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:
-
El valor en PPM
-
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.
-
Inicia sesión en tu cuenta de Sinric Pro y ve a Device Templates
-
Haz clic en Add Device Template. Escribe Air Quality Sensor como nombre y descripción y selecciona Air Quality Sensor como tipo de dispositivo

- Haz clic en Capabilities.
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.

-
¿Qué es la capacidad Range?
La capacidad Range sirve para representar un número. Por ejemplo: la velocidad actual de una batidora.
-
¿Qué es la capacidad Mode?
La capacidad Mode sirve para representar un valor de una lista de valores predefinidos. Por ejemplo: el programa de lavado actual de una lavadora.
-
¿Qué es la capacidad Push Notification?
La capacidad Notification permite enviar un mensaje de notificación push desde el código.
Haz clic en el botón Configure y configura las dos capacidades como se muestra a continuación.

Haz clic en Save para guardar.

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.

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
-
Inicia sesión en tu cuenta de Sinric Pro, abre el menú Devices a la izquierda y haz clic en el botón Add Device (arriba a la izquierda).
-
Escribe el nombre del dispositivo Air Quality Sensor, la descripción Air Quality Sensor y selecciona el tipo de dispositivo Air Quality Sensor en Your Device Templates.


-
Haz clic en la pestaña Others y después en Save
-
La siguiente pantalla muestra las credenciales necesarias para conectar el dispositivo que acabas de crear.

-
Copia Device Id, App Key y App Secret Mantén estos valores seguros. ¡NO LOS COMPARTAS EN FOROS PÚBLICOS!
-
Haz clic en Code Generator para generar el código. Haz clic en Download para descargarlo.

Paso 2 : Conéctate a Sinric Pro
Paso 2.1 Instala la librería Sinric Pro

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)?


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
-
Google Home y SmartThings no son compatibles.
-
Consulta nuestra página de Solución de problemas para más detalles.
Tutoriales relacionados
- Cómo controlar un ESP32 o ESP8266 con Alexa y Google Home
- Sensor de alcohol y gas MQ-3
- Sensor capacitivo de humedad del suelo (HW-390)
- Sensor de fugas de agua, inundación y lluvia
Este documento es de código abierto. ¿Has visto una errata? Crea una issue