找回密碼
 立即註冊
惟家LINE群QRCODE
    查看: 4|回覆: 0

    網路斷線自動偵測與重啟:完整腳本與注意事項

    [複製鏈接]

    !lvup!   100%

    363

    主題

    27

    回帖

    2200萬

    積分

    管理員

    積分
    22005752
    發表於 3 天前 | 顯示全部樓層 |閱讀模式
    網路偶爾會掛,而且常常是在你不在家的時候。

    這篇講怎麼讓它自己修好。



    先分清楚「斷在哪一層」

    「網路不通」可能是很多層出問題:


    • 第 1 層:裝置到路由器(Wi-Fi 或網路線)
    • 第 2 層:路由器本身(當機、記憶體滿)
    • 第 3 層:路由器到數據機
    • 第 4 層:數據機到 ISP(PPPoE 掉線)
    • 第 5 層:ISP 本身有問題
    • 第 6 層:DNS 解析失敗(網路通但用不了)


    不同層要用不同的方法修。
    一律「重開路由器」是很粗糙的做法,而且有時候沒用。

    偵測方法:不要只 ping 一個地方
    1. # 壞:只測一個
    2. ping -c 3 8.8.8.8
    3. # 好:分層測試
    4. ping -c 2 192.168.1.1        # 路由器通嗎(第 1、2 層)
    5. ping -c 2 1.1.1.1            # 外網 IP 通嗎(第 3、4、5 層)
    6. nslookup google.com          # DNS 通嗎(第 6 層)
    複製代碼

    為什麼要分開


    • 路由器通、外網不通 → 重開數據機或重撥 PPPoE
    • 外網 IP 通、DNS 不通 → 重啟 DNS 服務,不要重開路由器
    • 路由器都不通 → 重開路由器


    還有一點:不要只測一個目標

    1.1.1.1 自己也可能出問題。測三個不同的:
    1. for ip in 1.1.1.1 8.8.8.8 9.9.9.9; do
    2.     ping -c 1 -W 2 $ip > /dev/null 2>&1 && echo OK && break
    3. done
    複製代碼

    有一個通就算通。



    腳本一:在 OpenWrt 上自動重撥
    1. #!/bin/sh
    2. # /root/netcheck.sh
    3. # 分層檢查,只做最小必要的修復動作
    4. LOG=/tmp/netcheck.log
    5. STATE=/tmp/netcheck.state
    6. log() { echo "[$(date '+%F %T')] $*" >> "$LOG"; }
    7. # 保留最後 500 行,避免 /tmp 被塞爆
    8. tail -n 500 "$LOG" > "$LOG.tmp" 2>/dev/null && mv "$LOG.tmp" "$LOG"
    9. check_outside() {
    10.     for ip in 1.1.1.1 8.8.8.8 9.9.9.9; do
    11.         ping -c 1 -W 3 "$ip" > /dev/null 2>&1 && return 0
    12.     done
    13.     return 1
    14. }
    15. check_dns() {
    16.     nslookup google.com > /dev/null 2>&1
    17. }
    18. if check_outside; then
    19.     # 外網通,順便看 DNS
    20.     if ! check_dns; then
    21.         log "外網通但 DNS 失敗,重啟 dnsmasq"
    22.         /etc/init.d/dnsmasq restart
    23.     fi
    24.     echo 0 > "$STATE"
    25.     exit 0
    26. fi
    27. # 外網不通,累計失敗次數
    28. FAIL=$(cat "$STATE" 2>/dev/null || echo 0)
    29. FAIL=$((FAIL + 1))
    30. echo "$FAIL" > "$STATE"
    31. log "外網不通(第 $FAIL 次)"
    32. # 連續失敗 3 次才動作(避免短暫抖動就重撥)
    33. if [ "$FAIL" -lt 3 ]; then
    34.     exit 0
    35. fi
    36. if [ "$FAIL" -eq 3 ]; then
    37.     log "重撥 WAN"
    38.     ifup wan
    39.     exit 0
    40. fi
    41. if [ "$FAIL" -eq 6 ]; then
    42.     log "重撥沒用,重啟網路服務"
    43.     /etc/init.d/network restart
    44.     exit 0
    45. fi
    46. if [ "$FAIL" -ge 10 ]; then
    47.     log "還是不通,重新開機"
    48.     echo 0 > "$STATE"
    49.     reboot
    50. fi
    複製代碼
    1. chmod +x /root/netcheck.sh
    複製代碼

    加進 cron(每 2 分鐘)
    1. */2 * * * * /root/netcheck.sh
    複製代碼

    漸進式處理是重點


    • 先累計三次失敗才動作(避免短暫抖動)
    • 先試最輕的(重撥)
    • 不行才升級(重啟網路服務)
    • 最後才重開機


    直接「一偵測到就 reboot」是很糟的做法 ——
    網路抖一下就重開機,一天可能重開二十次。

    腳本二:用智能插座重開數據機

    有時候問題在數據機(光纖終端),而它沒有遠端管理。

    做法:把數據機接在智能插座上,讓 HA 斷電重開。
    1. alias: 網路斷線自動重開數據機
    2. id: auto_reboot_modem
    3. triggers:
    4.   - trigger: state
    5.     entity_id: binary_sensor.外網連線
    6.     to: "off"
    7.     for: "00:10:00"
    8. conditions:
    9.   # 一天最多做兩次,避免無限循環
    10.   - condition: template
    11.     value_template: >
    12.       {{ state_attr('automation.auto_reboot_modem','last_triggered') is none
    13.          or (now() - state_attr('automation.auto_reboot_modem','last_triggered')).total_seconds() > 21600 }}
    14. actions:
    15.   - action: notify.mobile_app_charles
    16.     data:
    17.       message: 網路斷線十分鐘,正在重開數據機
    18.   - action: switch.turn_off
    19.     target:
    20.       entity_id: switch.modem_power
    21.   - delay: "00:00:30"
    22.   - action: switch.turn_on
    23.     target:
    24.       entity_id: switch.modem_power
    25.   # 等它起來
    26.   - wait_template: "{{ is_state('binary_sensor.外網連線','on') }}"
    27.     timeout: "00:05:00"
    28.   - if: "{{ wait.completed }}"
    29.     then:
    30.       - action: notify.mobile_app_charles
    31.         data: {message: 網路已恢復}
    32.     else:
    33.       - action: notify.mobile_app_charles
    34.         data:
    35.           title: 網路還是不通
    36.           message: 重開數據機沒用,可能是 ISP 的問題
    37. mode: single
    複製代碼

    三個重要的注意事項

    1. 那個智能插座不能靠家裡的網路

    如果插座是 Wi-Fi 的,網路掛了 HA 就控制不到它 —— 完全沒用。

    一定要用 Zigbee 插座(Zigbee 網路不依賴 Wi-Fi 或對外連線)。

    這是最多人忽略的一點。

    2. HA 主機本身要在那個網路裡

    HA 也是靠網路運作的。但只要 HA 和 Zigbee 協調器都在本地,
    就算對外斷線,本地控制還是正常的

    3. 一天最多做兩次

    上面的條件用 last_triggered 做了六小時的冷卻。

    沒有這個的話,ISP 真的掛掉時,你的數據機會每十分鐘被重開一次
    反而更難恢復。



    HA 裡的偵測感測器

    方法一:用 Ping 整合(最簡單)

    設定 → 裝置與服務 → 新增整合 → Ping

    填 1.1.1.1,它會產生一個 binary_sensor。

    但 Ping 整合預設有重試和平滑處理,反應比較慢。

    方法二:自己寫 command_line(比較可控)
    1. command_line:
    2.   - binary_sensor:
    3.       name: 外網連線
    4.       unique_id: wan_alive
    5.       command: >
    6.         (ping -c 1 -W 2 1.1.1.1 ||
    7.          ping -c 1 -W 2 8.8.8.8 ||
    8.          ping -c 1 -W 2 9.9.9.9) > /dev/null 2>&1
    9.         && echo ON || echo OFF
    10.       payload_on: "ON"
    11.       payload_off: "OFF"
    12.       scan_interval: 60
    13.       device_class: connectivity
    14.   - binary_sensor:
    15.       name: DNS 正常
    16.       unique_id: dns_alive
    17.       command: >
    18.         nslookup home-assistant.io > /dev/null 2>&1
    19.         && echo ON || echo OFF
    20.       payload_on: "ON"
    21.       payload_off: "OFF"
    22.       scan_interval: 120
    23.       device_class: connectivity
    複製代碼

    方法三:從路由器回報(最準)

    在路由器的腳本裡,狀態改變時打 HA 的 webhook:
    1. # 在 netcheck.sh 裡加
    2. notify_ha() {
    3.     curl -s -X POST \
    4.       -H "Content-Type: application/json" \
    5.       -d "{"status":"$1"}" \
    6.       "http://192.168.1.50:8123/api/webhook/net-status-xxxxxxxx" \
    7.       > /dev/null 2>&1
    8. }
    複製代碼

    這個最準,因為路由器才真正知道 WAN 的狀態。

    記錄斷線歷史

    做一個統計,知道一個月斷幾次:
    1. sensor:
    2.   - platform: history_stats
    3.     name: 本月斷線時間
    4.     entity_id: binary_sensor.外網連線
    5.     state: "off"
    6.     type: time
    7.     start: "{{ now().replace(day=1, hour=0, minute=0, second=0) }}"
    8.     end: "{{ now() }}"
    9.   - platform: history_stats
    10.     name: 本月斷線次數
    11.     entity_id: binary_sensor.外網連線
    12.     state: "off"
    13.     type: count
    14.     start: "{{ now().replace(day=1, hour=0, minute=0, second=0) }}"
    15.     end: "{{ now() }}"
    複製代碼

    這個數據很有用 ——
    跟 ISP 客訴的時候,「這個月斷了 23 次,總共 4 小時」
    比「我覺得很不穩」有說服力太多了。

    ---

    我自己設了半年,統計是:


    • 自動重撥解決了約 70% 的斷線
    • 重開數據機解決了約 20%
    • 剩下 10% 是 ISP 真的有問題,只能等


    最有價值的其實不是「自動修好」,是「有紀錄」。
    知道什麼時候斷、斷多久、什麼方法有效,比盲目重開有用多了。
    您需要登入後纔可以回帖 登入 | 立即註冊

    本版積分規則

    Archiver|手機版|惟家的智能論壇

    GMT+8, 2026-9-24 11:31 , Processed in 0.079355 second(s), 24 queries .

    快速回覆 返回頂部 返回列表