【SwitchBotAPI】SwitchBotをCLIでイジれれば楽じゃねってなったから開発した

プログラミング

お疲れ様です。

現在筆者の部屋にはスマートホーム環境を構築しています。

操作は一般的にGoogleHomeに話しかけるorSwitchBotのスマホアプリから操作をするいずれかです。

そうPCから無言で部屋の照明をイジったりできないんですね。

少し調べてみるとCLIから操作できるものを開発している方もいるようなのですが、どうせなら自分で作るかーと
あとはできるだけシンプルにしたいなーって思ったのも大きいです。

要件

  • WindowsならTerminal(PowerShell)からMacならTerminal.appから
  • SwitchBotデバイスを最低限(ON/OFF)操作できる
  • デバイス一覧などは確認できるようにする
  • デバイスには自身が考えるユニークな名称をつけ、それを元に操作できる

APIトークンの発行

SwitchBotアプリの「Profile」→「Preferences」

→「About」

→「App Version」を連打する

トークンが出てくる。
ここに出てくるトークンがわかるとデバイスを操作できます。取り扱いにはご注意を。

CurlでAPI叩いてみる

デバイス一覧を取得

curl -X GET "https://api.switch-bot.com/v1.1/devices" \
-H "Authorization: さっきのtoken"

レスポンスを確認し、devicenameと対になっているdeviceIdを元に操作をします。

デバイスをON/OFF

curl -X POST "https://api.switch-bot.com/v1.1/devices/さっきのdeviceid/commands" \
-H "Authorization: さっきのtoken" \
-H "Content-Type: application/json" \
-d '{"command":"turnOn","parameter":"default","commandType":"command"}'

実行結果が返ってきます。
いい感じです。

コードを書いていくぅ

先ほどの情報を元にPowerShellスクリプトとシェルスクリプトに落とし込んでいきました。

要件のとおりにデバイス一覧を取得しjson→ユニークなデバイス名を追加→スクリプトからjsonを読み、ユニークなデバイス名を使用し状態を操作することができました。

参考までにMacでいい感じに動いたシェルスクリプトを貼っておきます。

sb.sh

#!/bin/bash

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
URL="https://api.switch-bot.com/v1.0"
ENV_FILE="$SCRIPT_DIR/.env"
DEVICES_FILE="$SCRIPT_DIR/devices.json"

# .envよりAPI_KEY
if [ -f "$ENV_FILE" ]; then
  export $(cat "$ENV_FILE" | xargs)
else
  exit 1
fi

# 引数なし
if [ $# -eq 0 ]; then
  echo "引数を指定してください"
  exit 1
fi

if [[ "$1" == "list" ]]; then
  case "$2" in
    devices)
      cat "$DEVICES_FILE"
      exit 0
      ;;
    *)
      echo "listの引数を指定してください"
      exit 1
      ;;
  esac
fi

# setコマンド
if [[ "$1" == "set" ]]; then
  case "$2" in
    key)
      read -p "Enter your API_KEY: " NEW_KEY
      echo "API_KEY=$NEW_KEY" > "$ENV_FILE"
      echo "APIKEY を $ENV_FILE に保存しました"
      exit 0
      ;;
    devices)
      NEW_JSON=$(curl -s -X GET "$URL/devices" -H "Authorization: $API_KEY")

      if [ -f "$DEVICES_FILE" ]; then
        EXISTING_JSON=$(cat "$DEVICES_FILE")
      else
        EXISTING_JSON='{"body":{"deviceList":[],"infraredRemoteList":[]}}'
      fi

      MERGED_JSON=$(jq -s '
        .[0] as $existing | .[1] as $new |
        {
          statusCode: $new.statusCode,
          message: $new.message,
          body: {
            deviceList: (
              ($existing.body.deviceList + $new.body.deviceList
              | map(. + ({unique: (.unique // "")}))
              | unique_by(.deviceId))
            ),
            infraredRemoteList: (
              ($existing.body.infraredRemoteList + $new.body.infraredRemoteList
              | map(. + ({unique: (.unique // "")}))
              | unique_by(.deviceId))
            )
          }
        }
      ' <(echo "$EXISTING_JSON") <(echo "$NEW_JSON"))

      echo "$MERGED_JSON" | jq '.' | tee "$DEVICES_FILE"
      ;;
    *)
      echo "何をsetするか指定してください"
      exit 1
      ;;
  esac
fi

# ON/OFF操作
DEVICE_NAME=$(jq -r --arg name "$1" '(.body.deviceList[]?, .body.infraredRemoteList[]?)| select(.unique==$name) | .deviceName' "$DEVICES_FILE")

DEVICE_ID=$(jq -r --arg name "$1" '(.body.deviceList[]?, .body.infraredRemoteList[]?) | select(.unique==$name) | .deviceId' "$DEVICES_FILE")

if [ -z "$DEVICE_ID" ] || [ "$DEVICE_ID" == "null" ]; then
  echo "デバイスが見つからない,あるいは変更がありませんでした"
  exit 1
fi

case "$2" in
  on)
    curl -s -X POST "$URL/devices/$DEVICE_ID/commands" \
      -H "Authorization: $API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"command":"turnOn","parameter":"default","commandType":"command"}' >/dev/null
    echo "${DEVICE_NAME}をONにしました"
    ;;
  off)
    curl -s -X POST "$URL/devices/$DEVICE_ID/commands" \
      -H "Authorization: $API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"command":"turnOff","parameter":"default","commandType":"command"}' >/dev/null
    echo "${DEVICE_NAME}をOFFにしました"
    ;;
  *)
    echo "ON/OFFを指定してください"
    exit 1
    ;;
esac


適切にパスを通すことで以下のように実行できるようになりました。
sb unique-devicename on/off
また上記コードでは.envに認証情報を格納。devices.jsonにデバイス情報を記録しています。

動いているところ

最後に

以上SwitchBotデバイスのON/OFFをTerminal上から操作できるスクリプトを書こーって話でした。

Webアプリ的に実装しても良かったのですが、「ブラウザ開く→該当ページに行く→マウスでポチポチ」よりもCLIでポチポチしたほうが早いんじゃねぇかなって。

ざっついコードなので参考にしないほうが良いですが、参考になれば嬉しいです。

最後まで見ていただきありがとうございました!

コメント

タイトルとURLをコピーしました