Raspberry Pi

Monitor de calidad del aire con Raspberry Pi, BME680 y MQTT

Conecta un BME680 a una Raspberry Pi, calibra una línea base de gas, calcula un índice sencillo de calidad del aire interior y envía todo a un broker MQTT que puedes consultar desde cualquier lugar.

Monitor de calidad del aire con Raspberry Pi y una placa con sensor BME680 que envía lecturas de gas, humedad y temperatura a un dashboard MQTT
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

Un monitor de calidad del aire con Raspberry Pi basado en el Bosch BME680 es uno de los pequeños proyectos de sensores más útiles que puedes instalar en una oficina, un taller o un dormitorio. En este tutorial conectarás el sensor, leerás en Python la temperatura, la humedad, la presión y la resistencia de gas, convertirás esos valores brutos en una estimación sencilla de la calidad del aire interior (IAQ) y lo publicarás todo por MQTT para que cualquier dashboard o teléfono pueda seguirlo en vivo.

Qué mide realmente el BME680

El BME680 combina cuatro mediciones en un encapsulado diminuto: temperatura, humedad relativa, presión barométrica y la resistencia de una capa de óxido metálico calentada que reacciona a los gases. Las tres primeras son magnitudes físicas directas. La cuarta es la interesante y también la que más se malinterpreta.

El sensor de gas no informa de un gas concreto ni de una concentración en ppm. Los compuestos orgánicos volátiles (COV) de productos de limpieza, la cocina, la pintura, las personas y los muebles reaccionan con la capa sensora calentada y reducen su resistencia. El aire limpio da una resistencia alta; el aire contaminado, una más baja. Eso convierte el valor bruto en un indicador relativo: excelente para detectar tendencias y eventos ("alguien acaba de empezar a cocinar", "hay que ventilar la sala"), no una medición de laboratorio.

Bosch distribuye una biblioteca de código cerrado llamada BSEC que convierte estas lecturas en un índice IAQ calibrado de 0 a 500 y en equivalentes estimados de CO2. Funciona bien, pero es un binario con su propia licencia y su propio esfuerzo de integración. Para un monitor de hobby o de laboratorio, una puntuación transparente basada en una línea base suele bastar, y eso es lo que construiremos aquí. Si más adelante necesitas BSEC, la parte MQTT de este proyecto se queda exactamente igual.

Lectura Unidad Rango interior típico Qué te indica
Temperatura °C 18 a 26 Confort, y un factor de corrección para la capa de gas
Humedad relativa % 30 a 60 Confort, riesgo de moho, parte del índice IAQ
Presión hPa 950 a 1050 Tendencia meteorológica, no calidad del aire
Resistencia de gas Ohm Decenas a cientos de kOhm Nivel relativo de COV; más alto es más limpio

Componentes y cableado

Necesitas:

  1. Cualquier Raspberry Pi con conector de 40 pines (Zero 2 W, 3, 4 o 5) con Raspberry Pi OS.
  2. Una placa breakout BME680. Funcionan las de Adafruit, Pimoroni y muchas genéricas; comprueba si la tuya usa la dirección I2C 0x76 o 0x77.
  3. Cuatro cables jumper.

Conecta la breakout a la Pi por I2C:

Pin del BME680 Pin de la Raspberry Pi
VIN / 3V3 Pin 1 (3,3 V)
GND Pin 6 (GND)
SDA / SDI Pin 3 (GPIO 2, SDA)
SCL / SCK Pin 5 (GPIO 3, SCL)

Monta el sensor alejado de la propia Pi. La CPU y el regulador de tensión calientan la placa, y un sensor situado justo encima del SoC marcará varios grados de más y bajará la humedad. Un cable de 10 a 15 cm o un pequeño separador marcan una diferencia notable.

Preparar la Raspberry Pi

Activa I2C, confirma que el sensor es visible y crea un entorno virtual de Python (Raspberry Pi OS Bookworm y posteriores lo exigen para instalar con pip):

sudo raspi-config nonint do_i2c 0
sudo apt update && sudo apt install -y i2c-tools python3-venv
i2cdetect -y 1          # expect 76 or 77 in the grid

python3 -m venv ~/aq-env
source ~/aq-env/bin/activate
pip install adafruit-circuitpython-bme680 paho-mqtt

Si i2cdetect muestra una cuadrícula vacía, revisa SDA y SCL (es fácil intercambiarlos) y asegúrate de que la placa se alimenta a 3,3 V. La documentación oficial de configuración de Raspberry Pi explica la configuración de I2C con más detalle si usas una imagen no estándar.

El script del monitor de calidad del aire con Raspberry Pi

El script siguiente hace cuatro cosas: lee el sensor cada diez segundos, ejecuta un calentamiento de cinco minutos para establecer una línea base de gas, calcula una estimación IAQ a partir del gas y la humedad, y publica un mensaje JSON en el servidor MQTT público gratuito de broker.connectmq.com. También configura un Last Will para que los suscriptores sepan cuándo el monitor se desconecta.

#!/usr/bin/env python3
"""Raspberry Pi air quality monitor: BME680 -> MQTT."""
import json
import time
import uuid

import board
import adafruit_bme680
import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
PORT = 1883
DEVICE_ID = "pi-aq-" + uuid.uuid4().hex[:6]
BASE_TOPIC = f"connectmq/demo/{DEVICE_ID}/air"
I2C_ADDRESS = 0x77          # cambiar a 0x76 en placas tipo Pimoroni
INTERVAL = 10               # segundos entre lecturas
BURN_IN = 300               # segundos para aprender la línea base de aire limpio
HUM_BASELINE = 40.0         # humedad interior ideal en porcentaje
HUM_WEIGHT = 0.25           # peso de la humedad en la puntuación


def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code)
    client.publish(f"{BASE_TOPIC}/status", "online", qos=1, retain=True)


def iaq_score(gas, hum, gas_baseline):
    """0-100, más alto es mejor. Estimación simple y transparente, no Bosch BSEC."""
    hum_offset = hum - HUM_BASELINE
    if hum_offset > 0:
        hum_score = (100 - HUM_BASELINE - hum_offset) / (100 - HUM_BASELINE)
    else:
        hum_score = (HUM_BASELINE + hum_offset) / HUM_BASELINE
    hum_score *= HUM_WEIGHT * 100

    gas_offset = gas_baseline - gas
    if gas_offset > 0:
        gas_score = (gas / gas_baseline) * (100 - HUM_WEIGHT * 100)
    else:
        gas_score = 100 - HUM_WEIGHT * 100
    return round(max(0.0, min(100.0, hum_score + gas_score)), 1)


def main():
    i2c = board.I2C()
    sensor = adafruit_bme680.Adafruit_BME680_I2C(i2c, address=I2C_ADDRESS)
    sensor.sea_level_pressure = 1013.25

    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=DEVICE_ID)
    client.will_set(f"{BASE_TOPIC}/status", "offline", qos=1, retain=True)
    client.on_connect = on_connect
    client.connect(BROKER, PORT, keepalive=60)
    client.loop_start()

    print(f"Burn-in for {BURN_IN} s, publishing to {BASE_TOPIC}/#")
    samples = []
    start = time.time()
    while time.time() - start < BURN_IN:
        samples.append(sensor.gas)
        time.sleep(1)
    gas_baseline = sum(samples[-50:]) / len(samples[-50:])
    print(f"Gas baseline: {gas_baseline:.0f} Ohm")

    while True:
        gas = sensor.gas
        hum = sensor.relative_humidity
        payload = {
            "ts": int(time.time()),
            "temperature_c": round(sensor.temperature, 2),
            "humidity_pct": round(hum, 1),
            "pressure_hpa": round(sensor.pressure, 1),
            "gas_ohm": int(gas),
            "iaq_score": iaq_score(gas, hum, gas_baseline),
        }
        client.publish(f"{BASE_TOPIC}/telemetry", json.dumps(payload), qos=1)
        print(payload)
        time.sleep(INTERVAL)


if __name__ == "__main__":
    main()

Ejecútalo con python aq_monitor.py. Durante el calentamiento, el calefactor se estabiliza; un sensor completamente nuevo deriva durante su primer o segundo día, así que no te fíes de la línea base de la primera ejecución. Un hábito práctico es arrancar el script con aire fresco (abre una ventana durante los primeros cinco minutos), porque la línea base define qué significa "limpio" durante el resto de la sesión.

Interpretar la estimación IAQ

La puntuación está invertida respecto al índice de Bosch: 100 significa aire tan limpio como la línea base con humedad ideal; cuanto más baja, peor. Una guía de lectura aproximada:

Puntuación Significado Acción típica
80 a 100 Cerca de la línea base Nada que hacer
60 a 80 COV apreciables o humedad fuera de objetivo Vigilarlo
40 a 60 Claramente peor que la línea base Ventilar la sala
Menos de 40 Fuente intensa cerca Buscar la fuente y ventilar ya

Como la línea base es relativa, compara las puntuaciones a lo largo del tiempo en la misma sala, no entre dispositivos distintos.

Ver los datos en vivo

Abre una segunda terminal (en la Pi o en tu portátil) y suscríbete con el cliente Mosquitto. Sustituye el ID de dispositivo por el que imprimió tu script:

mosquitto_sub -h broker.connectmq.com -p 1883 -i aq-viewer-$RANDOM \
  -t "connectmq/demo/pi-aq-1a2b3c/air/#" -v

Primero deberías ver el estado retenido online y después un mensaje de telemetría cada diez segundos. Detén el script de Python con Ctrl+C y, cuando expire el keepalive, el broker entregará el Last Will offline. Ten en cuenta que el servidor MQTT público gratuito es legible por cualquiera que conozca el topic, así que los datos de aire de una sala están bien, pero no publiques nada personal.

Ejecutar el monitor de forma desatendida

Un sensor que se detiene al cerrar la sesión SSH no es gran cosa como monitor. Crea una unidad systemd para que el script arranque con el sistema y se reinicie tras los fallos:

# /etc/systemd/system/aq-monitor.service
[Unit]
Description=BME680 air quality monitor
After=network-online.target
Wants=network-online.target

[Service]
User=pi
ExecStart=/home/pi/aq-env/bin/python /home/pi/aq_monitor.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now aq-monitor
journalctl -u aq-monitor -f

Ajusta el nombre de usuario y las rutas a tu instalación. El mismo patrón se explica con más detalle para otros sensores en el proyecto de temperatura con DS18B20 y el tutorial de humedad con DHT22, que puedes combinar con este en una sola Pi.

Pasar a un broker privado

Para cualquier cosa que vaya más allá de los experimentos, publica en tu propio broker con credenciales y TLS. En ConnectMQ te registras, creas un broker y obtienes un usuario, una contraseña y un client ID generados. Después cambia el bloque de conexión:

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID")
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set()                       # el almacén de CA del sistema valida el certificado de Let's Encrypt
client.will_set(f"{BASE_TOPIC}/status", "offline", qos=1, retain=True)
client.connect("broker.connectmq.com", 8883, keepalive=60)

Con un broker MQTT gestionado no tienes que mantener tú mismo una instancia de Mosquitto parcheada y accesible, y el explorador de topics en vivo del portal muestra la telemetría que llega sin herramientas adicionales. También puedes añadir una regla de alerta por umbral sobre iaq_score o humidity_pct para que el registro de alertas del portal anote cada vez que la sala cruce un límite.

Solución de problemas

  1. ValueError: No I2C device at address: la dirección es incorrecta. Usa la que muestra i2cdetect (0x76 o 0x77).
  2. Resistencia de gas atascada muy baja y que nunca sube: el sensor todavía se está acondicionando. Déjalo alimentado varias horas; la deriva del primer uso es normal.
  3. Temperatura varios grados demasiado alta: calor de la Pi o del propio calefactor del sensor. Aleja el sensor de la placa o aplica un offset fijo tras compararlo con un termómetro de referencia.
  4. Conexión rechazada en el broker privado: comprueba que el client ID coincide exactamente con las credenciales emitidas; ConnectMQ vincula los client IDs a las credenciales.
  5. Los mensajes se detienen tras un microcorte de red: paho se reconecta automáticamente mientras loop_start() está en marcha, pero los mensajes QoS 1 publicados sin conexión solo se encolan en memoria. Para cortes largos, añade un búfer local.

Ideas para ampliar el proyecto

Una vez que los datos fluyen, el resto es MQTT puro. Node-RED puede suscribirse y accionar un ventilador mediante un relé. Telegraf puede escribir el JSON en InfluxDB para gráficos a largo plazo. Una segunda Pi en otra sala puede publicar con su propio ID de dispositivo para comparar espacios lado a lado. Si la plataforma es nueva para ti, el tutorial de MQTT con Raspberry Pi cubre los fundamentos de clientes, topics y QoS sobre los que se apoya este proyecto.

Empieza con ConnectMQ

Pasa tu monitor de calidad del aire con Raspberry Pi del servidor público a uno privado y protegido con TLS en pocos minutos. ConnectMQ te ofrece un broker MQTT gestionado con un cliente MQTT en el navegador, un explorador de topics en vivo y alertas por umbral. Crea un broker Serverless gratuito, sin tarjeta de crédito, y apunta tu script hacia él.

Preguntas frecuentes

¿El valor IAQ del BME680 es el mismo que el índice BSEC de Bosch?

No. La puntuación de este tutorial es una estimación transparente basada en una línea base de gas y en la humedad. La biblioteca BSEC de Bosch produce un índice calibrado de 0 a 500 con seguimiento automático de la línea base, y puede incorporarse más adelante sin cambiar los topics MQTT.

¿Cuánto tiempo necesita el BME680 para calentarse?

El calefactor se estabiliza en minutos, por eso el script usa un calentamiento de cinco minutos. Un sensor completamente nuevo sigue derivando durante sus primeros uno o dos días de funcionamiento, así que las lecturas se vuelven más coherentes después.

¿Puedo medir CO2 con un BME680?

No directamente. El BME680 reacciona a los COV, y cualquier cifra de CO2 derivada de él es una estimación. Para medir CO2 de verdad usa un sensor NDIR como el SCD40 o el SCD41 y publícalo junto a los datos del BME680.

¿Qué broker MQTT debo usar para un monitor de calidad del aire doméstico?

El servidor público está bien para probar, pero cualquiera puede leerlo. Para un uso permanente, un broker privado con credenciales y TLS, como un broker Serverless gratuito de ConnectMQ, mantiene tus datos privados.

Artículos relacionados

Fiabilidad de la Raspberry Pi: cómo usar una Pi 24/7 como gateway IoT

Una guía práctica para mantener un gateway MQTT con Raspberry Pi funcionando durante meses: desgaste del almacenamiento, sistemas de archivos de solo lectura, alimentación, refrigeración, watchdogs de hardware y software y monitorización remota de la salud.

9 min de lectura

Pico W vs Pico 2 W para MQTT: rendimiento, memoria y TLS de RP2040 frente a RP2350

La Pico 2 W mantiene el formato y el chip Wi-Fi de la Pico W, pero sustituye el RP2040 por el RP2350, más rápido. Esta comparativa analiza qué significa para los dispositivos MQTT: CPU, memoria, TLS, funciones de seguridad, soporte de software y qué placa comprar para cada proyecto.

9 min de lectura

Registro de accesos Raspberry Pi RFID MQTT con el lector RC522

Conecta un lector RFID RC522 a una Raspberry Pi, lee etiquetas en Python, compáralas con una lista blanca local y publica cada intento de acceso como un evento MQTT que pueden consumir registradores, dashboards y herramientas de alertas.

8 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.