はじめに
今回は、SwitchBotの温湿度計のデータを、SwitchBotのクラウドAPI経由でZabbixに取り込む仕組みを作ったので、その過程をまとめました。
すでにZabbixで自宅のスイッチをSNMP監視しているので、「ついでに部屋の温湿度もZabbixで一元管理できたら便利だな」というのが今回のモチベーションです。
全体の構成
SwitchBotの温湿度計はBLE接続のデバイスですが、SwitchBot Hubを経由してクラウドにデータが上がっています。なので、自宅サーバーからインターネット越しにSwitchBot Cloud API v1.1を叩いてデータを取得し、それをZabbixに流し込む、という構成になります。
[SwitchBot温湿度計] ──Bluetooth── [SwitchBot Hub] ──── [SwitchBotクラウド]
↑ HTTPS API(HMAC認証)
[Rocky Linux VM(Proxmox上)]
└ Pythonスクリプト(cronで定期実行)
├ SwitchBot APIから温度・湿度・バッテリーを取得
└ ZabbixSender(Trapper)でZabbixに送信
↓
[Zabbix Server] ← データ受信、グラフ化・アラート
- ハイパーバイザー: Proxmox VE 9.2
- VM: Rocky Linux 9(Docker Composeで各種サービスを運用)
- 監視: Zabbix 7.0 LTS(Docker Compose上、MySQL 8.0 + Zabbix Server + Zabbix Web)
- 温湿度計: SwitchBot 温湿度計(deviceType:
MeterMeterPlusMeterPro)+ SwitchBot Hub
Step 1: SwitchBotのトークン・シークレットキーを取得
まず、APIを叩くための認証情報を取得します。スマホのSwitchBotアプリで以下の操作をします。
- プロフィール → 設定 → 基本データ
- 「アプリバージョン」の表示部分を連続でタップ
- 「開発者向けオプション」が出現する
- そこに トークン と クライアントシークレット が表示される
この2つを控えておきます。後でスクリプトに使います。
Step 2: HMAC認証でデバイス一覧を取得
SwitchBot Cloud API v1.1は、リクエストごとにHMAC-SHA256で署名を生成して付与する必要があります。ここが少しクセがありますが、一度書いてしまえば使い回せます。
まずはデバイス一覧を取得して、温湿度計の deviceId を確認します。
import hashlib, hmac, base64, time, requests
token = "ここにToken"
secret = "ここにSecret Key"
t = int(round(time.time() * 1000))
nonce = "requestid"
string_to_sign = f"{token}{t}{nonce}".encode("utf-8")
sign = base64.b64encode(
hmac.new(secret.encode("utf-8"), string_to_sign, hashlib.sha256).digest()
).decode("utf-8")
headers = {
"Authorization": token,
"sign": sign,
"t": str(t),
"nonce": nonce,
"Content-Type": "application/json"
}
res = requests.get("https://api.switch-bot.com/v1.1/devices", headers=headers)
print(res.json())
実行すると、登録されているデバイスの一覧がJSONで返ってきます。
返ってきたJSONの中から、deviceType が Meter(温湿度計系)のものを探し、その deviceId をメモします。
Step 3: 温湿度データが取れるか確認
デバイスIDが分かったら、そのデバイスのステータス(温度・湿度・バッテリー)が実際に取れるか確認します。エンドポイントが /devices/{deviceId}/status に変わるだけで、署名の作り方は同じです。
import hashlib, hmac, base64, time, requests
token = "ここにToken"
secret = "ここにSecret Key"
device_id = "D2831A7721E0"
t = int(round(time.time() * 1000))
nonce = "requestid"
string_to_sign = f"{token}{t}{nonce}".encode("utf-8")
sign = base64.b64encode(
hmac.new(secret.encode("utf-8"), string_to_sign, hashlib.sha256).digest()
).decode("utf-8")
headers = {
"Authorization": token,
"sign": sign,
"t": str(t),
"nonce": nonce,
"Content-Type": "application/json"
}
url = f"https://api.switch-bot.com/v1.1/devices/{device_id}/status"
res = requests.get(url, headers=headers)
print(res.json())
実行して、こんな感じで返ってくれば成功です。
{'statusCode': 100, 'body': {'version': 'V3.3', 'temperature': 25.3, 'battery': 100, 'humidity': 61, 'deviceId': 'D2831A7721E0', 'deviceType': 'Meter', 'hubDeviceId': 'EA5299B4B3AA'}, 'message': 'success'}
temperature、humidity、battery の値が含まれていればOKです。
Step 4: Zabbix Serverの10051番ポートを確認
Zabbix Senderは既定でTCP 10051番ポートのZabbix Serverへデータを送信します。Docker Composeで動かしているので、ポートが公開されているか確認します。
cat docker-compose.yml | grep -A 5 "zabbix-server:"
ports: に 10051:10051 があるか確認します。なければ追記します。
zabbix-server:
# ...既存の設定...
ports:
- "10051:10051"
追記したら再起動して、LISTENしているか確認します。
docker compose up -d
ss -tlnp | grep 10051
Step 5: Zabbix側でホストとアイテムを作成
Zabbix Web UIで作成します。
- 「データ収集」→「ホスト」→「ホストの作成」
- ホスト名:
switchbot-thermo - ホストグループ:
Sensors(新規作成でOK) - インターフェース: 不要
- ホスト名:
続けて、このホストにアイテムを3つ作成します。いずれもタイプは Zabbixトラッパー です。
| アイテム名 | キー | データ型 |
|---|---|---|
| Temperature | switchbot.temperature |
数値(浮動小数) |
| Humidity | switchbot.humidity |
数値(整数) |
| Battery | switchbot.battery |
数値(整数) |
Step 6: 本番スクリプトの作成
取得したデータをZabbixに送る本番スクリプトを書きます。送信には pyzabbix(ZabbixMetric + ZabbixSender)を使います。
まずインストールを確認します。
python3 -c "import pyzabbix; print('OK')"
入っていなければインストールします。
pip3 install --user py-zabbix
スクリプトを配置します。
import hashlib, hmac, base64, time, requests
from pyzabbix import ZabbixMetric, ZabbixSender
# --- SwitchBot API 認証情報 ---
TOKEN = "ここにToken"
SECRET = "ここにSecret Key"
DEVICE_ID = "D2831A7721E0"
# --- Zabbix 送信先 ---
ZABBIX_SERVER = "192.168.1.xx"
ZABBIX_HOST = "switchbot-thermo"
def get_status():
t = int(round(time.time() * 1000))
nonce = "requestid" #サンプルでは固定文字列を使っていますが、実運用ではUUIDなど毎回異なる値を使うことが推奨されています。
string_to_sign = f"{TOKEN}{t}{nonce}".encode("utf-8")
sign = base64.b64encode(
hmac.new(SECRET.encode("utf-8"), string_to_sign, hashlib.sha256).digest()
).decode("utf-8")
headers = {
"Authorization": TOKEN,
"sign": sign,
"t": str(t),
"nonce": nonce,
"Content-Type": "application/json"
}
url = f"https://api.switch-bot.com/v1.1/devices/{DEVICE_ID}/status"
res = requests.get(url, headers=headers, timeout=10)
return res.json()
def main():
data = get_status()
# APIが正常応答(statusCode 100)でなければ送信しない
if data.get("statusCode") != 100:
print(f"API error: {data}")
return
body = data["body"]
metrics = [
ZabbixMetric(ZABBIX_HOST, "switchbot.temperature", body["temperature"]),
ZabbixMetric(ZABBIX_HOST, "switchbot.humidity", body["humidity"]),
ZabbixMetric(ZABBIX_HOST, "switchbot.battery", body["battery"]),
]
result = ZabbixSender(ZABBIX_SERVER).send(metrics)
print(result)
if __name__ == "__main__":
main()
実行してこんな感じの出力が返ってくれば成功です。
{'failed': 0, 'processed': 3, 'total': 3, ...}
failed: 0、processed: 3 なら、温度・湿度・バッテリーの3項目すべてがエラーなくZabbixに送信されています。
最後にZabbix Web UIの「モニタリング」→「最新データ」で、ホスト switchbot-thermo を絞り込んで、値が表示されているか確認しましょう。
Step 7: cronで定期実行
手動実行ができたので、自動化します。
crontab -e
*/1 * * * * /usr/bin/python3 /home/xxx/switchbot-zabbix/fetch_and_send.py >> /home/xxx/switchbot.log 2>&1
これで1分おきに、自動でSwitchBotから温湿度を取得してZabbixに記録されます。cronでは最小1分単位で実行できます。
なお、SwitchBot Cloud APIは1日あたり10,000リクエストの利用制限があります。今回のようにcronで1分ごとに取得する場合は約1,440リクエスト/日となるため、この制限内で運用できます。
ログで動作を確認します。
tail -f ~/switchbot.log
おわりに
SwitchBotのクラウドAPIを使って、温湿度データをZabbixに取り込むところまでできました。
同じ仕組みは「外部API → 自作スクリプト → 別サービス」という形で他の連携にも応用が効きます。この後、ESP32とSHT41センサーを使って自作の温湿度センサーをMQTT経由でZabbixに送る仕組みも作ったのですが、その送信部分はこのSwitchBot連携のコードをほぼ流用できました。それはまた別の記事で書きたいと思います。
最後まで読んでいただきありがとうございました。
参考リンク
- SwitchBot API 公式ドキュメント: https://github.com/OpenWonderLabs/SwitchBotAPI
- Zabbix公式ドキュメント(Trapperアイテム): https://www.zabbix.com/documentation/current/jp/manual/config/items/itemtypes/trapper