<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>watchdog &#8211; El Cornijal de Linux</title>
	<atom:link href="https://linuxete.duckdns.org/category/watchdog/feed/" rel="self" type="application/rss+xml" />
	<link>https://linuxete.duckdns.org</link>
	<description>Un blog sobre Linux</description>
	<lastBuildDate>Sun, 01 Mar 2026 19:09:48 +0000</lastBuildDate>
	<language>es</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Tutorial: Failover en Raspberry Pi mediante Llamada Telefónica</title>
		<link>https://linuxete.duckdns.org/tutorial-failover-en-raspberry-pi-mediante-llamada-telefonica/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=tutorial-failover-en-raspberry-pi-mediante-llamada-telefonica</link>
					<comments>https://linuxete.duckdns.org/tutorial-failover-en-raspberry-pi-mediante-llamada-telefonica/#comments</comments>
		
		<dc:creator><![CDATA[raspberry]]></dc:creator>
		<pubDate>Tue, 13 Jan 2026 18:16:53 +0000</pubDate>
				<category><![CDATA[internet]]></category>
		<category><![CDATA[Seguridad]]></category>
		<category><![CDATA[Sistema]]></category>
		<category><![CDATA[watchdog]]></category>
		<category><![CDATA[A7670E]]></category>
		<category><![CDATA[Failover]]></category>
		<category><![CDATA[HAT 4G]]></category>
		<category><![CDATA[HAT 4G LTE CAT-1]]></category>
		<category><![CDATA[Waveshare]]></category>
		<guid isPermaLink="false">https://linuxete.duckdns.org/?p=3573</guid>

					<description><![CDATA[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 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>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.</p>
</blockquote>



<p>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, <strong>te avisará mediante una llamada telefónica</strong> y te reportará via Telegram cuando la red sea restablecida.</p>



<p>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 <strong>tarjeta SIM M2M</strong> (machine to machine) como las que emplean Vodafone u Orange para alarmas profesionales, ascensores , etc. Estas tarjetas suelen estar <strong>limitadas</strong> a voz o SMS y <strong>no disponen de datos móviles</strong>. Aprovecharemos la <strong>robusta red 2G</strong> 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.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img fetchpriority="high" decoding="async" width="800" height="800" src="https://linuxete.duckdns.org/wp-content/uploads/2026/01/hat-4g-lte-cat-1-para-raspberry-pi-a7670e.jpg" alt="" class="wp-image-3568" style="width:364px;height:auto" srcset="https://linuxete.duckdns.org/wp-content/uploads/2026/01/hat-4g-lte-cat-1-para-raspberry-pi-a7670e.jpg 800w, https://linuxete.duckdns.org/wp-content/uploads/2026/01/hat-4g-lte-cat-1-para-raspberry-pi-a7670e-300x300.jpg 300w, https://linuxete.duckdns.org/wp-content/uploads/2026/01/hat-4g-lte-cat-1-para-raspberry-pi-a7670e-150x150.jpg 150w, https://linuxete.duckdns.org/wp-content/uploads/2026/01/hat-4g-lte-cat-1-para-raspberry-pi-a7670e-768x768.jpg 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p><strong>¿Por qué es importante este sistema?</strong> 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.</p>



<p>¿Cómo funciona el flujo de trabajo?</p>



<ol start="1" class="wp-block-list">
<li><strong>Monitorización:</strong> La Raspberry Pi realiza «pings» constantes a servidores externos (como los DNS de Google o Cloudflare).</li>



<li><strong>Detección:</strong> Si el ping falla de forma consecutiva, el script activa el módulo A7670E.</li>



<li><strong>Alerta:</strong> El HAT ejecuta el comando AT de llamada y marca tu número de teléfono.</li>



<li><strong>Acción:</strong> Recibes la llamada y sabes, al instante, que algo va mal en casa.</li>
</ol>



<h2 class="wp-block-heading">Prepara el software de tu Raspberry.</h2>



<p>Para entrar a las funciones del HAT necesitaremos instalar el programa minicom.</p>



<pre class="wp-block-code"><code>sudo apt-get install minicom</code></pre>



<p>Para que nuestro script funcione, necesitas instalar la librería Python Serial:</p>



<pre class="wp-block-code"><code><code>sudo apt-get install python3-serial -y</code></code></pre>



<p>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.</p>



<p>Por eso motivo, ya que no será necesario, optaré por desinstalarlo con:</p>



<pre id="block-14c1177c-0d94-499d-9667-d03e8388d140" class="wp-block-preformatted">sudo apt-get purge modemmanager -y</pre>



<h3 class="wp-block-heading">Permisos del usuario.</h3>



<p>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.</p>



<p>Teclea el siguiente comando para ver los grupos a los que pertenece tu usuario.</p>



<pre class="wp-block-code"><code>groups</code></pre>



<p>Comprueba que tu usuario pertenece al grupo «dialout», si no es así, deberás agregarlo con este comando:</p>



<pre class="wp-block-code"><code>sudo usermod -a -G dialout <mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark></code></pre>



<p>Tras ejecutar este comando, <strong>reinicia</strong> tu Raspberry</p>



<pre class="wp-block-code"><code>sudo reboot</code></pre>



<h4 class="wp-block-heading">Forzar el modo de alta corriente (Si tu fuente es MUY buena)</h4>



<p>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. </p>



<p>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 <strong>1.2A compartidos</strong>.</p>



<p>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.</p>



<h5 class="wp-block-heading">1. Evitar el «ahorro de energía» del USB (El culpable del bloqueo)</h5>



<p>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.</p>



<p>Ejecuta este comando para editar el archivo de arranque:</p>



<pre class="wp-block-code"><code>sudo nano /boot/firmware/cmdline.txt</code></pre>



<p>Al final de la línea de texto (sin pulsar Enter, todo en la misma línea), añade un espacio y esto:</p>



<pre class="wp-block-code"><code>usbcore.autosuspend=-1</code></pre>



<h5 class="wp-block-heading">2. Estabilidad de Voltaje (Config.txt)</h5>



<p>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.</p>



<p>Edita el archivo de configuración:</p>



<pre class="wp-block-code"><code>sudo nano /boot/firmware/config.txt</code></pre>



<p>Añade estas líneas al final:</p>



<pre class="wp-block-code"><code># Forzar estabilidad de voltaje en puertos USB
avoid_warnings=1</code></pre>



<h2 class="wp-block-heading">El Hardware: HAT 4G LTE CAT-1 (A7670E)</h2>



<p>El <strong>HAT 4G LTE CAT-1 para Raspberry Pi (Modelo A7670E)</strong>, es un módulo compacto pero extremadamente versátil capaz de:</p>



<ul class="wp-block-list">
<li>Realizar y recibir llamadas de voz.</li>



<li>Enviar y recibir SMS.</li>



<li>Navegar por internet mediante 4G.</li>



<li>Obtener datos de GPS</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>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</p>
</blockquote>



<h3 class="wp-block-heading">Configurar la Raspberry para usar su puerto serie interno</h3>



<p>Por defecto, la Raspberry usa sus pines de transmisión para la «consola» (donde ves letras al arrancar). Hay que liberarlo:</p>



<ol start="1" class="wp-block-list">
<li>Ejecuta:<br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">sudo raspi-config</mark></code></li>



<li>Ve a <strong>Interface Options</strong> -&gt; <strong>Serial Port</strong>.</li>



<li>¿Deseas que la consola sea accesible por serie? <strong>NO</strong>.</li>



<li>¿Deseas que el hardware del puerto serie esté habilitado? <strong>SÍ</strong>.</li>



<li>Reinicia la Raspberry.</li>
</ol>



<h4 class="wp-block-heading">Localizar el nuevo puerto</h4>



<p>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 <code>/dev/ttyS0</code></p>



<pre class="wp-block-code"><code>sudo minicom -D /dev/ttyS0 -b 115200</code></pre>



<p>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.</p>



<h4 class="wp-block-heading">La terminal del módulo 4G</h4>



<p>Ahora que estás en la terminal de programación del módulo, escribe el siguiente comando.</p>



<pre class="wp-block-code"><code>AT$MYCONFIG?</code></pre>



<p>Si nos devuelve <strong><code>"usbnetmode"2</code></strong>, es porque el módulo está en modo <strong>Serial(modén)</strong> que es justo lo que necesitamos.</p>



<p>Pero, si nos devuelve <strong><code>"usbnetmode",0</code></strong>, es porque el módulo está en modo <strong>RNDIS (Red)</strong> y deberemos desactivarlo.</p>



<h3 class="wp-block-heading">Cómo desactivar RNDIS</h3>



<p><em>«Muchos tutoriales te obligan a usar el modo RNDIS, pero si tu objetivo es enviar alertas mediante llamadas, el modo <strong>Serie (usbnetmode,2)</strong> es el secreto para una estabilidad del 100% en placas Raspberry Pi, evitando conflictos de red innecesarios.»</em></p>



<p>Para dejarlo en modo <strong>«serie»</strong>, que es el la opción indicada para hacer solo llamadas perdidas desde la Raspberry Pi 4, ejecuta esta secuencia exacta en tu terminal:</p>



<ol start="1" class="wp-block-list">
<li><strong>Cambia al modo 2 (Modem/Serie):</strong><br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">AT$MYCONFIG="usbnetmode",2</mark></code></li>



<li><strong>Desactiva el intento de marcación automática:</strong><br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">AT+DIALMODE=1</mark></code></li>



<li><strong>Guarda los cambios en la memoria interna (Flash):</strong><br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">AT&amp;W</mark></code></li>



<li><strong>Reinicia el módulo para que aplique los cambios:</strong><br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">AT+CRESET</mark></code></li>
</ol>



<p>Para salir del terminal del HAT 4G pulsa Ctrl + A y luego Q y volverás a la terminal de Linux.</p>



<h2 class="wp-block-heading">EL Script</h2>



<p>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.</p>



<p>Crea un archivo llamado <code>netguard.py</code></p>



<pre class="wp-block-code"><code>nano netguard.py</code></pre>



<p>Pega el siguiente código.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>No olvides sustituir tu número de <strong>teléfono, </strong>tu<strong> Token </strong>de<strong> Telegram </strong>y tu<strong> ID </strong>de<strong> Telegram.</strong></p>
</blockquote>



<pre class="wp-block-code"><code>import os
import time
import serial
import subprocess
import requests
import sys

# --- CONFIGURACIÓN ---
TELEFONO = "<mark style="background-color:#7bdcb5" class="has-inline-color">600000000</mark>"
PUERTO_MODEM = "/dev/serial0"
INTERFAZ_FIBRA = "eth0"
TOKEN_TELEGRAM = "<mark style="background-color:#7bdcb5" class="has-inline-color">Tu_Token</mark>"
ID_CHAT = "<mark style="background-color:#7bdcb5" class="has-inline-color">Tu_ID</mark>"

fibra_estaba_caida = False
llamada_realizada_con_exito = False

def comprobar_fibra():
    try:
        resultado = subprocess.run(
            &#91;"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 = &#91;
        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&#91;{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(" &#91;+] 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" &#91;+] Registrado en red (intento {i+1})", flush=True)
                break
            print(f" &#91;...] Buscando torre... ({i+1}/30)", flush=True)
        else:
            print(" &#91;!] 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" &#x1f4de; Marcando a {TELEFONO}...", flush=True)
        ser.write(f"ATD{TELEFONO};\r\n".encode())
        time.sleep(1.5)  # esperar OK + VOICE CALL: BEGIN

        print(" &#91;?] Llamada en curso. Esperando que cuelgues (máx 45s)...", flush=True)

        timeout = time.time() + 45
        llamada_activa = False

        while time.time() &lt; 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(" &#x2705; 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(" &#x2705; Colgado detectado: CLCC desapareció", flush=True)
                return True

            # Backup: NO CARRIER
            if "NO CARRIER" in resp:
                print(" &#x2705; Colgado por NO CARRIER", flush=True)
                return True

        # Timeout → colgamos nosotros
        print(" &#x23f0; Timeout → colgando forzosamente", flush=True)
        ser.write(b"AT+CHUP\r\n")
        return False

    except Exception as e:
        print(f" &#91;!] 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"&#91;{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"&#91;{time.strftime('%H:%M:%S')}] &#x2705; 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": "&#x2705; Fibra recuperada"},
                timeout=10
            )
        except:
            pass
        fibra_estaba_caida = False
        llamada_realizada_con_exito = False

    time.sleep(20)
</code></pre>



<p>Para guardar pulsa Ctrl + o y  Ctrl + x para salir</p>



<p>No olvides hacerlo ejecutable con:</p>



<pre class="wp-block-code"><code>chmod +x netguard.py</code></pre>



<h4 class="wp-block-heading">¿Cómo funciona el script?</h4>



<p>El programa actúa como un centinela que vigila la interfaz de fibra (<code>eth0</code>) cada 20 segundos mediante pings ligeros. Su inteligencia reside en cómo gestiona las alertas:</p>



<ol start="1" class="wp-block-list">
<li>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):</li>



<li><strong>Paciencia de Registro (mejorada):</strong> No marca a ciegas. Primero interroga al módem con AT+CREG? para confirmar cobertura real (registrado en red roaming o home). Realiza hasta <strong>30 intentos</strong> (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.</li>



<li><strong>Inicialización Proactiva del Módem:</strong> 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.</li>



<li><strong>Detección Inteligente de Colgado (el gran salto):</strong> La clave de v5.7 es la detección <strong>proactiva y prioritaria</strong> usando URCs nativos del módulo:
<ul class="wp-block-list">
<li>Tras ATD&lt;numero>;, el módem envía automáticamente VOICE CALL: BEGIN cuando empieza a sonar.</li>



<li>Mientras la llamada está activa, polling frecuente con AT+CLCC para ver si sigue en lista (+CLCC: presente).</li>



<li><strong>Cuando cuelgas desde tu móvil</strong>, llega el URC VOICE CALL: END → detección inmediata y casi infalible.</li>



<li>Fallbacks: si CLCC desaparece tras haber estado activo, o aparece NO CARRIER.</li>



<li>Timeout máximo de <strong>45 segundos</strong> (más que suficiente para llamada perdida) → fuerza AT+CHUP si no cuelgas, evitando bloqueos eternos.</li>
</ul>
</li>



<li><strong>Flush=True, Timeouts y Limpieza de Buffers:</strong> 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».</li>



<li><strong>Reintento Inteligente y Persistencia Educada:</strong> 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 <strong>deja de llamar</strong> hasta que la fibra se recupere. Así evita saturar tu línea o gastar saldo innecesario.</li>



<li><strong>Informe de Retorno por Telegram:</strong> 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: «<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Fibra recuperada». Así sabes no solo la caída, sino también el momento exacto de recuperación.</li>
</ol>



<p>Ademas:</p>



<ol start="1" class="wp-block-list">
<li>Doble verificación de caída (ping + 5 s espera + segundo ping) antes de alertar.</li>



<li>Logs limpios: imprime solo lo esencial (puedes reducir aún más los «→ Sonando / activa» editando el contador).</li>



<li>Manejo de excepciones y cierre seguro del puerto serie (finally con ser.close()).</li>
</ol>



<p>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.</p>



<h4 class="wp-block-heading">Lanza tu script a ver que ocurre.</h4>



<pre class="wp-block-code"><code>python3 netguard.py</code></pre>



<h2 class="wp-block-heading">Crea el archivo del servicio.</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>«Haciéndolo Robusto: Creando un Servicio en Systemd»</strong> <em>«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.»</em></p>
</blockquote>



<p>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.</p>



<p>Lo ideal es crear un <strong>servicio en el sistema (Systemd)</strong>.</p>



<p>Ejecuta este comando para crear el archivo de configuración:</p>



<pre class="wp-block-code"><code>sudo nano /etc/systemd/system/netguard.service</code></pre>



<p>Copia y pega este contenido (asegúrate de que la ruta <code>/home/tu_usuario/netguard.py</code> sea la correcta donde guardaste el script):</p>



<pre class="wp-block-code"><code>&#91;Unit]
Description=Servicio Vigilante de Fibra por GSM
After=network.target

&#91;Service]
# Fuerza a Python a no guardar nada en memoria intermedia
Environment=PYTHONUNBUFFERED=1
ExecStart=/usr/bin/python3 -u /home/<mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark>/netguard.py
WorkingDirectory=/home/<mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark>
User=<mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark>
# 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

&#91;Install]
WantedBy=multi-user.target
</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><em>Nota: Cambia <mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark></em> por el tuyo propio.</p>
</blockquote>



<h4 class="wp-block-heading">Activar y arrancar el servicio</h4>



<p>Ahora dale las órdenes a la Raspberry para que lo ponga en marcha:</p>



<pre class="wp-block-code"><code># 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</code></pre>



<h4 class="wp-block-heading">¿Cómo saber si está funcionando?</h4>



<p>Puedes ver el estado del vigilante en tiempo real con este comando:</p>



<pre class="wp-block-code"><code>sudo systemctl status netguard.service</code></pre>



<p>Y si quieres ver los «logs» (lo que el script va imprimiendo):</p>



<pre class="wp-block-code"><code>journalctl -u netguard.service -f</code></pre>



<p>Un ejemplo tras varios dias de funcionamiento del script.</p>



<pre class="wp-block-code"><code>tu_usurio@raspberrypi:~ $ <strong>journalctl -u netguard.service -f</strong>
mar 01 15:53:48 tu_host python3&#91;3651558]: --- Vigilante M2M v5.7 (A7670E optimizado) ---
mar 01 15:54:13 tu_host python3&#91;3651558]: &#91;15:54:13] Caída de fibra detectada.
mar 01 15:54:22 tu_host python3&#91;3651558]: &#91;15:54:22] ALERTA: Sin internet → Iniciando llamada perdida...
mar 01 15:54:24 tu_host python3&#91;3651558]:  &#91;+] Esperando cobertura...
mar 01 15:54:25 tu_host python3&#91;3651558]:  &#91;+] Registrado en red (intento 1)
mar 01 15:54:25 tu_host python3&#91;3651558]:  &#x1f4de; Marcando a 600000000...
mar 01 15:54:27 tu_host python3&#91;3651558]:  &#91;?] Llamada en curso. Esperando que cuelgues (máx 45s)...
mar 01 15:54:28 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:54:28 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:54:29 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:54:30 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:54:30 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:54:31 tu_host python3&#91;3651558]:  → Sonando / activa
mar 01 15:55:00 tu_host python3&#91;3651558]:  &#x2705; Colgado detectado por URC 'VOICE CALL: END'
mar 01 15:55:21 tu_host python3&#91;3651558]: &#91;15:55:21] &#x2705; Fibra recuperada. Avisando por Telegram...

</code></pre>



<h2 class="wp-block-heading">Troubleshooting (solución de problemas)</h2>



<p>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 <strong>separar el consumo</strong>.</p>



<h2 class="wp-block-heading">Prueba final:</h2>



<p>Una vez que esté todo funcionando.</p>



<ol start="1" class="wp-block-list">
<li>Desconecta el cable <em>Ethernet</em> para provocar una llamada.</li>



<li>Abre abre una terminal y escribe <br><code><mark style="background-color:var(--ast-global-color-7)" class="has-inline-color">ls -R /</mark></code></li>



<li>Si ya no se bloquea, es que la fuente de la Pi 5 y el comando <code>autosuspend=-1</code> han solucionado el conflicto de energía.</li>
</ol>



<p></p>



<h2 class="wp-block-heading">Miscelánea</h2>



<p>Estos son los comandos clave para extraer estadísticas y gestionar tu Vigilante como un auténtico administrador de sistemas.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">1. El «Resumen de Batalla» (Estadísticas rápidas)</h3>



<p>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:</p>



<pre class="wp-block-code"><code>journalctl -u netguard.service | grep -E "Caída detectada|Llamada finalizada|Red recuperada"</code></pre>



<p><em>Esto te mostrará una lista limpia con los días y horas exactas de cada incidente.</em></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">2. Comprobar el estado del «Motor»</h3>



<p>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:</p>



<pre class="wp-block-code"><code>systemctl status netguard.service</code></pre>



<p><em>Fíjate en la línea que dice <code>Active: active (running) since...</code>. Te dirá cuántos días lleva encendido sin interrupciones.</em></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">3. Reiniciar tras cambios (SIM, teléfono, etc.)</h3>



<p>Si decides cambiar el número de teléfono o el token de Telegram en el archivo <code>.py</code>, no basta con guardar el archivo. Tienes que decirle a la Raspberry que cargue la nueva versión:</p>



<pre class="wp-block-code"><code>sudo systemctl restart netguard.service</code></pre>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxete.duckdns.org/tutorial-failover-en-raspberry-pi-mediante-llamada-telefonica/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Cómo crear un Watchdog para dispositivos en red.</title>
		<link>https://linuxete.duckdns.org/como-crear-un-watchdog-para-el-hub-tapo-h100-con-raspberry-pi/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=como-crear-un-watchdog-para-el-hub-tapo-h100-con-raspberry-pi</link>
					<comments>https://linuxete.duckdns.org/como-crear-un-watchdog-para-el-hub-tapo-h100-con-raspberry-pi/#respond</comments>
		
		<dc:creator><![CDATA[raspberry]]></dc:creator>
		<pubDate>Tue, 06 Jan 2026 09:57:17 +0000</pubDate>
				<category><![CDATA[Red]]></category>
		<category><![CDATA[Seguridad]]></category>
		<category><![CDATA[watchdog]]></category>
		<category><![CDATA[sensor fugas]]></category>
		<category><![CDATA[sensor inteligente]]></category>
		<category><![CDATA[tapo H100]]></category>
		<category><![CDATA[tapo P100]]></category>
		<category><![CDATA[tapo p110]]></category>
		<category><![CDATA[tapo T300]]></category>
		<guid isPermaLink="false">https://linuxete.duckdns.org/?p=3554</guid>

					<description><![CDATA[Después de haber sufrido una pequeña inundación en el sótano de casa, decidí crear un sistema de alerta y corte de suministro de agua. Para que mi instalación pueda ponerse en contacto conmigo, necesito la ayuda de sensores online que vigilen constantemente si se produce alguna avería. El ecosistema Tapo de TP-Link es excelente por [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Después de haber sufrido una pequeña inundación en el sótano de casa, decidí crear un sistema de alerta y corte de suministro de agua. </p>



<p>Para que mi instalación pueda ponerse en contacto conmigo, necesito la ayuda de sensores online que vigilen constantemente si se produce alguna avería.</p>



<p>El ecosistema Tapo de TP-Link es excelente por su relación calidad-precio, especialmente sus sensores de inundación T300. Sin embargo, tiene un «talón de Aquiles» crítico: <strong>la falta de notificaciones por desconexión</strong>. Si el Hub H100 o el enchufe P100 se apagan, tu sistema de seguridad muere en silencio.</p>



<p>Aquí te explico cómo convertir tu Raspberry Pi en un vigilante activo que te avisará en segundos si algo falla.</p>



<p><strong>El problema: El silencio de los dispositivos offline</strong></p>



<p id="block-dbcce1e7-b3fc-4fff-ad55-facaf6e3522c">Tanto si la centralita H100 (Hub) como el enchufe P100 que controla el cierre de agua, se avería, sufre un pico de tensión o alguien los desenchufa accidentalmente, el sistema se queda «ciego». El sensor de agua T300 no tiene a quién avisar y la orden de corte nunca se ejecuta.</p>



<p id="block-e2c406d9-9459-4324-b879-653848742da5">Lo más preocupante es que <strong>la App de Tapo no envía notificaciones si un dispositivo se queda fuera de línea</strong>. Para darte cuenta del fallo, tendrías que entrar manualmente en la aplicación y revisar el estado de los iconos uno por uno. En una emergencia o durante unas vacaciones, esta falta de aviso proactivo es un fallo de seguridad inaceptable.</p>



<p><strong>La solución: Un «Watchdog» con Raspberry Pi</strong></p>



<p>Para eliminar este punto ciego, utilizaremos una Raspberry Pi como <strong>Watchdog (Perro Guardián)</strong>. En lugar de esperar a que la App nos avise, la Pi interrogará constantemente a los dispositivos en la red local, si estos no responden, la Pi asume que el sistema está comprometido y dispara una alerta externa.</p>



<h2 class="wp-block-heading">1. Prepara tu Telegram.</h2>



<p>Aprovechando que tenemos telegram (si no lo tienes, ya estás tardando en instalarlo) vamos a utilizarlo para que nos lleguen los avisos de alerta de nuestro script. Para ello crearemos un bot, que será el encargado de gestionar los avisos provenientes de nuestra raspberry.</p>



<h3 class="wp-block-heading">Crear tu Bot en Telegram (El Emisor)</h3>



<p>Primero necesitamos crear la «entidad» que enviará los mensajes desde tu Raspberry Pi.</p>



<ol start="1" class="wp-block-list">
<li>Abre <strong>Telegram</strong> y busca al usuario <strong>@BotFather</strong>.</li>



<li>Escribe <code>/newbot</code> y dale a enviar.</li>



<li>Te pedirá un <strong>Nombre</strong> para el bot (ejemplo: <code>Vigilante Sótano</code>).</li>



<li>Te pedirá un <strong>Username</strong> (debe terminar en <code>_bot</code>, ejemplo: <code>mi_sotano_seguro_bot</code>).</li>



<li><strong>BotFather</strong> te responderá con un mensaje largo que contiene el <strong>API Token</strong> (algo parecido a <code>74839201:AAH-u7...</code>). <strong>Copia y guarda este código</strong>, es la clave de acceso.</li>
</ol>



<h3 class="wp-block-heading">Obtener tu Chat ID (El Receptor)</h3>



<p>Ahora necesitamos saber a qué cuenta de Telegram (la tuya) debe escribirle el bot.</p>



<ol start="1" class="wp-block-list">
<li>Busca en Telegram el bot <strong>@userinfobot</strong>.</li>



<li>Escríbele un mensaje cualquiera (ej. «Hola»).</li>



<li>Te responderá con tu <strong>ID</strong> (un número de 9 o 10 dígitos). Guárdalo también.</li>
</ol>



<h2 class="wp-block-heading">2. Crea tu script</h2>



<p>Abre tu terminal para crear el archivo con:</p>



<pre class="wp-block-code"><code><code>nano TapoGuard.py</code></code></pre>



<p>Pega este código (asegúrate de poner <strong>tu Token</strong>, <strong>tu ID</strong>, la <strong>IP del H100</strong> y la <strong>IP del P100</strong>):</p>



<pre class="wp-block-code"><code>import os
import time
import requests

# --- CONFIGURACIÓN ---
TOKEN = "<mark style="background-color:#7bdcb5" class="has-inline-color">Tu_TOKEN</mark>"
CHAT_ID = "<mark style="background-color:#7bdcb5" class="has-inline-color">TU_ID</mark>"

# Diccionario de dispositivos: "Nombre": "IP"
DISPOSITIVOS = {
    "Hub H100": "<mark style="background-color:#7bdcb5" class="has-inline-color">192.168.1.16</mark>",
    "Enchufe Válvula P110": "<mark style="background-color:#7bdcb5" class="has-inline-color">192.168.1.15</mark>"
}

REINTENTOS = 3
SEGUNDOS_ENTRE_CHEQUEOS = 60

# Diccionario para recordar el estado de cada uno (Todos empiezan como Online)
estados_caidos = {nombre: False for nombre in DISPOSITIVOS}

def enviar_telegram(mensaje):
    url = f"https://api.telegram.org/bot{TOKEN}/sendMessage"
    params = {"chat_id": CHAT_ID, "text": mensaje}
    try:
        requests.post(url, params=params, timeout=10)
    except Exception as e:
        print(f"Error de red: {e}")

def chequeo_ip(ip):
    # Lanza un ping. Devuelve True si responde.
    salida = os.system(f"ping -c 1 -W 1 {ip} &gt; /dev/null 2&gt;&amp;1")
    return salida == 0

print("--- Vigilante Tapo Iniciado ---")

while True:
    for nombre, ip in DISPOSITIVOS.items():
        exito = False

        # Intentos de ping para evitar falsas alarmas
        for i in range(REINTENTOS):
            if chequeo_ip(ip):
                exito = True
                break
            time.sleep(1)

        # Lógica de notificaciones individualizada
        if not exito and not estados_caidos&#91;nombre]:
            print(f"&#91;{time.strftime('%H:%M:%S')}] &#x274c; {nombre} CAÍDO")
            enviar_telegram(f"&#x26a0; ALERTA: El dispositivo '{nombre}' ({ip}) se ha caído de la red.")
            estados_caidos&#91;nombre] = True

        elif exito and estados_caidos&#91;nombre]:
            print(f"&#91;{time.strftime('%H:%M:%S')}] &#x2705; {nombre} RECUPERADO")
            enviar_telegram(f"&#x2705; OK: El dispositivo '{nombre}' ha vuelto a conectar.")
            estados_caidos&#91;nombre] = False

    time.sleep(SEGUNDOS_ENTRE_CHEQUEOS)</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Te aconsejo que pongas una IP fija a tus dispositivos, ya que si esta cambia, el script no funcionará.</p>
</blockquote>



<p>Guarda los cambios con <code>Ctrl + o</code> y sal con <code>Ctrl + x</code></p>



<p>Haz que tu archivo tenga permisos de ejecución.</p>



<pre class="wp-block-code"><code>chmod +x TapoGuard.py</code></pre>



<p>Y pruébalo con:</p>



<pre class="wp-block-code"><code>python3 TapoGuard.py</code></pre>



<p>Desconecta tu Hub del enchufe y observa que ocurre. ¿Te llegaron los mensajes? Ahora conéctalo y vuelve a mirar.</p>



<p>Si todo ha salido bien, tenemos al «cerebro» de la supervisión funcionando.</p>



<h2 class="wp-block-heading">3. Crea un servicio del sistema (systemd)</h2>



<p>Ahora, para que sea un sistema de seguridad permanente, necesitamos que se convierta en un <strong>servicio del sistema</strong> (un <em>daemon</em>).</p>



<p>De esta forma, si hay un apagón y la Pi se reinicia, el script se levantará solo sin que tengas que teclear nada.</p>



<p>Usa el editor de texto para crear un archivo de configuración en la carpeta del sistema: </p>



<pre class="wp-block-code"><code><code>sudo nano /etc/systemd/system/TapoGuard.service</code></code></pre>



<p>Copia y pega este contenido dentro del archivo (ajustando la ruta a tu usuario):</p>



<pre class="wp-block-code"><code>&#91;Unit]
Description=Vigilante del Hub Tapo H100
After=network.target

&#91;Service]
# Asegúrate de que la ruta /home/tu_usuario/TapoGuard.py es la correcta
ExecStart=/usr/bin/python3 /home/<mark style="background-color:#7bdcb5" class="has-inline-color">tu_usuario</mark>/TapoGuard.py
Restart=always
RestartSec=10
User=raspberry

&#91;Install]
WantedBy=multi-user.target</code></pre>



<p>No olvides cambiar tu_usuario por el tuyo propio.</p>



<p>Para guardar Ctrl + o y salir con Ctrl + x</p>



<h3 class="wp-block-heading">Activa el Servicio</h3>



<p>Ahora dale las órdenes a la Raspberry Pi para que lo ponga en marcha:</p>



<ol start="1" class="wp-block-list">
<li><strong>Recarga el sistema</strong> para que reconozca el nuevo archivo: <code>sudo systemctl daemon-reload</code></li>



<li><strong>Activa el inicio automático</strong> al arrancar: <code>sudo systemctl enable TapoGuard.service</code></li>



<li><strong>Inicia el servicio</strong> ahora mismo: <code>sudo systemctl start TapoGuard.service</code></li>
</ol>



<h3 class="wp-block-heading">¿Cómo compruebo que está «vivo»?</h3>



<p>Puedes ver el estado de tu vigilante con este comando: <code>sudo systemctl status TapoGuard.service</code></p>



<ul class="wp-block-list">
<li>Si sale en verde <strong>«active (running)»</strong>, es que está patrullando la IP de tu Hub.</li>



<li>Ya puedes cerrar la terminal, apagar tu ordenador e irte tranquilo: la Pi se encargará de avisar a tu Telegram si el <strong>Tapo H100</strong> deja de responder.</li>
</ul>



<p>Y si quieres ver los «logs» (lo que el script va imprimiendo):</p>



<pre class="wp-block-code"><code>journalctl -u TapoGuard.service -f</code></pre>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxete.duckdns.org/como-crear-un-watchdog-para-el-hub-tapo-h100-con-raspberry-pi/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
