13
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SwitchBot API v1.1を使って、スマートプラグ プラグミニの状態をZabbixでモニタリングできるようにした

Last updated at Posted at 2023-07-15

背景、事の始まり

私はSwitchBotのスマートプラグミニを3カ月ほど使用してきましたが、せっかくなら電圧や消費電力といった情報を取得したいと考えました。そこで調べてみたところ、SwitchBotには開発者用APIがあり、私でも利用することが可能であることを知りました。実は私はAPIを使用したことがなかったのですが、この機会に挑戦してみることにしました。

また、Grafanaを使ってモニタリングしている方がいるというのもTwitterで知り、私もそれにならって試してみようと考えましたが、自宅には既にZabbixが導入されているため、折角ならZabbixを利用して管理することにしました。

調べ始め

SwitchBotAPI v1.0でのモニタリング

どうやら同じことを考えた人は居たようです。
こちらの方は温湿度計をZabbixでモニタリングしているようですが、v1.0で利用しているみたいです。

SwitchBotAPI v1.1について

2022年9月にAPIのバージョンが1.1が公開されたようです。

どうやら今後発売される製品にはAPI v1.0が対応されないようです。
主な変更点としてはAPIの認証方法が変わり、API Headerに付与する情報が増えたようです。

  • v1.0の認証で必要なもの
    token(Switchbot Appで取得可能)

  • v1.1の認証で必要なもの
    Authorization(v1.0と同じtokenのこと)
    sign(特定のアルゴリズムを使用してトークンと秘密鍵から生成された署名)
    t(13 桁のタイムスタンプ)
    nonce(署名する文字列に組み込むために開発者自身が生成したランダムな UUID)

v1.1になったことでSwitchBotサーバーとの通信は安全になったらしいですが、特定のアルゴリズムで計算しないと認証が出来ないので、ちょっと面倒になったみたいです。

環境

  • Zabbix6.0
  • Ubuntu22.04
  • Python 3.10.6

手順

tokenとクライアントシークレット(秘密鍵)を取得する

iPhoneやAndroidでSwitchBot Appをダウンロードして、公式サイトの通りにトークンとクライアントシークレットを取得してください。

デバイスID一覧を取得する

各デバイスのパラメータを取得する前にデバイスIDが必要になるため、それを取得していきます。

import time
import hashlib
import hmac
import base64
import uuid
import requests
import pprint

def make_secret(secret_key):
    secret_key = bytes(secret_key, 'utf-8')
    return secret_key

def make_sign(secret_key, t, nonce):
    string_to_sign = '{}{}{}'.format(token, t, nonce)
    string_to_sign = bytes(string_to_sign, 'utf-8')
    sign = base64.b64encode(hmac.new(secret_key, msg=string_to_sign, digestmod=hashlib.sha256).digest())
    return sign

def make_t():
    t = int(round(time.time() * 1000))
    return str(t)

def make_nonce():
    nonce = str(uuid.uuid4())
    return nonce

#SwitchBotアプリから取得
secret_key = "your key"
token = "your token"

#Requestパラメータ作成
secret_key = make_secret(secret_key)
t = make_t()
nonce = make_nonce()
sign = make_sign(secret_key, t, nonce)

#URL指定
url = "https://api.switch-bot.com/v1.1/devices"

#APIheader作成
headers = {
    "Authorization": token,
    "sign": sign,
    "t": t,
    "nonce": nonce,
    "Content-Type": "application/json; charset=utf-8"
}

#requests処理
response = requests.get(url,headers=headers)

pprint.pprint(response.json())

これでデバイスIDの一覧が取得できたはずです。

[サンプル]
{'body': {'deviceList': [
    {
    'deviceId': '************',
    'deviceName': 'K10+',
    'deviceType': 'WoSweeperMini',
    'enableCloudService': True,
    'hubDeviceId': ''
    }
]},
 'message': 'success',
 'statusCode': 100}

Pythonファイルを作成する

デバイスのパラメータを取得するスクリプト

Pythonでパラメータを作成し、APIリクエストを実行するスクリプトを記述します。
また、後述しますがSwitchBotのデバイスIDと取得したい値のキーを引数として利用するため、引数の処理を入れています。

import time
import hashlib
import hmac
import base64
import uuid

#クライアントシークレットをbytes方に変更
def make_secret(secret_key):
    secret_key = bytes(secret_key, 'utf-8')
    return secret_key

#signを作成
def make_sign(secret_key, t, nonce):
    string_to_sign = '{}{}{}'.format(token, t, nonce)
    string_to_sign = bytes(string_to_sign, 'utf-8')
    sign = base64.b64encode(hmac.new(secret_key, msg=string_to_sign, digestmod=hashlib.sha256).digest())
    return sign

#tを作成
def make_t():
    t = int(round(time.time() * 1000))
    return str(t)

#nonceを作成
def make_nonce():
    nonce = str(uuid.uuid4())
    return nonce

#リクエストのレスポンス処理(jsonへの変更とデータ型の指定)
def get_value(response):
    if response.status_code == 200:
        data = response.json()
        if key == any(["voltage","weight","electricCurrent","temperature"]):
            value = float(data["body"][key])
        elif key == any(["electricityOfDay","battery","humidity"]):
            value = int(data["body"][key])
        else:
            value = str(data["body"][key])
        return value
    else:
        value = 0
        return value

#SwitchBotアプリから取得
secret_key = "your key"
token = "your token"

#引数を格納
key = sys.argv[1]
device_id = sys.argv[2]

#必要なパラメータを作成する
secret_key = make_secret(secret_key)
t = make_t()
nonce = make_nonce()
sign = make_sign(secret_key, t, nonce)

#URL指定
url = "https://api.switch-bot.com/v1.1/devices/{}/status".format(device_id)

#APIheader作成
headers = {
    "Authorization": token,
    "sign": sign,
    "t": t,
    "nonce": nonce,
    "Content-Type": "application/json; charset=utf-8"
}

#requests処理
response = requests.get(url,headers=headers)

#レスポンス処理とデータ型変更
print(get_value(response))

※secret_keyとtokenの値は各個人で異なるため、個別に入力してください。

zabbixサーバにPythonファイルを作成する

zabbixを構築しているサーバに先ほど作成したPythonファイルを配置します。
私は面倒なので/etc/zabbix/に保存しています。
ファイル名は任意ですが、私はswitchbot_api.pyにしています。

zabbix_agented.confファイルに設定を追加する

Zabbix Agentの設定ファイルにUserParameterと呼ばれるカスタムアイテムの定義を行います。
UserParameterの設定構文は下記の通り

UserParameter=<キー名>,<スクリプトのパス>

zabbix_agented.confファイルの末尾に下記の通り記述します。

UserParameter=switchbot.api[*],/usr/bin/python3 /etc/zabbix/switchbot_api.py "$1" "$2"

Zabbixエージェントサービスを再起動します。

systemctl restart zabbix-agent.service

Zabbixでの操作

ホストの作成

設定 > ホストで「ホストの作成」をクリックします。
任意でホスト名とグループを設定します。
インターフェースはエージェントを選び、127.0.0.1を設定すればOKです。
image.png
※私は後々の管理のためにSwitchBotというグループを作成しました。

アイテムの作成

先ほど作成したホストのアイテムをクリックします。
image.png

右上のアイテムの作成をクリック
image.png

任意の名前を設定します。
キーにはswitchbot.api[key,deviceID]を設定します。
取得したい値のkeyはSwitchBot公式が出しています。
今回は電圧を取得するのでvoltageを設定しています。
image.png
データ型についても任意で設定しますが、今回は浮動小数点数が含まれるので数値(浮動小数)を設定しています。

ページの一番下にテストボタンがあるのでクリックします。
image.png

下図が出てきたら「値の取得とテスト」をクリックします。
image.png

無事に値が取得出来たら問題ありません。
image.png

グラフ閲覧

Zabbixで監視データ > 最新データから任意のSwitchBotのアイテムを選択すればグラフが表示されます。
image.png

ダッシュボードを変更して、各プラグの状況をモニタリングしてもいいかもですね。
image.png

最後に

初めてAPIを使いましたが、中々奥深いものがありますね。
どうやらSwitchBotのAPIは機器の操作もできるらしいので、次は温湿度計の値を取得して、それをトリガーにエアコンの温度設定を自動で変更するとかやってみたいですね。

今回の記事が少しでも皆様のためになりますように。

13
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?