#Realtime Database側
こんな感じにしておく。
スキルが起動するとOn。キャンセルするとOffにする。
Root
-launch : on/off
#実装
'use strict';
const Alexa = require('ask-sdk-core');
const admin = require('firebase-admin');
const serviceAccount = require('秘密鍵jsonのパス');
admin.initializeApp( {
credential: admin.credential.cert(serviceAccount),
databaseURL: "データベースのURL"
} );
const db = admin.database();
const ref = db.ref(); //ハマりポイント1
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
async handle(handlerInput) {
await ref.update({
"launch" : "on"
}, (error)=>{
if(error) {
console.log("書き込み失敗");
console.log(error);
}else{
console.log("書き込み成功");
}
});
const speechText = '起動したよ';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.getResponse();
},
};
const CancelAndStopIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'
|| handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');
},
async handle(handlerInput) {
await ref.update({
"launch" : "off"
}, (error)=>{
if(error) {
console.log("書き込み失敗");
console.log(error);
}else{
console.log("書き込み成功");
}
});
const speechText = 'さようなら!';
return handlerInput.responseBuilder
.speak(speechText)
.getResponse();
},
};
let skill; //ハマりポイント2
exports.handler = async (event, context) =>{
console.log(skill);
if(!skill){
skill = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
LightRequestHandler)
.addErrorHandlers(ErrorHandler)
.create();
}
return skill.invoke(event);
}
#(ハマるとしたら多分私ぐらいだが)ハマりポイント解説
##Realtime Databaseのルート指定方法
const ref = db.ref();
色々な方のソースを参考にさせていただきましたが、どれもルートの下にちゃんと構造作られてて、ルート直下の要素を更新するサンプルが見つけられませんでした。
ちゃんと公式サイトに載ってました。この書き方でルートを指定できました。
##handlerの実装方法
ここの部分ですが・・・
let skill; //ハマりポイント2
exports.handler = async (event, context) =>{
console.log(skill);
if(!skill){
skill = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
LightRequestHandler)
.addErrorHandlers(ErrorHandler)
.create();
}
return skill.invoke(event);
}
こんな風にも書くこともできます。
const skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
.addRequestHandlers(
LaunchRequestHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
LightRequestHandler)
.addErrorHandlers(ErrorHandler)
.lambda();
一応公式でも「また、ASK SDK v2 for Node.jsで提供されるlambdaビルダー関数を使って、Skillのインスタンスを呼び出して応答を返すLambdaハンドラー関数を簡単に作成することもできます。」と説明されてます。
ASK SDK for Node.jsの公式ガイド
###ですが、動きが違いました。
後者の書き方だとRealtime Databaseのセッションが残ってしまい(?)、Lambdaでタイムアウトが発生して、結果的に「スキルからの応答に問題があります」とエラーが返ってきてしまいました。
(Realtime Databaseへの更新はうまくいきます)
今のところ理由は定かではありませんが、とりあえず前者のcreate()でハンドラ作る方法を推奨します。
#動きの違いが気になって試したこと
##goOfflineでRealtime Databaseとの接続を切れるらしい
###lambdaで試した
await ref.update({
"launch" : "on"
}, (error)=>{
if(error) {
console.log("書き込み失敗");
console.log(error);
}else{
console.log("書き込み成功");
}
});
db.goOffline(); //←これを追記
結果:タイムアウトは変わらず。ダメでした。
###ローカルで試したけど・・・
'use strict';
//省略
const db = admin.database();
const ref = db.ref();
const dbupdate = async () => {
await ref.update({"launch" : "on"});
db.goOffline();
};
dbupdate();
結果:こいつもダメでした。
間違いなどあったら訂正しますので是非ご指摘ください。
#追記
12/4 タイトルが日本語的にあれだったので直しました
12/6 ソース汚くて恥ずかしいのでスリム化しました
12/6 試したこと色々追記しました。田中みそさん、にしぞのさんのディスカッションも貴重。