76
92

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

google-home-notifier周りをほぼ自動化した

Last updated at Posted at 2017-12-10

はじめに

GoogleHomeMiniを買って意気揚々とGoogle先生に喋らせようと思ったら意外に融通が利かないのでラズパイ買ってgoogle-home-notifierを入れた人も多いのでは無いだろうか。
そんな方で以下のような経験をした人はいないだろうか。

満を持してgoogle-home-notifierを起動すると下のようにngrokのサーバーが自動で立ち上がり、

GET example:
curl -X GET https://xxxxxx.ngrok.io/google-home-notifier?text=Hello+Google+Home
POST example:
curl -X POST -d "text=Hello Google Home" https://xxxxxx.ngrok.io/google-home-notifier

curl叩いてGoogle先生喋ってくれて、よゆーやん、と思ってたら、
サービスを立ち上げるたびにngrokのURLが変わってしまうことに気づき絶望した人。(前振りが長い..)

これだとサーバーを起動しなおしたり、予期せぬ再起動が発生したときにいきなり繋がらない、となってしまう。

なので、今回はこの問題を解消する

2018/5/23 追記「8時間でURLが失効しないようにする」
2018/12/15 追記「google-tts-apiを最新にする」

大雑把な方針

まずgoogle-home-notifier自体はnodejsなのでforeverを使って永続化する。さらにラズパイ起動時にそれを呼び出すようにすれば常に起動状態が維持されるようになる。

次に問題のURLについて。こいつはgoogle-spreadsheetを使うことにした。常に最新のURLをgoogle-spreadsheetに記録しておくことで、各サービスはそのシートを参照することで常にアクセスできるようになる、という寸法

google-home-notifierを永続起動させる

node.jsスクリプトの自動起動を参考にforeverをインストールして、ラズパイ起動時に自動で立ち上がるようにした。ソースはこんな感じ

/etc/rc.local
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

# 以下の1行を追加
sudo -u pi /usr/bin/node /usr/bin/forever start -p /var/run/forever --pidfile /var/run/node-app.pid -l /home/pi/google-home-notifier/out.log -a -d /home/pi/google-home-notifier/example.js 
exit 0

あとはラズパイを再起動してあげて、サービスが起動しているかを確認すればOK

sudo reboot
forever list
info:    Forever processes running
data:        uid  command         script                                   forever pid id logfile                               uptime        
data:    [0] tYP0 /usr/bin/nodejs /home/pi/google-home-notifier/example.js 638     676    /home/pi/google-home-notifier/out.log 0:0:26:39.768 

google-home-notifierからgoogle-spreadsheetにURLを書き出す

API認証キーを作成する

下のページを参考にAPIの認証キーを作成する。
使用するAPIはGoogle Sheets API
http://www.yoheim.net/blog.php?q=20160411
作成されたJsonの認証キーはラズパイの方で使うので転送しておく。

また、作成時に発行されるサービスアカウントIDをコピーしておくこと。
サービスアカウントIdってのは<プロジェクト名>@<プロジェクトId>.iam.gserviceaccount.comみたいなやつ。

コピーし忘れた場合は、「認証情報」タブ→「サービスアカウントの管理」から確認できる。

GoogleSpreadSheetを作って共有設定をする

Google Driveで任意のspreadsheetを一つ作り保存する。中身は空欄でOK
次に「共有」→入力欄にサービスアカウントIdをいれる。
スクリーンショット 2017-12-10 22.50.09.png
メールを送るかとか聞かれるが「いいえ」でよい。
付与する権限を「編集者」にする。
設定が終わったら完了を押す。

これでアカウントIdに紐付いた認証キーからは編集可能になった。

最後にスプレッドシートのKeyをコピーしておく。URLの以下のxxxの部分
https://docs.google.com/spreadsheets/d/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/edit#gid=0

example.jsを修正してURLを書き出せるようにする

ほぼこの記事「node-google-spreadsheetを使う(超簡易的なテスト)」を参考にした。

使うモジュールをインストール
npm i google-spreadsheets

以下のようにexample.jsを修正

example.js
var ngrok = require('ngrok');
var bodyParser = require('body-parser');
var GoogleSpreadsheet = require('google-spreadsheet');
var ngrokUrlSheet = new GoogleSpreadsheet('xxxxxxxxxxxxxxxxxxxxxxxxxxx'); //コピーしたスプレッドシートのKey 
var credentials = require('./GoogleHomeNotifier-xxxxxxx.json'); //作成した認証キーへのパス
var app = express();
const serverPort = 8091; // default port

var deviceName = 'Google Home';
var ip = '192.168.xx.xx'; // default IP

var urlencodedParser = bodyParser.urlencoded({ extended: false });

var sheet;
ngrokUrlSheet.useServiceAccountAuth(credentials, function(err){
   ngrokUrlSheet.getInfo(function(err, data){
      sheet = data.worksheets[0];
   });
});

// 中略

app.listen(serverPort, function () {
  ngrok.connect(serverPort, function (err, url) {
    console.log('Endpoints:');
    console.log('    http://' + ip + ':' + serverPort + '/google-home-notifier');
    console.log('    ' + url + '/google-home-notifier');
    console.log('GET example:');
    console.log('curl -X GET ' + url + '/google-home-notifier?text=Hello+Google+Home');
	console.log('POST example:');
	console.log('curl -X POST -d "text=Hello Google Home" ' + url + '/google-home-notifier');
    // sheetの一番左上のCellを取得
    sheet.getCells({
       'min-row': 1,
       'max-row': 1,
       'min-col': 1,
       'max-col': 1,
       'return-empty': true
    }, function(error, cells) {
          var cell = cells[0];
          cell.value = url + '/google-home-notifier'; //アクセスしてほしいURLをセット
          cell.save(); //保存
          console.log('spread sheet update successful!!');
    }); 
  });
})

修正したら保存。foroeverが動いていれば自動で再起動がかかってくれるはず。かかってくれなかったらstop->startなど。

うまくいけばシートの左上のセルにURLがぶっこまれる。
あとはこのセルを見るようにしてあげれば常に最新のURLが参照できるようになる

トラブルシューティング

なんか動かないんだけど!って時に

8時間でURLが失効しないようにする

google-home-notifierが気づいたら動かなくなってた時の対処法
詳細は上記の記事にて。
この対応をしないとngrokの取得したURLが8時間で失効してしまい、GoogleHomeがレスポンスを受け取れなくなってしまう。なので、ほぼ必須。

google-tts-apiを更新する

google-home-notifierが気づいたら動かなくなってた時の対処法
詳細は上記の記事にて。
この対応をしないとそもそもgoogle-home-notifierが動かない。一応PRがあるけどまだマージされてないので対応は必須になる。

おまけ(GASからのアクセス例)

スプレッドシートと相性がいいのはやはりGAS(Google Apps Script)。
IFTTTからのWebhookも受けられるし、スクリプトの定期実行もできるのでおおよそやりたい放題できる。
なので、GASからgoogle-home-notifierへメッセージを飛ばすサンプルコードを載せておく

google-home-notifier-example.gs
function getNgrokUrl() {
  if (getNgrokUrl.instance) { return getNgrokUrl.instance; }
  var ngrokSheetId = "xxxxxxxxxxxxxxx"; //スプレッドシートのId
  var url = SpreadsheetApp.openById(ngrokSheetId).getSheetByName("yyyyy").getDataRange().getValues()[0][0]; //yyyyyはワークシート名
  return url;
}

function notify2GoogleHome(msg) {
  // msg = "テストメッセージ"; //debug用
  sendHttpPost(msg, getNgrokUrl());
}

/* 
* messageをpostする関数
*/
function sendHttpPost(msg, url){
   var payload =
   {
     "text" : msg
   };
//   var userid = "user"; //Basic認証をかけている場合にこの行を有効にする
//   var password = "password";  //Basic認証をかけている場合にこの行を有効にする
   var options =
   {
     "method" : "post",
// "headers" : {"Authorization" : " Basic " + Utilities.base64Encode(userid + ":" + password)}, //Basic認証をかけている場合にこの行を有効にする
     "payload" : payload
   };

   UrlFetchApp.fetch(url, options);
}

終わりに

スマートスピーカーアドベントカレンダー間に合わなかった...

76
92
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
76
92

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?