Nature Remo を使ってみてなんとなく分かったこと

# なんとなく分かった事
 1. [そもそも]トグル形式のボタンとの相性は悪い。(TV on/offなど）
 -  [そもそも]リモコンボタンの長押しは再現出来ません。（これは、アプリからのリモコンボタン連打でも再現不可でした）
 -  [アプリ]リモコンボタンの**ディレイ送信**は出来ません。（APIでは可能）
 -  [API]global APIを叩いて扱う方が用法的には簡単（というか、Local　APIはInterfaceが難解なので挫折しました）  
   なので、リクエスト送信頻度には気を付ける事（プログラムチックに投げると即、NGくらいます）
 - [API]エアコン以外は、signal idさえ分かれば、簡単にシグナルを送れます。
   エアコンの場合は"aircon_settings"に、”button=power-on" or "power-off"のPOSTパラメータを送れば反応します

## 構成図

![aws.png](https://qiita-image-store.s3.amazonaws.com/0/8999/efd188a9-1b80-6770-a4b0-76c6c00c8c5c.png)

## ちなみに、ここでは上記でいう**ディレイ送信**の実現についてのみ記載します。（IR機器のみ）

### あと端的にいうと、setTimeoutを使った、遅延Request実行をしているだけのコードとなります

その前提で
まずは、すべてのIR機器のニックネームとボタン名のマッピングファイルを用意します（ir.json)。
フォーマットは利便性も兼ねて、以下のようにしています。


```ir.json
{
	"電気": {
		"オン": "id",
		"暗く": "id",
		"オフ": "id"
	},
	"オーディオ": {
		"電源": "id",
		"plus": "id"
	},
	"ルンバ君": {
		"clean": "id",
		"やめ": "id"
	}
}
```

そして、このファイルは以下のコードで自動生成します。(AWS lambda)


```generateIR.js
exports.generateIRList = function(event, context, callback) {
  this.get({ url : "https://api.nature.global/1/appliances"},{},(err,res)=>{

    var contents = res.filter((e)=>{return e.type === "IR"}).reduce((prev,c)=>{
      prev[c.nickname] = c.signals.reduce((p,c)=>{p[c.name]=c.id;return p;},{});
      return prev;
    },{});

    var dt = JSON.stringify(contents,null,"\t");
    console.log(dt);
    fs.writeFile(`./ir.json`, dt, 'utf8');
    callback(null,dt);
  });

}

```

次に、どのような順番でそれぞれを呼び出すかを定義します。
上記のマッピングを事前に作ることにより、人にヤサシイ定義ができます。
各シグナルをどの程度の遅延で実行するかを定義してます。

```input.json
{
      orders : [
      {
        delay : 3000,
        order : ["電気","オン"]
      },
      {
        delay : 3000,
        order : ["電気","暗く"]
      },
      {
        delay : 3000,
        order : ["電気","オフ"]
      }
    ]
}
```


そして、このオーダーを以下event.ordersパラメータとしてリクエストします(AWS lambda)

```ctrlRemo.js

//lambda layer
exports.delayed = function(event, context, callback) {
  var irs = fs.readFileSync("./ir.json","utf8");
  irs = JSON.parse(irs);
  console.log(irs);
  var promises = [];
  event.orders.forEach((e,idx)=>{
    var id = irs[e.order[0]][e.order[1]];  //ここで実際に誰(nickname)に対して、何のシグナル(id)を送るかをir.jsonより決定

    var orderObj = urlfactroy("IR",id); 
    console.log(e.delay);
    console.log(orderObj);

    setTimeout((i)=>{
      promises.push(postImpl(orderObj.url));
      if(event.orders.length == (i+1)){
        Promise.all(promises).then((res)=>{  //すべてのリクエスト追加が終わってからpromise.allで待つ
            console.log("sending ok");
            callback(null,res); //完了
        });
      }
    },e.delay*(idx+1),idx);  //遅延起動時間 bug有り
  });
};

}

```


##　実行

３秒毎に、電気をオン、電気を暗く、電気をオフ。を実行してくれます。
なんの役にもたたないですが、自分のコードで家電が動く感動は、かなりあります。
これでようやく、電源オンに時間がかかるIR機の操作（我が家のオーディオ）は、操作可能になりそうです。

## 終わりに

Global API呼び出しに関しては、他の記事がたくさんあるので省略しました。
それも含めてみたければ、[こちら](https://github.com/anyworks/ctrlRemo)をどうぞ

ちなみに、エラーハンドリングは皆無です。
というのも理由は分かりませんが、**readFileSync**がalways empty stringを返すバグに直面して
1時間程格闘したのち、fs.readFileに書き換えて事なきを得た。ってのもあって完成させる気力が失われたからです。
ちなみに、以下がその問題のコードです。参考までに

```notworking.js
exports.delayed = function(event, context, callback) {
  var irs = fs.readFileSync("./ir.json","utf8");  <-- ここを readFile(callback version)にすると動作する。。
```

CROSの難解度やら、ベストプラクティスの移り変わりやらを見てきたのもあって、今後はJSには極力手を出すべきではないなと実感しました。

[その後はこちら](https://qiita.com/anyworks@github/items/6a3f303eaf6722f29aa0)