NAS来电断电自动开关机脚本 发表于 2025-01-24 | 更新于 2025-06-10 
| 总字数: 1.3k | 阅读时长: 5分钟 | 浏览量: | 
前情回顾:博主已经买了个 UPS 来保证家里断电后,电脑还能有足够的时间来处理未完成的任务并关机,从而保证数据还有硬件的安全。来电断电报警器也是为此准备的:断电后报警器发出信息,接着我可以远程关机,但避免不了我没法及时操作的情况,于是便有了此文。
博主已有一台 x86 的电脑和一台 ARM 的机顶盒,机顶盒已装好 Armbian,不接 UPS;电脑装了 ArchLinux 且开启了 WOL,接UPS。于是就可以写个脚本,让电脑在发现了机顶盒不在线(即断电)的一定时间后自动关机;当电脑关机且来电后,机顶盒开机,然后通过 WOL 唤醒电脑。
2024.02.09  经过十多天的测试发现,开启 WOL 后似乎会造成电脑没法完全关机,受限于个人能力和精力,只好放弃 WOL,转用 USB 串口继电器。。。 继电器连接着电脑的开关机线,然后机顶盒控制 USB 串口继电器吸合/断开,以此来操控电脑的开关机,详情请看图片&脚本:
2024.03.05  额……现在发现似乎是新 bios 的问题来着,有空再回退 bios 版本试试了。不过好在现在有可以远程控制的继电器。
2024.05.12  似乎确实是 bios 的问题,回退到上一个版本的就好了。现在依旧在使用继电器方案开关机,然后让 Copilot 优化了下代码。
2024.05.24  脚本更新:机顶盒端脚本同样使用 crontab 定时执行。
2024.06.10  脚本更新:机顶盒端脚本增加网关状态判断,如果网关 ping 不通则不动作。 起因:可能是因为上上个星期修改了路由器的配置,然后昨天光猫重新拨号后,路由器无法正确配置网络地址,接着电脑自动关机,机顶盒的脚本也没法正常工作,全部机器都失联了。。。 后续打算改用现成的电能计量模块来判断市电状态。
    [{"url":"https://pic-lrc-bed.haf208.cc/img/extra/nas-auto-shutdown/01.webp","alt":"10.2RMB 的 USB 串口继电器模块","title":""},{"url":"https://pic-lrc-bed.haf208.cc/img/extra/nas-auto-shutdown/02.webp","alt":"模块控制参数","title":""},{"url":"https://pic-lrc-bed.haf208.cc/img/extra/nas-auto-shutdown/03.webp","alt":"USB 串口继电器模块","title":""}]
   
 
连接好后,Armbian里可以看到连接的 CH340:
然后接线
    [{"url":"https://pic-lrc-bed.haf208.cc/img/extra/nas-auto-shutdown/04.webp","alt":"线已接好,同时也并联了机箱开关","title":""},{"url":"https://pic-lrc-bed.haf208.cc/img/extra/nas-auto-shutdown/05.webp","alt":"线已接好,同时也并联了机箱开关","title":""}]
   
 
机顶盒端脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #!/usr/bin/bash set  -o nounsetset  -o pipefailreadonly  gateway='192.168.0.1' readonly  server='192.168.1.5' readonly  log_file='/var/log/wol_wake.log' retry_count=0 up_time  () {    cat  /proc/uptime | cut  -d. -f1 } if  (($(up_time) < 60 )); then     sleep  60 fi log_w  () {    echo  "[$(date '+%Y/%m/%d %H:%M:%S') ] $*"  >> $log_file  } ping_server  () {    ping -c 2 $server  > /dev/null } open_server  () {    echo  -ne '\xa0\x01\x01\xa2'  > /dev/ttyUSB0        sleep  0.2     echo  -ne '\xa0\x01\x00\xa1'  > /dev/ttyUSB0    } main_func  () {         ping -c 2 $gateway  &> /dev/null     if  [ $? -ne 0 ]; then          sleep  120         ping -c 5 $gateway  &> /dev/null         if  [ $? -ne 0 ]; then              log_w "网关无法连接,退出进程"              exit          fi      fi      if  ! ping_server; then          sleep  20           if  ! ping_server; then                           open_server             retry_count=1             log_w "Waking up server..."              sleep  60         fi                   while  ! ping_server; do              if  ((retry_count >= 3 )); then                  log_w "Server maybe down..."                  exit  1             fi              if  ((retry_count == 2 )); then                  log_w "Server maybe stuck, try force shutdown..."                  echo  -ne '\xa0\x01\x01\xa2'  > /dev/ttyUSB0                    sleep  5                                                       echo  -ne '\xa0\x01\x00\xa1'  > /dev/ttyUSB0                    sleep  10             fi                           open_server             ((retry_count++))             log_w "Server maybe off, retrying...($retry_count )"              sleep  60         done          log_w "Server is stared."      fi  } main_func 
 
服务器端脚本(机顶盒需开启 http 服务,然后 index.html 里的内容为 “status-ok”):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #!/usr/bin/bash set  -o nounsetset  -o pipefailreadonly  server='192.168.1.6'  readonly  log_file='/var/log/http_shutdown.log' retry_count=0 log_w  () {    echo  "[$(date '+%Y/%m/%d %H:%M:%S') ] $*"  >> $log_file  } check_box_status  () {    [[ `curl -A 'Manjaro'  -s -m 1 $server ` == "status-ok"  ]] } main_func  () {    if  ! check_box_status; then                   sleep  30         if  check_box_status; then              exit          fi          shutdown 10         log_w "Power failure detected. System will shutdown in 10 minutes if power not restored."                   while  true ; do              if  ! check_box_status; then                  ((retry_count++))                 if  ((retry_count > 25 )); then  poweroff; fi                   log_w "Power maybe off, retrying...($retry_count )"                  sleep  30             else                  shutdown -c                 log_w "Power restored. Shutdown Canceled."                  retry_count=0                 break              fi          done      fi  } main_func