9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

◇はじめに

本記事はPostman Advent Calendar 2023の2日目の記事です。

今回は、Postmanを使って、スマート家電デバイスのSwitchBotデバイスの制御を行うAPIリクエストのセットを作成しました。

◇開発環境等

  • OS:
    • Windows 11 Home(Ver:22H2)
  • ブラウザ
    • Edge(バージョン 119.0.2151.72 (公式ビルド))
  • 使用ツール:
    • Postman(Web版)
  • 使用バイス:
    • SwitchBot ハブ2
    • SwitchBot ボット
    • SwitchBot 温湿度計
    • SwitchBot 防水温湿度計
    • SwitchBot プラグミニ(JP)
    • SwitchBot 開閉センサ

◇Postmanとは📮

[Postman Advent Calendar 2023](Postman Advent Calendar 2023)ページ内の概要の項目を一部引用します。

Postmanは、APIを構築し利用するためのAPIプラットフォームです。Postmanを使うとAPIライフサイクルの各ステップを簡単に行えるようになり、コラボレーションが効率化されることで、開発者はより良いAPIを速く作成することができるようになります。

Postmanを使用すると、プログラミング言語やcurlを使用せずにHTTPリクエストが発行できます(GraphWLやgRPCなどにも対応しているようです)。

Postman社員の方が過去に実施した際のセミナー資料なども公開されているため、この辺も参考にしてもらえればと思います。

◇SwitchBotとは🎚️

SwitchBot社が開発・販売しているスマート家電やホームオートメーションを実現するためのデバイス群です。
今回使用したデバイス以外にも、様々なデバイスが市販されています。
基本的には、スマホアプリを使用してデバイスデータの収集やデバイスの制御を行う仕様となっていますが、
GitHub上にWeb APIも公開されています(最新はVer1.1)。

今回は、このWeb API経由でデバイスの情報取得や遠隔制御を実現していきます。

◇最終的にできたもの

基本的に、GitHubに公開されているSwitchBot API v1.1の内容をベースにPostman上でAPIリクエストのセットを作成しました。
なお、手持ちにないデバイスについては、動作検証できなかった関係上、作成していません。

◇実装

実装手順について順にまとめていきます。
なお、このCollection自体はPostman上でも公開していますので、気軽に試したい場合はForkしてみてください。

Workspaces、Collections、Environmentsの作成(Postman)

まず、専用の環境を作成していきます。
なお、Workspacesについては、今回は新規で作成していますが、最初に用意されているMy Workspaceを使っても問題ありません。

Workspaces

Postmanのトップページから、Workspacesをクリックし、続いてCreate Workspaceをクリックします。

Workspace作成画面では、1ページ目にtemplatesの選択画面が表示されますが、今回はBlank workspaceを選択しています。
2ページ目でWorkspaceの名前を適宜入力し、WorkspaceのタイプでPersonalを選択して、Createボタンをクリックすれば完了です。

Collections

今回はSwitchBot API用に1つのCollectionを作成しています。
Collectionsのメニューからボタンをクリックし、続いてBlank collectionを選択します。
すると、New CollecitonというCollectionが作成されるので、わかりやすい名称を入力します。

Environments

Postmanではプログラミング言語と同じように、変数を扱うことができます。
詳細は前述のセミナー資料を確認もらえればと思いますが、

  • グローバル変数
  • コレクション変数
  • 環境変数

の3種類の変数があります。
先ほど作成したCollection上に変数(コレクション変数)を作成することもできますが、
コレクション変数の場合、secret設定ができないことから、secret設定が可能な「環境変数」も併せて使用しています。
「環境変数」を作成したい場合、先ほど作成したCollectionとは別に、まずEnvironmentを作成する必要があります。
なお、EnvironmentはWorkspace内でのみ有効となりますので、Workspaceを跨いで変数を使用したい場合は「グローバル変数」を使用する必要があります。

作成方法は、先ほどのCollectionとほぼ同じです。
今度は、PostmanのトップページからEnvironmentsをクリックし、続いてボタンをクリックします。
すると、New EnvironmentsというEnvironmentが作成されるので、わかりやすい名称を入力すれば作成完了です。

このあと、この作成した環境上に変数を追加していくのですが、その部分は後述します。

認証用Keyの発行(SwitchBot)

SwitchBot API v1.1を使用する場合、tokenとsecretが必要になります。
この2つはSwitchBotのスマホアプリ上から操作を行い、開発者向けオプションを表示する必要があります。

手順としては、公式サイトに記載の通りです。
一応、以下に公式サイトから引用した手順を記載しておきます(公式サイト上には画面キャプチャも載ってます)。

SwitchBot Appバージョン:V6.24以降
1.SwitchBotアプリを起動します。

2.プロフィール→設定→アプリバージョンまで進みます。

3.アプリバージョン(例えば 6.24)を数回(5回~15回)連続タップすると「開発者向けオプション」が出てきます。

4.「開発者向けオプション」をタップして、次の画面でトークン情報がございます。

表示されているトークンとクライアントシークレットのランダム文字列を後で使用しますので、
どこかにコピーしておきます。

Variables(変数)の設定(Postman)

次に、変数化しておきたいパラメータを検討します。
Postmanの変数については、以下の記事が詳しいので、こちらも参考にしてください。

SwitchBot API v1.1のREADME.md内のAPI Usageを確認したところ、
ベースとなるHost Domainがあるため、こちらは変数化をしておきます。
また、Headerに入れる必要があるパラメータとして、Request Headerの項目に以下のパラメータが列挙されているので、こちらも変数化しておきます。

  • Authorization(token)
  • sign
  • t
  • nonce

なお、Authenticationの項のPython 3 example codeを確認してみると、先ほどのパラメータの1つであるAuthorizationは前述したスマホアプリから発行したトークンがそのまま入っていることが分かります。
一方、アプリから発行したクライアントシークレットについては、signを算出するために使用されているため、別途変数化する必要があると考えられます。この変数をsecretとすると、全部で6つのパラメータの変数化が必要になります。

次に、それぞれのパラメータを3種類の内、どの変数の種類にするかについて考えます。

  • グローバル変数
  • コレクション変数
  • 環境変数

今回は、一つのCollectionでしか使用しない変数のため、「グローバル変数」は除外しました。
まず、Host Domainについては、SwitchBot APIで共通の内容のため、「コレクション変数」としました。
次に、スマホアプリ上から発行するトークン(token)とシークレット(secret)については、秘匿したい情報となるため、変数タイプをsecretとしたいため、「環境変数」としました(どっちもsecretで分かりにくい・・・)。
残りの3つのパラメータ(sign,t,nonce)についてはその都度演算されるパラメータのため、どちらでも問題ないかと思いますが、今回は「コレクション変数」としました。
まとめると以下のようになります。

  • グローバル変数
    • 未使用
  • コレクション変数
    • Host Domain
    • sign
    • t
    • nonce
  • 環境変数
    • token
    • secret

コレクション変数の追加

先ほど追加したCollectionを選択した状態で、Variablesをクリックします。
Variablesの項目に4つの変数を追加します。
なお、Host Domainについては変数名をbaseUrlとして、Current Valuehttps://api.switch-bot.comと入力しています。
一通り入力が完了したら、最後に右上のSaveボタンをクリックして完了です。

環境変数の追加

まず、トップメニューからEnvironmentsをクリックし、先ほど作成した環境を選択します。
Variableとして2つの変数を追加します。Typeについては、両方ともsecretに設定します。
最後に、Current valueにスマホアプリから発行した値を入力してSaveボタンをクリックします。

環境の有効化

環境変数を使用したい場合、その環境変数が格納されている環境(Environment)を有効化する必要があります。
手順としては、下の画像の✅マークの部分をクリックして、右上に、有効化したい環境名が表示されればOKです。
※1枚目画像が環境未設定の状態、2枚目が環境が有効化されている状態です

認証処理Pre-request Script(Postman)

SwitchBot API Authenticationにも記載があるように、Ver1.1のAPIでは認証するための情報(署名)をタイムスタンプ等を用いて動的に生成する必要があります。
これをPostmanで実現するためには、Pre-request Scriptという機能を使用します。
この機能を使用することで、先ほど作成した変数へのデータの取得・保存や署名生成処理を実装することができます。
本来は、README.mdに記載されているサンプルコードなどをベースに自分で作成する必要がありますが、以下の記事が大変参考になりましたので、この記事をベースにPre-request Scriptを作成しています。

基本処理の部分は記事と同じですが、変数の保存場所などが記事と異なるため、少し修正しています。コードは以下のようになります。

Pre-request Script
let token = pm.environment.get("token");
let secret = pm.environment.get("secret");

const t = Date.now(); // UnixTime
const uuid = require('uuid');
const nonce = uuid.v4();
const message = token + t + nonce;
const sign =
    CryptoJS.enc.Base64.stringify(
        CryptoJS.HmacSHA256(message, secret)
    );

pm.collectionVariables.set("sign", sign);
pm.collectionVariables.set("nonce", nonce);
pm.collectionVariables.set("t", t);

APIリクエストの追加&テスト(Postman)

いよいよAPIリクエストの追加をしていきますが、Collection内にFolderを作成して視認性を良くします。
Folderは、Collection名の3点メニューをクリックして、Add folderをクリックすれば作成できます。

作成したFolder毎に追加したAPIリクエストについて解説していきます。

デバイス情報取得

1. デバイス情報取得というFolder内にAPIリクエストを追加していきます。
APIリクエストは、追加したいFolderの3点メニューをクリックして、Add requestをクリックすることで追加できます。

APIリクエストの書き方について、デバイスリストを取得する例を挙げて説明していきます。

<登録デバイス一覧>

まず、HTTPメソッドとエンドポイント(URL)を指定します。この部分は、SwitchBot APIのREADME.mdを参考に入力しますが、今回はメソッドはGETでエンドポイントはhttps://api.switch-bot.com/v1.1/devicesとなります。
ただし、ベースのURLはコレクション変数で設定しているため、その変数を活用します。
変数を呼び出す際は、{{}}で囲むことで変数を使用できます。
そのため、今回はエンドポイントの部分は{{baseUrl}}/v1.1/devicesとなります。

次に、Headersの項目に、各種パラメータを設定します。こちらも公式のREADME.mdを参照すると、Request Headerの部分で4つのパラメータを含める必要があるとの支持がありますので、それに従ってパラメータを追加します。
なお、いずれのパラメータも変数化しているため、その変数を呼び出す形になります。詳細は以下の画像を参考にしてください。

これで、APIリクエストの設定ができましたので、テストしてみます。
右側にあるSendボタンをクリックすると、画面下のResponse欄に結果が表示されます。
結果はJSON形式で表示され、statusCodeが100なら成功です。その下にデバイスリストが表示されます。
自分の環境でやった例の画像を下に貼っておきます。
ここに表示されているdeviceIdをこの後の個別デバイスの設定用に使用します。

<個別デバイス情報>

次に、各デバイスの情報を取得するAPIリクエストを追加します。
こちらは、前述したようにデバイスの指定として、エンドポイント内にデバイスIDを指定する必要があります。

そこで、今回は以下の画像のようにエンドポイントを{{baseUrl}}/v1.1/devices/:deviceid/statusという形で指定しています。この中の、:deviceidと記載することで、その部分をパラメータ化することができます。
下のPath Variablesという項目にdeviceidというKeyが自動で追加されるため、Valueの欄に情報を取得したいデバイスIDを記載することができます。

なお、今回は更に{{deviceId}}という形でコレクション変数を追加しています。これは、ある特定のデバイスについて、複数のAPIリクエストを連続で実行したいときに、APIリクエスト毎にデバイスIDを書き換えるのが手間になると考えたためです。

デバイスIDを変数化するなら、エンドポイントを{{baseUrl}}/v1.1/devices/{{deviceId}}/statusとしても良いのではと思う人もいるかと思います。
実際、その記載方法でも問題なく動きます。ただし、今回はベースは変数化した共通の{{deviceId}}を使用するが、APIリクエストをデバイスIDを変えて何回も実行したい場合に、コレクション変数切り替え⏩APIリクエスト実行の手順を繰り返す場合、画面の切り替えが発生することから、Path Variables上でもパラメータを変更できる形としています。

こちらもデバイスIDを切り替えて実行すると、それぞれのデバイスの情報が取得できます。
温湿度計は温度や湿度、プラグミニは電圧や電流値などデバイスによって取得できる値は異なるので、詳細は公式ドキュメントを確認ください。
下の画像は、防水温湿度計に対して実行したレスポンス例です。

デバイス制御

次にデバイス制御のAPIリクエストを作成していきます。
今回使用したデバイスの中で制御リクエストに対応しているのは、以下2つのデバイスになります。

  • SwitchBot プラグミニ(JP)
  • SwitchBot ボット
<プラグミニ>

基本的に先ほどと変わりませんが、2箇所ほど変更しています。
1つは、HTTPメソッドが制御リクエストの場合、POSTになります。
もう1つは、Bodyにパラメータを指定しています。こちらもパラメータ内容はREADME.mdの内容を参考に設定していきますが、以下の画像のように、Body欄を選択して、[raw]-[JSON]を選択した状態でパラメータを記載します。
以下の画像は、給電ON時の画像になります。

給電ON、給電OFF、トグルそれぞれのjsonの記載は以下のようになります。

給電ON
{
    "command": "turnOn",
    "parameter": "default",
    "commandType": "command"
}
給電OFF
{
    "command": "turnOff",
    "parameter": "default",
    "commandType": "command"
}
トグル
{
    "command": "toggle",
    "parameter": "default",
    "commandType": "command"
}

テストする際は、プラグミニのデバイスIDを変数に設定した状態でそれぞれのAPIリクエストを実行し、プラグミニの給電状態が切り替わることが確認できればOKです。

<ボット>

ボットの場合もプラグミニとエンドポイントURLやBodyに設定するパラメータもほぼ同じです。
一点、注意点として、ボットには「Switchモード」と「Pressモード」の2種類があり、このモード変更はスマホアプリ上から行う必要があります。
「Switchモード」の場合は、ON/OFFの概念がありますが、「Pressモード」の場合は実行する度に元の位置に戻るため、APIリクエストは1種類になります。そのため、今回は「Switchモード」と「Pressモード」でFolderを分けてAPIリクエストを記載しています。パラメータ内容はREADME.mdの内容を参考に設定していきます。

ON、OFF、プレスそれぞれのjsonの記載は以下のようになります。

ON
{
    "command": "turnOn",
    "parameter": "default",
    "commandType": "command"
}
OFF
{
    "command": "turnOff",
    "parameter": "default",
    "commandType": "command"
}
プレス
{
    "command": "press",
    "parameter": "default",
    "commandType": "command"
}

テストする際は、「Switchモード」の状態でONとOFFのAPIリクエストを確認し、「Pressモード」の状態でプレスのAPIリクエストを確認できればOKです。

確認した限りでは、「Switchモード」の状態でプレスのAPIリクエストを実行するとエラーが返ってきました。
一方、「Pressモード」時にONとOFFのAPIリクエストを実行した場合は、いずれもプレス時と同様の動作をしているようでしたが、今回は判別しやすいように、Folder毎に分けています。

シーン制御

次にシーン制御のAPIリクエストを作成していきます。
シーンとは複数のSwitchBotデバイスの制御設定を予めひとまとめにして名前を付けておき、そのシーン制御をONにすると、一括でデバイス制御を行う機能となります。

以下に、参考になった記事を紹介します。似たような機能でオートメーションという機能もありますが、そちらについても以下の記事で紹介されています。

シーン制御を使うメリットとして、APIでは対応できない複雑な処理(e.g. ハブ2の赤外線機能で家電をONするなど)といった処理を予めシーンに登録しておくことで、APIリクエスト経由でも制御が可能になります。

公開されているAPIについては、登録シーンの一覧を取得するAPIと個別シーンの実行を行うAPIの2つになります。
それぞれ、公式のREADME.mdを参考にしながら実装します。

<登録シーン一覧>

基本的には、前述の<登録デバイス一覧>のAPIリクエストと作り方は一緒で、エンドポイントURLのみ変更しています。
自分の環境でやった例の画像を下に貼っておきます。
ここに表示されているsceneIdをこの後の<個別シーン実行>用に使用します。

<個別シーン実行>

個別シーンの実行も、<個別デバイス情報>のAPIリクエストと作り方はにてます。エンドポイントURL内にsceneIdを指定する必要があるため、前回同様パラメータを変数化しています。
なお、今回は情報取得ではなく、シーン実行という形になるため、HTTPメソッドはGETではなくPOSTになります。ただし、Body欄には特にパラメータは指定しなくてOKです。

テストする際は、APIリクエストを実行し、予め設定していたシーン通りにデバイスが制御されていればOKとなります。

Webhook

公式README.mdに記載されている最後のAPIとして、Webhookがあります。この機能は、スマホアプリでは設定できないため、現状API独自の機能となっています。

Webhook自体の説明はここでは省略しますが、いくつか参考となるサイトを挙げておきます。

Webhookを使用する場合、Webhook先のサービスが発行したURLをPostman側で指定する必要があるため、コレクション変数に{{webhookUrl}}という変数を追加しています。

なお、Webhook関係のAPIは全てPOSTメソッドを使います。

<Webhook登録>

新たにWebhookを登録するためのAPIリクエストになります。

パラメータはURL以外は基本固定値になります。deviceListについては、現状ALLのみサポートしているようです。

エンドポイントURL:{{baseUrl}}/v1.1/webhook/setupWebhook
HTTPメソッド:POST

Webhook登録
{
    "action":"setupWebhook",
    "url":"{{webhookUrl}}",
    "deviceList":"ALL"
}

登録に成功すればメッセージにsuccessと表示されます。既に登録済みの場合は、webhook is existというメッセージが返ってきます。

<Webhook URL取得、Webhook構成取得>

登録済みのWebhookのURLや構成情報を取得するAPIリクエストです。

エンドポイントURL:{{baseUrl}}/v1.1/webhook/queryWebhook
HTTPメソッド:POST

Webhook URL取得
{
    "action": "queryUrl"
}
Webhook構成取得
{
    "action": "queryDetails",
    "urls":["{{webhookUrl}}"]
}
<Webhook有効化、Webhook無効化>

登録したWebhookを無効化したり、再度有効化するためのAPIリクエストです。
enableパラメータのtrue/falseを返ることで、有効/無効を切り替えられます。

なお、ここで指定しているurlのパラメータに新たなWebhook URLを入力することで、URLを書き換えることも可能です。

エンドポイントURL:{{baseUrl}}/v1.1/webhook/updateWebhook
HTTPメソッド:POST

Webhook有効化
{
    "action": "updateWebhook",
    "config":{
        "url":"{{webhookUrl}}",
        "enable":true
    }
}
Webhook無効化
{
    "action": "updateWebhook",
    "config":{
        "url":"{{webhookUrl}}",
        "enable":false
    }
}
<Webhook削除>

登録したWebhookを削除するAPIリクエストです。先ほどの無効化と異なり、登録情報自体を削除します。

エンドポイントURL:{{baseUrl}}/v1.1/webhook/deleteWebhook
HTTPメソッド:POST

Webhook削除
{
    "action":"deleteWebhook",
    "url":"{{webhookUrl}}"
}

ここまででWebhookのAPIリクエストを一通り作成できたため、実際にWebhookが正しく動作するかテストしてみました。

しかし、TeamsやSlackでIncoming Webhookを試したところ上手く動作しませんでした(いつまで経っても通知がこない)。
なお、Postmanから直接Webhook先URLをPOSTで叩いた場合はWebhookが動作しており、原因は現状不明です。

そこで、一旦内容を解析するために、Azure Logic Appsを使用してTeamsにメッセージを送るフローを試したところ問題なくWebhook経由でTeamsにメッセージが届きました。

Azure Logic Appsのフローの詳細は省略しますが、内容を解析し、デバイスタイプが開閉センサまたはボットの場合のみ、Teamsのチャネルにメッセージを送るといった内容にしています。

こちらの記事でもWebhookはちゃんと動作しているようなので、Webhookが上手く動作するパターンもあるというのが、現状分かってる内容です。(とりあえず試してみるしかない・・・?)

ここまでで、README.mdに掲載されているAPIリクエストの登録は完了になります。
なお、本来は各APIの概要やパラメータなどをドキュメントに記載する必要があるのですが、今回は既にGitHubに公式のドキュメントがあることから、記載は最小限にして、後はGitHubへのリンクを張る形にしています。

◇おわりに

前述しましたが、今回のワークスペースはPostman上に公開しています。簡単に試してみたい場合は以下URLからforkして実行してみてください。

また、CollectionとEnvironmentをエクスポートしたjsonファイルをGitHub上でも公開していますので、そちらも参考にしてもらえればと思います。

記事は以上です。Postman Advent Calendar 2023の次の記事につなげたいと思います。

🔚END

9
4
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
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?