こんにちは。楽楽精算開発チームの岡本です。
会社で購入したGoogleHomeで自由に遊べる権利を頂いたので、色々と遊ばせてもらいました。
先日その内容を社内でプレゼンする機会があったのですが、せっかくなのでGoogleHome自身にプレゼンしてもらいました。
今回は、その際に実施した設定を説明しようと思います。
※設定方法についてはwest-cさんが既に書かれているので、設定した内容だけ書いていきます。
今回やりたいこと
- スマートフォンでプレゼン開始を指示する。
- ディスプレイにスライドが表示される。
- GoogleHomeがスライドの内容を喋り始める。
- スライドの内容を喋り終えると、次のスライドに切り替わる。
- スライドが終了するまで2~4を繰り返す。
準備するもの
Wan側
- Action on Google
- Dialogflow
- 自然言語の解析エンジンです。受取った音声データを解析してテキストに変換してくれます。
- また、Firebaseのホスティングを用いたスクリプト実行も可能なので、変換したテキストを他のWebサービスに連携させたりもできます。
- 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つを設定します。
Fulfillmentの設定
Inline Editor
をENABLED
に変更し、index.js
とpackage.json
を以下のように設定します。
'use strict';
const firebase = require("firebase");
const functions = require("firebase-functions");
const DialogflowApp = require("actions-on-google").DialogflowApp;
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();
actionMap.set("saveData", function(app) {
firebase.database().ref("/googlehome").set({word:"プレゼンを開始します"});
});
app.handleRequest(actionMap);
});
Firebaseへの接続情報
はFirebaseの画面でウェブアプリに Firebase を追加
をクリックして表示されるコードを使用します。
{
"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
const googlehome = require("google-home-notifier");
const language = "ja";
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
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を作成します。
const firebase = require("firebase");
const exec = require("child_process").exec;
const googlehome = require("google-home-notifier");
const language = "ja";
const deviceName = "Google-Home-XXXXXXXXXXXXXXXXXXXXXX";
googlehome.device(deviceName, language);
var config = {
apiKey: "XXXXXXXXXXXXXXXXXXXXXX",
authDomain: "XXXXXXXXXXXXXXXXXXXXXX",
databaseURL: "XXXXXXXXXXXXXXXXXXXXXX",
projectId: "XXXXXXXXXXXXXXXXXXXXXX",
storageBucket: "XXXXXXXXXXXXXXXXXXXXXX",
messagingSenderId: "XXXXXXXXXXXXXXXXXXXXXX"
};
firebase.initializeApp(config);
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) {
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);
}
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 === "プレゼンを開始します") {
db.ref(path).set({[key]: ""});
if (totalDisplayTIme > 0 || totalSpeakTIme > 0) {
return;
}
speak("承知しました。" + value, 10);
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液晶モジュールにいろいろ表示する