Documentación del Proyecto: IoT Sentinel

Sistema de Vigilancia de Espectro RF y Alerta OOB (Out-Of-Band)

Autor: [PoisonXploIT]

Estado: Prototipo Funcional (Fase Lógica Completada / Hardware GSM Simulado)

1. Resumen Ejecutivo

IoT Sentinel es un prototipo de dispositivo de seguridad diseñado para detectar anomalías en el espectro de radiofrecuencia (específicamente en la banda ISM de 433MHz), como intentos de inhibición (jamming) o tráfico inusual.

El objetivo principal es crear un sistema resiliente que no dependa de la infraestructura de red local (Wi-Fi/Ethernet) para reportar incidentes. Si detecta un ataque, el sistema debe utilizar un canal secundario “Fuera de Banda” (OOB), en este caso la red móvil GSM, para enviar una alerta SMS crítica al administrador.

Este documento detalla el desarrollo del prototipo utilizando un microcontrolador RP2040 y un transceptor NRF905, así como los desafíos encontrados en la implementación del módulo GSM y la solución de software adoptada.

2. Arquitectura del Sistema

El sistema se basa en una arquitectura de tres pilares:

  1. El Cerebro (Controlador): Un microcontrolador Raspberry Pi Pico (RP2040-Zero) corriendo CircuitPython. Gestiona la lógica de vigilancia, los umbrales de alarma y la comunicación entre módulos.

  2. El Oído (Sensor RF): Un módulo transceptor NRF905. Configurado en modo de solo escucha (RX) en 433MHz para monitorear la actividad del espectro. Se comunica con el cerebro vía SPI.

  3. La Voz (Comunicación OOB): Módulo GSM/GPRS (modelos probados: SIM800C USB y SIM900A UART) encargado de enviar alertas SMS mediante comandos AT.

3. Desarrollo FASE 1: Integración RF (NRF905)

3.1. Desafío Físico y Conexión

El primer reto fue la integración física del RP2040-Zero en la protoboard debido a su tamaño reducido, que dificultaba el acceso a los pines laterales. Se solucionó utilizando el canal central de la protoboard y distribuyendo la alimentación (3.3V y GND) a los rieles laterales para facilitar el cableado hacia el módulo NRF905.

Mapa de Conexiones SPI (RP2040 NRF905): | Señal | Pin RP2040 | Cable Color | | :--- | :--- | :--- | | SCK (Reloj) | GP 6 | Amarillo | | MOSI (Datos Salida)| GP 7 | Verde | | MISO (Datos Entrada)| GP 4 | Azul | | CSN (Chip Select) | GP 5 | Blanco | | TX_EN (Activar TX) | GP 0 | Naranja | | TRX_CE (Activar RX)| GP 1 | Morado |

3.2. Lógica de Software RF

Se utilizó la librería busio.SPI de CircuitPython para establecer la comunicación. El éxito de esta fase se confirmó al enviar un paquete de configuración al NRF905 y leer de vuelta el registro de estado, obteniendo el byte de confirmación 0x76 (indicador de conexión correcta en 433MHz).

3.3 Prueba de PINES

import board

import busio

import digitalio

import time

print(“\n--- INICIANDO FASE 2: TEST FINAL (Esquema Simplificado) ---”)

# --- 1. CONFIGURACIÓN SPI (Pines GP4, GP6, GP7) ---

try:

# SCK=GP6 (Amarillo), MOSI=GP7 (Verde), MISO=GP4 (Azul)

spi = busio.SPI(clock=board.GP6, MOSI=board.GP7, MISO=board.GP4)

print(“Bus SPI iniciado.”)

except Exception as e:

print(f”[ERROR] Fallo en SPI: {e}”)

# --- 2. PINES DE CONTROL ---

# CSN = GP5 (Blanco)

csn = digitalio.DigitalInOut(board.GP5)

csn.direction = digitalio.Direction.OUTPUT

csn.value = True # Desactivado (High)

# TX_EN = GP0 (Naranja)

tx_en = digitalio.DigitalInOut(board.GP0)

tx_en.direction = digitalio.Direction.OUTPUT

tx_en.value = False # Standby

# TRX_CE = GP1 (Morado)

trx_ce = digitalio.DigitalInOut(board.GP1)

trx_ce.direction = digitalio.Direction.OUTPUT

trx_ce.value = False # Standby

# NOTA: PWR_UP está conectado directo a 3.3V (Cable Marrón)

# --- 3. FUNCIONES DEL DRIVER ---

def nrf905_test():

"""Envía configuración y verifica si vuelve igual"""

# Configuración de prueba (433MHz básica)

# Byte 0 (0x76) es la clave que buscamos

config_pattern = bytearray([0x00, 0x76, 0x0E, 0x44, 0x20, 0x20, 0xCC, 0xCC, 0xCC, 0xCC, 0x58])

# 1. Poner en modo programación (Standby)

tx_en.value = False

trx_ce.value = False

time.sleep(0.1)

# 2. Escribir

while not spi.try_lock(): pass

csn.value = False

spi.write(config_pattern)

csn.value = True

spi.unlock()

print(“[TX] Configuración enviada…”)

time.sleep(0.01)

# 3. Leer

read_cmd = bytearray([0x10] + [0x00]*10) # Comando lectura

rx_buffer = bytearray(len(read_cmd))

while not spi.try_lock(): pass

csn.value = False

spi.write_readinto(read_cmd, rx_buffer)

csn.value = True

spi.unlock()

return rx_buffer[1:] # Quitamos el primer byte basura

# --- 4. EJECUCIÓN ---

while True:

print(“\nComprobando conexión con NRF905…”)

try:

resultado = nrf905_test()

byte_clave = resultado[0]

print(f”Leído: {[hex(x) for x in resultado]}”)

if byte_clave == 0x76:

print(“¡CONEXIÓN EXITOSA! El NRF905 responde.”)

print(“Ya puedes pasar a la siguiente fase.”)

break # Salimos del bucle si funciona

elif byte_clave == 0x00:

print(“ERROR: Todo Ceros. Revisa el cable AZUL (MISO) o el ROJO (Energía).”)

elif byte_clave == 0xFF:

print(“ERROR: Todo Unos. Revisa el cable NEGRO (GND) o el BLANCO (CSN).”)

else:

print(“ERROR: Datos corruptos. Revisa cables flojos.”)

except Exception as e:

print(f”Error grave: {e}”)

time.sleep(2)

4. Desarrollo FASE 2: El Desafío GSM y Análisis de Fallos

El objetivo era permitir que el RP2040 enviara comandos AT al módem GSM para despachar SMS. Esta fase enfrentó obstáculos de hardware significativos que impidieron la integración física final en este prototipo.

4.1. Intentos y Obstáculos

Intento A: Módulo SIM800C (Dongle USB) Se intentó controlar mediante interfaz serie USB.

  • Éxito parcial: Se logró comunicación básica mediante terminal PuTTY y comandos como AT (OK) y detección de señal AT+CSQ (Excelente: 18.0).

  • Fallo crítico: El módem reportaba persistentemente el error SIM not inserted a pesar de múltiples intentos de re-asentamiento de la tarjeta.

  • Diagnóstico: Fallo mecánico en el lector de tarjeta SIM del dongle o incompatibilidad con el adaptador de Nano a Micro-SIM utilizado.

Intento B: Módulo SIM900A (Placa UART) Se evaluó como alternativa.

  • Análisis de viabilidad: Este módulo requiere una fuente de alimentación externa dedicada de 5V y picos de 2A, que no podía ser suministrada directamente por el RP2040 sin riesgo de daño. Además, existe riesgo de bloqueo regional en unidades importadas de Asia.

  • Decisión: Se descartó su implementación inmediata para no añadir complejidad eléctrica al prototipo en esta etapa.

4.2. Decisión de Ingeniería

Ante la inviabilidad temporal del hardware GSM disponible, se tomó la decisión estratégica de no detener el desarrollo del software. Se optó por una estrategia de “Mocking” (Simulación de Software) para la capa de comunicación, una práctica estándar en ingeniería de software cuando una API externa no está disponible.

5. FASE 3: Solución Final y Código (Estrategia de Simulación)

Se completó el desarrollo de la lógica de defensa en el RP2040. El código final integra la vigilancia del espectro y la toma de decisiones. La función de envío de SMS real fue sustituida por una función mock que simula la salida por consola, permitiendo validar toda la cadena de eventos.

5.1. Lógica del Código Final

  1. Inicialización: El sistema arranca y simula la verificación de los módulos de hardware.

  2. Bucle de Vigilancia (Loop):

    • El sistema entra en un bucle infinito.

    • Simulación de Sensor: Se genera un valor aleatorio (nivel_ruido) para simular la lectura del RSSI (Indicador de Fuerza de Señal Recibida) del NRF905.

    • Se visualiza en consola una “barra de radar” en tiempo real.

  3. Evaluación de Amenaza:

    • Se compara el nivel de ruido con un UMBRAL_ALARMA predefinido (ej. 80%).
  4. Respuesta a Incidentes:

    • Si se supera el umbral, se dispara la alerta.

    • Se llama a la función enviar_alerta_oob_simulada(), que imprime en consola el payload exacto que se enviaría vía SMS, confirmando que la lógica de disparo funciona.

    • El sistema entra en un periodo de “enfriamiento” para evitar la saturación de alertas.

5.2. Código Fuente Final (CircuitPython)

Python

import time

import random

# --- CONFIGURACIÓN E INICIO ---

print(“\n” + ”=“*50)

print(” IoT SENTINEL - SISTEMA DE DEFENSA ACTIVA”)

print(” Modo: PROTOTIPO LÓGICO (GSM Simulado)”)

print(”=“*50)

print(“\n[BOOT] Iniciando Kernel de Seguridad…”)

time.sleep(1)

print(“[BOOT] Cargando módulos de Análisis de Espectro… OK”)

print(“[BOOT] Verificando canal OOB (GSM Mock)… OK”)

print(“[SYSTEM] SISTEMA ARMADO Y VIGILANDO.\n”)

# Configuración de sensibilidad

# Si el ruido supera este porcentaje, se dispara la alarma.

UMBRAL_ALARMA = 80

# --- CAPA DE COMUNICACIÓN (MOCK/SIMULACIÓN) ---

def enviar_alerta_oob_simulada(mensaje):

"""

Simula el envío de un SMS crítico.

NOTA: Esta función sustituye a los comandos AT reales (ej: AT+CMGS)

debido a fallos mecánicos en el hardware GSM disponible durante el desarrollo.

"""

print(“\n” + ”!”*40)

print(” [GSM OUT-OF-BAND] PROTOCOLO DE EMERGENCIA ACTIVADO”)

print(f” [GSM] Destino: ADMINISTRADOR_SYS (+34666…)”)

print(f” [GSM] Payload: ‘{mensaje}’”)

time.sleep(1) # Simulación de latencia de red

print(” [GSM] Estado: ENVIADO OK (+CMGS: 15)”)

print(”!”*40 + “\n”)

time.sleep(2) # Pausa para visualizar la alerta

# --- BUCLE PRINCIPAL DE VIGILANCIA (CEREBRO) ---

while True:

# 1. Adquisición de Datos (Simulación del NRF905)

# Generamos ruido aleatorio para simular la entrada del sensor RF.

# La mayoría del tiempo el ruido es bajo, con picos ocasionales.

nivel_ruido = random.randint(10, 95)

# Visualización en consola tipo “Radar”

barra_grafica = ”|” * (nivel_ruido // 4)

print(f”Escaneo 433MHz: {barra_grafica} ({nivel_ruido}%)”)

# 2. Lógica de Decisión

# Si el nivel de ruido supera el umbral establecido…

if nivel_ruido > UMBRAL_ALARMA:

print(f”\n[!!!] ANOMALÍA DETECTADA (Nivel {nivel_ruido}% > Umbral {UMBRAL_ALARMA}%)”)

print(“[ANÁLISIS] Patrón de onda coincide con posible INHIBIDOR.”)

# 3. Disparo de Respuesta

enviar_alerta_oob_simulada(“ALERTA CRITICA: Jamming detectado en 433MHz.”)

print(“[SYSTEM] Enfriando sensores tras alerta…”)

time.sleep(4) # Evitar spam de alertas consecutivas

print(“[SYSTEM] Reanudando vigilancia.\n”)

# Pequeña pausa para facilitar la lectura del radar

time.sleep(0.5)

6. Conclusiones y Futuros Pasos

Este prototipo demuestra con éxito la viabilidad lógica de un sistema de defensa IoT autónomo. Se ha logrado implementar la arquitectura de detección y decisión en el microcontrolador RP2040.

La decisión de utilizar simulación para la capa GSM permitió finalizar el desarrollo del software a pesar de las fallas del hardware específico disponible.

Pasos para la siguiente versión:

  1. Sustitución de Hardware GSM: Adquirir un módulo GSM fiable (ej. SIM800L) con su fuente de alimentación adecuada e integrarlo vía UART.

  2. Descomentar Código GSM: Reemplazar la función simulada enviar_alerta_oob_simulada por la implementación real de comandos AT sobre UART.

  3. Lectura Real de RSSI: Implementar la lectura del registro de “Carrier Detect” (CD) del NRF905 para obtener datos reales de intensidad de señal en lugar de valores aleatorios.