こんにちは。楽楽精算開発チームの岡本です。
会社で購入したGoogleHomeで自由に遊べる権利を頂いたので、色々と遊ばせてもらいました。
先日その内容を社内でプレゼンする機会があったのですが、せっかくなのでGoogleHome自身にプレゼンしてもらいました。
今回は、その際に実施した設定を説明しようと思います。
※設定方法についてはwest-cさんが既に書かれているので、設定した内容だけ書いていきます。
今回やりたいこと
- スマートフォンでプレゼン開始を指示する。
- ディスプレイにスライドが表示される。
- GoogleHomeがスライドの内容を喋り始める。
- スライドの内容を喋り終えると、次のスライドに切り替わる。
- スライドが終了するまで2~4を繰り返す。
準備するもの
Wan側
- Action on Google
- Googleアシスタント内で呼出し可能な
チャットアプリ
*1を構築できるサービスです。 - 構築した
チャットアプリ
から更に別のWebサービスを呼び出すこともできるので、この仕組を用いればGoogleアシスタントから直接Webサービスを呼び出せます。 - 今回はDialogflowを呼び出すように構築しています。
- Googleアシスタント内で呼出し可能な
- Dialogflow
- Firebase
- いわゆるBaasです。
- 今回はホスティング機能とDB機能を使用します。
Lan側
- RaspberryPi
- 超小型のコンピューターです。
- 今回は以下の機能を実装しています。
- ディスプレイへのスライド切替え通知
- GoogleHomeへのメッセージ通知
- GoogleHome
- いわゆるスマートスピーカー。今回は喋らせるだけなのでスマートな機能は使いません。
ざっくりとした処理の流れ
- スマートフォンのGoogleアシスタントからAction on Googleで構築した
チャットアプリ
を呼び出す。 チャットアプリ
で入力した音声データをDialogflowに連携する。- Dialogflowの解析結果テキストをFirebaseのDBに保存する。
- 保存したテキストをRaspberryPiに通知する。
(通知されたテキストがプレゼン開始キーワードの場合は、プレゼンを開始する。) - スライドの表示/切り替えをディスプレイに通知する。
- 喋らせるメッセージをGoogleHomeに通知する。
Action on Googleの設定
Action on Googleで新規プロジェクトを作成しAction
とApp information
を設定します。
Action
ADD ACTIONS
からDialogflowを選択します。
App information
重要なのはAssistant app name
の項目だけです。
Assistant app name
で設定した名前でGoogleアシスタントでチャットアプリ
を呼び出すことになります。
今回は「発表アプリ」にしたので、スマホに「OK Google 発表アプリにつないで」と話しかけるとチャットアプリ
が起動します。
それ以外の項目については適当に設定してしまって問題ないです。
以上でAction on Googleの設定は完了です。
Dialogflowの設定
Action on GoogleのAction
設定から、Dialogflow画面に遷移できるので、新規プロジェクトを作成しIntents
とFulfillment
を設定します。
Intentsの設定
チャットアプリ
で入力した音声データに対して、どのように振舞うのかを設定します。今回は以下の2つを設定します。
- Default Welcome Intent
チャットアプリ
が起動した時の振舞いを設定します。
今回は、アプリ起動時にチャットアプリ
が「発表アプリを起動しました。」と応答するようにText response
を設定しました。
- プレゼン開始
チャットアプリ
にプレゼン開始を指示した時の振舞いを設定します。今回は以下のような振舞いを想定しています。
1.チャットアプリに「プレゼン開始」と音声入力する。
2.「プレゼン開始」のキーワードをFirebaseに保存する。
3.チャットアプリが「プレゼンを開始しました。」と応答する。
「プレゼン開始」の音声入力でsaveData
というアクションが実行されるように設定します。
saveData
の内容についてはFulfillment
で設定します。
アクション実行後、チャットアプリ
が「プレゼンを開始しました。」と応答するように設定します。
Fulfillmentの設定
Inline Editor
をENABLED
に変更し、index.js
とpackage.json
を以下のように設定します。
/** index.js **/ 'use strict'; const firebase = require("firebase"); const functions = require("firebase-functions"); const DialogflowApp = require("actions-on-google").DialogflowApp; // Firebaseへの接続情報 var config = { apiKey: "XXXXXXXXXXXXXXXXXXXXXX", authDomain: "XXXXXXXXXXXXXXXXXXXXXX", databaseURL: "XXXXXXXXXXXXXXXXXXXXXX", projectId: "XXXXXXXXXXXXXXXXXXXXXX", storageBucket: "XXXXXXXXXXXXXXXXXXXXXX", messagingSenderId: "XXXXXXXXXXXXXXXXXXXXXX" }; firebase.initializeApp(config); exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { var app = new DialogflowApp({request, response}); let actionMap = new Map(); // saveDataアクションを登録 actionMap.set("saveData", function(app) { // Firebaseにキーワードを保存する firebase.database().ref("/googlehome").set({word:"プレゼンを開始します"}); }); app.handleRequest(actionMap); });
Firebaseへの接続情報
はFirebaseの画面でウェブアプリに Firebase を追加
をクリックして表示されるコードを使用します。
/** package.json **/ { "name": "dialogflowFirebaseFulfillment", "description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase", "version": "0.0.1", "private": true, "license": "Apache Version 2.0", "author": "Google Inc.", "engines": { "node": "~6.0" }, "scripts": { "start": "firebase serve --only functions:dialogflowFirebaseFulfillment", "deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment" }, "dependencies": { "actions-on-google": "^1.5.x", "firebase": "^4.8.0", "firebase-admin": "^4.2.1", "firebase-functions": "^0.5.7", "apiai": "^4.0.3" } }
設定後、DEPLOY
をクリックしFirebaseへスクリプトをデプロイします。
以上でDialogflowの設定は完了です。
Firebaseの設定
FirebaseのDatabase
にデータ保存場所とアクセスルールを設定します。
データ保存場所の設定
Database
> データ
から保存場所を作成します。今回は/googlehome/word
に作成します。
作成した保存場所には、PUTでデータを保存出来ます。
curl -X PUT \ https://XXXXXX.firebaseio.com/googlehome/word.json \ -H 'content-type: application/json' \ -d '"保存キーワード"'
保存したデータはGETで取得できます。
curl -X GET \ https://XXXXXX.firebaseio.com/googlehome/word.json \ -H 'content-type: application/json'
アクセススールの設定
Database
> ルール
からDBへのアクセスルールを設定します。
今回は設定簡易化のため/googlehome
配下のデータには認証無しでアクセスできるように設定しています。
{ "rules": { "googlehome": { ".read": true, ".write": true }, ".read": "auth != null", ".write": "auth != null" } }
以上でFirebaseの設定は完了です。
RaspberryPiの設定
以下の内容をスクリプト化し、RaspberryPiのNode.js上で実行します。
- GoogleHomeへのメッセージ通知
- ディスプレイへのスライド表示通知
- FirebaseのDB更新通知の受信
※RaspberryPiに初期インストールされているNode.jsはバージョンが古いので、最新の安定バージョンに更新する必要があります。
GoogleHomeへのメッセージ通知
GoogleHome任意のメッセージをプッシュするNode.js用ライブラリが公開されているので、ありがたく使わせていただきます。
→google-home-notifier
- ライブラリのインストール
$ npm init $ npm install google-home-notifier
- 動作確認
/** testMessage.js **/ const googlehome = require("google-home-notifier"); const language = "ja"; // デバイス設定(Google-Homeで始まる全デバイスにメッセージが通知される。) googlehome.device("Google-Home", language); // 通知するメッセージ googlehome.notify("こんにちは。私はグーグルホームです。", function(res) { console.log(res); });
※test.jsの文字コードはUTF8で作成する。
$ node testMessage.js Device "Google-Home-XXXXXXXXXXXXXXXXXXXXXX" at 192.168.1.11:8009 <- 応答したGoogleHomeのデバイス名 Device notified
ディスプレイへのスライド表示通知
スライドの表示にはfbi
というコマンドを使います。
- コマンドのインストール
$ sudo apt-get install fbi
- 動作確認
$ sudo fbi -nocomments -noverbose -a -T 1 -d {出力場所} {画像ファイルのパス}
※コンソール出力の場合は、{出力場所}に/dev/fb0
を、HDMI出力の場合は/dev/fb1
を設定します。
FirebaseのDB更新通知の受信
Firebaseのドキュメントを元に設定します。
- ライブラリのインストール
$ npm install firebase
- 動作確認
/** testFirebase.js **/ // Firebaseへの接続情報(Dialogflowの項目で設定したものと同じ) var config = { apiKey: "XXXXXXXXXXXXXXXXXXXXXX", authDomain: "XXXXXXXXXXXXXXXXXXXXXX", databaseURL: "XXXXXXXXXXXXXXXXXXXXXX", projectId: "XXXXXXXXXXXXXXXXXXXXXX", storageBucket: "XXXXXXXXXXXXXXXXXXXXXX", messagingSenderId: "XXXXXXXXXXXXXXXXXXXXXX" }; firebase.initializeApp(config); const path = "/googlehome"; const key = "word"; const db = firebase.database(); // 更新通知を受信した時の処理を記述 db.ref(path).on("value", function(changedSnapshot) { // 更新された値をログに表示 console.log("取得キーワード:" + changedSnapshot.child(key).val()); });
$ node testFirebase.js # Firebaseに「テスト」をPUTしてDBを更新する 取得キーワード:テスト
index.js作成
実行ファイルとしてindex.jsを作成します。
/** index.js **/ const firebase = require("firebase"); const exec = require("child_process").exec; const googlehome = require("google-home-notifier"); // メッセージを通知するGoogleHomeの設定 const language = "ja"; const deviceName = "Google-Home-XXXXXXXXXXXXXXXXXXXXXX"; googlehome.device(deviceName, language); // Firebaseへの接続情報を設定 var config = { apiKey: "XXXXXXXXXXXXXXXXXXXXXX", authDomain: "XXXXXXXXXXXXXXXXXXXXXX", databaseURL: "XXXXXXXXXXXXXXXXXXXXXX", projectId: "XXXXXXXXXXXXXXXXXXXXXX", storageBucket: "XXXXXXXXXXXXXXXXXXXXXX", messagingSenderId: "XXXXXXXXXXXXXXXXXXXXXX" }; firebase.initializeApp(config); // GoogleHomeへメッセージを通知 var notifyGoogleHome = function(word) { googlehome.notify(word, function(res) { console.log(res); }); }; var totalSpeakTIme = 0; var speak = function(word, speakTime) { // 前回メッセージの終了後、メッセージを通知 setTimeout(function() { notifyGoogleHome(word); }, totalSpeakTIme); // 今回メッセージの秒数分カウントアップ totalSpeakTIme += (speakTime * 1000); } // ディスプレイへスライドの表示を通知 var notifyDisplay = function(imgPath) { // fbiコマンドを使ってディスプレイに画像を表示 exec("fbi -nocomments -noverbose -a -T 1 -1 -d /dev/fb0 " + imgPath, function(err, stdout, stderr){ if (err) { console.log(err); } }); }; var totalDisplayTIme = 0; var show = function(imgPath, speakTime) { // 前回スライドの終了後、表示を通知 setTimeout(function() { notifyDisplay(imgPath); }, totalDisplayTIme); // 今回スライドの表示秒数分カウントアップ totalDisplayTIme += (speakTime * 1000); } // Firebaseの更新通知を受取った時の処理 const path = "/googlehome"; const key = "word"; const db = firebase.database(); db.ref(path).on("value", function(changedSnapshot) { // 更新された値を取得 const value = changedSnapshot.child(key).val(); if (value === "プレゼンを開始します") { // 開始キーワードの場合はプレゼン開始 // 登録された値をFirebaseから消しておく db.ref(path).set({[key]: ""}); // プレゼン中は何もしない if (totalDisplayTIme > 0 || totalSpeakTIme > 0) { return; } // プレゼン開始メッセージをGoogleHomeに喋らせる speak("承知しました。" + value, 10); // 1枚目のスライドを表示する show("./img/001.jpg", 15); // 以下、プレゼン用スクリプトを記述 } });
ファイルが作成できたら、実行します。
$ sudo node index.js
※fbi
コマンドの実行時にroot権限が必要なのでsudo
付きで実行します。
以上でRaspberryPiの設定は完了です。
実際にやってみる
設定完了後、スマホに対して「発表アプリにつないで」「プレゼン開始」と指示すると、index.jsに書かれた内容でGoogleHomeがプレゼンをしてくれます。
長いので冒頭部分だけですが、実際にこんな感じでGoogleHomeにプレゼンしてもらいました。
参考
Google Home開発入門 / google-home-notifier解説
Raspberry Pi でTFT液晶モジュールにいろいろ表示する
*1:Googleアシスタントと会話できるアプリ