{"id":4750,"date":"2025-11-15T23:29:45","date_gmt":"2025-11-15T23:29:45","guid":{"rendered":"https:\/\/www.it-react.com\/?p=4750"},"modified":"2026-01-05T10:15:40","modified_gmt":"2026-01-05T10:15:40","slug":"the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover","status":"publish","type":"post","link":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/","title":{"rendered":"The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover"},"content":{"rendered":"\n<p>In the first two parts of this series, I focused on building the foundation of a smart holiday home hub.<\/p>\n\n\n\n<p><a href=\"https:\/\/www.it-react.com\/index.php\/2025\/11\/11\/the-autonomous-holiday-home-part-1-building-a-docker-based-hub-on-raspberry-pi-5\/\">In Part 1<\/a>, I set up the hardware and base software stack: a Raspberry Pi 5 running Docker, Home Assistant, and Node-RED, designed to be compact, power-efficient, and easy to maintain remotely.<\/p>\n\n\n\n<p><a href=\"https:\/\/www.it-react.com\/index.php\/2025\/11\/11\/the-autonomous-holiday-home-part-2-connectivity-and-sensor-monitoring-with-mqtt\/\">Part 2<\/a> expanded the system with real-world data. I integrated temperature and humidity sensors using a mix of local Bluetooth (BLE) and cloud-based APIs, wired everything through Node-RED and MQTT, and brought all sensor data into Home Assistant under a single, consistent dashboard.<\/p>\n\n\n\n<p>With monitoring and visibility in place, the next step was to make the system more complete, more resilient, and accessible from anywhere.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Additional integrations \u2013 extending the system<\/h3>\n\n\n\n<p>Beyond sensors, I gradually added several practical integrations that turn monitoring into actual control and insight.<\/p>\n\n\n\n<p>For climate control, I integrated a Cooper&amp;Hunter air conditioner using the Gree Climate integration. This allows basic control and status visibility directly from Home Assistant, without relying on the vendor\u2019s mobile app.<\/p>\n\n\n\n<p>For energy awareness, I added Shelly devices to monitor electricity consumption. This gives real-time insight into power usage and lays the groundwork for future automations based on load or availability.<\/p>\n\n\n\n<p>I also integrated two important devices that still rely on the Smart Life (Tuya) ecosystem:<\/p>\n\n\n\n<p>\u2013 a radiant heating panel<br>\u2013 a depth \/ level sensor<\/p>\n\n\n\n<p>Even though these entities are cloud-based, they fit cleanly into the overall system and are treated no differently than local devices once they appear in Home Assistant.<\/p>\n\n\n\n<p>At this stage, the goal was not perfection or full local control, but practical coverage: visibility and control over all important systems in the house.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Philosophy: Building for the &#8220;Worst Case&#8221;<\/h3>\n\n\n\n<p>In rural areas, the power grid and ISP reliability are often the weakest links. A minor surge trips a breaker, or a fiber line goes dark, and suddenly your &#8220;Smart Home&#8221; is just a collection of expensive, offline bricks. To solve this, I\u2019ve implemented a layered defense strategy using a self-reclosing electrical breaker, 24-hour battery backup, and an intelligent Python-based network failover. For me, the priority is <strong>differentiation<\/strong>: I need to know if I&#8217;ve simply lost my internet connection or if the entire house has lost power.<\/p>\n\n\n\n<p>This is critical because I have a pellet boiler that requires electricity to operate. Currently, the boiler isn&#8217;t on a UPS (that&#8217;s the next project), so knowing the power status is the difference between a warm house and a potential freeze-up.<\/p>\n\n\n\n<p>The idea is simple: the house must survive on its own. If the power fluctuates, the house must restart itself. If the primary internet dies, the house must find another way to talk to me.<\/p>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69f5b86e4a90a&quot;}\" data-wp-interactive=\"core\/image\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"679\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on-async--click=\"actions.showLightbox\" data-wp-on-async--load=\"callbacks.setButtonStyles\" data-wp-on-async-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/11\/The-Autonomous-Holiday-Home-1024x679.jpg\" alt=\"\" class=\"wp-image-4776\" srcset=\"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/11\/The-Autonomous-Holiday-Home-1024x679.jpg 1024w, https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/11\/The-Autonomous-Holiday-Home-300x199.jpg 300w, https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/11\/The-Autonomous-Holiday-Home-768x509.jpg 768w, https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/11\/The-Autonomous-Holiday-Home.jpg 1234w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on-async--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Section 1: The Hardware Guard \u2013 Schneider Acti9 RED<\/h3>\n\n\n\n<p>The most common failure point is the residual current device (RCD) tripping during a storm. Normally, that\u2019s game over. To solve this, I installed the <a href=\"https:\/\/www.amazon.de\/dp\/B089XB1D76?ref=ppx_yo2ov_dt_b_fed_asin_title\"><strong>Schneider Acti9 RED (A9CR2225)<\/strong>.<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/61P7Qqi4C-L._SL1500_-1024x1024.jpg\" alt=\"\" class=\"wp-image-4753\" style=\"width:265px;height:auto\" srcset=\"https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/61P7Qqi4C-L._SL1500_-1024x1024.jpg 1024w, https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/61P7Qqi4C-L._SL1500_-300x300.jpg 300w, https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/61P7Qqi4C-L._SL1500_-150x150.jpg 150w, https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/61P7Qqi4C-L._SL1500_-768x768.jpg 768w, https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/61P7Qqi4C-L._SL1500_.jpg 1500w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>How it works:<\/strong> This isn&#8217;t just a breaker; it\u2019s an intelligent recloser. When it detects a trip, it doesn&#8217;t just wait for a human. It performs a quick insulation check of the downstream circuit. If the fault was just a transient &#8220;hiccup&#8221; from a lightning strike or a surge, it <strong>mechanically re-arms itself<\/strong>.<\/p>\n\n\n\n<p>This ensures the house power returns the second the grid is stable. To protect the electronics during these transitions, the Raspberry Pi 5, the network switch, and the 4G router are backed by a battery system with <strong>over 24 hours of autonomy<\/strong>. The &#8220;brain&#8221; of the house stays alive and continues to report data even while the boiler is temporarily offline.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Section 2: The Network Logic \u2013 Dual IPs and <code>router_monitor.py<\/code><\/h3>\n\n\n\n<p>Connectivity follows the same philosophy. I have a primary Fiber link and a secondary 4G\/5G router. My Raspberry Pi 5 uses a single ethernet port, but I&#8217;ve configured it with <strong>dual IP addresses<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>192.168.100.100<\/strong> (to talk to the Primary Fiber Router)<\/li>\n\n\n\n<li><strong>192.168.200.100<\/strong> (to talk to the Secondary 4G Router)<\/li>\n<\/ul>\n\n\n\n<p>This allows the Pi to stay in constant contact with both gateways. I wrote a custom Python watchdog to handle the &#8220;decision making.&#8221; It differentiates between a router failure and an ISP failure:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Internal Link (<code>192.168.100.1<\/code>):<\/strong> If this pings, the primary router is powered.<\/li>\n\n\n\n<li><strong>External Link (<code>8.8.8.8<\/code>):<\/strong> If this pings, the fiber line is passing data.<\/li>\n<\/ul>\n\n\n\n<p>If the external link fails but the internal is up, it\u2019s an ISP issue. If both are down, I know the primary router (and likely the rest of the house) has lost power.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/usr\/bin\/env python3\nimport subprocess\nimport time\nimport signal\nimport sys\nfrom pathlib import Path\nfrom typing import Optional\nimport logging\nfrom logging.handlers import RotatingFileHandler\nimport paho.mqtt.client as mqtt\nfrom datetime import datetime\nimport os\n\n# -----------------------------\n# CONFIGURATION\n# -----------------------------\n\nINTERNAL_IP = \"192.168.100.1\"\nEXTERNAL_IP = \"8.8.8.8\"\n\nPRIMARY_GW = \"192.168.100.1\"\nSECONDARY_GW = \"192.168.200.1\"\nPRIMARY_IFACE = \"eth0\"\n\n# Target for testing primary line while on backup\nPRIMARY_TEST_IP = \"1.1.1.1\"\n\nPING_TIMEOUT = 2\nCHECK_INTERVAL = 30          # seconds between checks\nFAIL_THRESHOLD = 6           # 3 minutes total\nPRIMARY_OK_THRESHOLD = 6     # 3 minutes total\n\nLOG_FILE = Path(\"\/home\/ioan\/scripts\/router_monitor.log\")\n\n# MQTT configuration\nMQTT_ENABLED = True\nMQTT_HOST = \"192.168.100.100\"\nMQTT_PORT = 1883\nMQTT_TOPIC_STATUS = \"network\/failover\/status\"\nMQTT_TOPIC_LAST_SWITCH = \"network\/failover\/last_switch\"\nMQTT_TOPIC_INTERNAL = \"network\/failover\/internal_ok\"\nMQTT_TOPIC_EXTERNAL = \"network\/failover\/external_ok\"\n\nMQTT_USER = os.getenv(\"MQTT_USER\")\nMQTT_PASS = os.getenv(\"MQTT_PASS\")\n\n# -----------------------------\n# LOGGING SETUP\n# -----------------------------\n\nLOG_FILE.parent.mkdir(parents=True, exist_ok=True)\nlogger = logging.getLogger(\"router_monitor\")\nlogger.setLevel(logging.INFO)\nformatter = logging.Formatter(\"%(asctime)s %(message)s\", \"%Y-%m-%d %H:%M:%S\")\n\nfile_handler = RotatingFileHandler(LOG_FILE, maxBytes=1_000_000, backupCount=5)\nfile_handler.setFormatter(formatter)\nlogger.addHandler(file_handler)\n\nconsole_handler = logging.StreamHandler(sys.stdout)\nconsole_handler.setFormatter(formatter)\nlogger.addHandler(console_handler)\n\ndef log_event(msg: str) -&gt; None:\n    logger.info(msg)\n\n# -----------------------------\n# MQTT FUNCTIONS\n# -----------------------------\n\nmqtt_client: Optional&#91;mqtt.Client] = None\n\ndef mqtt_connect() -&gt; None:\n    \"\"\"Connect to MQTT broker with auth.\"\"\"\n    global mqtt_client\n    if not MQTT_ENABLED:\n        return\n    try:\n        mqtt_client = mqtt.Client()\n        if MQTT_USER and MQTT_PASS:\n            mqtt_client.username_pw_set(MQTT_USER, MQTT_PASS)\n            log_event(\"MQTT: Authenticating with user credentials\")\n\n        mqtt_client.connect(MQTT_HOST, MQTT_PORT, 60)\n        mqtt_client.loop_start()\n        log_event(\"MQTT: Connected to broker\")\n    except Exception as e:\n        log_event(f\"MQTT: Failed to connect: {e}\")\n        mqtt_client = None\n\ndef mqtt_publish(topic: str, payload: str, retain: bool = True) -&gt; None:\n    \"\"\"Helper for MQTT publishing.\"\"\"\n    if MQTT_ENABLED and mqtt_client is not None:\n        try:\n            mqtt_client.publish(topic, payload, retain=retain)\n        except Exception as e:\n            log_event(f\"MQTT: Publish error on {topic}: {e}\")\n\ndef mqtt_publish_status(mode: str) -&gt; None:\n    \"\"\"Publish current mode and switch timestamp.\"\"\"\n    mqtt_publish(MQTT_TOPIC_STATUS, mode)\n    now = datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")\n    mqtt_publish(MQTT_TOPIC_LAST_SWITCH, now)\n    log_event(f\"MQTT: Mode '{mode}' and timestamp reported\")\n\n# -----------------------------\n# NETWORK HELPERS\n# -----------------------------\n\ndef ping(ip: str) -&gt; bool:\n    \"\"\"Check reachability via current default route.\"\"\"\n    result = subprocess.run(\n        &#91;\"ping\", \"-c\", \"1\", \"-W\", str(PING_TIMEOUT), ip],\n        stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,\n    )\n    return result.returncode == 0\n\ndef get_default_gateway() -&gt; Optional&#91;str]:\n    \"\"\"Get active default gateway.\"\"\"\n    try:\n        out = subprocess.check_output(&#91;\"ip\", \"route\", \"show\", \"default\"], text=True)\n        parts = out.split()\n        if \"via\" in parts:\n            return parts&#91;parts.index(\"via\") + 1]\n    except Exception as e:\n        log_event(f\"Routing error: {e}\")\n    return None\n\ndef set_default_route(gw: str) -&gt; None:\n    \"\"\"Change route and restart tunnel service.\"\"\"\n    try:\n        # 1. Update route\n        subprocess.run(&#91;\"ip\", \"route\", \"replace\", \"default\", \"via\", gw, \"dev\", PRIMARY_IFACE], check=True                                                       )\n        log_event(f\"Default route changed to {gw}\")\n\n        # 2. Stop tunnel\n        subprocess.run(&#91;\"systemctl\", \"stop\", \"autossh.service\"], check=False)\n\n        # 3. Clear cache\n        subprocess.run(&#91;\"ip\", \"route\", \"flush\", \"cache\"], check=False)\n        time.sleep(2)\n\n        # 4. Restart tunnel\n        subprocess.run(&#91;\"systemctl\", \"start\", \"autossh.service\"], check=False)\n        log_event(\"Autossh restarted for the new gateway\")\n\n        # 5. Notify HA\n        mode = \"primary\" if gw == PRIMARY_GW else \"secondary\"\n        mqtt_publish_status(mode)\n\n    except subprocess.CalledProcessError as e:\n        log_event(f\"Failed to switch route: {e}\")\n\ndef test_primary_internet() -&gt; bool:\n    \"\"\"Check primary line while on secondary via temporary specific route.\"\"\"\n    try:\n        subprocess.run(&#91;\"ip\", \"route\", \"add\", PRIMARY_TEST_IP, \"via\", PRIMARY_GW, \"dev\", PRIMARY_IFACE],                                                        check=False)\n        return ping(PRIMARY_TEST_IP)\n    finally:\n        subprocess.run(&#91;\"ip\", \"route\", \"del\", PRIMARY_TEST_IP, \"via\", PRIMARY_GW, \"dev\", PRIMARY_IFACE],                                                        check=False)\n\n# -----------------------------\n# MAIN LOOP\n# -----------------------------\n\nmqtt_connect()\nfail_count_primary = 0\nprimary_ok_count_on_secondary = 0\nprev_internal_ok = None\nprev_external_ok = None\nprev_mode = None\n\nlog_event(\"Starting loop...\")\n\nwhile True:\n    gw = get_default_gateway()\n    current_mode = \"primary\" if gw == PRIMARY_GW else \"secondary\" if gw == SECONDARY_GW else \"unknown\"\n\n    # Current connectivity checks\n    internal_ok = ping(INTERNAL_IP)\n    external_ok = ping(EXTERNAL_IP)\n\n    # Always publish health status to MQTT sensors\n    mqtt_publish(MQTT_TOPIC_INTERNAL, \"ON\" if internal_ok else \"OFF\")\n    mqtt_publish(MQTT_TOPIC_EXTERNAL, \"ON\" if external_ok else \"OFF\")\n\n    # Log changes\n    if (internal_ok != prev_internal_ok or external_ok != prev_external_ok or current_mode != prev_mode):\n        log_event(f\"Status: INT={internal_ok}, EXT={external_ok}, Mode={current_mode}\")\n        if current_mode != prev_mode and current_mode != \"unknown\":\n            mqtt_publish_status(current_mode)\n\n        prev_internal_ok, prev_external_ok, prev_mode = internal_ok, external_ok, current_mode\n\n    # Failover Logic\n    if current_mode == \"primary\":\n        if not (internal_ok and external_ok):\n            fail_count_primary += 1\n        else:\n            fail_count_primary = 0\n\n        if fail_count_primary &gt;= FAIL_THRESHOLD:\n            log_event(\"Primary WAN lost. Switching to SECONDARY.\")\n            set_default_route(SECONDARY_GW)\n            fail_count_primary = 0\n\n    elif current_mode == \"secondary\":\n        if test_primary_internet():\n            primary_ok_count_on_secondary += 1\n        else:\n            primary_ok_count_on_secondary = 0\n\n        if primary_ok_count_on_secondary &gt;= PRIMARY_OK_THRESHOLD:\n            log_event(\"Primary WAN is back. Switching to PRIMARY.\")\n            set_default_route(PRIMARY_GW)\n            primary_ok_count_on_secondary = 0\n\n    time.sleep(CHECK_INTERVAL)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Script Breakdown: The &#8220;Brain&#8221; of the Failover<\/h3>\n\n\n\n<p>The script is essentially a persistent watchdog that manages my system&#8217;s routing table based on real-time health checks. Here is how it\u2019s structured:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">1. Configuration &amp; Logging<\/h4>\n\n\n\n<p>The script starts by defining my &#8220;source of truth&#8221;: IP addresses for the Primary and Secondary gateways, check intervals (30 seconds), and MQTT topics. It uses RotatingFileHandler for logging, which is a professional touch\u2014it prevents the log file from eating up my disk space by overwriting old entries.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">2. MQTT Communication Layer<\/h4>\n\n\n\n<p>This section handles the &#8220;talk&#8221; with Home Assistant. It connects to my broker using credentials stored in environment variables (for security). It doesn&#8217;t just send the current status; it also sends a timestamp of the <strong>Last Network Switch<\/strong>, which is invaluable for debugging when exactly a provider went down.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">3. Network Helpers (The &#8220;Check&#8221; Phase)<\/h4>\n\n\n\n<p>Here we have the low-level functions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>ping<\/code><\/strong>: A simple reachability test.<\/li>\n\n\n\n<li><strong><code>set_default_route<\/code><\/strong>: This is the &#8220;heavy lifter.&#8221; It uses <code>ip route replace<\/code> to swap gateways and <strong>restarts the autossh service<\/strong>, ensuring your remote tunnel is re-established on the new link.<\/li>\n\n\n\n<li><strong><code>test_primary_internet<\/code><\/strong>: A clever function that adds a temporary, specific route to check if the Fiber is back online while the system is still technically using the 4G backup.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">4. The Main Loop (The &#8220;Decision&#8221; Phase)<\/h4>\n\n\n\n<p>This is an infinite <code>while True<\/code> loop that runs every 30 seconds. It follows a simple logic flow:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Monitor<\/strong>: Ping the internal router and external internet (8.8.8.8).<\/li>\n\n\n\n<li><strong>Report<\/strong>: Update MQTT sensors so Home Assistant stays in the loop.<\/li>\n\n\n\n<li><strong>Failover<\/strong>: If the Primary fails for 6 consecutive checks (3 minutes), it triggers the switch to 4G.<\/li>\n\n\n\n<li><strong>Failback<\/strong>: If it\u2019s on 4G and sees the Primary Fiber has been stable for 3 minutes, it gracefully switches back to the main line.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Making it Permanent: The Systemd Service<\/h3>\n\n\n\n<p>For a failover system to be reliable, it needs to be a first-class citizen of the operating system. We don&#8217;t want to run this script manually; we want it to breathe with the Raspberry Pi. I configured it as a <strong>systemd service<\/strong> to ensure it starts as soon as the network is online and restarts itself if anything goes wrong.<\/p>\n\n\n\n<p><strong>The Service Configuration<\/strong> Create the file at <code>\/etc\/systemd\/system\/router-monitor.service<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;Unit]\nDescription=Started connection monitoring and 5G router relay control (User=root)\nAfter=network-online.target\nWants=network-online.target\n\n&#91;Service]\nType=simple\nUser=root\nWorkingDirectory=\/home\/ioan\/scripts\nExecStart=\/usr\/bin\/python3 \/home\/ioan\/scripts\/router_monitor.py\nRestart=on-failure\nRestartSec=5\nEnvironment=PYTHONUNBUFFERED=1\nEnvironment=\"MQTT_USER=homeauto\"\nEnvironment=\"MQTT_PASS=My_Secure_Password\"\n\n&#91;Install]\nWantedBy=multi-user.target\n<\/code><\/pre>\n\n\n\n<p><strong>Why this specific setup works:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>User=root<\/strong>: Necessary because the script needs permission to modify the kernel routing table.<\/li>\n\n\n\n<li><strong>After=network-online.target<\/strong>: We wait until the OS confirms networking is up before we start trying to ping the world.<\/li>\n\n\n\n<li><strong>PYTHONUNBUFFERED=1<\/strong>: This ensures our Python <code>print<\/code> and <code>logging<\/code> statements are sent immediately to the system logs, which is vital for remote debugging.<\/li>\n\n\n\n<li><strong>Restart=on-failure<\/strong>: If the script crashes, systemd will try to bring it back every 5 seconds.<\/li>\n<\/ul>\n\n\n\n<p><strong>Activation<\/strong> To get this &#8220;guardian&#8221; running, use the standard systemd commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl daemon-reload\nsudo systemctl enable router-monitor.service\nsudo systemctl start router-monitor.service<\/code><\/pre>\n\n\n\n<p>Now, from 2,000km away, I can simply type <code>journalctl -u router-monitor.service -f<\/code> and watch my network&#8217;s heartbeat in real-time.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Section 3: The Secret Backdoor \u2013 Reverse SSH Tunneling<\/h3>\n\n\n\n<p>When the system pivots to 4G, you face the &#8220;hidden host&#8221; problem. Mobile providers almost never give you a public IP. To maintain access, I don&#8217;t try to connect <em>to<\/em> the house; I have the house connect <em>to me<\/em>.<\/p>\n\n\n\n<p>I use <strong>AutoSSH<\/strong> to maintain a persistent reverse tunnel to a public VPS. This creates a bridge that stays open regardless of which router is currently providing the internet.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">1. Why <code>autossh<\/code>?<\/h4>\n\n\n\n<p>Standard SSH is fragile. If the connection blinks during the switch from Fiber to 4G, the process just sits there, orphaned. <code>autossh<\/code> is a watchdog; it monitors the connection and, if it fails, it kills the old process and starts a new one immediately.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">2. The Service Configuration<\/h4>\n\n\n\n<p>I configured this as a dedicated systemd service. It\u2019s &#8220;failover-friendly&#8221; because it\u2019s designed to reconnect quickly the moment the new gateway becomes active.<\/p>\n\n\n\n<p><strong>The Service File (<code>\/etc\/systemd\/system\/autossh-reverse.service<\/code>):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;Unit]\nDescription=AutoSSH reverse tunnels to VPS (failover-friendly)\nAfter=network-online.target\nWants=network-online.target\n\n&#91;Service]\nUser=ioan\n\n# Force quick reconnection\nEnvironment=\"AUTOSSH_GATETIME=0\"\nEnvironment=\"AUTOSSH_POLL=20\"\nEnvironment=\"AUTOSSH_FIRST_POLL=20\"\n\nExecStart=\/usr\/bin\/autossh \\\n  -M 20000:20001 \\\n  -N \\\n  -o ServerAliveInterval=15 \\\n  -o ServerAliveCountMax=2 \\\n  -o ExitOnForwardFailure=yes \\\n  -o IdentitiesOnly=yes \\\n  -o StrictHostKeyChecking=no \\\n  -i \/home\/ioan\/.ssh\/id_ed25519 \\\n  -R 3334:localhost:8123 \\\n  -R 3333:localhost:22 \\\n  root@vps.my-domain.de\n\nRestart=always\nRestartSec=10\n\n&#91;Install]\nWantedBy=multi-user.target\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">3. Why this works for us<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Dual Port Forwarding:<\/strong> * <strong>Port 3333<\/strong> maps to the Pi&#8217;s SSH (Port 22). I can log in from anywhere by connecting to the VPS on port 3333.\n<ul class=\"wp-block-list\">\n<li><strong>Port 3334<\/strong> maps to the Home Assistant Web UI (Port 8123). Even if the standard cloud access fails, I have a direct path to the dashboard.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Aggressive Monitoring:<\/strong> <code>AUTOSSH_POLL=20<\/code> and <code>ServerAliveInterval=15<\/code> ensure that the tunnel doesn&#8217;t stay dead for more than a few seconds.<\/li>\n\n\n\n<li><strong>The &#8220;Relay&#8221; Logic:<\/strong> In my <code>router_monitor.py<\/code> script, I trigger a <code>systemctl restart autossh-reverse.service<\/code>. This forces the tunnel to drop the &#8220;zombie&#8221; session from the old ISP and immediately re-establish itself over the new 4G route.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">4. Security: Passwordless Authentication<\/h4>\n\n\n\n<p>For <code>autossh<\/code> to work as a background service, it cannot prompt for a password. I used <strong>SSH Key-based Authentication<\/strong> to establish a trusted relationship between the Raspberry Pi and the VPS.<\/p>\n\n\n\n<p><strong>The Setup:<\/strong><\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Generate the key on the Pi:<\/strong> <code>ssh-keygen -t ed25519<\/code> (using Ed25519 for better security and performance).<\/li>\n\n\n\n<li><strong>Transfer the public key to the VPS:<\/strong> <code>ssh-copy-id -i ~\/.ssh\/id_ed25519.pub root@vps.my-domain.de<\/code>.<\/li>\n<\/ol>\n\n\n\n<p>Now, the Pi can &#8220;talk&#8221; to the VPS securely and automatically, which is exactly what we need for a service that must survive a reboot or a network failover without human intervention.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">5. Critical VPS Side Configuration<\/h4>\n\n\n\n<p>Creating the tunnel from the Pi is only half the battle. By default, SSH tunnels only listen on the VPS&#8217;s loopback interface (<code>127.0.0.1<\/code>). If you want to access your Home Assistant from the public internet using <code>vps.my-domain.de:3334<\/code>, you need to tweak the VPS.<\/p>\n\n\n\n<p><strong>A. The SSH Daemon Config<\/strong> Edit <code>\/etc\/ssh\/sshd_config<\/code> on your VPS and ensure this line is set:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>GatewayPorts yes<\/code><\/pre>\n\n\n\n<p><strong>Why?<\/strong> Without <code>GatewayPorts yes<\/code>, the VPS will only allow connections to ports 3333 and 3334 from <em>inside<\/em> the VPS itself. This setting tells SSH to bind these ports to all interfaces, making them accessible from the outside world.<\/p>\n\n\n\n<p>Don&#8217;t forget to restart the service: <code>sudo systemctl restart ssh<\/code> (sau <code>sshd<\/code>).<\/p>\n\n\n\n<p><strong>B. The Firewall (ufw\/iptables)<\/strong> Your VPS firewall will block these ports by default. You must explicitly open them:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ufw allow 3333\/tcp\nsudo ufw allow 3334\/tcp<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Section 4: Home Assistant \u2013 The Command Center<\/h3>\n\n\n\n<p>Now that we have power (Schneider RED), routing (Python), and access (AutoSSH) secured, we finally have a dashboard we can trust. I\u2019ve mapped these network states into Home Assistant so I can monitor the infrastructure health from my <strong>Pixel 9 Pro XL<\/strong>.<\/p>\n\n\n\n<p>This setup gives me three critical data points: Is the LAN up? Is the WAN up? And which route are we currently using? I need to see exactly what is happening so I can make decisions\u2014whether that&#8217;s calling for local help or simply knowing I can relax.<\/p>\n\n\n\n<p>I&#8217;ve added the following sensors to my already existing sensor list in configuration.yaml <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>--------------------\n    # Track which gateway is active (Primary vs Secondary)\n    - name: \"Raspberry Pi Internet Route\"\n      state_topic: \"network\/failover\/status\"\n      unique_id: \"rpi5_network_route\"\n      icon: \"mdi:router-network\"\n      value_template: \"{{ value | capitalize }}\"\n\n    # Timestamp of the last routing change\n    - name: \"Last Network Switch\"\n      state_topic: \"network\/failover\/last_switch\"\n      unique_id: \"rpi5_last_switch\"\n      icon: \"mdi:clock-outline\"\n\n  binary_sensor:\n    # Visual status of the failover system\n    - name: \"Internet Backup Active\"\n      state_topic: \"network\/failover\/status\"\n      payload_on: \"secondary\"\n      payload_off: \"primary\"\n      device_class: connectivity\n      unique_id: \"rpi5_failover_binary\"\n\n    # Status of the Primary Router (LAN reachability)\n    - name: \"Primary Router Status\"\n      state_topic: \"network\/failover\/internal_ok\"\n      payload_on: \"ON\"\n      payload_off: \"OFF\"\n      device_class: connectivity\n      unique_id: \"rpi5_primary_router_lan\"\n\n    # Status of the Internet (WAN reachability via Primary Line)\n    - name: \"Primary Internet Status\"\n      state_topic: \"network\/failover\/external_ok\"\n      payload_on: \"ON\"\n      payload_off: \"OFF\"\n      device_class: connectivity\n      unique_id: \"rpi5_primary_internet_wan\"<\/code><\/pre>\n\n\n\n<p><strong>Why this matters for a remote home:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Diagnostic Precision:<\/strong> If &#8220;Primary Router Status&#8221; is OFF, I know the fiber router is unpowered. If only &#8220;Primary Internet Status&#8221; is OFF, I know the ISP is having an outage, but my hardware is fine.<\/li>\n\n\n\n<li><strong>The Switch History:<\/strong> Knowing the exact time of the <strong>Last Network Switch<\/strong> allows me to correlate outages with weather events or power fluctuations reported by the village.<\/li>\n\n\n\n<li><strong>Visual Confidence:<\/strong> On my <strong>Pixel 9 Pro XL<\/strong>, the <code>device_class: connectivity<\/code> ensures that I see clear, color-coded indicators. Green means &#8220;Primary\/Stable&#8221;; Amber means &#8220;Backup Active.&#8221;<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Section 5: Putting Data to Work \u2013 Home Assistant Automations<\/h3>\n\n\n\n<p>Monitoring is only half the battle. The true power of this setup lies in its ability to turn data into proactive alerts. I\u2019ve configured several key automations in Home Assistant to ensure I\u2019m never guessing about the state of the remote house.<\/p>\n\n\n\n<p>automations.yaml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>- id: '1762986200717'\n  alias: Alarm Boiler Room\n  description: The temperature in the boiler room has dropped below 10\u00b0C.\n  triggers:\n  - trigger: numeric_state\n    entity_id:\n    - sensor.cobor_centrala_temperature\n    for:\n      hours: 0\n      minutes: 2\n      seconds: 0\n    below: 10\n  conditions: &#91;]\n  actions:\n  - action: notify.mobile_app_pixel_9_pro_xl\n    metadata: {}\n    data:\n      message: The temperature in the boiler room has dropped below 10\u00b0C.\n      title: \u2744\ufe0f Temperature Boiler Room\n  - action: persistent_notification.create\n    metadata: {}\n    data:\n      message: The temperature in the boiler room has dropped below 10\u00b0C.\n      title: \u2744\ufe0f Temperature Boiler Room\n  mode: single\n- id: network_failover_notification\n  alias: Network Failover Alert\n  description: Alerts when the system switches to backup internet\n  triggers:\n  - entity_id: binary_sensor.internet_backup_active\n    from: 'off'\n    to: 'on'\n    trigger: state\n  conditions: &#91;]\n  actions:\n  - data:\n      title: \u26a0\ufe0f Network Failover\n      message: 'Primary WAN is down. Switched to backup router (4G\/5G). Router LAN:\n        {{ ''OK'' if is_state(''binary_sensor.primary_router_status'', ''on'') else\n        ''FAIL'' }} Internet WAN: {{ ''OK'' if is_state(''binary_sensor.primary_internet_status'',\n        ''on'') else ''FAIL'' }}\n\n        '\n    action: notify.persistent_notification\n  - action: notify.mobile_app_pixel_9_pro_xl\n    metadata: {}\n    data:\n      message: Primary WAN is down. Switched to backup router (4G\/5G).\n      title: \u26a0\ufe0f Network Failover\n  mode: single\n- id: network_failback_notification\n  alias: Network Failback Alert\n  description: Alerts when the system switches back to primary internet\n  triggers:\n  - entity_id: binary_sensor.internet_backup_active\n    from: 'on'\n    to: 'off'\n    trigger: state\n  actions:\n  - data:\n      title: \u2705 Network Restored\n      message: Primary internet connection is stable. Switched back to main router.\n    action: notify.persistent_notification\n  - action: notify.mobile_app_pixel_9_pro_xl\n    metadata: {}\n    data:\n      title: \u2705 Network Restored\n      message: Primary internet connection is stable. Switched back to main router.\n  mode: single<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">1. The Frost Sentinel (Boiler Room Alarm)<\/h4>\n\n\n\n<p>If the temperature in the boiler room drops below <strong>10\u00b0C<\/strong> for more than 2 minutes, the system triggers a critical alert. This is my early warning that the pellet boiler has stopped, allowing me to investigate before the pipes are at risk of freezing.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">2. Network Transition Intelligence<\/h4>\n\n\n\n<p>When the <code>router_monitor.py<\/code> script triggers a failover, Home Assistant doesn&#8217;t just tell me the internet is on backup; it provides a diagnostic report. Using Jinja2 templates, the notification tells me if the local Fiber router is completely unpowered (LAN FAIL) or if it&#8217;s just an ISP outage (WAN FAIL).<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">3. Redundancy in Notifications<\/h4>\n\n\n\n<p>For every critical event, I use a dual-action approach:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Mobile Push Notifications:<\/strong> Instant alerts on my <strong>Pixel 9 Pro XL<\/strong> for immediate action.<\/li>\n\n\n\n<li><strong>Persistent Notifications:<\/strong> These stay visible in the Home Assistant sidebar until I manually dismiss them, serving as a log of events for when I next log in to the dashboard.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Conclusion: Autonomy for Awareness<\/h3>\n\n\n\n<p>This setup isn&#8217;t about over-engineering for the sake of it; it&#8217;s about building a system that can manage itself while keeping me informed. By combining the <strong>Schneider RED<\/strong> for power recovery, a <strong>24h battery buffer<\/strong>, and the <strong>Systemd-managed services<\/strong>, I\u2019ve created a resilient hub. I no longer have to wonder about the state of the house\u2014the logs and sensors give me the clarity I need to manage it effectively from any distance.<\/p>\n\n\n\n<p><strong>What&#8217;s next?<\/strong> Now that the network and power brain are solid, I\u2019m looking at the pellet boiler. Beyond just adding a UPS for longer blackouts, I\u2019m starting to investigate the possibility of tapping into the boiler\u2019s serial port. The goal would be to extract real-time operational data directly from the source. I can\u2019t promise a tutorial on that just yet\u2014it involves some deep digging into protocols\u2014but if I manage to &#8220;crack the code,&#8221; it will definitely be the next chapter in this series.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the first two parts of this series, I focused on building the foundation of a smart holiday home hub. In Part 1, I set up the hardware and base software stack: a Raspberry Pi 5 running Docker, Home Assistant, and Node-RED, designed to be compact, power-efficient, and easy to maintain remotely. Part 2 expanded [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":4760,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_FSMCFIC_featured_image_caption":"","_FSMCFIC_featured_image_nocaption":"","_FSMCFIC_featured_image_hide":"","footnotes":""},"categories":[16,7,62],"tags":[18,54,4],"class_list":["post-4750","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-iot","category-linux","category-network","tag-raspberry","tag-smarthome","tag-ssh"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover - IT-REACT<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover - IT-REACT\" \/>\n<meta property=\"og:description\" content=\"In the first two parts of this series, I focused on building the foundation of a smart holiday home hub. In Part 1, I set up the hardware and base software stack: a Raspberry Pi 5 running Docker, Home Assistant, and Node-RED, designed to be compact, power-efficient, and easy to maintain remotely. Part 2 expanded [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/\" \/>\n<meta property=\"og:site_name\" content=\"IT-REACT\" \/>\n<meta property=\"article:published_time\" content=\"2025-11-15T23:29:45+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-01-05T10:15:40+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/livia-mjE1VxiGc-Y-unsplash-e1767569512484.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1080\" \/>\n\t<meta property=\"og:image:height\" content=\"540\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Ioan Penu\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ioan Penu\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/\"},\"author\":{\"name\":\"Ioan Penu\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#\\\/schema\\\/person\\\/bf08cffeb4b02ee6baff5d56ab17c8f0\"},\"headline\":\"The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover\",\"datePublished\":\"2025-11-15T23:29:45+00:00\",\"dateModified\":\"2026-01-05T10:15:40+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/\"},\"wordCount\":2236,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#\\\/schema\\\/person\\\/bf08cffeb4b02ee6baff5d56ab17c8f0\"},\"image\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.it-react.com\\\/wp-content\\\/uploads\\\/2026\\\/01\\\/livia-mjE1VxiGc-Y-unsplash-e1767569512484.jpg\",\"keywords\":[\"raspberry\",\"smarthome\",\"ssh\"],\"articleSection\":[\"IoT\",\"Linux\",\"Network\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/\",\"url\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/\",\"name\":\"The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover - IT-REACT\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.it-react.com\\\/wp-content\\\/uploads\\\/2026\\\/01\\\/livia-mjE1VxiGc-Y-unsplash-e1767569512484.jpg\",\"datePublished\":\"2025-11-15T23:29:45+00:00\",\"dateModified\":\"2026-01-05T10:15:40+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.it-react.com\\\/wp-content\\\/uploads\\\/2026\\\/01\\\/livia-mjE1VxiGc-Y-unsplash-e1767569512484.jpg\",\"contentUrl\":\"https:\\\/\\\/www.it-react.com\\\/wp-content\\\/uploads\\\/2026\\\/01\\\/livia-mjE1VxiGc-Y-unsplash-e1767569512484.jpg\",\"width\":1080,\"height\":540,\"caption\":\"Foto von Livia auf Unsplash\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/11\\\/15\\\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.it-react.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#website\",\"url\":\"https:\\\/\\\/www.it-react.com\\\/\",\"name\":\"it-react\",\"description\":\"Ctrl\u2022Alt\u2022Automate\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#\\\/schema\\\/person\\\/bf08cffeb4b02ee6baff5d56ab17c8f0\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.it-react.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#\\\/schema\\\/person\\\/bf08cffeb4b02ee6baff5d56ab17c8f0\",\"name\":\"Ioan Penu\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g\",\"caption\":\"Ioan Penu\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover - IT-REACT","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/","og_locale":"en_US","og_type":"article","og_title":"The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover - IT-REACT","og_description":"In the first two parts of this series, I focused on building the foundation of a smart holiday home hub. In Part 1, I set up the hardware and base software stack: a Raspberry Pi 5 running Docker, Home Assistant, and Node-RED, designed to be compact, power-efficient, and easy to maintain remotely. Part 2 expanded [&hellip;]","og_url":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/","og_site_name":"IT-REACT","article_published_time":"2025-11-15T23:29:45+00:00","article_modified_time":"2026-01-05T10:15:40+00:00","og_image":[{"width":1080,"height":540,"url":"https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/livia-mjE1VxiGc-Y-unsplash-e1767569512484.jpg","type":"image\/jpeg"}],"author":"Ioan Penu","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Ioan Penu","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/#article","isPartOf":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/"},"author":{"name":"Ioan Penu","@id":"https:\/\/www.it-react.com\/#\/schema\/person\/bf08cffeb4b02ee6baff5d56ab17c8f0"},"headline":"The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover","datePublished":"2025-11-15T23:29:45+00:00","dateModified":"2026-01-05T10:15:40+00:00","mainEntityOfPage":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/"},"wordCount":2236,"commentCount":2,"publisher":{"@id":"https:\/\/www.it-react.com\/#\/schema\/person\/bf08cffeb4b02ee6baff5d56ab17c8f0"},"image":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/#primaryimage"},"thumbnailUrl":"https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/livia-mjE1VxiGc-Y-unsplash-e1767569512484.jpg","keywords":["raspberry","smarthome","ssh"],"articleSection":["IoT","Linux","Network"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/","url":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/","name":"The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover - IT-REACT","isPartOf":{"@id":"https:\/\/www.it-react.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/#primaryimage"},"image":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/#primaryimage"},"thumbnailUrl":"https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/livia-mjE1VxiGc-Y-unsplash-e1767569512484.jpg","datePublished":"2025-11-15T23:29:45+00:00","dateModified":"2026-01-05T10:15:40+00:00","breadcrumb":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/#primaryimage","url":"https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/livia-mjE1VxiGc-Y-unsplash-e1767569512484.jpg","contentUrl":"https:\/\/www.it-react.com\/wp-content\/uploads\/2026\/01\/livia-mjE1VxiGc-Y-unsplash-e1767569512484.jpg","width":1080,"height":540,"caption":"Foto von Livia auf Unsplash"},{"@type":"BreadcrumbList","@id":"https:\/\/www.it-react.com\/index.php\/2025\/11\/15\/the-autonomous-holiday-home-part-3-self-healing-power-and-dual-wan-failover\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.it-react.com\/"},{"@type":"ListItem","position":2,"name":"The Autonomous Holiday Home (Part 3): Self-Healing Power and Dual-WAN Failover"}]},{"@type":"WebSite","@id":"https:\/\/www.it-react.com\/#website","url":"https:\/\/www.it-react.com\/","name":"it-react","description":"Ctrl\u2022Alt\u2022Automate","publisher":{"@id":"https:\/\/www.it-react.com\/#\/schema\/person\/bf08cffeb4b02ee6baff5d56ab17c8f0"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.it-react.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.it-react.com\/#\/schema\/person\/bf08cffeb4b02ee6baff5d56ab17c8f0","name":"Ioan Penu","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g","caption":"Ioan Penu"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g"}}]}},"_links":{"self":[{"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/posts\/4750","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/comments?post=4750"}],"version-history":[{"count":16,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/posts\/4750\/revisions"}],"predecessor-version":[{"id":4780,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/posts\/4750\/revisions\/4780"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/media\/4760"}],"wp:attachment":[{"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/media?parent=4750"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/categories?post=4750"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/tags?post=4750"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}