Raspberry Pi

Sensor MQTT con Pico W a batería, lightsleep y ciclos de trabajo

Convierte una Raspberry Pi Pico W en un sensor MQTT alimentado por batería que despierta, mide, publica y vuelve a dormir. Cubre lightsleep en MicroPython, el apagado del Wi-Fi, la lectura de la tensión de la batería y los errores que agotan las pilas.

Raspberry Pi Pico W sobre un portapilas despertando periódicamente para enviar una lectura MQTT a un broker en la nube
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 sensor Pico W a batería con MQTT solo funciona si la placa pasa casi toda su vida dormida y apenas unos segundos despierta. En este tutorial construirás un nodo sensor en MicroPython que despierta con un temporizador, lee un sensor y la tensión de su propia batería, publica un mensaje QoS 1 en un broker MQTT, apaga la radio y vuelve a lightsleep. También aprenderás qué decisiones de diseño influyen de verdad en la autonomía y cuáles son esfuerzo perdido.

Por qué la alimentación por batería es difícil en la Pico W

La Pico W se diseñó como una placa de microcontrolador barata y flexible, no como una plataforma de sensores de ultra bajo consumo. El RP2040 en sí es bastante eficiente, pero tres cosas juegan en tu contra cuando funcionas con baterías:

  • El chip Wi-Fi CYW43439 consume mucha más corriente mientras se asocia y transmite que el microcontrolador mientras calcula. Cada segundo con la radio encendida cuesta más que minutos de sueño.
  • El regulador buck-boost integrado tiene una corriente de reposo que nunca desaparece, ni siquiera cuando el RP2040 duerme.
  • Los modos de sueño en MicroPython son limitados en comparación con chips como el ESP32. machine.lightsleep() detiene los relojes y conserva la RAM, lo que es útil, pero la placa sigue consumiendo bastante más que un nodo diseñado específicamente para bajo consumo.

La consecuencia práctica es sencilla: la autonomía depende sobre todo de con qué frecuencia despiertas y de cuánto tarda la conexión Wi-Fi. Optimizar el código Python que lee un sensor apenas cambia nada. Pasar de un intervalo de publicación de 30 segundos a 5 minutos, o recortar el tiempo de conexión de ocho a tres segundos, cambia muchísimo.

Si todavía no has conectado una Pico W a MQTT, empieza por la guía de Raspberry Pi Pico W y MQTT y vuelve aquí cuando funcione una publicación básica.

El diseño del ciclo de trabajo

Cada despertar sigue el mismo guion breve. Mantenerlo estrictamente lineal (sin tareas en segundo plano ni conexiones de larga duración) es lo que lo hace predecible.

  1. Despertar de lightsleep (o arrancar en frío tras un corte de alimentación).
  2. Leer la tensión de la batería antes de encender el Wi-Fi.
  3. Leer el sensor.
  4. Encender el Wi-Fi con una configuración estática y un timeout estricto.
  5. Conectar con el broker, publicar un mensaje con QoS 1 y esperar la confirmación.
  6. Desconectar limpiamente, apagar la radio y desinicializarla.
  7. Entrar en lightsleep durante el intervalo configurado y repetir.
Decisión de diseño Efecto en la autonomía Recomendación
Intervalo de publicación El factor individual más importante De 5 a 15 minutos para datos de clima interior
Tiempo de conexión Wi-Fi El segundo factor más importante Buena señal, WPA2, timeout corto
Mantener MQTT conectado durante el sueño La radio sigue parcialmente activa Nunca con baterías
Publicación con QoS 1 Un viaje de ida y vuelta extra Merece la pena: sabes que el mensaje llegó
Lightsleep frente a time.sleep() activo Lightsleep detiene los relojes Usa siempre lightsleep entre ciclos
LED parpadeando para indicar estado Consumo pequeño pero constante Desactívalo en producción
Chip temporizador externo (TPL5110 o similar) Corta por completo la alimentación de la placa La mejor opción para varios meses de autonomía

Hardware y cableado

Necesitas una Pico W (o una Pico 2 W), un sensor y una fuente de alimentación en VSYS. Una configuración habitual son tres pilas AA o AAA en serie conectadas directamente a VSYS, o una sola celda LiPo a través de una placa de protección. No superes el límite de VSYS que indica la hoja de datos oficial y nunca conectes baterías a VBUS con el USB enchufado sin un diodo.

Como sensor sirve cualquier componente I2C con baja corriente en reposo. Este ejemplo usa un BME280 en I2C0 (GP4 = SDA, GP5 = SCL), pero la lógica del ciclo de trabajo es independiente del sensor.

La Pico W puede medir su propia tensión de alimentación en ADC3, que está conectado a VSYS mediante un divisor 1:3. En la Pico W ese pin (GP29) se comparte con el reloj SPI del chip Wi-Fi, así que debes leerlo con la radio apagada y con GP25 a nivel alto. Por eso la lectura de tensión se hace al principio del ciclo.

Prepara MicroPython y la librería MQTT

Graba una versión actual de MicroPython para la Pico W desde la documentación oficial de Raspberry Pi y después instala la librería umqtt.simple y un driver para el BME280 con mpremote:

pip install mpremote
mpremote mip install umqtt.simple
mpremote cp bme280.py :bme280.py

Crea un secrets.py en la placa para que las credenciales queden fuera del script principal:

# secrets.py
WIFI_SSID = "your-ssid"
WIFI_PASSWORD = "your-wifi-password"

MQTT_HOST = "broker.connectmq.com"
MQTT_PORT = 1883
MQTT_CLIENT_ID = "pico-bat-7f3a91"   # must be non-empty and unique
MQTT_USER = None                     # set YOUR_USERNAME for a private broker
MQTT_PASSWORD = None                 # set YOUR_PASSWORD for a private broker
TOPIC = "connectmq/demo/7f3a91/garden/climate"

INTERVAL_S = 600                     # 10 minutes between readings

El servidor público broker.connectmq.com acepta conexiones anónimas con cualquier client ID no vacío. Todo lo que se publica allí puede leerlo cualquiera, así que usa un prefijo de topic aleatorio y nunca envíes datos personales. La guía del servidor MQTT público gratuito enumera sus límites.

El script completo de MQTT con batería

Guárdalo como main.py. Se ejecuta automáticamente en cada arranque y, como el bucle usa lightsleep en lugar de un reinicio, el estado en RAM, como el contador de ciclos, se conserva entre despertares.

# main.py - battery-powered Pico W MQTT sensor
import time
import json
import network
import machine
from machine import Pin, ADC, I2C
from umqtt.simple import MQTTClient
import bme280
import secrets

led = Pin("LED", Pin.OUT)
led.off()

i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=100_000)
cycle = 0


def read_vsys():
    """Read VSYS on the Pico W. Must run while the Wi-Fi chip is off."""
    Pin(25, Pin.OUT).value(1)          # deselect the CYW43 SPI bus
    Pin(29, Pin.IN, None)              # release the shared pin for the ADC
    adc = ADC(3)
    total = 0
    for _ in range(8):
        total += adc.read_u16()
        time.sleep_ms(2)
    raw = total / 8
    return round(raw * 3.3 * 3 / 65535, 3)


def read_sensor():
    sensor = bme280.BME280(i2c=i2c)
    t, p, h = sensor.read_compensated_data()
    # The driver returns hundredths of a degree, Pa*256 and %RH*1024
    return round(t / 100, 2), round(h / 1024, 1), round(p / 25600, 1)


def wifi_up(timeout_ms=10_000):
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(secrets.WIFI_SSID, secrets.WIFI_PASSWORD)
    start = time.ticks_ms()
    while not wlan.isconnected():
        if time.ticks_diff(time.ticks_ms(), start) > timeout_ms:
            return wlan, False
        time.sleep_ms(100)
    return wlan, True


def wifi_down(wlan):
    try:
        wlan.disconnect()
    except OSError:
        pass
    wlan.active(False)
    wlan.deinit()


def publish(payload):
    client = MQTTClient(
        secrets.MQTT_CLIENT_ID,
        secrets.MQTT_HOST,
        port=secrets.MQTT_PORT,
        user=secrets.MQTT_USER,
        password=secrets.MQTT_PASSWORD,
        keepalive=30,
    )
    client.connect()
    # QoS 1: publish() blocks until the broker returns PUBACK
    client.publish(secrets.TOPIC, payload, qos=1)
    client.disconnect()


while True:
    cycle += 1
    vbat = read_vsys()
    try:
        temp_c, rh, hpa = read_sensor()
    except OSError:
        temp_c, rh, hpa = None, None, None

    awake_start = time.ticks_ms()
    wlan, ok = wifi_up()
    if ok:
        msg = json.dumps({
            "t": temp_c, "rh": rh, "hpa": hpa,
            "vbat": vbat, "cycle": cycle,
            "rssi": wlan.status("rssi"),
            "awake_ms": time.ticks_diff(time.ticks_ms(), awake_start),
        })
        try:
            publish(msg)
        except OSError as exc:
            print("MQTT failed:", exc)
    wifi_down(wlan)

    # Back off harder when the battery is low to protect the cells
    sleep_s = secrets.INTERVAL_S if vbat > 3.3 else secrets.INTERVAL_S * 3
    machine.lightsleep(sleep_s * 1000)

Algunos detalles son deliberados. El script informa de awake_ms y rssi en cada mensaje para que puedas ver, desde el lado del broker, si un nodo tarda demasiado en conectarse. La rama de batería baja triplica el intervalo en lugar de detenerse por completo, lo que te da tiempo para cambiar las pilas sin perder el nodo. Y deinit() después de active(False) garantiza que el driver CYW43 libere la radio antes de que la placa duerma.

Prueba los mensajes MQTT de la Pico W con batería

Antes de usar pilas, prueba por USB con un intervalo corto, como 30 segundos. Suscríbete desde tu portátil:

mosquitto_sub -h broker.connectmq.com -p 1883 -i laptop-7f3a91 \
  -t 'connectmq/demo/7f3a91/#' -v

Deberías ver un mensaje JSON por ciclo. Fíjate en el campo awake_ms. En una red sana se estabiliza en un rango estrecho y repetible. Si varía mucho, el problema es el punto de acceso, no tu código.

Ten en cuenta que, cuando la Pico W duerme conectada por USB, el REPL serie se desconecta. Es normal. Para recuperar el control, desenchúfala, mantén pulsado BOOTSEL si hace falta o usa mpremote justo después de encenderla, antes de que main.py entre en su primer sueño. Un truco útil es añadir al principio de main.py una ventana de dos segundos que salga al REPL si se mantiene pulsado un botón conectado a un GPIO.

Exprimir más autonomía de la Pico W

Una vez que el ciclo básico funciona, estas mejoras ofrecen el mejor retorno:

  • Alarga primero el intervalo. Reducir a la mitad el número de despertares reduce aproximadamente a la mitad la energía de la radio, que es el mayor consumidor.
  • Agrupa las lecturas. Lee el sensor cada minuto durante el lightsleep, guarda los valores en una lista y publícalos todos en un único mensaje cada diez minutos. Pagas el Wi-Fi una vez en lugar de diez.
  • Mejora el enlace Wi-Fi. Coloca el nodo donde la señal sea buena. Una señal débil implica reintentos, velocidades de datos más bajas y más tiempo despierto.
  • Usa un temporizador de alimentación externo. Un chip temporizador que corta la alimentación de toda la placa y la restablece según un horario elimina por completo las corrientes del regulador y del sueño. En ese diseño, el script se ejecuta una vez desde el arranque en frío, publica y luego indica al temporizador que corte la alimentación. Pierdes la RAM entre ciclos, así que guarda los contadores en flash con moderación o deja que el broker conserve el estado mediante mensajes retenidos.
  • Desactiva todo lo que parpadee. Los LED de estado de la Pico y de las placas de los sensores consumen corriente todo el tiempo. Quita o corta el LED de alimentación de las placas de sensores cuando puedas.

Producción: pasa a credenciales privadas y TLS

El servidor público es ideal para el desarrollo, pero un sensor desplegado debe usar tus propias credenciales. En un broker MQTT gestionado como ConnectMQ, creas un broker en el portal y recibes un usuario, una contraseña y un client ID generados. Ponlos en secrets.py como YOUR_USERNAME, YOUR_PASSWORD y YOUR_CLIENT_ID. El client ID está vinculado a las credenciales emitidas, así que cada nodo necesita el que se generó para él.

TLS en el puerto 8883 añade un handshake a cada despertar, lo que cuesta tiempo despierto adicional y, por tanto, batería. Para sensores en una red doméstica de confianza hay quien acepta TCP sin cifrar; para cualquier cosa que salga de un edificio, el cifrado compensa el coste. El tutorial de Pico W con MQTT sobre TLS muestra la configuración del contexto SSL en MicroPython. Mide awake_ms antes y después para conocer el impacto real en tu nodo.

Los mensajes retenidos también son útiles aquí. Si publicas la última lectura con el flag retain, un panel que se abra horas después mostrará de inmediato el valor más reciente en lugar de esperar hasta diez minutos al siguiente despertar. ConnectMQ admite mensajes retenidos en todos los planes, y el panel y el explorador de topics en vivo de su portal te permiten ver cómo llegan los mensajes de cada nodo sin escribir un suscriptor.

Solución de problemas

Síntoma Causa probable Solución
vbat marca casi cero o valores aleatorios Lectura del ADC con el Wi-Fi activo Lee VSYS antes de wlan.active(True)
El nodo publica una vez y se detiene Wi-Fi no desinicializado antes del lightsleep Llama a active(False) y deinit()
OSError: -2 al conectar Falló el DNS o el Wi-Fi no estaba del todo activo Comprueba isconnected() y reintenta una vez
awake_ms no deja de crecer Señal débil o punto de acceso saturado Mueve el nodo o el punto de acceso
La batería se agota mucho antes de lo esperado LED, reposo del sensor o consumo del regulador Quita los LED, revisa el modo de reposo del sensor, añade un temporizador de alimentación

Empieza con ConnectMQ

Cuando tu prototipo de Pico W esté listo para salir del banco de trabajo, crea un broker privado en el portal de ConnectMQ en app.connectmq.com. El plan gratuito Serverless no requiere tarjeta de crédito, admite QoS 1 y hasta 25 conexiones, lo que cubre con holgura una pequeña flota de sensores a batería. Para más proyectos con Pi, el tutorial de Raspberry Pi y MQTT reúne la serie completa.

Preguntas frecuentes

¿Cuánto dura una Pico W con baterías usando MQTT?

Depende sobre todo del intervalo de publicación, del tiempo de conexión Wi-Fi y de las pilas que uses, así que mide tu propio nodo en lugar de fiarte de una cifra única. Registrar awake_ms y vbat durante unos días te da una tendencia fiable para extrapolar.

¿Puede la Pico W seguir conectada a MQTT mientras duerme?

No de una forma compatible con las baterías. Mantener viva la sesión MQTT exige que la radio siga asociada, lo que agota las pilas rápidamente, así que reconecta en cada despertar.

¿Debo usar QoS 0 o QoS 1 en un sensor a batería?

QoS 1 suele ser la mejor opción, porque publish() espera la confirmación del broker antes de que apagues la radio. El viaje de ida y vuelta adicional es pequeño comparado con el coste de unirse al Wi-Fi.

¿Es machine.deepsleep mejor que lightsleep en la Pico W?

En el port de MicroPython para RP2040 la diferencia es modesta, y deepsleep reinicia la placa, con lo que pierdes el estado en RAM. Para la máxima autonomía, un temporizador externo que corte la alimentación por completo supera a ambos.

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.