Clovaに話しかけて家電を操作してみる

# はじめに
7/12に「Clova Extensions Kit」（以下CEK）が公開されました。
まだ審査やリリースはできませんが、開発自体はできます！
早速ちょこちょこ触りがてら、そういえばClova Friendsから家電操作できないなと思い、手始めに家電操作スキルを作ってみました。

↓こんなかんじの。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">今日ちょっと暑すぎなのでClovaさんにエアコンつけてもらえるようにした。<a href="https://twitter.com/hashtag/clova?src=hash&amp;ref_src=twsrc%5Etfw">#clova</a> <a href="https://twitter.com/hashtag/clova_cek?src=hash&amp;ref_src=twsrc%5Etfw">#clova_cek</a> <a href="https://twitter.com/hashtag/%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%82%B9%E3%83%94%E3%83%BC%E3%82%AB%E3%83%BC?src=hash&amp;ref_src=twsrc%5Etfw">#スマートスピーカー</a> <a href="https://t.co/ODMv3k3yfe">pic.twitter.com/ODMv3k3yfe</a></p>&mdash; 田中みそ (@miso_develop) <a href="https://twitter.com/miso_develop/status/1018030755237097473?ref_src=twsrc%5Etfw">2018年7月14日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



# 処理の流れ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/207109/ae6ea0ac-92b6-5926-c4c5-46d0c84e9acd.png)

今回はCEKの実装に絞って書いていきます。
Firebaseから先は既存の仕組みを使うので、過去記事を参照下さい。
[Google Homeに話しかけてエアコンを操作してみる](https://qiita.com/miso_develop/items/204b2e16b1e58e52dc07)
[Google Home、IFTTT、Firebase、Node.js、irMagicianを使ってシーリングライトを音声操作する](https://qiita.com/miso_develop/items/c2008235cb4a8567cfa9)



# 環境
とりあえず一時的に動かしてみたので以下の構成です。
サーバもAWSなりGCPなりのクラウドは使わず、express + ngrokでローカルサーバを立ててます。
常時稼働させるならラズパイとクラウドでの運用となります。

* OS: Windows 10
* 言語: Node.js v8.11.3
* サーバ: express + ngrok



# CEK開発の流れ
おおまかに以下の流れになります。

* [Clova Developer Centerでスキルの新規作成、基本設定](#clova-developer-centerでスキルの新規作成基本設定)
* [Clova Developer Centerでインテント、スロット定義](#clova-developer-centerでインテントスロット定義)
* [Node.jsでのサーバサイド実装](#nodejsでのサーバサイド実装)
* [うごかしてみる](#うごかしてみる)

## Clova Developer Centerでスキルの新規作成、基本設定
dotstudioさんの記事が分かりやすく説明されてます。
[本日リリース！LINE Clovaのスキル開発の始め方〜申請編〜](https://dotstud.io/blog/line-clova-skill-tutorial/#clova-developer-center%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9)

なお「サーバー設定」、「配布情報」、「個人情報の保護および規約同意」はすっとばせます。
「サーバー設定」については[うごかしてみる](#うごかしてみる)で後ほど設定します。



## Clova Developer Centerでインテント、スロット定義
最後のページで「対話モデル」のボタンをクリックすると、別窓でインテントやスロットを定義する画面が開きます。
ここの操作は@imajoririさんの記事でわかりやすく説明されています。
[[入門]Clovaスキル(CEK)は作りながら覚えて行く（インテント、スロットなど登録編）](https://qiita.com/imajoriri/items/604ff74c4e81859771e2#slots%E7%99%BB%E9%8C%B2)

### スロット
以下の２つのスロットを定義します。

**target**

|代表後|同義語|
|---|---|
|電気|ライト|
|テレビ|　|
|エアコン|　|

![image](https://qiita-image-store.s3.amazonaws.com/0/207109/48f93bbe-a538-d05b-ff7d-e0fc6e81872a.png)

**action**

|代表後|同義語|
|---|---|
|消して|オフ|
|つけて|起動, オン|

とりあえずオンオフのみを。

![image](https://qiita-image-store.s3.amazonaws.com/0/207109/fda01200-7039-a561-835f-2de80155bf09.png)

### インテント
以下の1つのインテントを定義します。

**ControllIntent**

|サンプル発話|
|---|
|target action|

|スロット名|スロットタイプ|スロット値|
|---|---|---|
|target|target|target|
|action|action|action|

単純にスロット並べただけです。

![image](https://qiita-image-store.s3.amazonaws.com/0/207109/204375da-bac2-8f19-7cb1-5a21498e805a.png)

以上を定義したらビルドしましょう。
ビルドはそこそこ時間（3分～5分）かかってビルド感あります。



## Node.jsでのサーバサイド実装

### 環境構築
まずは環境を作りましょう。

使用する言語はNode.jsです。
私のバージョンは以下の通りです。

* Node.js: 8.11.3
* npm: 5.6.0

適当にディレクトリ作って移動。

```
$ mkdir rimocon
$ cd rimocon
```

続いてNode.jsパッケージをインストール。
入れるのはCEKのSDKである`@line/clova-cek-sdk-nodejs`、あと今回ローカルのexpressをサーバとするので`express`と`body-parser`、そしてラズパイと音声操作情報のやりとりの経路に使う`firebase`です。

```
$ npm i @line/clova-cek-sdk-nodejs express body-parser firebase
```

以上で環境は整いました。

### index.jsの作成
ではサーバサイドプログラムを書いて行きましょう。
とりあえずindex.jsを作成します。

```
(Windowsの場合)
$ echo.>index.js

(Unix系OSの場合)
touch index.js
```

そして以下のソースをコピペします。
このうち`firebase.initializeApp`の中身のjsonをFirebaseのコンソールからもってくるのと、`const firebasePath = "/xxxxxxxx/word";`をFirebaseのパスに合わせます。
この辺りはラズパイからの家電操作部に関連してくるので、詳しくは[過去記事](https://qiita.com/miso_develop/items/c2008235cb4a8567cfa9#firebase%E3%81%AE%E8%A8%AD%E5%AE%9A)を参照してみて下さい。

```js
const clova = require('@line/clova-cek-sdk-nodejs');
const express = require('express');
const bodyParser = require('body-parser');

//firebase
const firebase = require("firebase");
// 中身のjsonをFirebaseコンソールからもってくる
firebase.initializeApp({
  apiKey: "xxxxxxxx",
  authDomain: "xxxxxxxx.firebaseapp.com",
  databaseURL: "https://xxxxxxxx.firebaseio.com",
  projectId: "xxxxxxxx",
  storageBucket: "xxxxxxxx.appspot.com",
  messagingSenderId: "xxxxxxxx"
});
const db = firebase.database();
//Firebaseのパスに合わせる
const firebasePath = "/xxxxxxxx/word";

//clova
const clovaSkillHandler = clova.Client
  .configureSkill()
  .onLaunchRequest(responseHelper => {
    console.log("LaunchRequest!");
    responseHelper.setSimpleSpeech(
      clova.SpeechBuilder.createSpeechText('うん')
    );
  })
  .onIntentRequest(async responseHelper => {
    const intent = responseHelper.getIntentName();
    const slots = responseHelper.getSlots();

    switch (intent) {
      case 'ControllIntent':
        console.log('ControllIntent');
        
        //家電名称を既存システムに沿って置き換え
        const target = slots.target.replace("エアコン", "aircon").replace("テレビ", "tv").replace("電気", "light")
        //Firebaseに命令書き込み
        db.ref(firebasePath).set(`${target} ${slots.action.substr(0, 2)}`);
        
        //返答フレーズ作成
        const speech = `${slots.target}を${slots.action.substr(0, slots.action.length - 1) + "ます"}`
        
        responseHelper.setSimpleSpeech(
          clova.SpeechBuilder.createSpeechText(speech)
        );
        break
        
      default:
        console.log('default');
        responseHelper.setSimpleSpeech(
          clova.SpeechBuilder.createSpeechText('すみません、よくわかりません。')
        );
        break
    }
  })
  .onSessionEndedRequest(responseHelper => {})
  .handle();

const app = new express();
app.listen(3000);
app.post('/clova', bodyParser.json(), clovaSkillHandler);
```

`const clovaSkillHandler = clova.Client`から下がClovaの処理です。
Goole HomeやAlexaの開発した事あるなら何やってるかは一目瞭然ですね。
シンプルなつくりになってます。

以上で一通り完成です。



## うごかしてみる
今回はngrokを使ってローカルでサーバを立ててみます。
というのもClovaはまだ審査・リリースが出来ないのでクラウドに置くメリットはあまりありません。
ローカル実行の方がデプロイの手間も省けますし、ログの確認も瞬時にできます。
また後述しますが`nodemon`というNodeプログラムを使えば、ソース変更時に自動でnodeプロセスが再起動されます（超便利）。

### ngrokの導入
私の環境に沿ってWindowsで説明すると、[こちら](https://ngrok.com/download)からzipをダウンロードすると中にexeが1つ入ってます。
それをどこかに置いて実行するだけです。インストールもいりません。
[こちら](https://ngrok.com/download)から他のOSのzipもダウンロードできるので、他でも同じぐらい簡単なんじゃないでしょうか。

とりあえずさっき作成した`rimocon`ディレクトリに置いて実行してみましょう。

```
$ ngrok http 3000
```

`3000`は`index.js`の最後のほうの`app.listen(3000);`の数字と一緒でポート番号です。
で、実行結果として以下の感じの表示に変わります。

```
ngrok by @inconshreveable                                       (Ctrl+C to quit)

Session Status                online
Account                       Miso Tanaka (Plan: Free)
Version                       2.2.8
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://xxxxxxxx.ngrok.io -> localhost:3000
Forwarding                    https://xxxxxxxx.ngrok.io -> localhost:3000

Connections                   ttl     opn     rt1     rt5     p50     p90
                              26      0       0.00    0.00    5.05    9.54

HTTP Requests
-------------
```

この`https://xxxxxxxx.ngrok.io`のアドレスがローカルのexpressサーバと繋がります。
`xxxxxxxx`の部分は実行する度に乱数が入ります。
ちなみに有料版もあって、そちらならドメインが固定できます。

このアドレスをCEKコンソールのサーバ設定画面の「ExtensionサーバーのURL」に貼っつけます。
アドレスの末尾に`/clova/`を追加して、`https://xxxxxxxx.ngrok.io/clova/`って感じで。
無料版の場合ngrokを起動する度にドメインが変わるので、その度にここも書き換えないといけません…

![image](https://qiita-image-store.s3.amazonaws.com/0/207109/cbf54ccf-a269-05d0-0b06-a99d53aebe58.png)

### Node実行
ここまでくればあとはNodeを実行してexpressサーバをたてるだけです。
以下のコマンドを実行しましょう。

```
$ node index.js
```

そして対話モデル画面のテストか、実機に以下のように話かけてみましょう。
Clovaは開発アカウントとClovaに紐付いてるアカウントが一緒なら勝手に開発中のスキルがテストできるようになります。いい子。

あなた「Clova、リモコンを開いて」
Clova 「うん」
あなた「エアコンつけて」
Clova 「エアコンをつけます」

これでエアコンが操作できればおっけーです！



### nodemonでの実行
先程ちらっと書きましたが、ローカルでサーバを動かして開発するときこのnodemonがすごく便利です。

nodemonについて詳しくはこちら。
[Node.jsのソース修正後、nodemonで自動再起動](https://qiita.com/twipg/items/cb969b335d66c4aee690)

とりあえず使ってみるならnpmでインストールして（-gオプションつけてグローバルインストールでいいと思います）、

```
npm i nodemon -g
```

さきほどのindex.jsの実行を以下のコマンドに置き換えてみましょう。

```
nodemon index.js
```

そしてソースを修正してみると自動でnodeプロセスも再起動してくれます！
超便利！

これはGoogle HomeやAlexaの開発でも同様に使えるので、クラウドへデプロイやログ反映のタイムラグに消耗してる方は是非ともngrok + nodemonでの開発をお試しください！



# おわりに
Clovaさんからもエアコン操作できるようになったので、今年の夏もなんとか乗り越えられそうです。

ちなみにClova Friendsでも別売りクレードルを使うと赤外線を使えます。
まだ発売時期が明確になってませんが、待ち遠しいですね。

なおClova WAVEなら赤外線機能は内蔵されてます。
が、Clova Extensions Kitでの開発はできません…

IFTTTのthis対応もしてくれないかなあ。