你是否也有一些電器需要定時重啟,或者想在深夜自動斷電的家電?如果你手邊剛好有 UniFi 的電源管理設備(像我是使用 USP-Strip ),以及一台 Synology NAS (DSM),那麼你其實不需要手動打開 UniFi App,透過一個簡單的 Shell Script 配合 DSM 的「任務排程器」,就能實現完全自動化的定時開關機。
今天就來分享如何透過 API 指令,讓這兩個系統完美聯動。
為什麼要這樣做?
像我為何會需要這個功能,在夜間我會排程將備份的 Synology DS1819+ 以及 DX517 設定時間自動排程啟動起來,接著主力的 Synology DS1823xs+ 便開始透過 HyperBackup 自動化將資料從 DS1823xs+ 備份到 DS1819+。所以在深夜期間其實整個機櫃同時有大量的硬碟在進行發熱,尤其在夏天的時候硬碟的溫度很容易會因為散熱不佳而超過60度NAS發出警示通知。長期處於高溫對硬碟的壽命來說總是不是件好事,所以我準備了一些 USB 風扇來對著 NAS 進行散熱,如此的確就可以把硬碟溫度控制在50度左右,不過由於大部分時間 DS1819+/DX517 都是關機狀態,只有深夜才會啟動,USB風扇吹了一整天,但其實應該只要深夜啟動風扇進行散熱就行。
UniFI Network Application 原本就可以從網頁或手機APP中控制 USP-Strip 插座的電源開關狀態,但目前仍然無法針對 USP-Strip的插座進行自動化排程開關電源。網路上找了一些方法,最後一直微調測試出來一個可用的 shell script 腳本。大概說明一下,這個腳本的關鍵在於需要有一個可以管理 UniFi Network 的帳號(最好是本地帳號),測試登入 UniFi Network 取得 Cookie 及 x-csrf-token,接著直接呼叫 UniFi API 控制 USP-Strip 將特定插座電源打開或關閉,最後把 cookie及 x-csrf-token 檔案刪除。
準備工作
UniFi Controller 設定:
建議在 UniFi Console 建立一個專用的 本地管理帳號(Local User),並賦予 Network 管理權限。
記錄下你的 Controller IP(例如 192.168.xx.1)。
獲取 Device ID:
在執行腳本前,我們必須告訴程式要控制哪一台設備。UniFi 的 Device ID 是一串 24 字元的十六進位字串(例如 66586abeb5c...),在目前文章撰寫的時間 UniFi Network Application版本(10.1.85),並沒有很好找到 Device ID的方法,我是透過 Chrome 的開發者工具來實際開關USP-Strip的插座,然後呼叫電源開關的那個 API,這樣才找到 USP-Strip 的 Device ID。(注意:隨著 Network Application 版本的異動,以下方法可能就會失效)
- 在 UniFi 設備頁面,按下鍵盤的
F12開啟「開發者工具」。 - 切換到 Network (網路) 分頁。
- 實際點擊 USP-Strip 特定插座,將電源開啟或關閉,然後按下最下方的 Apply Change,找到最後發送的那個API
- 點開 Preview (預覽) 或 Response (回應)。
- 展開 JSON 資料夾,尋找
model為 USP-Strip的項目,其中的_id欄位就是我們要的Device ID。
確認插座編號 (Index)
UniFi 的電源排插每個插座都有編號,這在腳本中對應到 Index 參數:
- USP-Strip: 編號通常為
1到 6,USB插座則為編號 7。 - 特別注意 USB 4 個插座,並沒有辦法獨立開關,而是一起開啟,或一起關閉。
- 小撇步:建議在 UniFi App 裡先幫每個插座命名,這樣你在寫腳本時,只要對應 App 上的順序就不會錯。
核心腳本:usp_control.sh
這支腳本利用 curl 模擬登入 UniFi Controller,並透過 Python3 處理 JSON 資料(使用 Python 處理較為簡單)。
請將以下程式碼儲存至 DSM 的某個資料夾(例如 /volume1/scripts/usp_control.sh),並修改開頭的設定區域:
#!/bin/bash
# --- 設定區域 ---
CONTROLLER_IP="192.168.xx.1"
USERNAME="api_user"
PASSWORD='你的密碼'
DEVICE_ID="你的設備ID"
# ---------------
# 檢查輸入參數 (需要兩個參數:Index 和 Status)
if [ "$#" -ne 2 ]; then
echo "使用方式: $0 [插槽編號1-7] [on|off]"
echo "範例: $0 5 off (關閉 5 號插槽設備)"
exit 1
fi
TARGET_INDEX=$1
STATUS_ARG=$2
if [ "$STATUS_ARG" == "on" ]; then
NEW_STATE="True"
elif [ "$STATUS_ARG" == "off" ]; then
NEW_STATE="False"
else
echo "狀態錯誤: 請輸入 on 或 off"
exit 1
fi
COOKIE_FILE="/tmp/unifi_cookie"
HEADER_FILE="/tmp/unifi_headers"
DATA_FILE="/tmp/unifi_current_data"
# 1. 登入獲取 Cookie 與 CSRF Token
curl -k -i -c $COOKIE_FILE -X POST \
-H "Content-Type: application/json" \
-d "{\"username\":\"$USERNAME\", \"password\":\"$PASSWORD\"}" \
https://$CONTROLLER_IP/api/auth/login > $HEADER_FILE
TOKEN=$(grep -i "x-csrf-token:" $HEADER_FILE | awk '{print $2}' | tr -d '\r')
# 2. 獲取目前設備完整 JSON 狀態,因為後面異動插座狀態時需上送完整七個插座資料,所以需先查詢原來狀態,然後只異動特定插座即可
curl -k -b $COOKIE_FILE -X GET \
"https://$CONTROLLER_IP/proxy/network/api/s/default/stat/device" > $DATA_FILE
# 3. 使用 Python 修改特定插槽狀態,並保持 API 要求的資料格式
FINAL_PAYLOAD=$(python3 -c "
import json, sys
from collections import OrderedDict
try:
with open('$DATA_FILE', 'r', encoding='utf-8') as f:
data = json.load(f)
device = next(d for d in data['data'] if d['_id'] == '$DEVICE_ID')
overrides = []
for item in device['outlet_table']:
entry = OrderedDict()
entry['index'] = item['index']
# 修改目標插槽,其餘保留
if item['index'] == $TARGET_INDEX:
entry['relay_state'] = $NEW_STATE
else:
entry['relay_state'] = item['relay_state']
entry['name'] = item['name']
entry['cycle_enabled'] = item.get('cycle_enabled', False)
overrides.append(entry)
print(json.dumps({'outlet_overrides': overrides}, ensure_ascii=False))
except Exception as e:
sys.exit(1)
")
if [ $? -ne 0 ]; then
echo "錯誤:解析 JSON 失敗或找不到設備。"
exit 1
fi
# 4. 發送更新指令至 UniFi Controller
curl -k -i -b $COOKIE_FILE -X PUT \
-H "Content-Type: application/json" \
-H "x-csrf-token: $TOKEN" \
-d "$FINAL_PAYLOAD" \
"https://$CONTROLLER_IP/proxy/network/api/s/default/rest/device/$DEVICE_ID"
# 5. 清理暫存檔
rm $COOKIE_FILE $HEADER_FILE $DATA_FILE
echo "任務執行成功:插槽 $TARGET_INDEX 已設定為 $STATUS_ARG"
在 Synology DSM 中設定自動排程
有了腳本後,我們只需在 DSM 的 控制台 進行簡單設定:
上傳腳本:將 usp_control.sh 上傳到 NAS,並記下路徑。
進入 控制台 > 任務排程器。
點擊 新增 > 排程任務 > 使用者定義的指令碼。
設定開機排程:
任務名稱:開啟USB風扇
執行設定:輸入 bash /路徑/usp_control.sh 5 on
(假設 5 號是想控制的目標插座,注意:如果是USB插座就是 7 號,而且是 4 個USB插座一起開一起關,無法單獨開關)。
排程:設定每天凌晨2:00。
設定關機排程:
任務名稱:關閉USB風扇
執行設定:輸入 bash /路徑/usp_control.sh 5 off。
排程:設定每天凌晨 05:00。
透過這套方法,你可以把原本「手動」的智慧插座,真正升級為「自動」的智慧系統。不僅能節能省電,更能讓那些偶爾發神經的網通設備(例如以前大名鼎鼎的華x系列路由器),在每天深夜自動重開一次,來保持網路設備連線穩定!