はじめに
7/12に「Clova Extensions Kit」(以下CEK)が公開されました。
まだ審査やリリースはできませんが、開発自体はできます!
早速ちょこちょこ触りがてら、そういえばClova Friendsから家電操作できないなと思い、手始めに家電操作スキルを作ってみました。
↓こんなかんじの。
今日ちょっと暑すぎなのでClovaさんにエアコンつけてもらえるようにした。#clova #clova_cek #スマートスピーカー pic.twitter.com/ODMv3k3yfe
— 田中みそ (@miso_develop) 2018年7月14日
処理の流れ
今回はCEKの実装に絞って書いていきます。
Firebaseから先は既存の仕組みを使うので、過去記事を参照下さい。
Google Homeに話しかけてエアコンを操作してみる
Google Home、IFTTT、Firebase、Node.js、irMagicianを使ってシーリングライトを音声操作する
環境
とりあえず一時的に動かしてみたので以下の構成です。
サーバもAWSなりGCPなりのクラウドは使わず、express + ngrokでローカルサーバを立ててます。
常時稼働させるならラズパイとクラウドでの運用となります。
- OS: Windows 10
- 言語: Node.js v8.11.3
- サーバ: express + ngrok
CEK開発の流れ
おおまかに以下の流れになります。
Clova Developer Centerでスキルの新規作成、基本設定
dotstudioさんの記事が分かりやすく説明されてます。
本日リリース!LINE Clovaのスキル開発の始め方〜申請編〜
なお「サーバー設定」、「配布情報」、「個人情報の保護および規約同意」はすっとばせます。
「サーバー設定」についてはうごかしてみるで後ほど設定します。
Clova Developer Centerでインテント、スロット定義
最後のページで「対話モデル」のボタンをクリックすると、別窓でインテントやスロットを定義する画面が開きます。
ここの操作は@imajoririさんの記事でわかりやすく説明されています。
[入門]Clovaスキル(CEK)は作りながら覚えて行く(インテント、スロットなど登録編)
スロット
以下の2つのスロットを定義します。
target
代表後 | 同義語 |
---|---|
電気 | ライト |
テレビ | |
エアコン |
action
代表後 | 同義語 |
---|---|
消して | オフ |
つけて | 起動, オン |
とりあえずオンオフのみを。
インテント
以下の1つのインテントを定義します。
ControllIntent
サンプル発話 |
---|
target action |
スロット名 | スロットタイプ | スロット値 |
---|---|---|
target | target | target |
action | action | action |
単純にスロット並べただけです。
以上を定義したらビルドしましょう。
ビルドはそこそこ時間(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のパスに合わせます。
この辺りはラズパイからの家電操作部に関連してくるので、詳しくは過去記事を参照してみて下さい。
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で説明すると、こちらからzipをダウンロードすると中にexeが1つ入ってます。
それをどこかに置いて実行するだけです。インストールもいりません。
こちらから他の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を起動する度にドメインが変わるので、その度にここも書き換えないといけません…
Node実行
ここまでくればあとはNodeを実行してexpressサーバをたてるだけです。
以下のコマンドを実行しましょう。
$ node index.js
そして対話モデル画面のテストか、実機に以下のように話かけてみましょう。
Clovaは開発アカウントとClovaに紐付いてるアカウントが一緒なら勝手に開発中のスキルがテストできるようになります。いい子。
あなた「Clova、リモコンを開いて」
Clova 「うん」
あなた「エアコンつけて」
Clova 「エアコンをつけます」
これでエアコンが操作できればおっけーです!
nodemonでの実行
先程ちらっと書きましたが、ローカルでサーバを動かして開発するときこのnodemonがすごく便利です。
nodemonについて詳しくはこちら。
Node.jsのソース修正後、nodemonで自動再起動
とりあえず使ってみるなら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対応もしてくれないかなあ。