Pei's Lab

Google HomeでLINEを送信する

はじめに

これまでの記事でLINEで送ったメッセージをGoogle Homeで読み上げるプログラムは完成させました。

今回はその逆、Google Homeに話しかけてLINEでメッセージを送信するプログラムを作っていきます。

全体像

LINEを送りっぱなしの片道でも良いのですが、今回はGoogleHomeに戻ってくるところまで実装したいと思います。

Google HomeからRaspberry Piまでの流れの詳細はこちらの記事をご覧ください。
LINE Developersの設定についてはこちらの記事をご覧ください。

IFTTTの設定

My Applets => New Applet => ThisにGoogle Assistantを選択
“Say a phrase with a text ingredient”を選択し、
下記の様に設定します。(パパの場合)

続いてThatにはWebhookを選択し、以下の様に設定します。

これで設定は完了したので、Google Homeに話しかけてみます。

「OK, Google. パパ 何時に帰ってくる?」
と話しかけると、すぐにFirebaseが更新されます。

こんな感じになりました。
Google Assistantの仕様かIFTTTの仕様かわかりませんが、勝手に形態素解析をして分かち書きをしてくれているようです。
今回のプログラムにおいては完全におせっかいになってしまっています。

後々コード書くときにはスペースがあることに注意しましょう。

ちなみに”帰ってくる”の”る”は表示されていないだけでデータベースにはしっかり記録されています。

Line bot SDKのインストール

工程を一つ飛ばして、先にLINEbotに関わるSDKの準備をします。
Raspberry Pi上のお好きなところにディレクトリを作成し、

$ npm init

しましょう。
私の環境では下記のような構造になっています。

真ん中あたりのindex.jsが後々プログラムを書いていくファイル(ps4の記事で作成したプログラム)です。

下の方のLineが今npm initしたディレクトリで、ここにline-bot-sdkを入れます。
では引き続き、

$ npm install @line/bot-sdk --save

とします。

これでsdkのインストールが完了し、ラズパイからLINEbotを弄れるようになります。

ラズパイのコーディング

次に、Firebaseの更新を検知してLINEbotにメッセージを送信させるプログラムを書いていきます。

前述の通り、home-controller/index.jsを編集することにします。

index.js

//firebaseとその他必要なファイルをインポート
var firebase = require("firebase")
var ps4 = require("./ps4.js")	//ps4操作に関わる処理を記載
var fnc = require("./functions.js")	//いろんなプログラムで使うことになりそうな関数をまとめて記載

//追加部① Lineディレクトリ直下にvoice2line.jsというファイルを作成しておきます。コードは後述。
var v2l = require("../../Line/voice2line.js")

//firebaseのconfig
var firebaseConfig = {
        apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        authDomain: "project-name.firebaseapp.com",
        databaseURL: "https://project-name.firebaseio.com",
        projectId: "project-name",
        storageBucket: "project-name.appspot.com",
        messagingSenderId: "9999999999999",
        appId: "1:99999999999:web:c6bxx99xx99xx99x99"
      };

firebase.initializeApp(firebaseConfig);



//dbに接続する準備
const path = "/googlehome";
const keyword = "action";
var db =firebase.database();
var ref = db.ref(path);

//以下の形で待ち受けると、db更新時にfunctionが起動する(いわゆるリスナー)
//dbから呼び込まれたデータをsnapshotとして引数に設定する。
ref.on("value",function(snapshot){
    //snapshot.val()でjson形式のデータを取得できる。
    //functions.jsに作ったgetJsonData関数を使って、必要な部分だけを取り出す。
    var action = fnc.getJsonData("action",snapshot.val());

    // actionには「ps4 起動」のような文字列が入っている
    // action.split(" ")で単語ごとの配列に分解し、
    //1つ目の要素(上の例なら「ps4」)を取り出して場合分けする
    switch (action.split(" ")[0]) {

        //ps4に関わるコマンドの場合
        case "ps4":
            ps4.command(action);
            break;

        //追加部②「パパ」「ママ」それれの場合を作成
        case "パパ":
	    v2l.command(action);
            break;

       	case "ママ":
	    v2l.command(action);
            break;

        //ps4以外のコントロールを追加する場合はここに追記する
        //case "":
            //break;
            
        default:

    }
})

変更点は2箇所です。

①LINEbotに関わるプログラムを記載するvoice2line.jsをrequireします。
ディレクトリが異なるので、パスの書き方に注意してください。
“../”は一つ上の階層を表しています。

②ps4だけで寂しかったswitch文にパパとママを追加します。
FirebaseのActionのデータが「パパ ◯◯」「ママ □□」の形になったときに起動します。

ps4と同様に、とりあえずActionのテキスト全体を引数にして処理してくれる関数に投げてしまいます。

続いて、Line/voice2line.jsです。

var fnc = require("../Firebase/home-controler/functions.js")

//送信先のLine userIDです。
//今回は少人数なので、ハードコーディングしています。
//候補が多い場合などはなんらかのデータベースから読み込む様にした方がベターです。
const father = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const mother = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

//line機能あれこれ使える様にする
const line = require('@line/bot-sdk');

//クライアントを設定
//チャンネルアクセストークンはチャンネル基本設定から取得
const client = new line.Client({
  channelAccessToken : 'xxxxxxxxxxxxxxx'
});

exports.command = function(text){

  //textには分かち書きされたメッセージが含まれているので、
  //空白を削除して綺麗な文章を取得する

  //index=0は送信先識別(パパ・ママ)なのでi=1からはじめる
  i = 1

  //textをスペースで分割して配列にする。
  arrText = text.split(" ")

  //text初期化
  text = ""

 //配列arrTextの2番目の要素から最後の要素までを連結させる。
  while(i<arrText.length){
    text = text + arrText[i];
    i++;
  }

  //lineで送信する内容の設定
  const message = {
    type:'text',
    text:text
  }

  //引数の人物名をLINEユーザーIDに変える
  switch(arrText[0]){
    case "パパ":
      person = father
      break;

    case "ママ":
      person = mother
      break;
  }

  //いざ送信
  client.pushMessage(person,message)
    .then(()=>{
      //うまくいった時の処理をここに書く
      fnc.notifyGoogleHome(text + "と送信しました")
    })
    .catch((err)=>{
      //エラーの時の処理をここに書く
      fnc.notifyGoogleHome("送信に失敗しました")
    });
}

functions.js

//googlehomeに喋らせる関数
exports.notifyGoogleHome = function(message){
    //google-home-notifierの準備
    const googlehome = require('google-home-notifier')
    const language = 'ja';

    googlehome.device('リビングルーム', language);
    googlehome.ip("192.168.xx.xx");

    googlehome.notify(message, function(res){
        console.log(res);
    })
}

これで完成です!