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:
- Cualquier Raspberry Pi con conector de 40 pines (Zero 2 W, 3, 4 o 5) con Raspberry Pi OS.
- Una placa breakout BME680. Funcionan las de Adafruit, Pimoroni y muchas genéricas; comprueba si la tuya usa la dirección I2C
0x76o0x77. - 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
ValueError: No I2C device at address: la dirección es incorrecta. Usa la que muestrai2cdetect(0x76o0x77).- 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.
- 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.
- 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.
- 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.



