Nature Remo APIとAlexaで部屋中の家電を操作する話

# はじめに

先日待ちに待ったNature Remoの公式APIが公開されました

- [APIを公開しました！！！ — Nature](http://nature.global/jp/blog/2018/1/30/api)

で、Qiitaでこんなの素晴らしい記事も見つけました

- [Amazon Echoで「○○をつけて」と言って家電を操作する - Qiita](https://qiita.com/machu/items/122c8403b35748bd5f4c)
- [Amazon Echoに「アレクサ、NHK」、「アレクサ、日テレ」と呼び掛けてテレビのチャンネルを変える - Qiita](https://qiita.com/machu/items/4cb2654eb60b9e1e5c3f)

これらを組み合わせてみます
Node-REDって今回はじめて使ったのですが、めちゃくちゃ便利ですね。これは楽しい

# フロー的なもの

1.Echoに自然な感じで話しかける
　「アレクサ、テレビつけて」「エアコンつけて」「テレビの音量下げて」「電気消して」
2.Node-RED Alexa Home Skill Bridgeで受け取ってローカル（今回はラズパイ）のNode-REDに渡す
3.Node-REDからNature RemoのAPIを叩いて家電を操作

めっちゃ簡単そうに見える（簡単とは言っていない）

# やったこと

## Node-REDの登録とインストールと準備

この辺は[前述の記事](https://qiita.com/machu/items/122c8403b35748bd5f4c#amazon-echo--macbook-pro--nature-remo%E3%81%A7%E5%AE%B6%E9%9B%BB%E3%82%92%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E8%A8%AD%E5%AE%9A%E6%89%8B%E9%A0%86)の「Amazon Echo + Macbook Pro + Nature Remoで家電を操作するための設定手順」がすごくわかりやすいのでそちらを参考に進めると良いです

まずは[Node-RED Alexa Home Skill Bridge](https://alexa-node-red.bm.hardill.me.uk)にユーザ登録し、操作したいDeviceを登録
登録したDevicesはこんな感じ
![nodered.png](https://qiita-image-store.s3.amazonaws.com/0/127332/c3770d09-139e-7677-574e-bade9a5b71b3.png)
Nameはアレクサに呼びかけるときの対象の名前で、これはあとでアプリから変更することもできるっぽいんですが、下手に変更すると管理しづらくなったり混乱するので最初から呼びかける名前で付けます
「アレクサ、照明つけて」より「電気つけて」のほうが呼びかけやすいし自然ですよね
Descriptionはまあ適当に。こっちはあとからEditできます
Actionは、デスクライトはオンオフのみ、テレビと電気は後述しますが音量や明るさを設定するために％も指定（＋％、－％だとうまくいかず）、エアコンはわかりやすく温度とその＋－ですね

次はスマホのalexaアプリか[web画面](https://alexa.amazon.co.jp/spa/index.html#appliances)から操作です
まずはalexaに「Node-RED」のスキルを追加し、先程登録したDeviceを検出
web画面なら「検出」を、スマホアプリなら「＋デバイスを追加」をタップで読み込んでくれます

Node-RED環境は、私はラズパイ上に構築したので元記事とちょっと違いました
困ったときの公式ドキュメント

- [Node-RED日本ユーザ会 : Running on Raspberry Pi](https://nodered.jp/docs/hardware/raspberrypi)

私のラズパイにはNode-REDがプリインストールされていたっぽいので、お勧めに従いアップグレードしてみる

```
$ bash <(curl -sL https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered)
（なんか色々聞かれたけどとりあえずYって答えるとしばらく待たされる）
$ update-nodejs-and-nodered
（同じくYでまたしばらく待たされる）
```

これでインストールが完了したはず
`node-red`コマンドを実行してStart的なメッセージが出たらOK
`http://<ラズパイのIP>:1880/`にアクセスするとNode-REDの画面が出てきます

ついでに自動起動設定もするとなお良し

```
$ sudo systemctl enable nodered.service
```

## Node-REDのフロー作成

ここからは`http://<ラズパイのIP>:1880/`のGUIから操作

やはり[元記事](https://qiita.com/machu/items/122c8403b35748bd5f4c#%E6%89%8B%E9%A0%863-%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E7%92%B0%E5%A2%83%E3%81%ABnode-red%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B)が素晴らしいので、手順3の後半に従って`node-red-contrib-alexa-home-skill`というNode-RED用プラグイン（パレットと呼ぶらしい）をインストール
このとき検索結果に`node-red-contrib-alexa-home`という似た名前のものも出てくるので注意
こっちも使えるのかもだけど使ったことないのでわからんです

次はNode-REDのフローを作成。こんな感じです
![nodered-flow.png](https://qiita-image-store.s3.amazonaws.com/0/127332/08e333e0-e8f7-9f5c-8a7a-d67f71260967.png)

基本的には左側メニューからノードを持ってきていい感じにつなぐだけです。どれを選ぶかは図から判断してください
一応エアコンだけ中を載せます

![nodered-aircon1.png](https://qiita-image-store.s3.amazonaws.com/0/127332/c4f2e4dc-fbdd-6f38-1bcc-9558dcedf70e.png)
Accountのペンマークから手順1で登録した登録したユーザを入力し、Deviceの更新マークをクリックで登録したDeviceが出てくるので選択

![nodered-aircon2.png](https://qiita-image-store.s3.amazonaws.com/0/127332/8b6e66c3-f65b-90ba-5c94-1104be010b58.png)
ここでは手順1で登録したDeviceに対応するActionのコマンドが選べます
コマンドは[ここの一覧](https://alexa-node-red.bm.hardill.me.uk/docs#buildFlows)から対応するものを選択

![nodered-aircon3.png](https://qiita-image-store.s3.amazonaws.com/0/127332/975b90f5-23c5-1cce-c897-d49d49b89195.png)
changeノードでは次のノードであるexecノードに渡すパラメータを指定します
`msg.payload`はデフォルトのままで良く、`on`としているところは短くわかりやすいパラメータ名がおすすめ

![nodered-aircon4.png](https://qiita-image-store.s3.amazonaws.com/0/127332/220d3649-b21b-4368-7259-a29a8e79e097.png)
最後にここで実行するシェルスクリプトを指定します
まだ作ってなければ空でもOK

すべての編集操作が終わったら必ず右上の「デプロイ」ボタンを押しましょう
これ以降、何かしら変更を加えた際にも同じくです

## Nature Remo APIを使おう

ここからは前項の最後で出てきたシェルスクリプトを作成します
今回はシェルスクリプトからNature Remo APIを叩くことで家電を操作するので、APIを色々といじくり回します
Nature Remo APIの公式ドキュメントはこちら

- [Swagger UI](http://swagger.nature.global)

swagger、いいですよね（独り言）

まずは[ここから](https://home.nature.global)トークンを発行
一度表示されたトークンは二度と表示されないので何処かファイルにでもメモっておきましょう
こいつを使ってとりあえず自分のremoに登録されてる家電と操作を取得してみます

```sh
curl https://api.nature.global/1/appliances -H "Authorization: Bearer <accesstoken>" | jq .
```
`<accesstoken>`には取得したトークンを指定しましょう
ちなみにこのときトークンをファイルに1行ペロッと書き込んでると

```sh
curl https://api.nature.global/1/appliances -H "Authorization: Bearer $(cat /path/to/token.txt)" | jq .
```
みたいにそのまま読み込めるのでめっちゃ楽です
また、結果はJSONで返ってくるので整形するのにjqを使ってます
jqについてはこちらがわかりやすいです

- [jq コマンドを使う日常のご紹介 - Qiita](https://qiita.com/takeshinoda@github/items/2dec7a72930ec1f658af)

さて結果です

```json
[
  {
    "id": "6c10f1a1-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "device": {
      "name": "Remo",
      "id": "837b1dc8-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "created_at": "2017-11-12T09:05:04Z",
      "updated_at": "2018-02-12T07:47:31Z",
      "firmware_version": "Remo/1.0.62-gabbf5bd",
      "temperature_offset": 0,
      "humidity_offset": 0
    },
    "model": {
      "id": "DCF7AEC4-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "manufacturer": "daikin",
      "remote_name": "xxxxxxxx",
      "series": "Daikin AC",
      "name": "Daikin AC 002",
      "image": "ico_ac_1"
    },
    "nickname": "Daikin AC 002",
    "image": "ico_ac_1",
    "type": "AC",
    "settings": {
      "temp": "26",
      "mode": "warm",
      "vol": "auto",
      "dir": "",
以下略
```
なげえよ。。。
まあでも取得できるのがわかったので良し

次に家電を操作するための信号を送信してみます
先程の結果から一部を抜粋

```json
  {
    "nickname": "デスクライト",
    "signals": [
      {
        "id": "5320d922-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "name": "オン",
        "image": "ico_record"
      }
    ]
  }
```
この`id`の値を使って、こんな感じ

```sh
curl -X POST https://api.nature.global/1/signals/5320d922-xxxx-xxxx-xxxx-xxxxxxxxxxxx/send -H "Authorization: Bearer $(cat /path/to/token.txt)
```
はいデスクライトついたー（はず）
他も基本的には同じです
が、エアコンだけはAPIが違います
先程の結果の一部を再度抜粋

```json
  {
    "id": "6c10f1a1-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "device": {
      "name": "Remo",
      "id": "837b1dc8-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "created_at": "2017-11-12T09:05:04Z",
      "updated_at": "2018-02-12T07:47:31Z",
      "firmware_version": "Remo/1.0.62-gabbf5bd",
      "temperature_offset": 0,
      "humidity_offset": 0
    },
    "model": {
      "id": "DCF7AEC4-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "manufacturer": "daikin",
      "remote_name": "xxxxxxxx",
      "series": "Daikin AC",
      "name": "Daikin AC 002",
      "image": "ico_ac_1"
    },
    "nickname": "Daikin AC 002",
    "image": "ico_ac_1",
    "type": "AC",
    "settings": {
      "temp": "26",
      "mode": "warm",
      "vol": "auto",
      "dir": "",
以下略
```
使うのはやはり`id`です
このとき`device.id`や`model.id`と間違えやすいのでご注意を
とりあえず電源オンしてみますが、`aircon_settings`APIでは操作はすべてform dataで送信します
で、電源オン・オフは`button`の項目で指定しますが、その説明がこちら

```
Specify “power-off” always if you want the air conditioner powered off. Empty means powered on.
```
> 意訳："power-off"指定でオフ、空文字指定でオンだよ

~~は？　クソ設計~~ あまり見かけない斬新な設計ですね！
やってみた

```sh
curl -X POST https://api.nature.global/1/appliances/6c10f1a1-xxxx-xxxx-xxxx-xxxxxxxxxxxx/aircon_settings -H "Authorization: Bearer $(cat /path/to/token.txt)" -d "button="
```
たぶんこれでエアコンがついたはずです
温度操作も同じくform dataでの指定ですが、現在の設定に対する＋－には対応しておらず、値を直接指定するしかないです

```sh
curl -X POST https://api.nature.global/1/appliances/6c10f1a1-xxxx-xxxx-xxxx-xxxxxxxxxxxx/aircon_settings -H "Authorization: Bearer $(cat /path/to/token.txt)" -d "temperature=27"
```
これってエアコン側の縛りなんですかね？　~~クソ~~素敵すぎる
幸いにして現在の設定は最初に叩いた`appliances`APIでGETできるJSONに含まれているので、こんな感じで抽出します

```sh
curl https://api.nature.global/1/appliances -H "Authorization: Bearer $(cat /path/to/token.txt)" | jq -r '.[] | select(.id == "6c10f1a1-xxxx-xxxx-xxxx-xxxxxxxxxxxx") | .settings.temp' | cat
# =>27
```
jqのselect文めっちゃ便利

今回使うのはこの辺ですかね
シェルスクリプト化していきましょう

## シェルスクリプトを作成

**githubに上げたのでそれを見ていただければほぼOKです！！！（ぶん投げ）**

- [jutaroi01/nodered-remo](https://github.com/jutaroi01/nodered-remo)

一応いくつか解説します

テレビ用スクリプト

```tv.sh
#!/bin/bash

echo `date` "exec command $1" >> /path/to/log/tv.log

TOKEN=$(cat /path/to/token.txt)

case $1 in
  on|off)
    curl -X POST https://api.nature.global/1/signals/2c9aa4b9-xxxx-xxxx-xxxx-xxxxxxxxxxxx/send -H "Authorization: Bearer $TOKEN";;
  11)
    # 1ch
    curl -X POST https://api.nature.global/1/signals/0ddd912a-xxxx-xxxx-xxxx-xxxxxxxxxxxx/send -H "Authorization: Bearer $TOKEN";;
  4)
    # 4ch
    curl -X POST https://api.nature.global/1/signals/8ab05d9a-xxxx-xxxx-xxxx-xxxxxxxxxxxx/send -H "Authorization: Bearer $TOKEN";;
  10)
    # volume down
    curl -X POST https://api.nature.global/1/signals/da9efa43-xxxx-xxxx-xxxx-xxxxxxxxxxxx/send -H "Authorization: Bearer $TOKEN"
    curl -X POST https://api.nature.global/1/signals/da9efa43-xxxx-xxxx-xxxx-xxxxxxxxxxxx/send -H "Authorization: Bearer $TOKEN"
    curl -X POST https://api.nature.global/1/signals/da9efa43-xxxx-xxxx-xxxx-xxxxxxxxxxxx/send -H "Authorization: Bearer $TOKEN";;
  100)
    # volume up
    curl -X POST https://api.nature.global/1/signals/85a0f17d-xxxx-xxxx-xxxx-xxxxxxxxxxxx/send -H "Authorization: Bearer $TOKEN"
    curl -X POST https://api.nature.global/1/signals/85a0f17d-xxxx-xxxx-xxxx-xxxxxxxxxxxx/send -H "Authorization: Bearer $TOKEN"
    curl -X POST https://api.nature.global/1/signals/85a0f17d-xxxx-xxxx-xxxx-xxxxxxxxxxxx/send -H "Authorization: Bearer $TOKEN";;
  *)
    echo `date` "unknown command $1" >> /path/to/log/tv.log
esac
```
Node-REDフローの最後のexecノードに渡されるパラメータ（`msg.payload`）に応じてcase文で分岐させます
あとはまあログを出したりIDとTOKENを変数化したりしてますがその辺は読んで察してください
で、工夫点として後述する「定型アクション」のためにチャンネル選択と音量の上下を数値で指定しています。これは照明用の`light.sh`も同様
あと音量は一度のコールで3つずつ上下するようにしています
我が家の場合、音量が1だけ上がっても大して変わらないからですね
この辺は実際に運用して調整すると良いです

こいつをNode-REDで指定してデプロイすればもうアレクサに話しかければオンオフくらいの操作はできるはずです
「アレクサ、テレビつけて」「電気つけて」「エアコンの温度上げて」「エアコンの温度を26度にして」など
ちなみにエアコン関連の操作は「すみません、よくわかりませんでした」と答えながらもしっかり操作してくれてることが多いです
アレクサさんマジ~~ポンコツ~~お茶目

## 定型アクションを設定

今のままだとテレビの音量を上げるのに「テレビを100にして」という必要があります
なので、これを自然な呼びかけでいけるようにします

定型アクションは、alexaのスマホアプリの左側メニューにある「定型アクション」から追加します

1. 右上の＋ボタンをタップ
2. 「実行条件」から呼びかけるための「開始フレーズ」を入力。短くわかりやすいフレーズが良い
3. 「アクションを追加」から、スマートホーム＞操作したいデバイスを選択して【オン・オフ】と【パーセント】を指定
4. 下にある「作成」ボタンを押すことで保存（地味に忘れがち）

ポイントは2.で【パーセント】を指定するところです
例えば先程のテレビ用スクリプトの例では、100を指定することで音量を上げるようにしていたので以下のように指定します
<img width="375" alt="iOS からアップロードされた画像 (1).png" src="https://qiita-image-store.s3.amazonaws.com/0/127332/64520d5d-c70c-e863-acb0-4d5a7d0dd77b.png">
これにより、このアクションが呼ばれるとNode-REDに『100％が指定された』というコマンドが送られ、結果シェルスクリプトの100の分岐に入って音量を上げる処理が実行されます
しかしそもそもここで％指定じゃなくて単純な＋－が指定できれば、「100を指定する＝音量上げる」みたいなわけのわからない設計にしなくて済んだんですけどね。。。
これはNode-REDスキルの問題なのかな

さて、そしてこっちは完全にバグっぽい挙動なのですが、パーセント指定の最小値である1を指定してアクションを作成すると、実際の実行時には何故か『100％が指定された』ことになります
謎い
そのため、私はNHKをつけるためのアクションでは1のかわりに11を指定するようにしています
1chだから1のほうがわかりやすいんですけど、まあそこはどうせ隠蔽されるので気にしない方向で

というわけで1～4を繰り返すことで一通り指定した結果がこちら
<img width="375" alt="iOS からアップロードされた画像.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/127332/f078accf-529b-7f8f-6cf1-6d1b0cb29989.jpeg">

まあ無難ですね
ちなみにNHKと日テレしかないのは私が主にそれしか観ないからですｗ
そしてよく見ると**「NHK」と「つけて」の間に半角スペース**が入ってます
これは、半角スペースなしだとalexaがフレーズをうまく認識してくれなかったからです
アルファベットと日本語の組み合わせは苦手みたいですね

# まとめ

- Node-REDめっちゃ便利。しかも直感的にフローが組める。神か
 - alexaスキルの方はもうちょい改善されると嬉しいです。＋－をなにとぞ！
- Nature Remo APIも素晴らしい。いちいち赤外線情報とか送信しないで済むのが良いですね
- 定型アクションのおかげでalexaさんが自然な日本語を理解してくれる。これはもっと使いみちがありそう
 - そもそも本来はワンフレーズで複数アクションを実行させる、みたいな用途みたいですね

一度一通り組んでしまえば、機器や操作の追加はちょろで済むので色々遊びたいですね
出かけるときや寝るときなどに一声で色々消えるとか？
、、、と思ったけどこれは定型アクションでいけるか
何しようかなあ。。。

# 参考

- [APIを公開しました！！！ — Nature](http://nature.global/jp/blog/2018/1/30/api)
- [Amazon Echoで「○○をつけて」と言って家電を操作する - Qiita](https://qiita.com/machu/items/122c8403b35748bd5f4c)
- [Amazon Echoに「アレクサ、NHK」、「アレクサ、日テレ」と呼び掛けてテレビのチャンネルを変える - Qiita](https://qiita.com/machu/items/4cb2654eb60b9e1e5c3f)
- [Node-RED日本ユーザ会 : Running on Raspberry Pi](https://nodered.jp/docs/hardware/raspberrypi)
- [jq コマンドを使う日常のご紹介 - Qiita](https://qiita.com/takeshinoda@github/items/2dec7a72930ec1f658af)
- [シェルの入出力制御あれこれ - Qiita](https://qiita.com/tag1216/items/7ce35b7c27d371165e56)

素晴らしい記事をありがとうございました！