Nature Remo miniと SORACOM LTE-M Buttonで家電を簡単操作する

# はじめに
本記事は [SORACOM LTE-M Button powered by AWS Advent Calendar](https://qiita.com/advent-calendar/2018/soracom) 13日目の記事です。
Nature Remo mini との連携による家電の操作についてご紹介します。

# 背景
この夏、我が家の家電操作を一元化したいと思いスマホから操作できるスマート家電リモコンを購入しました。
しかし問題がありました。。。**手数の多さ**です。

1. スマホを取り出す
2. スマホをアンロックする
3. アプリを探して立ち上げる
4. アプリのメニューから利用するスマートリモコンを選択
5. 操作する家電を選択（居間のライト、など）
6. 具体的な操作を選択（全灯、など）

以上のようにせっかく一元化したのに６ステップもあり余り便利ではありません。
そこで Amazon Echo との連携を設定し声で操作できるようにしました。
Echo の導入により手数の問題は改善されましたが、次のような別の問題が出てきました。

- **割と失敗する**  
私の話し方の問題か10回に１回程度は聞き取ってもらえません。
- **声を出すのが面倒**  
聴き取ってもらおうと Echo 用の発声を心がけるためか特に喉の調子が悪い時など億劫です。
- **２台の Echo が同時に反応**  
我が家には寝室と居間に1台ずつ Echo が設置されており、微妙な位置・声量で指示を出すと両方反応してしまいます（家電リモコンとの連携は片方のみ）。
一時期は片方のウェイクワードを「Echo」に変更してみたのですが、今度は定期的にウェイクワードを間違って話しかけてしまい、ストレスが溜まるのでやめてしまいました。

# １ボタンで解決する
以上のような背景から「SORACOM LTE-M Button powered by AWS」を使って、よく実行する３つの操作を１ボタンから実行できるようにしました。

**対象操作**  

- 照明の ON/OFF
- エアコンの ON
- エアコンの OFF

## 準備
今回ご紹介する方法では、以下の環境を予め揃えておく必要があります。

- インターネット接続
- 無線LAN環境
- SORACOM アカウント
- SORACOM LTE-M Button powered by AWS
- AWS アカウント（AWS Lambda, AWS IoT 1-Click を利用）
- [Nature Remo mini](https://nature.global/jp/top) *アプリからのセットアップ時にアカウント作成

## 手順
### Nature Remo mini の設定

0. 本体を電源に接続します。
1. [アプリ](https://itunes.apple.com/jp/app/nature-remo/id1193531669?mt=8)をダウンロードしてWifiへ接続し、操作したい家電のリモコンを登録します。
2. 続いてAPI へのアクセストークンを[こちら](https://home.nature.global/home)から発行します。
3. きちんと登録されているかAPI経由で確認しましょう。「ライト」と「エアコン」はそれぞれ私がアプリ上でつけた名前です。

```bash
$ curl -X GET "https://api.nature.global/1/appliances" -H "accept: application/json" -k --header "Authorization: Bearer <API TOKEN>" | jq '.[] | .id, .nickname, .signals'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  5178  100  5178    0     0   6344      0 --:--:-- --:--:-- --:--:--  6337
"<APPLIANCE ID>"
"ライト"
[
  {
    "id": "<SIGNAL ID>",
    "name": "電源",
    "image": "ico_io"
  }
]
"<APPLIANCE ID>"
"エアコン"
[]
```

照明とエアコンでは API の呼び出し方が異なります。

- 照明： 実行したい操作の SIGNAL ID を URI に埋めて送信する。
- エアコン： 上記で取得した APPLIANCE ID を URI に埋め、操作はリクエストのBodyに記述する。

まずは`curl`で動作確認です。具体的には次のような呼びだし方になります。

**照明**

```bash
$ curl -X POST "https://api.nature.global/1/signals/<SIGNAL ID>/send" -H "accept: application/json" -k --header "Authorization: Bearer <API TOKEN>"
```

**エアコン（電源オン操作）**

```bash
$ curl -X POST  -d 'button=power-on' "https://api.nature.global/1/appliances/<APPLIANCE ID>/aircon_settings" -H "accept: application/json" -k --header "Authorization: Bearer <API TOKEN>"
```

詳しくは [Nature Remo API](https://developer.nature.global/) をご確認ください。

### SORACOM LTE-M Button と AWS Lambda の設定
手順は [SORACOM LTE\-M Button powered by AWS をクリックしてSlackに通知する](https://dev.soracom.io/jp/start/aws_button_slack/) と同じです。
Lambda 関数のランタイムも上記チュートリアルと同じ `Node.js 8.10` を使用しました。
異なるのは関数のコードと環境変数のみです。

**関数**

```javascript

const https = require('https');
const url = require('url');
const natureBaseUrl=process.env['NATURE_URL']
const natureApiToken=process.env['NATURE_API_TOKEN']
const airconApplianceId=process.env['AIRCON_APPLIANCE_ID']
const livingLightSignalId=process.env['LIVING_LIGHT_SIGNAL_ID']

exports.handler = (event, context, callback) => {
        
    function controlAircon(order) {
        var postData = '';
        switch(order){
            case 'start':
                postData = 'button=power-on';
                break;
            case 'stop':
                postData = 'button=power-off';
                break;
        }
        
        var natureReqOptions = url.parse(`${natureBaseUrl}/appliances/${airconApplianceId}/aircon_settings`);
        natureReqOptions.method = 'POST';
        natureReqOptions.headers = {"accept": "application/json", 
                                    "Authorization": `Bearer ${natureApiToken}`, 
                                    "Content-Type": "application/x-www-form-urlencoded",
                                    "Content-Length": Buffer.byteLength(postData)
                                    };
        
        var req = https.request(natureReqOptions, function(res) {
            res.on('data', (chunk) => {
                console.log(`INFO: response = ${chunk}`);
            });
           if (res.statusCode === 200) {
                console.log(`INFO: successfully ${order} air-conditioner`);
            } else {
                console.log(`ERROR: failed to ${order} air-conditioner - ${res.statusCode}`)
            }
        });
        req.on('error', (e) => {
            console.error(`ERROR: ${e.message}`);
        });
        req.write(postData);
        req.end();
    }
    
    function turnOnOffLight(){
        var natureReqOptions = url.parse(`${natureBaseUrl}/signals/${livingLightSignalId}/send`);
        natureReqOptions.method = 'POST';
        natureReqOptions.headers = {"accept": "application/json", 
                                    "Authorization": `Bearer ${natureApiToken}`
                                    };
        
        var req = https.request(natureReqOptions, function(res) {
            res.on('data', (chunk) => {
                console.log(`INFO: response = ${chunk}`);
            });
            if (res.statusCode === 200) {
                console.log('INFO: successfully turn on/off living lights');
            } else {
                console.log(`ERROR: failed to turn on/off living lights - ${res.statusCode}`)
            }
        });
        req.on('error', (e) => {
            console.error(`ERROR: ${e.message}`);
        });
        req.end();
    }
    
    console.log('Received event:', JSON.stringify(event, null, 2));
    var cType = event.deviceEvent.buttonClicked.clickType;
    
    switch( cType ) {
        case 'SINGLE':
            console.log('INFO: received SINGLE click - start air‐conditioner');
            controlAircon('start');
            break;
     
        case 'DOUBLE':
            console.log('INFO: received DOUBLE click - turn on/off living lights');
            turnOnOffLight();
            break;
     
        case 'LONG':
            console.log('INFO: received LONG click - stop air‐conditioner');
            controlAircon('stop');
            break;
    }
};
```

|環境変数 |説明 |
|---|---|---|
|AIRCON_APPLIANCE_ID     | エアコンの APPLIANCE ID です。 |
|LIVING_LIGHT_SIGNAL_ID  | 照明の電源操作に対応する SIGNAL ID です。  |
|NATURE_API_TOKEN        | 外部ネットワーク経由でリモコン操作を実行するためのトークンです。 | 
|NATURE_URL | API エンドポイント `https://api.nature.global/1` です。| 

以上を設定することで、次の3つの操作が可能になりました！

- シングルクリック： エアコン開始
- ロングクリック（通信ランプが点滅開始するまで押し込んだまま）： エアコン停止
- ダブルクリック： 照明ON/OFF

# まとめ
Nature Remo mini を利用することで SORACOM LTE-M ボタンの３つのクリック動作（シングルクリック、ダブルクリック、ロングクリック）と3種類のリモコン操作を結びつけることができました。
これにより今まで Amazon Echo にお願いしていた操作を無言で実行できるようになりました。
もちろん、何ステップもかけてスマホを操作する必要もありません。

現在のところはリモコン操作のみを行っていますが Nature Remo mini は操作時の時間と気温も取れますので、「照明ON/OFFの時間帯」や「エアコン操作と気温の関係」などを貯めることで単なる便利な１ボタン操作デバイスを超えてライフログデバイスとしても有効に使えるのではないかと考えています。

# リンク
- [Nature](https://nature.global/)
- [Nature Remo API](https://developer.nature.global/)
- [SORACOM LTE\-M Button powered by AWS をクリックしてSlackに通知する \| Getting Started with SORACOM LTE\-M Button \| SORACOM Developers](https://dev.soracom.io/jp/start/aws_button_slack/)