Pei's Lab

LINEで送ったメッセージをGoogleHomeで喋らせる 第1弾

はじめに

我が家には1歳過ぎの子供がいます。
少しずつ話せる様になってきましたが、文字の入力はおろか、
文字が読める様になるのもまだまだ遠い未来です。

そこで、外出中の私と自宅の子供がコミュニケーションを取れる環境を作っていきたいと思います。
今回は第一弾として外出先から自宅のGoogleHomeを喋らせられる様にしていきます。

(2019/6/10追記)
この記事のプログラムのままでは、グループトークに対応できないことがわかりました。
他にもいくつか改善点が見つかったので、記事を分けて少しずつプログラムを充実させていくことにします。

関連記事


全体像

こんな感じになる様にしたいと思います。
前回の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です。スマホ見て。」と喋り出します。