はじめに
我が家には1歳過ぎの子供がいます。
少しずつ話せる様になってきましたが、文字の入力はおろか、
文字が読める様になるのもまだまだ遠い未来です。
そこで、外出中の私と自宅の子供がコミュニケーションを取れる環境を作っていきたいと思います。
今回は第一弾として外出先から自宅のGoogleHomeを喋らせられる様にしていきます。
(2019/6/10追記)
この記事のプログラムのままでは、グループトークに対応できないことがわかりました。
他にもいくつか改善点が見つかったので、記事を分けて少しずつプログラムを充実させていくことにします。
関連記事
- 第1弾:基本的な設定(本記事)
- 第2弾:グループトークに対応させる
- 第3弾:取りこぼしがない様にする(作成中)
全体像
こんな感じになる様にしたいと思います。
前回のps4-wakerのプログラムで、Firebase→RasberryPiのロジックはできているので、その前後を作り込んでいきます。
Firebaseの構成
ps4-wakerの記事で作ったRealtime Databeseの構成を更新します。
googlehomeに加え、lineという項目を追加しました。
lineの配下にはrecieveとsendを用意します。
今回はrecieveを使ってlineからrevieveしたメッセージをgooglehomeへ送ります。
LINE Developersへ登録
LINEからFirebaseにデータを送るために、LINE Messaging APIを使います。
これはいわゆるbotのことで、芸能人のアカウントやMicrosoftのチャットボットである「りんな」などもこのサービスがベースとなっています。
登録はこちらからできます。
案内に沿ってプロバイダーとMessaging APIのチャンネルを作成してください。
登録が完了したらコンソールから作成したプロバイダー、チャンネルを選択していきます。
「チャンネルの基本設定」の中に「Webhook送信」という項目があります。
デフォルトでは利用しないになっているので、ここを利用するに変更します。
併せて、「Webhook URL」を設定します。
上図の通り、データを保存したいfirebaseのパスを入力します。
右のほうにある「接続確認」ボタンで正しく書き込みできるか確かめましょう。
同じページの下方に、botを登録するためのQRコードがあります。
手持ちのスマホなどから読み取り、botを登録しましょう。
Firebaseまでの動作確認
それでは登録したbotになにかメッセージを送ってみましょう。
すぐに既読となり、自動の返信が送られてきます。
(前述の「チャンネル基本設定」から自動返信のオンオフも切り替えられます)
Firebaseのコンソールからrecieveにデータが追加されていることを確認しましょう。
こんな感じになっていればOKです。
botを使う人が何人かいる場合(パパとママなど)はそれぞれの人にテストしてもらって、
それぞれのuserIdを確認しておきます。
プログラム作成
あとはプログラム書いてラズパイにおけば終わりです。
プログラムはこの記事とこの記事に書いたコードを組み合わせればあっという間です。
index.js
//lineを送った人のID const father = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; const mother = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; //google-home-notifierの準備 const googlehome = require('google-home-notifier') const language = 'ja'; googlehome.device('リビングルーム', language); //リビングルームはgooglehomeの名前。ipを設定する場合は間違っていてもOK googlehome.ip("192.168.xx.xx"); //firebaseの準備 const fnc = require("../home-controler/functions.js") var firebase = require("firebase") var firebaseConfig = { apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", authDomain: "project-name.firebaseapp.com", databaseURL: "https://project-name.firebaseio.com", projectId: "project-name", storageBucket: "project-name.appspot.com", messagingSenderId: "9999999999999999", appId: "1:9999999999999:web:xxxxxxxxxxxxxx" }; firebase.initializeApp(firebaseConfig); const path = "/line/recieve"; const keyword = "recieve"; var db =firebase.database(); var ref = db.ref(path); //dbの更新があったら全てを取得するfunction起動 // ref.on("value", function(snapshot){ // var word = snapshot.val(); // console.log(word) // }) //dbにレコードが追加されたら追加されたところだけを取得するfunction起動 ref.on("child_added",function(snapshot){ var newMessage = snapshot.val(); var spokenMessage = (newMessage.events[0]['message']['text']); var userId = newMessage.events[0]['source']['userId']; console.log(spokenMessage); var person = false; if (userId == father){ person = "パパからラインです。" }else if (userId == mother) { person = "ママからラインです。" } if (person){ googlehome.notify(person+spokenMessage, function(res){ console.log(res); }) } })
ps4-wakerではref.on(“value”,function(){})の形を使いましたが
今回はvalueをchild_addedにしています。
valueとchild_addedの違いは
value:追加・修正・削除によらず、データに変化があったら全部のデータを取得する。
child_added:要素が追加されたら、追加されたデータだけを取得する。
という感じです。
今回は古いメッセージを蓄積するので毎度全部のデータを読み込む必要がありあません。なのでchild_addedを使用します。
jsonのデータの抜き取り方法は色々あるのかもしれませんが、
構造が分かっているため力技で抜き取りました。
39行目は普通ならnewMessage[‘events’][0][‘message’][‘text’]としたくなるところですが
newMessage.events[0][‘message’][‘text’]としています。
firebaseのドキュメントに「.」で子要素を取得する方法が書いてあったのでこうしています。
しかし、newMessage.events.0.message.textやnewMessage.events[0].message.textなどの表記ではうまくいきませんでした。
原因も仕組みもよくわかりませんが、深追いはやめておきます。
(なんかすごくレベルの低いことを言っている気がする…)
実行はいつも通り
$ node index.js
です。
まとめ
いい感じにLINEからgooglehomeを喋らせることができました。
ただ今のプログラムだと、一度しか話してくれないため、
googlehomeのある部屋にいなかったりして聞き逃すと再確認ができません。
recieveにデータを蓄積しているので
「OK Google、新着ラインある?」的なトリガーで
蓄積しているデータを全て吐き出し、一度クリアーするプログラムなんかを作っても良いかもしれません。
気が向いたら作ります。
後日談
子供のために作ったプログラムでしたが、想定外の使われ方をしています。
私は普段スマホをマナーモードにしているくせに自宅にいるときは身につけていないので、
ラインや着信があっても気づかないことが多々あります。
するとgooglehomeが「ママからLINEです。スマホ見て。」と喋り出します。