ロボ図鑑

SwitchBot API v1.1をAIから叩く — トークン取得から署名生成、MCP化のひと手間まで

公開: 2026-08-09

SwitchBotは「AIから操作できる物理デバイス」への入口として最も敷居が低い部類だ。公式クラウドAPIが公開されており、ハブ経由なら赤外線家電まで含めてHTTPで操作できる。本稿は2026年8月時点の公式ドキュメント(OpenWonderLabs/SwitchBotAPI)を実確認した上で、トークン取得からv1.1の署名生成、AIエージェントへの組み込みまでを一気に通す。ハブ本体の選定はSwitchBot Hub 2のデバイスページを参照。

トークンとクライアントシークレットの取得

スマホアプリ(V6.14以降)から取得する。V9.0以降の手順:

  1. プロフィール → 設定 → アプリについて
  2. 「アプリバージョン」を10回タップすると「開発者向けオプション」が出現
  3. 開発者向けオプションを開き「トークンを取得」

ここでトークンクライアントシークレットの2つが表示される。v1.1では両方使うので控えておく(V9.0未満は「プロフィール → 設定」直下でバージョン10回タップ、以降同じ)。

v1.1の署名方式

v1.0はトークンをヘッダーに入れるだけだったが、v1.1はHMAC-SHA256署名が必須になった。リクエストごとに次の4ヘッダーを付ける。

ヘッダー 内容
Authorization トークンそのまま
t 13桁ミリ秒UNIXタイムスタンプ
nonce ランダムUUID
sign token + t + nonce を連結した文字列を、シークレットを鍵にHMAC-SHA256 → Base64

公式のPython 3サンプル(README掲載のまま):

import json
import time
import hashlib
import hmac
import base64
import uuid

apiHeader = {}
token = '' # copy and paste from the SwitchBot app V6.14 or later
secret = '' # copy and paste from the SwitchBot app V6.14 or later
nonce = uuid.uuid4()
t = int(round(time.time() * 1000))
string_to_sign = '{}{}{}'.format(token, t, nonce)

string_to_sign = bytes(string_to_sign, 'utf-8')
secret = bytes(secret, 'utf-8')

sign = base64.b64encode(hmac.new(secret, msg=string_to_sign, digestmod=hashlib.sha256).digest())

apiHeader['Authorization']=token
apiHeader['Content-Type']='application/json'
apiHeader['charset']='utf8'
apiHeader['t']=str(t)
apiHeader['sign']=str(sign, 'utf-8')
apiHeader['nonce']=str(nonce)

一点注意: ドキュメント本文の手順説明には「署名を大文字に変換する」とあるが、公式Pythonサンプル自体は大文字化していない(Base64は大文字小文字を区別するため両者は食い違っている)。コードサンプルを正として使い、もし署名エラーが返る場合に大文字化を試す、という順で扱うのが安全だ。

curlで叩くなら署名生成はopensslで代用できる(公式にcurl例はなく、以下は筆者による移植・動作未検証):

TOKEN='あなたのトークン'
SECRET='あなたのシークレット'
T=$(date +%s%3N)
NONCE=$(uuidgen)
SIGN=$(printf '%s' "${TOKEN}${T}${NONCE}" \
  | openssl dgst -sha256 -hmac "$SECRET" -binary | base64)

curl -s https://api.switch-bot.com/v1.1/devices \
  -H "Authorization: $TOKEN" -H "sign: $SIGN" \
  -H "t: $T" -H "nonce: $NONCE"

デバイス一覧の取得とコマンド送信

ベースURLは https://api.switch-bot.com。まず GET /v1.1/devices でデバイス一覧を取り、deviceId を控える。

{
    "statusCode": 100,
    "body": {
        "deviceList": [
            {
                "deviceId": "500291B269BE",
                "deviceName": "Living Room Humidifier",
                "deviceType": "Humidifier",
                "hubDeviceId": "000000000000"
            }
        ]
    }
}

statusCode: 100 が成功。操作は POST /v1.1/devices/{deviceId}/commands に次のボディを送る。

import requests
# apiHeader は上の公式サンプルで組み立てたもの
r = requests.get('https://api.switch-bot.com/v1.1/devices', headers=apiHeader)
print(r.json())

body = {"command": "turnOn", "parameter": "default", "commandType": "command"}
r = requests.post(
    'https://api.switch-bot.com/v1.1/devices/500291B269BE/commands',
    headers=apiHeader, json=body)
print(r.json())

署名はタイムスタンプとnonceを含むため、実運用ではリクエストのたびにヘッダーを組み立てる関数にまとめるのが実際的だ(後述の自作ラッパー骨格がその形)。

レート制限 — 1日10,000回

公式README明記: "The amount of API calls per day is limited to 10000 times." 1日10,000回で正しい。人間が使う分には十分だが、AIエージェントに状態ポーリングをさせるとあっさり溶ける数字でもある(10秒間隔のポーリングで8,640回/日)。状態監視はポーリングでなくWebhookに寄せるのが定石だ。

Webhook — 状態変化をAI側に押す口

デバイスの状態変化をこちらのURLへPOSTさせられる。設定系エンドポイントは4本、すべてPOSTで、認証ヘッダーは通常APIと同じ。

用途 パス 主なボディ
登録 /v1.1/webhook/setupWebhook action, url, deviceList(現状 "ALL")
照会 /v1.1/webhook/queryWebhook action, url
更新 /v1.1/webhook/updateWebhook action, config
削除 /v1.1/webhook/deleteWebhook action, url

登録後、状態変化時にこちらのURLへ次の形のJSONが飛んでくる:

{
    "eventType": "changeReport",
    "eventVersion": "1",
    "context": {
        "deviceType": "WoHand",
        "deviceMac": "DEVICE_MAC_ADDR",
        "power": "on",
        "battery": 10,
        "timeOfSample": 123456789
    }
}

受け口を自作サーバーやn8nで立て、イベント駆動でエージェントを起動する構成にすれば、レート制限をほぼ消費せずに「部屋の状態に反応するAI」が作れる。

AIエージェントから使う3つの形

① ツール定義で直叩き

Claude APIなどのtool useに list_devicessend_command の2関数を生やすだけで動く。依存が増えず、挙動が完全に自分の制御下にあるのが利点。書き込み系(commands)を自動実行させるか承認制にするかは設置環境次第で、判断の枠組みはAI手足マップにまとめてある。

② コミュニティMCPサーバー

実在をリポジトリで確認済み(2026年8月):

yasu89版のClaude Desktop設定例(リポジトリREADMEより):

{
  "mcpServers": {
    "switchbot": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "--name", "switch-bot-mcp-server",
               "-e", "SWITCH_BOT_TOKEN", "-e", "SWITCH_BOT_SECRET",
               "yasu89/switch-bot-mcp-server:latest"],
      "env": {
        "SWITCH_BOT_TOKEN": "YOUR_TOKEN",
        "SWITCH_BOT_SECRET": "YOUR_SECRET"
      }
    }
  }
}

③ 自作MCPラッパー

v1.1で面倒なのは署名生成だけで、そこを関数化すればMCP化は薄いラッパーで済む。Python(FastMCP)での骨格(動作未検証・署名部分は公式サンプルの移植):

# switchbot_mcp.py — 骨格(動作未検証)
import base64, hashlib, hmac, os, time, uuid
import requests
from mcp.server.fastmcp import FastMCP

TOKEN = os.environ["SWITCHBOT_TOKEN"]
SECRET = os.environ["SWITCHBOT_SECRET"]
BASE = "https://api.switch-bot.com/v1.1"

def _headers():
    t = int(round(time.time() * 1000))
    nonce = str(uuid.uuid4())
    string_to_sign = '{}{}{}'.format(TOKEN, t, nonce).encode('utf-8')
    sign = base64.b64encode(hmac.new(SECRET.encode('utf-8'),
        msg=string_to_sign, digestmod=hashlib.sha256).digest())
    return {"Authorization": TOKEN, "Content-Type": "application/json",
            "t": str(t), "sign": sign.decode(), "nonce": nonce}

mcp = FastMCP("switchbot")

@mcp.tool()
def list_devices() -> dict:
    """SwitchBotデバイス一覧を返す"""
    return requests.get(f"{BASE}/devices", headers=_headers()).json()

@mcp.tool()
def send_command(device_id: str, command: str, parameter: str = "default") -> dict:
    """デバイスにコマンドを送る(turnOn / turnOff など)"""
    body = {"command": command, "parameter": parameter, "commandType": "command"}
    return requests.post(f"{BASE}/devices/{device_id}/commands",
                         headers=_headers(), json=body).json()

if __name__ == "__main__":
    mcp.run()

どの形を選んでも、API側の実体は「一覧取得」と「コマンド送信」の2エンドポイントに過ぎない。この「公式クラウドAPI + 署名ひと手間」という構成をAI操作性の観点でどう採点しているかは、当サイトの評価基準を参照してほしい。

参考情報

いずれも2026年8月9日にWebFetchで内容を実確認したもの。

他のガイド