リモート開発メインのソフトウェア開発企業のエンジニアブログです

TypeScriptとNode.jsを使ってSwitchBotのDeviceListを確認する(リクエストの署名)

概要

前回VSCodeでのTS、Node.jsの開発実行環境を用意しました。

これを使ってSwitchBotAPIを利用する手始めとして、登録されているデバイスを確認したいと思います。

デバイスIDが確認できれば、機器の操作や状態の確認が出来ます。

しかし、SwitchBotAPI v1.1からリクエスト送信時に署名をする必要があるようです。

環境 前提条件

Windows11

VSCode 1.84.2 拡張機能Japanese Language インストール済み

Node.js v20.10.0

PowerShell 5.1.22621.2506

SwitchBotAPI v1.1

プロジェクトのファイル構造

ルートフォルダをtsとしています。

各種jsonの設定は前回の記事を御覧ください。

https://engineering.mobalab.net/2023/12/04/vscode%E3%81%A7typescript%E3%81%AEnode-js%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B/

プロジェクトのファイル構成

/ts/.vscode/launch.json
/ts/.vscode/tasks.json
/ts/dist/index.js
/ts/src/index.ts
/ts/package.json
/ts/tsconfig.json

Nodeモジュールのインストール

1.Powershell /ps/

npm install uuid
npm install --save @types/uuid

デバイスリストの確認

参考

https://github.com/OpenWonderLabs/SwitchBotAPI#javascript-example-code

こちらのコードを参考にTSで書いてみました。

TS初学者のため誤りや正しくない所が散見されると思いますが、ご容赦ください。

/ts/src/index.ts

import crypto from "crypto";
import https from "https";
import { v4 as uuidv4 } from "uuid";

const token: string = "YOUR_TOKEN";
const secret: string = "YOUR_SECRET";
const t: number = Date.now();
const nonce: string = uuidv4();
const data: string = token + t + nonce;
const signTerm: Buffer = crypto
  .createHmac("sha256", secret)
  .update(Buffer.from(data, "utf-8"))
  .digest();
const sign: string = signTerm.toString("base64");

const host: string = "api.switch-bot.com";
const path: string = "/v1.1/devices";

const postOptions: https.RequestOptions = {
  host: host,
  path: path,
  method: "GET",
  port: 443,
  headers: {
    "Content-Type": "application/json",
    Authorization: token,
    sign: sign,
    t: t,
    nonce: nonce,
  },
};

function getDevices(getOptions: https.RequestOptions): Promise<any> {
  return new Promise((resolve, reject) => {
    const req = https.request(getOptions, (res) => {
      let queue: Buffer[] = [];
      res.on("data", (chunk) => {
        queue.push(chunk);
      });
      res.on("end", () => {
        const data = Buffer.concat(queue);
        resolve(data.toString());
      });
    });
    req.on("error", (e) => {
      console.log(`request error:${JSON.stringify(e)}`);
      reject(e);
    });
    req.end();
  });
}

(async () => {
  try {
    const result = await getDevices(postOptions);
    JSON.parse(result).body.deviceList.forEach((devices: any) => {
      console.log(`devices:${JSON.stringify(devices)}\n`);
    });
    JSON.parse(result).body.infraredRemoteList.forEach(
      (infraredRemote: any) => {
        console.log(`infraredRemote:${JSON.stringify(infraredRemote)}\n`);
      }
    );
  } catch (e) {
    console.log(`error:${JSON.stringify(e)}`);
  }
})();

YOUR_TOKENとYOUR_SECRETを書き換える必要があります。

TokenとSecretの取得

23/12/09 現在、APIv1.1ではiOS,Androidアプリ上でTokenとSecretを取得することができます。

https://support.switch-bot.com/hc/ja/articles/12822710195351-%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AE%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95

簡単に記述すると、プロフィール-設定-アプリバージョン、アプリバージョンを複数回タップすると開発者オプションが表示されます。開発者オプションを開くとTokenとSecretが表示されており、Secretはタップするごとに変更出来るようです。

リクエストの署名について

APIへのリクエストにはヘッダーに署名情報を付与する必要があるようです。

  headers: {
    "Content-Type": "application/json",
    Authorization: token,
    sign: sign,
    t: t,
    nonce: nonce,
  },

Authorizationには取得したTokenをそのまま使用します。

signはtoken + t + nonceを結合した文字列をsecret使って暗号化したものをbase64に変換しています。

この点については各言語サンプルがあるため、基本的にはそれに従って処理すればよいと思います。

tはUNIX時間の整数。

nonceには任意の文字列を入れる様です。今回はUUIDを入れることでリクエストごとに変えています。

実行結果

{
  "result": {
    "statusCode": 100,
    "body": {
      "deviceList": [
        {
          "deviceId": "xxxx",
          "deviceName": "ハブ2",
          "deviceType": "Hub 2",
          "enableCloudService": true,
          "hubDeviceId": "xxxx"
        },
        {
          "deviceId": "xxxx",
          "deviceName": "人感センサー",
          "deviceType": "Motion Sensor",
          "enableCloudService": true,
          "hubDeviceId": "xxxx"
        }
      ],
      "infraredRemoteList": [
        {
          "deviceId": "xxxx",
          "deviceName": "エアコン",
          "remoteType": "Air Conditioner",
          "hubDeviceId": "xxxx"
        }
      ]
    },
    "message": "success"
  }
}

レスポンスはJsonで帰ってきます。

SwitchBotに登録した製品とHUBに設定したリモコンが表示されました。

この時確認できたdeviceIdを使って特定機器の情報の取得や命令ができます。

まとめ

今回はTSでSwitchBotAPIに署名したリクエストを送信して製品のdeviceIdを確認することができました。

Node.jsで動くようにすることやTSへの書き換えは、公式のJSのサンプルから比較的簡単に作成でき、

署名とリクエストの部分さえ作ってしまえばAPIの各種操作が簡単に行うことができました。

次回はSwitchbotAPIを利用してWebhookを設定し、Lambdaを経由してDiscordにメッセージを飛ばすものを作成したいと考えています。

← 前の投稿

GitHub の Pull request は Squash and merge にしてみている

次の投稿 →

VSCodeでTypeScriptのNode.jsを実行する

コメントを残す