SwitchBotは「AIから操作できる物理デバイス」への入口として最も敷居が低い部類だ。公式クラウドAPIが公開されており、ハブ経由なら赤外線家電まで含めてHTTPで操作できる。本稿は2026年8月時点の公式ドキュメント(OpenWonderLabs/SwitchBotAPI)を実確認した上で、トークン取得からv1.1の署名生成、AIエージェントへの組み込みまでを一気に通す。ハブ本体の選定はSwitchBot Hub 2のデバイスページを参照。
トークンとクライアントシークレットの取得
スマホアプリ(V6.14以降)から取得する。V9.0以降の手順:
- プロフィール → 設定 → アプリについて
- 「アプリバージョン」を10回タップすると「開発者向けオプション」が出現
- 開発者向けオプションを開き「トークンを取得」
ここでトークンとクライアントシークレットの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_devices と send_command の2関数を生やすだけで動く。依存が増えず、挙動が完全に自分の制御下にあるのが利点。書き込み系(commands)を自動実行させるか承認制にするかは設置環境次第で、判断の枠組みはAI手足マップにまとめてある。
② コミュニティMCPサーバー
実在をリポジトリで確認済み(2026年8月):
- yasu89/switch-bot-mcp-server — Go製、Dockerイメージ配布。環境変数
SWITCH_BOT_TOKEN/SWITCH_BOT_SECRETを渡すだけで、get_switch_bot_devices/get_switch_bot_device_status/execute_commandなどのツールが生える。 - genm/switchbot-mcp — TypeScript製。デバイス操作に加えシーン実行(
switchbot_execute_scene)まで対応。npmパッケージは準備中でソースからのビルドが必要(確認時点)。
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で内容を実確認したもの。
- OpenWonderLabs/SwitchBotAPI — 公式APIドキュメント(トークン取得手順・署名仕様・レート制限・Webhook仕様・各サンプルコードの出典)
- yasu89/switch-bot-mcp-server — Go製コミュニティMCPサーバー
- genm/switchbot-mcp — TypeScript製コミュニティMCPサーバー