Raspberry Pi

Receptor Raspberry Pi LoRa MQTT: Encaminhe Pacotes SX127x para a Nuvem

Receba pacotes LoRa ponto a ponto em um Raspberry Pi com um HAT RFM95 ou SX127x, alinhe as configurações de rádio com seus transmissores e republique cada pacote como JSON em um broker MQTT.

Raspberry Pi com um bonnet de rádio LoRa e antena recebendo pacotes de longo alcance, ilustrando raspberry pi lora mqtt
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 receptor Raspberry Pi LoRa MQTT é a forma mais simples de coletar dados de sensores que estão longe demais para o Wi-Fi: uma lavoura, uma fazenda, um estacionamento ou o outro extremo de um site grande. Neste tutorial você vai ligar um rádio baseado em SX127x (RFM95W, RFM96W ou um bonnet LoRa) a um Pi, receber pacotes ponto a ponto dos seus próprios transmissores e republicar cada um como JSON em um broker MQTT. Você vai começar com broker.connectmq.com e terminar com uma configuração pronta para produção.

LoRa ponto a ponto vs. LoRaWAN

LoRa é uma modulação de rádio; LoRaWAN é um protocolo de rede completo construído sobre ela, com registro de dispositivos, chaves de criptografia, um network server e gateways multicanal. Se você já opera uma rede LoRaWAN, seu network server publica os uplinks no MQTT e o que você procura é a integração MQTT do ChirpStack.

O LoRa ponto a ponto dispensa tudo isso. Seu transmissor (muitas vezes um ESP32 ou Arduino com um módulo SX1276) envia um pequeno pacote em uma frequência fixa com configurações fixas, e um receptor de canal único o escuta. É fácil de entender e fica totalmente sob o seu controle, o que o torna adequado para projetos pessoais, protótipos e redes privadas de sensores em que você é dono das duas pontas. A contrapartida é que endereçamento, verificações de integridade e limites de duty cycle ficam por sua conta.

Hardware

Item Observações
Raspberry Pi Qualquer modelo com o conector de 40 pinos; um Zero 2 W basta
Rádio SX127x Adafruit LoRa Radio Bonnet, breakout RFM95W ou módulo SPI semelhante
Antena Sintonizada para a sua faixa; nunca transmita sem ela
Nó transmissor ESP32, Arduino ou um segundo Pi com rádio compatível
Frequência 868 MHz na Europa, 915 MHz na América do Norte (no Brasil, a faixa usual também é a de 915 MHz), 433 MHz em algumas regiões; siga as regras locais

A ligação de um breakout segue os pinos SPI: SCK no GPIO 11, MOSI no GPIO 10, MISO no GPIO 9, CS no CE1 (GPIO 7), RESET no GPIO 25, mais 3,3 V e terra. O bonnet da Adafruit usa exatamente esses pinos, e é por isso que o código abaixo os usa como padrão.

Instale as bibliotecas

Ative o SPI com sudo raspi-config (Interface Options, SPI) e crie um ambiente com o Adafruit Blinka, que fornece os módulos board e busio no Linux, e o driver RFM9x:

sudo raspi-config nonint do_spi 0
ls /dev/spidev*
python3 -m venv ~/lora/.venv
source ~/lora/.venv/bin/activate
pip install adafruit-blinka adafruit-circuitpython-rfm9x "paho-mqtt>=2.0"

O guia de instalação do Blinka no site da Adafruit lista passos extras para alguns modelos de Pi, por exemplo instalar o lgpio nas versões mais novas. Se import board falhar, siga esse guia antes de continuar.

Alinhe as configurações de rádio

Um receptor LoRa só escuta pacotes enviados com a mesma frequência, spreading factor, largura de banda, coding rate, sync word e preâmbulo. Uma divergência não gera erros; gera silêncio. Anote as configurações uma vez e use-as nos dois lados.

Configuração Valor de exemplo Observações
Frequência 868.1 MHz Precisa ser legal na sua região
Spreading factor 7 Maior significa mais alcance e mais tempo no ar
Largura de banda 125 kHz Padrão comum
Coding rate 4/5 Definido como 5 no driver
CRC Ligado Ative no transmissor e no receptor
Cabeçalho Depende do transmissor Veja a observação sobre o RadioHead abaixo

A armadilha do cabeçalho RadioHead. O driver Adafruit RFM9x segue a convenção do RadioHead e, por padrão, remove um cabeçalho de 4 bytes (to, from, id, flags) dos pacotes recebidos. Transmissores que usam a biblioteca Arduino LoRa de Sandeep Mistry não adicionam esse cabeçalho, então os primeiros quatro bytes do seu payload desaparecem silenciosamente. Chame receive(with_header=True) quando o seu transmissor não usar RadioHead, como faz o script abaixo.

O script Raspberry Pi LoRa MQTT

O transmissor deste exemplo envia um payload de texto curto como n1,21.4,63,3.92 (ID do nó, temperatura, umidade, tensão da bateria). O receptor o valida, adiciona metadados de rádio e publica em um topic por nó. Pacotes desconhecidos ou malformados vão para um topic raw separado para depuração, em vez de serem descartados silenciosamente.

import json
import os
import time
import uuid

import adafruit_rfm9x
import board
import busio
import digitalio
import paho.mqtt.client as mqtt

BROKER = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
USERNAME = os.getenv("MQTT_USERNAME")
PASSWORD = os.getenv("MQTT_PASSWORD")
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", f"lora-rx-{uuid.uuid4().hex[:8]}")
PREFIX = os.getenv("TOPIC_PREFIX", "connectmq/demo/l9r3x5/lora")
FREQ_MHZ = float(os.getenv("LORA_FREQ", "868.1"))

spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
cs = digitalio.DigitalInOut(board.CE1)
reset = digitalio.DigitalInOut(board.D25)
rfm9x = adafruit_rfm9x.RFM9x(spi, cs, reset, FREQ_MHZ)
rfm9x.spreading_factor = 7
rfm9x.signal_bandwidth = 125000
rfm9x.coding_rate = 5
rfm9x.enable_crc = True


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


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
if USERNAME:
    client.username_pw_set(USERNAME, PASSWORD)
if PORT == 8883:
    client.tls_set()
client.will_set(f"{PREFIX}/receiver/status", "offline", qos=1, retain=True)
client.reconnect_delay_set(1, 60)
client.on_connect = on_connect
client.connect_async(BROKER, PORT, keepalive=60)
client.loop_start()


def parse(text):
    parts = text.split(",")
    if len(parts) != 4 or not parts[0].startswith("n"):
        return None
    node, temp, hum, vbat = parts
    return node, {"temperature": float(temp), "humidity": float(hum), "vbat": float(vbat)}


print(f"listening on {FREQ_MHZ} MHz")
try:
    while True:
        packet = rfm9x.receive(timeout=5.0, with_header=True)
        if packet is None:
            continue
        meta = {"rssi": rfm9x.last_rssi, "snr": rfm9x.last_snr, "ts": int(time.time())}
        try:
            parsed = parse(packet.decode("ascii").strip())
        except (UnicodeDecodeError, ValueError):
            parsed = None
        if parsed:
            node, values = parsed
            client.publish(f"{PREFIX}/{node}", json.dumps({**values, **meta}), qos=1, retain=True)
            print(node, values, meta)
        else:
            client.publish(f"{PREFIX}/raw", json.dumps({"hex": packet.hex(), **meta}), qos=0)
except KeyboardInterrupt:
    pass
finally:
    client.publish(f"{PREFIX}/receiver/status", "offline", qos=1, retain=True)
    client.loop_stop()
    client.disconnect()

Em um transmissor ESP32 com a biblioteca Arduino LoRa, a configuração correspondente é LoRa.begin(868.1E6), LoRa.setSpreadingFactor(7), LoRa.setSignalBandwidth(125E3), LoRa.setCodingRate4(5) e LoRa.enableCrc(). Depois envie com LoRa.beginPacket(); LoRa.print("n1,21.4,63,3.92"); LoRa.endPacket();.

Acompanhe os resultados a partir de qualquer máquina:

mosquitto_sub -h broker.connectmq.com -p 1883 -i lora-viewer-l9r3x5 -t "connectmq/demo/l9r3x5/lora/#" -v

Deixando os pacotes mais robustos

Texto puro é fácil de depurar, mas desperdiça tempo no ar, e o tempo no ar é o recurso escasso no LoRa. Quando o enlace estiver funcionando, considere estas melhorias:

  1. Payloads binários. Empacote os valores com escala fixa, por exemplo a temperatura como int16 em centésimos. Uma leitura de 4 campos cai de cerca de 16 bytes para 7, o que encurta o tempo no ar e aumenta a vida da bateria.
  2. ID do nó e número de sequência. Um contador de sequência permite ao receptor detectar pacotes perdidos e duplicados, e permite reportar a perda de pacotes por nó como uma métrica própria.
  3. Integridade. O CRC do rádio detecta corrupção. Se vizinhos puderem transmitir com as mesmas configurações, adicione um identificador curto ou um HMAC para ignorar pacotes que não são seus.
  4. Duty cycle. Muitas regiões limitam quanto tempo um dispositivo pode transmitir por hora em uma sub-banda. Spreading factors altos e envios frequentes podem ultrapassar esse limite rapidamente, então mantenha os payloads pequenos e os intervalos razoáveis.
  5. Saúde do receptor. Publique um heartbeat a partir do receptor e acompanhe o horário da última mensagem de cada nó, para que um transmissor morto e um receptor morto apareçam de forma diferente no dashboard.

Os valores de SNR e RSSI publicados com cada pacote são sua melhor ferramenta para posicionar a antena. SNR positivo significa um enlace confortável; valores próximos do limite de sensibilidade do seu spreading factor indicam que você está perto do limite do alcance.

Rodando sem supervisão

Um receptor na parede de um galpão ou em um mastro precisa sobreviver a quedas de energia e de rede. Rode o script como serviço do systemd para que ele reinicie automaticamente, guarde as leituras localmente quando o uplink cair com um buffer MQTT offline em SQLite e siga as dicas de confiabilidade do Raspberry Pi sobre desgaste do cartão SD e fontes de alimentação. Para locais remotos com conexão celular, o MQTT é uma boa escolha porque a conexão é apenas de saída e o overhead do protocolo é pequeno.

Saindo do servidor de testes

O servidor MQTT público é perfeito para acertar o enlace de rádio, mas tudo o que é publicado nele fica visível para qualquer pessoa; ele serve para testes, não para dados de produção. Para uma implantação real, crie um broker no ConnectMQ, um broker MQTT gerenciado, pegue no portal o usuário, a senha e o client ID gerados e inicie o receptor com MQTT_PORT=8883 e esses valores no ambiente. O TLS usa um certificado Let's Encrypt, então o tls_set() funciona com o repositório de CAs padrão do Pi. Um broker MQTT na nuvem também permite que vários receptores em locais diferentes, como talhões distintos de uma fazenda, publiquem em uma única árvore de topics que seus dashboards, suas regras de alerta ou um gêmeo digital da operação podem ler em um só lugar.

Novo no MQTT com o Pi? O tutorial MQTT com Raspberry Pi cobre os fundamentos usados aqui, e o guia de gateway IoT com Raspberry Pi mostra como um receptor LoRa pode conviver com entradas BLE, Modbus e outras em um único dispositivo.

Envie seus dados LoRa para o ConnectMQ

Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito, e você terá credenciais TLS para o seu receptor em minutos. O explorador de topics ao vivo do ConnectMQ mostra cada nó conforme ele reporta, e regras de alerta por limite podem sinalizar um valor de temperatura ou bateria que ultrapasse um limite.

Perguntas frequentes

Um único receptor SX127x pode funcionar como gateway LoRaWAN?

Não de verdade. Gateways LoRaWAN escutam vários canais e spreading factors ao mesmo tempo usando chips concentradores como o SX1302. Um único SX127x escuta uma configuração por vez, o que serve para uso ponto a ponto.

Que alcance posso esperar?

O alcance depende muito da altura da antena, do terreno e do spreading factor. Com visada direta e antenas elevadas, ele vai muito mais longe do que através de edificações, então meça RSSI e SNR no local.

Por que meu receptor recebe pacotes com bytes faltando?

Quase sempre é a divergência do cabeçalho RadioHead. Use receive(with_header=True) quando o transmissor não adicionar o cabeçalho RadioHead de 4 bytes.

O Pi pode enviar comandos de volta para os nós?

Sim, o driver RFM9x pode transmitir. Assine um topic de comando e chame rfm9x.send(), mas lembre-se de que os nós precisam estar escutando naquele momento, o que transmissores alimentados por bateria normalmente só fazem por pouco tempo depois de transmitir.

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.