【12日目】部屋の温湿度をSwitchBotで取得してDiscordに自動で送る（Node.js）

# はじめに
こんにちは、なりかくんです。
今回は、Node.jsで部屋に置いている温湿度計（SwitchBot）でDiscordに自動で送るプログラムを作ってみようと思います。

# 今回使う機器
今回は、SwitchBot 温湿度計とSwitchBot ハブミニです。

SwitchBot 温湿度計は長く使っていますが全く電池を交換していないのにずっと動いていますしかなり正確に温度と湿度を見ることが出来るので重宝しています。そしてなんといってもスマホからグラフ化してみることが出来るのがワンポイントです。

https://www.switchbot.jp/products/switchbot-meter

SwitchBot ハブミニは、温湿度計をインターネットから操作できるようにするだけではなく、部屋の赤外線などで操作できる家電もスマホなどで外から操作できるように出来るという優れたものです。

https://www.switchbot.jp/collections/home-automation/products/switchbot-hub-mini

# SwitchBot API
今回は、SwitchBotにあるAPIを使って温度と湿度を取得します。なお、このAPIを使うにはハブミニが必要になります。
SwitchBot APIの詳細の仕様はGitHubに公開されていますのでそちらをお読みください。

https://github.com/OpenWonderLabs/SwitchBotAPI

まあ、仕様書なんて読まなくても非常に簡単に使うことが出来るのですが（笑）

API KeyとClient Secretの取得はSwitchBotのアプリから行う事が出来ます。
[プロフィール] -> [設定]で、[アプリのバージョン]を10回タップすることで開発者オプションが表示されます。
そこにAPI KeyとClient Secretが表示されます。

# SwitchBotのDeviceIdを取得する。
まず、温湿度計のDeviceIdを取得する必要があります。以下のURLから取得できます。
```
GET https://api.switch-bot.com/v1.1/devices
```

以下のコードで取得できます。
```js:switchbot.js Get DeviceId
const request = require("request");
const crypto = require("crypto");

const token = "Token";
const secret = "Client Secret";
const t = Date.now();
const nonce = "discordSwitchBot";
const data = token + t + nonce;
const signTerm = crypto.createHmac('sha256', secret)
    .update(Buffer.from(data, 'utf-8'))
    .digest();
const sign = signTerm.toString("base64");

let result = getDeviceId();
console.log(result);

async function getDeviceId () {
    let getDevices = await getRequest({
        url: "https://api.switch-bot.com/v1.1/devices",
        json: true,
        headers: {
            "Authorization": token,
            "sign": sign,
            "nonce": nonce,
            "t": t
        }
    });
    return getDevices.body;
}

function getRequest(option) {
    return new Promise((resolve, reject) => {
        request(option, function (error, response, body) {
            if (error) {
                reject(error);
            } else {
                resolve(body);
            }
        });
    });
}
```

これで取得すると、私の環境では以下のように出力されます。（ID等はすべて`XXXXXXXXXX`で隠しています。）
```js
{
  deviceList: [
    {
      deviceId: 'XXXXXXXXXX',
      deviceName: 'なりかくんのハブミニ',
      deviceType: 'Hub Mini',
      hubDeviceId: '000000000000'
    },
    {
      deviceId: 'XXXXXXXXXX',
      deviceName: 'なりかくんの温湿度計',
      deviceType: 'Meter',
      enableCloudService: true,
      hubDeviceId: 'XXXXXXXXXX'
    }
  ],
  infraredRemoteList: [
    {
      deviceId: 'XXXXXXXXXX',
      deviceName: 'なりかくんのエアコン',
      remoteType: 'Air Conditioner',
      hubDeviceId: 'XXXXXXXXXX'
    }
  ]
}
```
今回は、これの温湿度計のDeviceIdを利用します。これをメモしておきましょう。

# 温度と湿度を取得する
次に先ほど取得したDeviceIdから温湿度計のデバイスステータスを確認して、温度と湿度を取得します。
以下のURLから取得できます。
```
GET https://api.switch-bot.com/v1.1/devices/<DeviceId>/status
```
これらをまとめて先ほど作ったプログラムと合わせるとこのようなコードを書くことが出来ます。
```js
async function getDeviceStatus (Id) {
    let getDevices = await getRequest({
        url: `https://api.switch-bot.com/v1.1/devices/${Id}/status`,
        json: true,
        headers: {
            "Authorization": token,
            "sign": sign,
            "nonce": nonce,
            "t": t
        }
    });
    return [getDevices.body.humidity, getDevices.body.temperature];
}
```
これを実行すると配列として返ってきます。配列は、`[getDevices.body.humidity, getDevices.body.temperature]`としているので、`humidity`が湿度、`temperature`が温度となります。
この記事を書いている時点で、以下の配列が出力されました。
```json
[ 39, 23 ]
```

# すべて組み合わせて1分毎に送る
では、先ほど紹介したコードをすべて組み合わせて1分毎にDiscordに送信するプログラムを作ります。
Discordへの送信は、WebHookを使って送信します。WebHookでの送信は9日目と11日目に扱っているのでそちらをご覧ください。

https://qiita.com/narikakun/items/2d606ba58d97d56fe3fb

今回作ったコード全体はこちらになります。
```js:switchbot.js
const request = require("request");
const crypto = require("crypto");

const token = "Token";
const secret = "Secret";
const t = Date.now();
const nonce = "discordSwitchBot";
const data = token + t + nonce;
const signTerm = crypto.createHmac('sha256', secret)
    .update(Buffer.from(data, 'utf-8'))
    .digest();
const sign = signTerm.toString("base64");

const deviceId = "DeviceId";

sendData();
setInterval(sendData, 60000);

async function sendData () {
    let getResult = await getDeviceStatus(deviceId);
    let time = parseInt(new Date().getTime()/1000);
    await getRequest({
        url: "WebHook URL",
        method: "POST",
        json: {
            content: `温度: ${getResult[1]}° , 湿度: ${getResult[0]}% (<t:${time}>)`
        }
    });
}

async function getDeviceStatus (Id) {
    let getDevices = await getRequest({
        url: `https://api.switch-bot.com/v1.1/devices/${Id}/status`,
        json: true,
        headers: {
            "Authorization": token,
            "sign": sign,
            "nonce": nonce,
            "t": t
        }
    });
    return [getDevices.body.humidity, getDevices.body.temperature];
}


async function getDeviceId () {
    let getDevices = await getRequest({
        url: "https://api.switch-bot.com/v1.1/devices",
        json: true,
        headers: {
            "Authorization": token,
            "sign": sign,
            "nonce": nonce,
            "t": t
        }
    });
    return getDevices.body;
}

function getRequest(option) {
    return new Promise((resolve, reject) => {
        request(option, function (error, response, body) {
            if (error) {
                reject(error);
            } else {
                resolve(body);
            }
        });
    });
}
```

これを実行してみると、以下のように毎分温度と湿度が送信されるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/903fd204-1684-49d8-e6fc-deefcb619061.png)

# 最後に
SwitchBotを活用してほかにもいろいろなことが出来るような気がしてきました。
以上です、最後までお読みいただきありがとうございました。