Raspberry Pi

Sensor MQTT com Pico W a Bateria usando Lightsleep e Duty Cycling

Transforme um Raspberry Pi Pico W em um sensor MQTT a bateria que acorda, mede, publica e volta a dormir. Cobre lightsleep no MicroPython, desligamento do Wi-Fi, leitura da tensão da bateria e as armadilhas que esgotam as pilhas.

Raspberry Pi Pico W em um suporte de pilhas acordando periodicamente para enviar uma leitura MQTT a bateria para um broker na nuvem
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

Um sensor Pico W a bateria com MQTT só funciona se a placa passar quase toda a vida dormindo e apenas alguns segundos acordada. Neste tutorial você vai montar um nó sensor em MicroPython que acorda por timer, lê um sensor e a própria tensão da bateria, publica uma mensagem QoS 1 em um broker MQTT, desliga o rádio e volta ao lightsleep. Você também vai descobrir quais decisões de projeto realmente aumentam a autonomia e quais são esforço desperdiçado.

Por que a alimentação por bateria é difícil no Pico W

O Pico W foi projetado como uma placa microcontroladora barata e flexível, não como uma plataforma de sensores de ultrabaixo consumo. O RP2040 em si é eficiente o suficiente, mas três fatores jogam contra você quando o assunto é bateria:

  • O chip Wi-Fi CYW43439 consome muito mais corrente ao se associar e transmitir do que o microcontrolador ao processar. Cada segundo com o rádio ligado custa mais do que minutos de sono.
  • O regulador buck-boost da placa tem uma corrente quiescente que nunca desaparece, mesmo com o RP2040 dormindo.
  • Os modos de sono do MicroPython são limitados em comparação com chips como o ESP32. machine.lightsleep() para os clocks e mantém a RAM, o que é útil, mas a placa ainda consome visivelmente mais do que um nó de baixo consumo dedicado.

A consequência prática é simples: a autonomia é dominada por com que frequência você acorda e quanto tempo leva a conexão Wi-Fi. Otimizar o código Python que lê o sensor quase não faz diferença. Passar de um intervalo de publicação de 30 segundos para 5 minutos, ou reduzir o tempo de conexão de oito para três segundos, faz uma diferença enorme.

Se você ainda não conectou um Pico W ao MQTT, comece pelo guia de MQTT com Raspberry Pi Pico W e volte aqui quando uma publicação básica estiver funcionando.

O projeto do duty cycle

Todo despertar segue o mesmo roteiro curto. Mantê-lo estritamente linear (sem tarefas em segundo plano, sem conexão de longa duração) é o que o torna previsível.

  1. Acordar do lightsleep (ou de um cold boot após uma queda de energia).
  2. Ler a tensão da bateria antes de ligar o Wi-Fi.
  3. Ler o sensor.
  4. Ligar o Wi-Fi com uma configuração estática e um timeout rígido.
  5. Conectar ao broker, publicar uma mensagem com QoS 1 e aguardar a confirmação.
  6. Desconectar de forma limpa, desligar o rádio e desinicializá-lo.
  7. Entrar em lightsleep pelo intervalo configurado e repetir o ciclo.
Decisão de projeto Efeito na autonomia Recomendação
Intervalo de publicação Maior fator isolado 5 a 15 minutos para dados de clima ambiente
Tempo de conexão Wi-Fi Segundo maior fator Sinal forte, WPA2, timeout curto
Manter o MQTT conectado durante o sono O rádio fica parcialmente ativo Nunca com bateria
Publicação QoS 1 Uma ida e volta extra Vale a pena, você sabe que a mensagem chegou
Lightsleep vs. time.sleep() ativo Lightsleep para os clocks Sempre lightsleep entre ciclos
LED piscando para status Consumo pequeno, mas constante Desative em produção
Chip timer externo (TPL5110 ou similar) Corta totalmente a alimentação da placa Melhor opção para meses de autonomia

Hardware e ligações

Você precisa de um Pico W (ou Pico 2 W), um sensor e uma fonte de energia no VSYS. Uma configuração comum são três pilhas AA ou AAA em série alimentando o VSYS diretamente, ou uma única célula LiPo com placa de proteção. Não ultrapasse o limite de VSYS indicado no datasheet oficial e nunca conecte baterias ao VBUS com o USB ligado sem um diodo.

Para o sensor, qualquer componente I2C com baixa corrente em standby serve. Este exemplo usa um BME280 no I2C0 (GP4 = SDA, GP5 = SCL), mas a lógica de duty cycle independe do sensor.

O Pico W consegue medir a própria tensão de alimentação no ADC3, que está ligado ao VSYS por um divisor 1:3. No Pico W esse pino (GP29) é compartilhado com o clock SPI do chip Wi-Fi, então você precisa lê-lo com o rádio desligado e com o GP25 em nível alto. É por isso que a leitura de tensão acontece primeiro no ciclo.

Prepare o MicroPython e a biblioteca MQTT

Grave um firmware MicroPython atual para o Pico W a partir da documentação oficial do Raspberry Pi e depois instale a biblioteca umqtt.simple e um driver do BME280 com o mpremote:

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

Crie um secrets.py na placa para manter as credenciais fora do 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"   # não pode ser vazio e deve ser único
MQTT_USER = None                     # defina YOUR_USERNAME para um broker privado
MQTT_PASSWORD = None                 # defina YOUR_PASSWORD para um broker privado
TOPIC = "connectmq/demo/7f3a91/garden/climate"

INTERVAL_S = 600                     # 10 minutos entre leituras

O servidor MQTT público em broker.connectmq.com aceita conexões anônimas com qualquer client ID não vazio. Tudo o que é publicado ali pode ser lido por qualquer pessoa, então use um prefixo de topic aleatório e nunca envie dados pessoais. O guia do servidor MQTT público gratuito lista os limites dele.

O script MQTT completo para bateria

Salve como main.py. Ele roda automaticamente a cada boot e, como o loop usa lightsleep em vez de reset, o estado da RAM, como o contador de ciclos, sobrevive entre os despertares.

# main.py - sensor MQTT com Pico W alimentado por bateria
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)          # desseleciona o barramento SPI do CYW43
    Pin(29, Pin.IN, None)              # libera o pino compartilhado para o 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()
    # O driver retorna centésimos de grau, Pa*256 e %UR*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() bloqueia até o broker devolver o 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)

    # Recua mais quando a bateria está baixa para proteger as células
    sleep_s = secrets.INTERVAL_S if vbat > 3.3 else secrets.INTERVAL_S * 3
    machine.lightsleep(sleep_s * 1000)

Alguns detalhes são intencionais. O script informa awake_ms e rssi em cada mensagem, para que você veja, do lado do broker, se um nó está demorando demais para conectar. O ramo de bateria baixa triplica o intervalo em vez de parar de vez, o que dá tempo de trocar as pilhas sem perder o nó. E o deinit() após active(False) garante que o driver do CYW43 libere o rádio antes de a placa dormir.

Teste as mensagens MQTT do Pico W a bateria

Antes de rodar com pilhas, teste no USB com um intervalo curto, como 30 segundos. Faça a assinatura a partir do seu notebook:

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

Você deve ver uma mensagem JSON por ciclo. Observe o campo awake_ms. Em uma rede saudável ele se estabiliza em uma faixa estreita e repetível. Se variar muito, o problema é o access point, não o seu código.

Observe que, quando o Pico W dorme conectado ao USB, o REPL serial se desconecta. Isso é normal. Para retomar o controle, desconecte o cabo, segure o BOOTSEL se necessário ou use o mpremote logo após ligar a placa, antes de o main.py entrar no primeiro sono. Um truque útil é adicionar uma janela de dois segundos bem no início do main.py que sai para o REPL se um botão em um pino GPIO estiver pressionado.

Como extrair mais autonomia do Pico W

Quando o ciclo básico estiver funcionando, estes refinamentos dão o melhor retorno:

  • Aumente o intervalo primeiro. Reduzir pela metade o número de despertares corta aproximadamente pela metade a energia do rádio, que é o maior consumidor.
  • Agrupe leituras. Leia o sensor a cada minuto durante o lightsleep, guarde os valores em uma lista e publique todos em uma única mensagem a cada dez minutos. Você paga pelo Wi-Fi uma vez em vez de dez.
  • Melhore o caminho do Wi-Fi. Posicione o nó onde o sinal for forte. Sinal fraco significa retransmissões, taxas de dados menores e mais tempo acordado.
  • Use um timer de alimentação externo. Um chip timer que corta a energia da placa inteira e a religa conforme um agendamento elimina totalmente as correntes do regulador e de sono. Nesse projeto o script roda uma vez a partir do cold boot, publica e sinaliza ao timer para desligar. Você perde a RAM entre os ciclos, então grave contadores na flash com moderação ou deixe o broker guardar o estado por meio de retained messages.
  • Desative tudo o que pisca. LEDs de status do Pico e das placas breakout dos sensores consomem corrente o tempo todo. Remova ou corte o LED de alimentação das breakouts quando possível.

Produção: migre para credenciais privadas e TLS

O servidor público é ideal para desenvolvimento, mas um sensor implantado deve usar suas próprias credenciais. Em um broker MQTT gerenciado como o ConnectMQ, você cria um broker no portal e recebe usuário, senha e client ID gerados. Coloque-os no secrets.py como YOUR_USERNAME, YOUR_PASSWORD e YOUR_CLIENT_ID. O client ID fica vinculado às credenciais emitidas, então cada nó precisa do que foi gerado para ele.

TLS na porta 8883 adiciona um handshake a cada despertar, o que custa tempo acordado extra e, portanto, bateria. Para sensores em uma rede doméstica confiável, algumas pessoas aceitam TCP puro; para qualquer coisa que saia do prédio, a criptografia vale o custo. O tutorial de MQTT sobre TLS com Pico W mostra a configuração do contexto SSL no MicroPython. Meça o awake_ms antes e depois para conhecer o impacto real no seu nó.

Retained messages também são úteis aqui. Se você publicar a última leitura com a flag retain, um dashboard aberto horas depois mostra o valor mais recente imediatamente, em vez de esperar até dez minutos pelo próximo despertar. O ConnectMQ suporta retained messages em todos os planos, e o dashboard do portal e o explorador de topics ao vivo permitem acompanhar as mensagens de cada nó chegando sem escrever um subscriber.

Solução de problemas

Sintoma Causa provável Correção
vbat perto de zero ou aleatório ADC lido com o Wi-Fi ativo Leia o VSYS antes de wlan.active(True)
O nó publica uma vez e para Wi-Fi não desinicializado antes do lightsleep Chame active(False) e deinit()
OSError: -2 ao conectar Falha de DNS ou Wi-Fi não totalmente ativo Verifique isconnected() e tente de novo uma vez
awake_ms não para de crescer Sinal fraco ou access point congestionado Mova o nó ou o AP
A bateria acaba muito antes do esperado LED, standby do sensor ou consumo do regulador Remova LEDs, verifique o modo de sono do sensor, adicione um timer de alimentação

Comece com o ConnectMQ

Quando o protótipo com Pico W estiver pronto para sair da bancada, crie um broker privado no portal do ConnectMQ em app.connectmq.com. O plano Serverless gratuito não exige cartão de crédito, suporta QoS 1 e até 25 conexões, o que cobre com folga uma pequena frota de sensores a bateria. Para mais projetos com Pi, o tutorial de MQTT com Raspberry Pi reúne a série completa.

Perguntas frequentes

Quanto tempo um Pico W dura com bateria usando MQTT?

Depende principalmente do intervalo de publicação, do tempo de conexão Wi-Fi e das pilhas usadas, então meça o seu próprio nó em vez de confiar em um número único. Registrar awake_ms e vbat por alguns dias dá uma tendência confiável para extrapolar.

O Pico W pode ficar conectado ao MQTT enquanto dorme?

Não de forma amigável à bateria. Manter a sessão MQTT ativa exige que o rádio continue associado, o que esgota as pilhas rapidamente, então reconecte a cada despertar.

Devo usar QoS 0 ou QoS 1 em um sensor a bateria?

QoS 1 costuma ser a melhor escolha, porque publish() aguarda a confirmação do broker antes de você desligar o rádio. A ida e volta extra é pequena comparada ao custo de entrar no Wi-Fi.

machine.deepsleep é melhor que lightsleep no Pico W?

No port do MicroPython para o RP2040 a diferença é modesta, e o deepsleep reinicia a placa, então você perde o estado da RAM. Para a maior autonomia, um timer externo que corta totalmente a alimentação supera os dois.

Artigos relacionados

Registro de Acessos Raspberry Pi RFID MQTT com o Leitor RC522

Ligue um leitor RFID RC522 a um Raspberry Pi, leia tags em Python, confira-as em uma lista de permissões local e publique cada tentativa de acesso como um evento MQTT que loggers, dashboards e ferramentas de alerta podem consumir.

8 min de leitura

Confiabilidade do Raspberry Pi: Rodando um Pi 24/7 como Gateway IoT

Um guia prático para manter um gateway MQTT com Raspberry Pi rodando por meses: desgaste do armazenamento, sistemas de arquivos somente leitura, alimentação, refrigeração, watchdogs de hardware e software e monitoramento remoto de saúde.

9 min de leitura

Pico W vs Pico 2 W para MQTT: Desempenho, Memória e TLS do RP2040 vs RP2350

O Pico 2 W mantém o formato e o chip Wi-Fi do Pico W, mas troca o RP2040 pelo RP2350, mais rápido. Esta comparação mostra o que isso significa para dispositivos MQTT: CPU, memória, TLS, recursos de segurança, suporte de software e qual placa comprar para cada projeto.

9 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.