Switchbot API V1.1のアクセスに必要なヘッダーを作る方法を調べました

# 事の始まり
Switchbotのデータを読み込んだり、操作するために必要なことを調べていたら、Switchbot APIを利用するのが良さそうだと言うことで、[【SwitchBot】基本的な API の使い方](https://note.com/klayer123/n/nb14086840351)と言う記事に辿り着きました。とりあえず試してみようと思ったのですが、なぜかエラーが発生。コピペだけで済ましているので、エラーの本質的な理由が分かりませんでした。
## 何が悪かったのか、結論
簡単に書くと、参考記事の時とAPIのバージョンが変わっていました。バージョンが変わっていようと、今でも古いv1.0は残っているので、とりあえず動作しないかと色々原因を追求したところ、v1.0のAPIでは新しいデバイス（当方の環境では[Switchbotキーパッドタッチ](https://www.switchbot.jp/collections/new-products/products/switchbot-keypad-touch)が該当）の情報を返すことができないと言うのが理由でした。新しめのデバイスを利用するには否が応でもv1.1に対応する必要がありました。

## 動作確認環境
- Linux(Raspberry Pi) or macos
- Python3（ちょっと修正すればPython2でも動くはずです）

## Switchbot API V1.1について
[Swithbot API](https://github.com/OpenWonderLabs/SwitchBotAPI)の最初の方の記述を見ると、結構最近にAPIの仕様が変わったようです。以前のバージョンではtoken（APIキー）だけで利用でしたのですが、V1.1では

- token
- secret（Switchbot App  V6.14以降で取得可）
- t（13桁のタイムスタンプ）
- sign（特定のアルゴリズムで作成した文字列）
- nonce （利用するプログラムで生成したUUIDキー）

これらが必須の情報だそうです。

上記APIのページにはPython(2or3)とjavascriptでの作成サンプルがありましたので、これをまんま利用しました。

```
#!/usr/bin/env python3
# coding: utf-8

''' Create Switchbot sign header '''

import time
import hashlib
import hmac
import base64
import json
import uuid

def gensign(token, secret):
    '''
    Generate Switchbot API v1.1 sign header
    Args:
        token: string  :copy and paste from the SwitchBot app V6.14 or later
        secret: string :copy and paste from the SwitchBot app V6.14 or later
    Returns:
         Switchbot API v1.1 sign header
    '''

    nonce = str(uuid.uuid4())
    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())
    
    header={}
    header["Authorization"] = token
    header["sign"] = str(sign, 'utf-8')
    header["t"] = str(t)
    header["nonce"] = nonce

    return header
```
(https://gist.github.com/iCarrot0605/472dd85f887985a67b9f956070cf9864)

コードの難しいことは分かりませんが、「token、t、nonce」を繋ぎ合わせた文字列をsecretを使って署名？することでsignは出来上がります。
　nonceはuuid.uuid4()を使ってみました。元々のサンプルにあるように何も指定しなくても動作します。

tokenとsecretはSwitchbot App（V6.14以降）で、「プロフィール」＞「設定」へと進み、「アプリバージョン」のフィールドを10回タップすると表示される「開発者向けオプション」から取得することができます。

## APIを利用してみる
サンプルコードは[【SwitchBot】基本的な API の使い方](https://note.com/klayer123/n/nb14086840351)にあるコードを少し修正しました。上に書いたコード（switchbot_sign.py）と同じディレクトリに以下のコードを置きます。
```
#!/usr/bin/env python3
# coding: utf-8

import requests
import json
import switchbot_sign

token = '' # copy and paste from the SwitchBot app V6.14 or later
secret = '' # copy and paste from the SwitchBot app V6.14 or later

header = switchbot_sign.gensign(token, secret)
# Get all device information in your switchbot hub
response = requests.get("https://api.switch-bot.com/v1.1/devices", headers=header)
devices  = json.loads(response.text)

# Get switchbot bot "deviceId" in all device information
bots_id  = [device["deviceId"] for device in devices['body']['deviceList'] if "Bot" == device["deviceType"]]


# Get all switchbot bot power state and output on your display
for bot_id in bots_id:
    response = requests.get("https://api.switch-bot.com/v1.1/devices/" + bot_id + "/status", headers=header)
    bot      = json.loads(response.text)
    power    = bot['body']['power']
    
    print("bot id (" + bot_id + ") power : " + power)
```

あとは
```
python3 （保存したスクリプト名)
```
実行結果
```
bot id (XXXXXXXX) power : off
```
となるはずです。

## APIの利用について
1日に利用できる回数が10000回です。上記のサンプルスクリプトでは2回APIを利用しています。よっぽどのことがないと使い切ることはないと思いますが。

# まとめ
まとめというよりは初めてのQiitaでの記事作成にMarkdown記法の勉強から始まりました。ちゃんとした体裁になっているかも良く分かりませんが、誰かの参考になれば幸いです。