ããã«ã¡ã¯ã楜楜粟ç®éçºããŒã ã®å²¡æ¬ã§ãã äŒç€Ÿã§è³Œå
¥ããGoogleHomeã§èªç±ã«éã¹ãæš©å©ãé ããã®ã§ãè²ã
ãšéã°ããŠããããŸããã å
æ¥ãã®å
容ã瀟å
ã§ãã¬ãŒã³ããæ©äŒããã£ãã®ã§ããããã£ãããªã®ã§GoogleHomeèªèº«ã«ãã¬ãŒã³ããŠããããŸããã ä»åã¯ããã®éã«å®æœããèšå®ã説æããããšæããŸãã â»èšå®æ¹æ³ã«ã€ããŠã¯ west-cãã ãæ¢ã«æžãããŠããã®ã§ãèšå®ããå
容ã ãæžããŠãããŸãã ä»åããããããš ã¹ããŒããã©ã³ ã§ãã¬ãŒã³éå§ãæç€ºããã ãã£ã¹ãã¬ã€ã«ã¹ã©ã€ãã衚瀺ãããã GoogleHomeãã¹ã©ã€ãã®å
容ãåãå§ããã ã¹ã©ã€ãã®å
容ãåãçµãããšã次ã®ã¹ã©ã€ãã«åãæ¿ããã ã¹ã©ã€ããçµäºãããŸã§ïŒïœïŒãç¹°ãè¿ãã æºåãããã® WanåŽ Action on Google Googleã¢ã·ã¹ã¿ã³ã å
ã§åŒåºãå¯èœãª ãã£ããã¢ã㪠*1 ãæ§ç¯ã§ãããµãŒãã¹ã§ãã æ§ç¯ãã ãã£ããã¢ã㪠ããæŽã«å¥ã® WebãµãŒãã¹ ãåŒã³åºãããšãã§ããã®ã§ããã®ä»çµãçšããã° Googleã¢ã·ã¹ã¿ã³ã ããçŽæ¥ WebãµãŒãã¹ ãåŒã³åºããŸãã ä»å㯠Dialogflow ãåŒã³åºãããã«æ§ç¯ããŠããŸãã 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ã€ãèšå®ããŸãã Default Welcome Intent ãã£ããã¢ã㪠ãèµ·åããæã®æ¯èããèšå®ããŸãã ä»åã¯ãã¢ããªèµ·åæã« ãã£ããã¢ã㪠ããçºè¡šã¢ããªãèµ·åããŸãããããšå¿çããããã« Text response ãèšå®ããŸããã ãã¬ãŒã³éå§ ãã£ããã¢ã㪠ã«ãã¬ãŒã³éå§ãæç€ºããæã®æ¯èããèšå®ããŸããä»åã¯ä»¥äžã®ãããªæ¯èããæ³å®ããŠããŸãã ïŒïŒãã£ããã¢ããªã«ããã¬ãŒã³éå§ããšé³å£°å
¥åããã ïŒïŒããã¬ãŒã³éå§ãã®ããŒã¯ãŒããFirebaseã«ä¿åããã ïŒïŒãã£ããã¢ããªãããã¬ãŒã³ãéå§ããŸãããããšå¿çããã ããã¬ãŒã³éå§ãã®é³å£°å
¥åã§ 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ã¢ã·ã¹ã¿ã³ã ãšäŒè©±ã§ããã¢ããª