Nota, no recomiendo usar este hat si estás usando un disco SSD conectado a los puertos usb, si no es a través de un hub, debido a los picos de corriente que genera provocando desconexiones y problemas en los mismos.
En este tutorial, aprenderemos a configurar un sistema de alerta crítica. Si tu conexión a internet falla —ya sea por una avería de tu proveedor (ISP) o un fallo en tu propio router—, la Raspberry Pi detectará la caída de inmediato, te avisará mediante una llamada telefónica y te reportará via Telegram cuando la red sea restablecida.
Para que este sistema sea infalible, no podemos depender de la propia conexión de fibra que estamos monitorizando. Necesitamos una vía de comunicación externa. En este caso práctico, utilizaremos un módulo HAT 4G LTE CAT-1 (A7670E), junta a una tarjeta SIM M2M (machine to machine) como las que emplean Vodafone u Orange para alarmas profesionales, ascensores , etc. Estas tarjetas suelen estar limitadas a voz o SMS y no disponen de datos móviles. Aprovecharemos la robusta red 2G para garantizar que, en caso de caída de la conexión de fibra, la Raspberry Pi ejecute una llamada de voz a nuestro teléfono móvil de forma prioritaria.

¿Por qué es importante este sistema? Si confías en la domótica para la seguridad de tu hogar (alarmas, detectores de inundación o cámaras), una caída de la red, te deja «a ciegas». Saber que tu red ha caído en tiempo real te permite reaccionar antes de que sea tarde.
¿Cómo funciona el flujo de trabajo?
- Monitorización: La Raspberry Pi realiza «pings» constantes a servidores externos (como los DNS de Google o Cloudflare).
- Detección: Si el ping falla de forma consecutiva, el script activa el módulo A7670E.
- Alerta: El HAT ejecuta el comando AT de llamada y marca tu número de teléfono.
- Acción: Recibes la llamada y sabes, al instante, que algo va mal en casa.
Prepara el software de tu Raspberry.
Para entrar a las funciones del HAT necesitaremos instalar el programa minicom.
sudo apt-get install minicom
Para que nuestro script funcione, necesitas instalar la librería Python Serial:
sudo apt-get install python3-serial -y
Por alguna extraña razón, (que solo he podido observar en Raspberry Pi, ModemManager no se lleva bien con este HAT, intenta secuestrarlo constantemente, como si fuese un módem de los antiguos.
Por eso motivo, ya que no será necesario, optaré por desinstalarlo con:
sudo apt-get purge modemmanager -y
Permisos del usuario.
Tu usuario debe de tener permiso para usar el puerto serie (el módem) por defecto. Si no es así, el script intentará abrir el puerto y al no conseguirlo, se quedará esperando una respuesta que el sistema le bloqueará y no llegará a marcar.
Teclea el siguiente comando para ver los grupos a los que pertenece tu usuario.
groups
Comprueba que tu usuario pertenece al grupo «dialout», si no es así, deberás agregarlo con este comando:
sudo usermod -a -G dialout tu_usuario
Tras ejecutar este comando, reinicia tu Raspberry
sudo reboot
Forzar el modo de alta corriente (Si tu fuente es MUY buena)
En una Raspberry pi 4 es algo común, que si usas varios dispositivos conectados a los puertos USB, Pines GPIO, etc, sufras de cuelgues del sistema y se te queden tus proyectos mas tiesos que la mojama.
Si tienes la fuente oficial de 3A (o una mejor), puedes intentar decirle a la Pi que desbloquee el límite de los USB, aunque esto es automático hasta cierto punto, a veces ayuda asegurar el voltaje. Sin embargo, hay un detalle técnico importante: en la Raspberry Pi 4, el límite de corriente de los USB está fijado por hardware a 1.2A compartidos.
Pero, para «darle chicha» y asegurar que el sistema no entre en pánico cuando el SSD y el HAT 4G trabajen juntos, vamos a aplicar dos ajustes de «estabilidad máxima» que debes tener en cuenta.
1. Evitar el «ahorro de energía» del USB (El culpable del bloqueo)
Cuando el SSD y el HAT piden energía a la vez, el kernel de Linux puede intentar suspender el puerto USB para protegerse, y ahí es donde se congela la Pi. Vamos a prohibirle que lo haga.
Ejecuta este comando para editar el archivo de arranque:
sudo nano /boot/firmware/cmdline.txt
Al final de la línea de texto (sin pulsar Enter, todo en la misma línea), añade un espacio y esto:
usbcore.autosuspend=-1
2. Estabilidad de Voltaje (Config.txt)
Vamos a añadir un parámetro para que la CPU no baje su rendimiento bruscamente cuando detecte picos de consumo del USB, lo que evita que se cuelgue el sistema.
Edita el archivo de configuración:
sudo nano /boot/firmware/config.txt
Añade estas líneas al final:
# Forzar estabilidad de voltaje en puertos USB
avoid_warnings=1
El Hardware: HAT 4G LTE CAT-1 (A7670E)
El HAT 4G LTE CAT-1 para Raspberry Pi (Modelo A7670E), es un módulo compacto pero extremadamente versátil capaz de:
- Realizar y recibir llamadas de voz.
- Enviar y recibir SMS.
- Navegar por internet mediante 4G.
- Obtener datos de GPS
Nota: A partir de este momento, no es necesario tener conectado el cable USB al Módulo 4G, tan solo debe de estar conectado a los pines GPIO
Configurar la Raspberry para usar su puerto serie interno
Por defecto, la Raspberry usa sus pines de transmisión para la «consola» (donde ves letras al arrancar). Hay que liberarlo:
- Ejecuta:
sudo raspi-config - Ve a Interface Options -> Serial Port.
- ¿Deseas que la consola sea accesible por serie? NO.
- ¿Deseas que el hardware del puerto serie esté habilitado? SÍ.
- Reinicia la Raspberry.
Localizar el nuevo puerto
Una vez iniciado el sistema, vuelve a ingresar a la terminal para que podamos entrar por el puerto físico de los pines de la Raspberry, que suele ser /dev/ttyS0
sudo minicom -D /dev/ttyS0 -b 115200
Si todo va bien, entrarás a la terminal de configuración del módulo. Ahora, debemos comprobar el modo de funcionamiento en el que se encuentra el HAT 4G.
La terminal del módulo 4G
Ahora que estás en la terminal de programación del módulo, escribe el siguiente comando.
AT$MYCONFIG?
Si nos devuelve "usbnetmode"2, es porque el módulo está en modo Serial(modén) que es justo lo que necesitamos.
Pero, si nos devuelve "usbnetmode",0, es porque el módulo está en modo RNDIS (Red) y deberemos desactivarlo.
Cómo desactivar RNDIS
«Muchos tutoriales te obligan a usar el modo RNDIS, pero si tu objetivo es enviar alertas mediante llamadas, el modo Serie (usbnetmode,2) es el secreto para una estabilidad del 100% en placas Raspberry Pi, evitando conflictos de red innecesarios.»
Para dejarlo en modo «serie», que es el la opción indicada para hacer solo llamadas perdidas desde la Raspberry Pi 4, ejecuta esta secuencia exacta en tu terminal:
- Cambia al modo 2 (Modem/Serie):
AT$MYCONFIG="usbnetmode",2 - Desactiva el intento de marcación automática:
AT+DIALMODE=1 - Guarda los cambios en la memoria interna (Flash):
AT&W - Reinicia el módulo para que aplique los cambios:
AT+CRESET
Para salir del terminal del HAT 4G pulsa Ctrl + A y luego Q y volverás a la terminal de Linux.
EL Script
Tras varias pruebas, este script en su versión 4.7, es una solución de monitorización en lenguaje Python, diseñada para informar cuando tu conexión de internet principal falla.
Crea un archivo llamado netguard.py
nano netguard.py
Pega el siguiente código.
No olvides sustituir tu número de teléfono, tu Token de Telegram y tu ID de Telegram.
import os
import time
import serial
import subprocess
import requests
import sys
# --- CONFIGURACIÓN ---
TELEFONO = "600000000"
PUERTO_MODEM = "/dev/serial0"
INTERFAZ_FIBRA = "eth0"
TOKEN_TELEGRAM = "Tu_Token"
ID_CHAT = "Tu_ID"
fibra_estaba_caida = False
llamada_realizada_con_exito = False
def comprobar_fibra():
try:
resultado = subprocess.run(
["ping", "-I", INTERFAZ_FIBRA, "-c", "2", "-W", "3", "1.1.1.1"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
return resultado.returncode == 0
except:
return False
def inicializar_modem(ser):
"""Configuración inicial recomendada para A7670E"""
comandos = [
b"AT+CMEE=2\r\n", # Errores verbosos
b"AT+CRC=1\r\n", # Resultados extendidos (útil)
b"AT+COLP=1\r\n", # Muestra número cuando contestan (opcional)
b"AT+CVHU=0\r\n", # Modo hangup correcto
b"AT+CLCC=1\r\n", # (no siempre necesario pero no hace daño)
]
for cmd in comandos:
ser.write(cmd)
time.sleep(0.4)
ser.read_all() # descartar respuesta
def realizar_llamada_perdida():
ser = None
try:
print(f"\n[{time.strftime('%H:%M:%S')}] ALERTA: Sin internet → Iniciando llamada perdida...", flush=True)
ser = serial.Serial(PUERTO_MODEM, 115200, timeout=1)
inicializar_modem(ser)
# Limpieza completa
ser.reset_input_buffer()
ser.reset_output_buffer()
# Registro en red (mejor usar CEREG para LTE, pero CREG también funciona)
print(" [+] Esperando cobertura...", flush=True)
for i in range(30):
ser.write(b"AT+CREG?\r\n")
time.sleep(1)
resp = ser.read_all().decode(errors='ignore')
if ",1" in resp or ",5" in resp:
print(f" [+] Registrado en red (intento {i+1})", flush=True)
break
print(f" [...] Buscando torre... ({i+1}/30)", flush=True)
else:
print(" [!] Sin cobertura. Reiniciando módulo...", flush=True)
ser.write(b"AT+CFUN=1,1\r\n")
return False
# Colgar cualquier llamada residual
ser.write(b"AT+CHUP\r\n")
time.sleep(0.8)
ser.read_all()
# MARCAR
print(f" 📞 Marcando a {TELEFONO}...", flush=True)
ser.write(f"ATD{TELEFONO};\r\n".encode())
time.sleep(1.5) # esperar OK + VOICE CALL: BEGIN
print(" [?] Llamada en curso. Esperando que cuelgues (máx 45s)...", flush=True)
timeout = time.time() + 45
llamada_activa = False
while time.time() < timeout:
# Polling CLCC + lectura de URCs
ser.write(b"AT+CLCC\r\n")
time.sleep(0.7)
resp = ser.read_all().decode(errors='ignore').strip()
# URC directo del módulo (lo más fiable)
if "VOICE CALL: END" in resp:
print(" ✅ Colgado detectado por URC 'VOICE CALL: END'", flush=True)
return True
# CLCC desapareció → colgado por receptor
if "+CLCC:" in resp:
llamada_activa = True
print(" → Sonando / activa", flush=True)
elif llamada_activa and "+CLCC:" not in resp and "OK" in resp:
print(" ✅ Colgado detectado: CLCC desapareció", flush=True)
return True
# Backup: NO CARRIER
if "NO CARRIER" in resp:
print(" ✅ Colgado por NO CARRIER", flush=True)
return True
# Timeout → colgamos nosotros
print(" ⏰ Timeout → colgando forzosamente", flush=True)
ser.write(b"AT+CHUP\r\n")
return False
except Exception as e:
print(f" [!] Error serie: {e}", flush=True)
return False
finally:
if ser and ser.is_open:
ser.close()
# --- BUCLE PRINCIPAL ---
print("--- Vigilante M2M v5.7 (A7670E optimizado) ---", flush=True)
while True:
hay_internet = comprobar_fibra()
if not hay_internet:
if not fibra_estaba_caida:
print(f"[{time.strftime('%H:%M:%S')}] Caída de fibra detectada.", flush=True)
time.sleep(5)
if not comprobar_fibra(): # doble chequeo
fibra_estaba_caida = True
if realizar_llamada_perdida():
llamada_realizada_con_exito = True
else:
time.sleep(30) # reintentar más lento si falló
elif not llamada_realizada_con_exito:
if realizar_llamada_perdida():
llamada_realizada_con_exito = True
else:
time.sleep(60)
elif hay_internet and fibra_estaba_caida:
print(f"[{time.strftime('%H:%M:%S')}] ✅ Fibra recuperada. Avisando por Telegram...", flush=True)
try:
requests.post(
f"https://api.telegram.org/bot{TOKEN_TELEGRAM}/sendMessage",
data={"chat_id": ID_CHAT, "text": "✅ Fibra recuperada"},
timeout=10
)
except:
pass
fibra_estaba_caida = False
llamada_realizada_con_exito = False
time.sleep(20)
Para guardar pulsa Ctrl + o y Ctrl + x para salir
No olvides hacerlo ejecutable con:
chmod +x netguard.py
¿Cómo funciona el script?
El programa actúa como un centinela que vigila la interfaz de fibra (eth0) cada 20 segundos mediante pings ligeros. Su inteligencia reside en cómo gestiona las alertas:
- El script actúa como un centinela incansable que vigila la interfaz de fibra (eth0) cada 20 segundos mediante pings ligeros. Su inteligencia reside en cómo gestiona las alertas de forma robusta y eficiente, aprovechando al máximo las capacidades del módulo A7670E (según el manual oficial SIMCom A76XX v1.09):
- Paciencia de Registro (mejorada): No marca a ciegas. Primero interroga al módem con AT+CREG? para confirmar cobertura real (registrado en red roaming o home). Realiza hasta 30 intentos (más margen que antes), con pausas de 1 segundo, dando tiempo al hardware para sincronizarse con la torre más cercana. Si falla tras los intentos, fuerza un reinicio profundo del módulo (AT+CFUN=1,1) para «despertarlo» y buscar señal de nuevo.
- Inicialización Proactiva del Módem: Antes de cualquier operación crítica, envía comandos de configuración recomendados por SIMCom: AT+CMEE=2 (errores verbosos), AT+CRC=1 (resultados extendidos), AT+COLP=1 (muestra número al contestar, opcional), AT+CVHU=0 (modo colgado correcto). Esto evita errores comunes y mejora la fiabilidad.
- Detección Inteligente de Colgado (el gran salto): La clave de v5.7 es la detección proactiva y prioritaria usando URCs nativos del módulo:
- Tras ATD<numero>;, el módem envía automáticamente VOICE CALL: BEGIN cuando empieza a sonar.
- Mientras la llamada está activa, polling frecuente con AT+CLCC para ver si sigue en lista (+CLCC: presente).
- Cuando cuelgas desde tu móvil, llega el URC VOICE CALL: END → detección inmediata y casi infalible.
- Fallbacks: si CLCC desaparece tras haber estado activo, o aparece NO CARRIER.
- Timeout máximo de 45 segundos (más que suficiente para llamada perdida) → fuerza AT+CHUP si no cuelgas, evitando bloqueos eternos.
- Flush=True, Timeouts y Limpieza de Buffers: Todas las impresiones usan flush=True para logs inmediatos en journalctl. Las lecturas/escrituras serie tienen timeout=1 y se limpian buffers (reset_input_buffer()) antes y después de comandos clave. Nada se queda «colgado».
- Reintento Inteligente y Persistencia Educada: Si la llamada falla (sin cobertura, timeout, etc.), el script reintenta en el siguiente ciclo de vigilancia (cada ~20-60 s según estado). Pero una vez que logra que tu móvil suene con éxito (colgado detectado), marca llamada_realizada_con_exito = True y deja de llamar hasta que la fibra se recupere. Así evita saturar tu línea o gastar saldo innecesario.
- Informe de Retorno por Telegram: Tras la alerta por voz, el script entra en modo «escucha». En cuanto detecta que la fibra ha vuelto (doble chequeo ping para evitar falsos positivos), envía mensaje por Telegram: «✅ Fibra recuperada». Así sabes no solo la caída, sino también el momento exacto de recuperación.
Ademas:
- Doble verificación de caída (ping + 5 s espera + segundo ping) antes de alertar.
- Logs limpios: imprime solo lo esencial (puedes reducir aún más los «→ Sonando / activa» editando el contador).
- Manejo de excepciones y cierre seguro del puerto serie (finally con ser.close()).
En resumen: v5.7 es más fiable, rápida en detección y respetuosa con tu móvil y saldo, gracias a los URC nativos y la configuración proactiva del módulo.
Lanza tu script a ver que ocurre.
python3 netguard.py
Crea el archivo del servicio.
«Haciéndolo Robusto: Creando un Servicio en Systemd» «Un vigilante no sirve de nada si tienes que arrancarlo a mano. Al convertir nuestro script en un servicio de Linux, garantizamos que la vigilancia sea 24/7, incluso si hay un apagón y la Raspberry se reinicia sola. El sistema se encarga de que el script esté siempre vivo.»
Para que este script sea realmente autónomo, debería arrancar al inicio del sistema y si falla o se cierra por un error inesperado, Linux lo reinicia automáticamente en pocos segundos.
Lo ideal es crear un servicio en el sistema (Systemd).
Ejecuta este comando para crear el archivo de configuración:
sudo nano /etc/systemd/system/netguard.service
Copia y pega este contenido (asegúrate de que la ruta /home/tu_usuario/netguard.py sea la correcta donde guardaste el script):
[Unit]
Description=Servicio Vigilante de Fibra por GSM
After=network.target
[Service]
# Fuerza a Python a no guardar nada en memoria intermedia
Environment=PYTHONUNBUFFERED=1
ExecStart=/usr/bin/python3 -u /home/tu_usuario/netguard.py
WorkingDirectory=/home/tu_usuario
User=tu_usuario
# El grupo dialout es clave para que el usuario tenga permiso al módem
Group=dialout
Restart=always
RestartSec=10
# Estas líneas aseguran que Systemd vuelque todo al journal al instante
StandardOutput=journal
StandardError=journal
TTYPath=/dev/ttyS0
[Install]
WantedBy=multi-user.target
Nota: Cambia tu_usuario por el tuyo propio.
Activar y arrancar el servicio
Ahora dale las órdenes a la Raspberry para que lo ponga en marcha:
# Recargar el sistema para que vea el nuevo servicio
sudo systemctl daemon-reload
# Activar para que arranque siempre al encender la Pi
sudo systemctl enable netguard.service
# Arrancar el servicio ahora mismo
sudo systemctl start netguard.service
¿Cómo saber si está funcionando?
Puedes ver el estado del vigilante en tiempo real con este comando:
sudo systemctl status netguard.service
Y si quieres ver los «logs» (lo que el script va imprimiendo):
journalctl -u netguard.service -f
Un ejemplo tras varios dias de funcionamiento del script.
tu_usurio@raspberrypi:~ $ journalctl -u netguard.service -f
mar 01 15:53:48 tu_host python3[3651558]: --- Vigilante M2M v5.7 (A7670E optimizado) ---
mar 01 15:54:13 tu_host python3[3651558]: [15:54:13] Caída de fibra detectada.
mar 01 15:54:22 tu_host python3[3651558]: [15:54:22] ALERTA: Sin internet → Iniciando llamada perdida...
mar 01 15:54:24 tu_host python3[3651558]: [+] Esperando cobertura...
mar 01 15:54:25 tu_host python3[3651558]: [+] Registrado en red (intento 1)
mar 01 15:54:25 tu_host python3[3651558]: 📞 Marcando a 600000000...
mar 01 15:54:27 tu_host python3[3651558]: [?] Llamada en curso. Esperando que cuelgues (máx 45s)...
mar 01 15:54:28 tu_host python3[3651558]: → Sonando / activa
mar 01 15:54:28 tu_host python3[3651558]: → Sonando / activa
mar 01 15:54:29 tu_host python3[3651558]: → Sonando / activa
mar 01 15:54:30 tu_host python3[3651558]: → Sonando / activa
mar 01 15:54:30 tu_host python3[3651558]: → Sonando / activa
mar 01 15:54:31 tu_host python3[3651558]: → Sonando / activa
mar 01 15:55:00 tu_host python3[3651558]: ✅ Colgado detectado por URC 'VOICE CALL: END'
mar 01 15:55:21 tu_host python3[3651558]: [15:55:21] ✅ Fibra recuperada. Avisando por Telegram...
Troubleshooting (solución de problemas)
Si tu sistema sigue experimentando cuelgues o hace cosas extrañas cuando intenta hacer una llamada, prueba a usar un Hub USB con alimentación propia (La más segura). Conecta el SSD a un Hub USB que tenga su propia fuente de alimentación. Así, la energía para mover el módulo la da el Hub y no la Raspberry. La Pi solo se encarga de los datos. Por lo que, lo más efectivo es separar el consumo.
Prueba final:
Una vez que esté todo funcionando.
- Desconecta el cable Ethernet para provocar una llamada.
- Abre abre una terminal y escribe
ls -R / - Si ya no se bloquea, es que la fuente de la Pi 5 y el comando
autosuspend=-1han solucionado el conflicto de energía.
Miscelánea
Estos son los comandos clave para extraer estadísticas y gestionar tu Vigilante como un auténtico administrador de sistemas.
1. El «Resumen de Batalla» (Estadísticas rápidas)
Si quieres saber cuántas veces se ha caído la fibra o cuántas llamadas ha hecho el script sin leer miles de líneas, usa este comando. Filtrará el log y te dará solo los hitos importantes:
journalctl -u netguard.service | grep -E "Caída detectada|Llamada finalizada|Red recuperada"
Esto te mostrará una lista limpia con los días y horas exactas de cada incidente.
2. Comprobar el estado del «Motor»
Si alguna vez dudas de si el script sigue vivo (aunque ya hemos visto que es eterno), este comando te da el informe de salud de Systemd:
systemctl status netguard.service
Fíjate en la línea que dice Active: active (running) since.... Te dirá cuántos días lleva encendido sin interrupciones.
3. Reiniciar tras cambios (SIM, teléfono, etc.)
Si decides cambiar el número de teléfono o el token de Telegram en el archivo .py, no basta con guardar el archivo. Tienes que decirle a la Raspberry que cargue la nueva versión:
sudo systemctl restart netguard.service
Brutal, una puta pasada… mi gurú informático…sublime una vez más!