VSCodeから家電(SwitchBot)を制御して快適なスマート家電ライフを送ろう

## SwitchBotが便利

最近、アプリで制御できるスマートな家電が増えていますよね？

例えば、今回ご紹介する「[SwitchBot](https://www.switchbot.jp/)」も、とっても便利なんです。スマートではない旧来的な家電であっても制御できる赤外線を出してくれるリモコンになってくれるガジェット(`SwitchBot ハブ`)や、お風呂のスイッチなどの物理的なスイッチを押すことができるガジェット(`SwitchBot ボット`(←微妙にネーミングが分かりづらい))があったりします。

https://www.switchbot.jp/

私は `SwitchBot ハブ` を使って、スマートではない家電として、古めのテレビのOn/Off、チャンネル変更や、エアコンのOn/Off、運転モードの変更を SwitchBotのアプリから行えるようにして、まるでスマートな家電のように使えるようにしています。
( 寒い冬の朝でも布団の中から暖房をOnにすることができるのでとっても便利です。 )

ちなみに SwitchBotのアプリ画面 はこんな感じです。様々な SwitchBotのガジェットや家電を登録でき、アプリから家電の制御が可能です。

![Screenshot_20221207-140633.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21106/b4b4e2ea-1b2f-3113-b191-a2520bd75fa6.png)

さらに SwitchBot は アレクサ や Google Home に対応しているので、スマートでない家電でも声で制御できるようになるのも嬉しいポイントです。

## 1. コーディング中に家電を操作したい

コーディング中に家電の操作をしたくなることがあります。
アレクサに音声で頼んだり、SwitchBotのアプリを起動してアプリ画面から操作しても良いのですが、ノリノリのコーディングのテンポが崩れる感はあります。やはり、**VSCodeから家電を操作したい** ですよね。

本記事では、VSCodeから家電の制御をできるようにする方法として、VSCodeの `REST Client` 拡張機能を活用して、家電のAPIを呼び出すコードを自動生成し、VSCodeの `タスク` の機能を活用して、簡単にコードを呼び出せるようにする方法をご紹介します。

## 2. SwitchBotAPI を試してみる

SwitchBot には API が用意されているようです。以下の公式ブログやドキュメントを参照して、ちょっと叩いてみましょう。

公式ブログ:

https://blog.switchbot.jp/announcement/api-v1-1/

ドキュメント(GitHub):

https://github.com/OpenWonderLabs/SwitchBotAPI

前準備として、公式ブログに記載されている説明の通り、SwitchBotのアプリ上でちょっとしたイースターエッグ的な操作を行い、隠されている `開発者向けオプション` を出現させ、トークンとクライアントシークレットの文字列を表示し、控えておきます。

![Screenshot_20221207-140728.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21106/3f50737a-d8b5-45b9-16bf-fc8daaa56442.png)

## 3. VSCode の REST Client 拡張機能でAPIを叩く

さっそくVSCodeからAPIを叩きます。こんなときは大人気の拡張機能「[REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) 」の出番です。

https://marketplace.visualstudio.com/items?itemName=humao.rest-client

VSCodeで テキストファイル `hoge.rest` を作成し、送信したいHTTPリクエスト内容を以下のように記述します。

```
GET https://api.switch-bot.com/v1.1/devices
Authorization: 控えておいたトークン
t: 13桁のUnixタイムスタンプ
sign: シグネチャ文字列
nonce: ランダムな文字列(uuidなど)
```

すると、`REST Client` 拡張機能により、以下スクリーンショット画面左のように、リクエスト内容のテキストの上部に`Send Request` というボタンが表示されます。
`Send Request` ボタンを押下するとリクエストを送信でき、以下スクリーンショット画面右のようにレスポンスを表示してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21106/90bbe8ca-3ad3-5577-8909-cbe5dddcd7dd.png)

このように`REST Client` 拡張機能はさくっとAPIの利用方法の確認や検証をする際に便利です。検証したいリクエストの内容をテキストで記述・記録できるのが良いですね。

なお、`t` や`sign` は、前述のドキュメントに 記載されている Python、JavaScript、C#、Java のサンプルコードで生成可能です。
`nonce` はサンプルコードでは空文字ですが、uuidなどランダムな文字列を生成して指定するとより良いと思います。

以下は Pythonのサンプルコードです。

```python
import time
import hashlib
import hmac
import base64

# open token
token = '' # copy and paste from the SwitchBot app V6.14 or later
# secret key
secret = '' # copy and paste from the SwitchBot app V6.14 or later
nonce = ''
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())
print ('Authorization: {}'.format(token))
print ('t: {}'.format(t))
print ('sign: {}'.format(str(sign, 'utf-8')))
print ('nonce: {}'.format(nonce))
```

レスポンスボディは以下のようなjsonとなっており、SwitchBotに登録している家電の一覧が含まれています。
私の場合、`温湿度計`、`Hub Mini 3E`、`テレビ`、`エアコン`の4つの家電が含まれています。

```bash
HTTP/1.1 200 OK
Date: Wed, 07 Dec 2022 09:28:51 GMT
Content-Type: application/json
Content-Length: 592
Connection: close
x-amzn-RequestId: 1e7b2b74-7f37-4cc1-a7d0-414b0479d031
x-amz-apigw-id: cxNxBEE-IAMFyUw=
X-Amzn-Trace-Id: Root=1-63905cd3-3130e5e74742e8e815ccae2e;Sampled=0

{
  "statusCode": 100,
  "body": {
    "deviceList": [
      {
        "deviceId": "xxxxxxxxxxx",
        "deviceName": "温湿度計",
        "deviceType": "Meter",
        "enableCloudService": true,
        "hubDeviceId": "xxxxxxxxxxx"
      },
      {
        "deviceId": "xxxxxxxxxxx",
        "deviceName": "Hub Mini 3E",
        "deviceType": "Hub Mini",
        "enableCloudService": false,
        "hubDeviceId": "xxxxxxxxxxx"
      }
    ],
    "infraredRemoteList": [
      {
        "deviceId": "xx-xxxxxxxxxxx-xxxxxxxxxxx",
        "deviceName": "テレビ",
        "remoteType": "TV",
        "hubDeviceId": "xxxxxxxxxxx"
      },
      {
        "deviceId": "xx-xxxxxxxxxxx-xxxxxxxxxxx",
        "deviceName": "エアコン",
        "remoteType": "Air Conditioner",
        "hubDeviceId": "xxxxxxxxxxx"
      }
    ]
  },
  "message": "success"
}
```

各家電を操作するAPIを叩く際、`deviceId` が必要となりますので控えておきます。

## 4. VSCode の REST Client 拡張機能で各家電を操作する

さっそく、それぞれの家電をAPIで操作してみましょう。
テレビの電源をOnとする以下のようなリクエスト内容を `hoge.rest` に追記します。
( リクエストを複数記述する際、`###` で区切ることができます。 )

```bash
### テレビをOnにするぞ

POST https://api.switch-bot.com/v1.1/devices/対象の家電(テレビやエアコンなど)のdeviceId/commands
Authorization: xxxxxxxxxxx
t: xxxxxxxxxxx
sign: xxxxxxxxxxx
nonce: xxxxxxxxxxx

{
    "command": "turnOn",
    "commandType": "command"
}
```

上記のリクエストを送信後、以下のようなレスポンスが返ってくればOKです。
普段、SwitchBotのアプリから操作するときと同様に、`SwitchBot ハブ` のLEDが点滅し、赤外線を発してテレビの電源をOnにしてくれれば成功です！

```bash
HTTP/1.1 200 OK
Date: Wed, 07 Dec 2022 09:33:32 GMT
Content-Type: application/json
Content-Length: 149
Connection: close
x-amzn-RequestId: 4e4d9487-2de7-4f67-ba80-fc81b0d66fbb
x-amz-apigw-id: cxOdAEbBoAMFpUQ=
X-Amzn-Trace-Id: Root=1-63905dec-61309c4d7a4e7f995bedc243;Sampled=0

{
  "statusCode": 100,
  "body": {
    "items": [
      {
        "deviceID": "xx-xxxxxxxxxxx-xxxxxxxxxxx",
        "code": 100,
        "status": {
          "power": 1
        },
        "message": "success"
      }
    ]
  },
  "message": "success"
}
```

ここまでの検証により、VSCode の `REST Client` 拡張機能を使って SwitchBotAPI の使用方法を確認することが出来ました。

温湿度計やエアコンなど、その他の家電も同じように操作できますので、各家電のAPIの呼び出し方につきましてはGitHubのドキュメントをご参照いただくと良いと思います。

この方法でもVSCode から家電の操作を可能にすることができていますが、`タスク`化することでもう少し簡単に制御できるようにしてみたいと思います。

## 5. VSCode の タスク の機能で家電を操作する

VSCodeには`タスク`という機能があり、ビルドやテストなどのコマンドを登録しておいてコマンドパレットから呼び出すことができます。

https://code.visualstudio.com/docs/editor/tasks

任意のスクリプトも登録できますので、SwitchBotAPI を叩くスクリプトを登録してみましょう。

### 5.1. 家電を操作するスクリプトを準備する

ここでも `REST Client` 拡張機能が活躍します。リクエストを送信するコードを自動生成できるんです。
`hoge.rest` に記述したリクエスト文字列上にカーソルがある状態で、コマンドパレットから `Copy Request As cURL` を呼び出すことで、リクエストを送信するためのcurl コマンド文字列を自動生成してくれます。
先ほどまでの方法で検証したリクエストと同じリクエストを送信するスクリプトを書く際に便利です。

以下は 温湿度計 のstatus取得APIを利用して温度や湿度を取得・表示するスクリプトの例です。
`SIGN` は前述のドキュメントに記載されているサンプルコードで生成しています。
`TOKEN`、`SECRET` は `params.sh` に記載しています。

```bash
#!/bin/bash

# env
. ./params.sh

# params
deviceId=xxxxxxxxxxx

# generate SIGN
NONCE=$(uuidgen) # uuid文字列
TIMESTAMP=$(date +%s%3N) # 13桁(ミリ秒まで含む)
SIGN=$(python3 sign.py ${TOKEN} ${SECRET} ${NONCE} ${TIMESTAMP})

# request
curl -s --request GET \
--url https://api.switch-bot.com/v1.1/devices/${deviceId}/status \
--header "Authorization: ${TOKEN}" \
--header "sign: ${SIGN}" \
--header "nonce: ${NONCE}" \
--header "t: ${TIMESTAMP}" \
| jq -r '.body | "温度は" + (.temperature|tostring) + "℃です！" + "\n湿度は" + (.humidity|tostring) + "％です！"'
```

その他、エアコンやテレビの制御を行うスクリプト(  `air-conditioner.sh` や `tv.sh` ) も同様に準備可能です。
今回準備した全ての設定ファイルやスクリプトは以下に格納しています。

https://github.com/loftkun/SwitchBotAPI-example

なお、今回はシェルスクリプトを作成するために `Rest Client` 拡張機能を活用して curl のコマンド文字列を自動生成しましたが、
コマンドパレットから `Rest Client: Generate Code Snippet` を呼び出すことで、様々なプログラミング言語でリクエストを送信するコードを自動生成することも可能です。

`Rest Client` 拡張機能を活用したAPI呼び出しの検証と、リクエスト送信コードの自動生成、本当に便利ですね。

### 5.2. 家電を操作するスクリプトをVSCodeのタスクに登録する

作成したスクリプトをVSCodeから簡単に呼び出せるよう`タスク`に登録します。
コマンドパレットから`Tasks: Configure Task` -> `Create tasks.json file from template` -> `Others` を呼び出します。
すると、`.vscode` ディレクトリ配下に 以下のような内容で サンプルのタスクが定義されている `tasks.json` が生成されます。

`echo Hello` というコマンドを実行する `echo` という名前のタスク定義が含まれています。

```json
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "echo",
            "type": "shell",
            "command": "echo Hello"
        }
    ]
}
```

タスクを呼び指すには、`Tasks: Run Task` -> `echo` -> `Continue without scanning the task output` を実行します。
`echo Hello` というコマンドが実行され、ターミナルに `Hello` と表示されることが分かります。
これが タスクの基本的な使用方法です。

ここまで来ればあとは簡単です。
`tasks.json` に 様々な家電を制御するスクリプトを呼び出すタスクを追記していけばOKです。

今回は以下のようなタスクを登録してみました。

|             タスク名              |               タスクの内容               |      スクリプト・引数      |
| --------------------------------- | ---------------------------------------- | -------------------------- |
| SwitchBot get devices             | 家電の一覧を取得する。deviceIDの確認用。 | get-devices.sh             |
| SwitchBot get meter               | 温湿度計の情報(温度、湿度)を取得する     | get-meter.sh               |
| SwitchBot turnOn TV               | テレビをOnにする                         | tv.sh turnOn               |
| SwitchBot turnOff TV              | テレビをOffにする                        | tv.sh turnOff              |
| SwitchBot turnOn Air Conditioner  | エアコンをOnにする                       | air-conditioner.sh turnOn  |
| SwitchBot turnOff Air Conditioner | エアコンをOffにする                      | air-conditioner.sh turnOff |

以下は各タスクの定義例です。

```json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "SwitchBot get devices",
            "type": "shell",
            "command": "/bin/bash /home/loft/xxx/get-devices.sh",
            "windows": {
                "command": "echo dummy"
            }
        },
        {
            "label": "SwitchBot get meter",
            "type": "shell",
            "command": "/bin/bash /home/loft/xxx/get-meter.sh",
            "windows": {
                "command": "echo dummy"
            },
            "problemMatcher": []
        },
        {
            "label": "SwitchBot turnOn TV",
            "type": "shell",
            "command": "/bin/bash /home/loft/xxx/tv.sh turnOn",
            "windows": {
                "command": "echo dummy"
            }
        }
        ,
        {
            "label": "SwitchBot turnOff TV",
            "type": "shell",
            "command": "/bin/bash /home/loft/xxx/tv.sh turnOff",
            "windows": {
                "command": "echo dummy"
            }
        },
        {
            "label": "SwitchBot turnOn Air Conditioner",
            "type": "shell",
            "command": "/bin/bash /home/loft/xxx/air-conditioner.sh turnOn",
            "windows": {
                "command": "echo dummy"
            }
        }
        ,
        {
            "label": "SwitchBot turnOff Air Conditioner",
            "type": "shell",
            "command": "/bin/bash /home/loft/xxx/air-conditioner.sh turnOff",
            "windows": {
                "command": "echo dummy"
            }
        }
    ]
}
```

なお、コマンドパレットから `Tasks: Open User Tasks` を実行することで開かれる `tasks.json` に記述すると、
ワークスペースレベルではなく、ユーザーレベルのタスク定義とすることができ、
どのワークスペースからもタスクを呼び出せるようになり便利です。

ご参考(User level tasks):

https://code.visualstudio.com/docs/editor/tasks#_user-level-tasks

### 5.3. VSCodeから家電を操作するタスクを実行する

各家電を操作する `タスク`を定義できましたので、早速呼び出していきましょう。
コマンドプロンプトから `Tasks Run Task` を呼び出すと、以下のようにタスクの一覧が表示され、簡単に呼び出すことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21106/26bcd366-8aff-399e-8e6d-db2e245aaf8d.png)

試しにテレビをOnにするタスク `SwitchBot turnOn TV` を実行してみました。
レスポンスに`success` が含まれており、API呼び出しに成功しています。
また、テレビも付きました(画像や動画がないと伝わりづらいかと思いますが・・・^^)！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21106/a1aacb57-4adb-4f70-3d43-f55eed4e4ab6.png)

温湿度計の情報(温度、湿度)を`SwitchBot get meter` タスクで取得してみると、以下のように表示されました。
温湿度計ガジェットの液晶画面の表示とも一致しており、温湿度計の情報取得にも成功しています！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21106/4b075529-2e11-5e40-5c26-1a1f71d7eef5.png)

エアコンのOn・Offも今回定義したタスクを呼び出すだけで制御可能となりました！
なお、テレビは、チャンネル変更(`SetChannel`)や音量ボリュームの増減(`volumeAdd`、`volumeSub`)、エアコンは、温度や冷暖房モードの設定(`setAll`)ができるAPIも用意されており、そのような操作も今回ご紹介した手順によりタスクにすることも可能です。

## 6. まとめ

VSCodeから家電の制御をできるようにする方法として、VSCodeの `REST Client` 拡張機能と `タスク` の機能を活用しました。

`REST Client` 拡張機能を活用して、APIの使用方法を検証し、
検証済みの方法でAPIを呼び出せるcurlコマンド(もしくは各種プログラム言語のソースコード)文字列を生成してスクリプト作成に役立てることができました。
作成したスクリプトをVSCodeの`タスク`に登録することでVSCodeから簡単に呼び出すことができるようになりました。

今回は SwitchBot を題材としましたが、アイディア次第で様々な作業をVSCodeから素早く呼び出して実行できるようになりそうですね。
本記事でご紹介した方法が日々の作業効率化のご参考となりましたら幸いです。