Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LoRa Sniffer — RTL-SDR + gr-lora RF95 Decoder

Herramienta para capturar, extraer y decodificar tramas LoRa (RH_RF95 / RadioHead) usando un dongle RTL-SDR y gr-lora sobre GNU Radio.

Probado con RTL-SDR Blog V4 (R828D) y ESP32 + RFM95W transmitiendo con la librería RadioHead.

Hardware necesario

  • RTL-SDR compatible (probado con RTL-SDR Blog V4)
  • Antena 868 MHz (o la frecuencia que use tu módulo LoRa)
  • Transmisor LoRa basado en RH_RF95 (ESP32 + RFM95W, por ejemplo)

1. Instalación — Dependencias del sistema

sudo apt update
sudo apt install -y \
    build-essential cmake git \
    libusb-1.0-0-dev rtl-sdr librtlsdr-dev \
    gnuradio python3-gnuradio \
    liblog4cpp5-dev libboost-all-dev libgnuradio-runtime-dev \
    swig python3-dev python3-pip python3-venv \
    soapysdr-tools soapysdr-module-rtlsdr

2. Instalación — Blacklist driver DVB-T

El kernel carga por defecto el driver DVB-T que bloquea el acceso al dongle RTL-SDR. Hay que deshabilitarlo:

sudo tee /etc/modprobe.d/blacklist-rtlsdr.conf <<EOF
blacklist dvb_usb_rtl28xxu
blacklist rtl2832
blacklist rtl2830
EOF

sudo update-initramfs -u

Desconectar y reconectar el dongle USB. Verificar:

rtl_test -t

La salida debe mostrar Found 1 device(s) y el nombre del tuner (R828D para Blog V4).

3. Instalación — Regla udev (acceso sin sudo)

sudo tee /etc/udev/rules.d/20-rtlsdr.rules <<EOF
SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE="0666", GROUP="plugdev"
EOF

sudo usermod -aG plugdev $USER
sudo udevadm control --reload-rules

Reconectar el dongle y cerrar/abrir sesión para que el grupo aplique.

4. Instalación — libliquid-dsp (desde source)

gr-lora requiere la librería liquid-dsp que no está disponible como paquete en Ubuntu 24.04+:

cd /tmp
git clone https://github.com/jgaeddert/liquid-dsp.git
cd liquid-dsp
./bootstrap.sh
./configure
make -j$(nproc)
sudo make install
sudo ldconfig

Verificar:

find /usr/local -name "liquid.h"
# Debe mostrar: /usr/local/include/liquid/liquid.h

5. Instalación — gr-lora (decoder LoRa para GNU Radio)

cd ~/proyectos   # o el directorio que prefieras
git clone https://github.com/rpp0/gr-lora.git
cd gr-lora
mkdir build && cd build
cmake ..
make -j$(nproc)
sudo make install
sudo ldconfig

Verificar:

python3 -c "import lora; print('gr-lora OK')"

6. Instalación — Dependencias Python del proyecto

cd lora-sniffer   # directorio de este proyecto
pip install -r requirements.txt

7. Verificación completa

# Dongle detectado
lsusb | grep -i rtl

# RTL-SDR funcional
rtl_test -t

# SoapySDR lo ve
SoapySDRUtil --probe="driver=rtlsdr"

# gr-lora importable
python3 -c "import lora; print('OK')"

Uso

Proceso completo (captura + extracción + decodificación)

python3 lora_sniffer.py --duration 60

Esto ejecuta los tres pasos en secuencia:

  1. Captura 60 segundos de señal IQ en 868 MHz
  2. Detecta y extrae las tramas LoRa del archivo de captura
  3. Decodifica cada trama con gr-lora y parsea el payload RadioHead

Solo captura

python3 lora_sniffer.py --capture-only --duration 30

Solo extraer + decodificar (archivo existente)

python3 lora_sniffer.py --input captura_lora.cu8

Solo decodificar tramas ya extraídas

python3 lora_sniffer.py --decode-only --input-dir ./tramas/

Parámetros configurables

Parámetro Default Descripción
--freq 868000000 Frecuencia central en Hz
--sample-rate 1000000 Sample rate del RTL-SDR
--gain 40 Ganancia del tuner en dB
--sf 7 Spreading Factor LoRa (7–12)
--bw 125000 Bandwidth LoRa en Hz
--cr 4 Coding Rate (4 = 4/5)
--duration 60 Duración de captura en segundos
--output-dir ./output Directorio de salida
--input Archivo .cu8 existente para analizar

Estructura del proyecto

lora-sniffer/
├── README.md
├── requirements.txt
├── lora_sniffer.py          # Script principal — proceso unificado
├── lib/
│   ├── __init__.py
│   ├── capture.py           # Captura IQ con rtl_sdr
│   ├── extractor.py         # Detección y extracción de tramas
│   ├── decoder.py           # Decodificación gr-lora
│   └── parser.py            # Parseo de payload RadioHead/RH_RF95
└── output/                  # Directorio de salida (generado)
    ├── captura.cu8
    ├── espectrograma.png
    ├── tramas/
    │   ├── trama_001.cf32
    │   └── trama_002.cf32
    └── resultados.json

Formato del payload (RadioHead RH_RF95)

RadioHead añade una cabecera de 4 bytes antes del payload del usuario:

[TO (1B)] [FROM (1B)] [ID (1B)] [FLAGS (1B)] [PAYLOAD...]

Por defecto TO=0xff y FROM=0xff (broadcast). El payload corresponde al struct Message del firmware:

struct Message {
    uint32_t id;          // ID del mensaje
    uint32_t ts;          // Timestamp en segundos (millis()/1000)
    char     text[56];    // Texto del mensaje
};

Resolución de problemas

No devices found: verificar blacklist DVB-T, reconectar dongle, comprobar lsusb.

import lora falla: verificar que se ejecutó sudo make install y sudo ldconfig en gr-lora.

liquid/liquid.h not found: instalar liquid-dsp desde source (sección 4).

-llog4cpp not found: ejecutar sudo apt install liblog4cpp5-dev.

Tramas detectadas pero sin decodificar: ajustar SF y BW a los parámetros del transmisor. Los defaults de RadioHead son SF7, BW125k.

Señal con offset de frecuencia: normal en RTL-SDR. gr-lora tiene corrección de drift. Si es muy grande, ajustar --freq unos kHz arriba o abajo.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages