中華製スマートプラグを node で制御する

# ⚠このセットアップ方法は非推奨です！

2020/5/2追記：**この方法は deprecated になりました。**
新しいセットアップ方法は次の記事にありますので、そちらを参照してください。

[新版・中華製スマートプラグを node で制御する](https://qiita.com/plageoj/items/dd2f1c8b55c39625d550)

# スマートプラグを API で叩きたい

Amazonで [スマートプラグ](https://www.amazon.co.jp/gp/product/B07QKTNFW9) を見つけたので購入してみました。

公式の言うところによると、こいつは Google Home / Alexa / IFTTT との連携が
可能とのこと（IFTTTのみ動作確認しました）。おうちハックがはかどりそうです。

セットアップ後、スマートフォンアプリからはほとんどラグなく操作できるのに、
IFTTT 経由だと最大 10秒近く遅延することがあったので、API で直接叩けたらいいのにな……

と思っていたのですが、ちょいと面倒だったので記事にしておきます。

## デバイス ID を調べる

セットアップにはアプリが必要です。
今回指定されたのは [Smart Life](https://play.google.com/store/apps/details?id=com.tuya.smartlife) でしたが、デベロッパーが Tuya.Inc になっているものは
全部同じ方法でいけると思います（未検証）。

まずはアプリを使ってデバイスをセットアップしておきます。

API を使う場合の設定方法は [github](https://github.com/codetheweb/tuyapi/blob/master/docs/SETUP.md) に書いてありますが、
不親切なのでここにも書いておきます。

デバイスが Wi-Fi に繋がったら、PC に Tuya API CLI とプロキシツールをインストールします。

```bash
$ npm i -g @tuyapi/cli
$ npm i -g anyproxy
```

オレオレルート証明書を生成します。

コマンド実行後は証明書のインストールを促されますが、この証明書は
スマートフォンからの通信を傍受するために使うので、PCにインストールする
必要はありません。

```bash
$ anyproxy-ca
```

ここで生成した証明書をスマートフォンにインストールします。
あらかじめ、スマートフォンと PC を同じネットワークに接続しておき、お互いに
見えていることを確認します。

```bash
$ tuya-cli list-app
Scan this QR code with your phone to setup the certificate:
Set your HTTP proxy IP to 169.254.95.40 with port 8001.
```

コマンドを実行すると QR コードが表示されるので、これを読み取ればよいのですが
PC に複数のネットワークが設定されているときはウソのアドレスが表示される
ことがあるようです。

QR コードを読み取っても証明書のダウンロードが始まらなければ、スマートフォンの
URL 入力欄で IP アドレスを疎通ができるものに手動で書き換えてみてください。

証明書をインストールするとき、タイプには `VPNs and apps` を選択します。

この状態で、**スマートフォン側で**接続中のネットワークのプロキシ設定を指示されたものに変更します。
さきほど IP アドレスが間違っていたなら、プロキシのホストも変更します。

設定が終わったら Smart Life アプリのデバイス一覧を表示し、プルダウンして更新すると
登録されているデバイスの ID と key を取得できます。

```
Devices(s):
[
  { id: '42122031840d8e8b', key: '*****' },
  { id: '42572234807d3a49', key: '*****' },
  { id: '42122031cc50e3c3', key: '*****' }
]
```

英語が間違っているのはご愛嬌です。

## API を叩く

ID と key が取得できたら、あとは簡単です。
[codetheweb/tuyapi](https://github.com/codetheweb/tuyapi) をダウンロードしてきて、readme にある通り書けば動きます。

```bash
$ npm i -S codetheweb/tuyapi
```

```javascript:readmeより転載
const TuyAPI = require('tuyapi');

const device = new TuyAPI({
  id: 'xxxxxxxxxxxxxxxxxxxx',
  key: 'xxxxxxxxxxxxxxxx'});

let stateHasChanged = false;

// Find device on network
device.find().then(() => {
  // Connect to device
  device.connect();
});

// Add event listeners
device.on('connected', () => {
  console.log('Connected to device!');
});

device.on('disconnected', () => {
  console.log('Disconnected from device.');
});

device.on('error', error => {
  console.log('Error!', error);
});

device.on('data', data => {
  console.log('Data from device:', data);

  console.log(`Boolean status of default property: ${data.dps['1']}.`);

  // Set default property to opposite
  if (!stateHasChanged) {
    device.set({set: !(data.dps['1'])});

    // Otherwise we'll be stuck in an endless
    // loop of toggling the state.
    stateHasChanged = true;
  }
});

// Disconnect after 10 seconds
setTimeout(() => { device.disconnect(); }, 10000);
```

ちなみに、`on('data')` で取得できる `data` はこんな感じなのですが、

```javascript:data
{
  devId: '42122031cc50e3c3',
  dps: {
    '1': false,
    '9': 0,
    '18': 0,
    '19': 0,
    '20': 1074,
    '21': 1,
    '22': 1428,
    '23': 14342,
    '24': 18691,
    '25': 965
  }
}
```
`dps[1]` がスイッチの状態 (`false` = オフ / `true` = オン) であること以外、
まったくわかりません。おそらく電波強度とかだと思うのですが。

どなたかドキュメントを見つけたら編集リクエストをいただけると助かります。

19/7/25 追記：[node-red-contrib-tuyapi-cloud](https://flows.nodered.org/node/node-red-contrib-tuya-smart) にそれっぽい内容が。