Node.js
GoogleHome

Google Home開発入門 / google-home-notifier解説

More than 1 year has passed since last update.

はじめに

今年は、Google Home や Amazon Echo が発売されるなどスマートスピーカーが揃ってきた年になりましたね!
自分もGoogle Home Miniを発売日に買って、心の中で「未来を買ってしまった…!」なんて思ったりしてました。

実際のところ、目覚ましにしか使っていませんが…w
(目覚まし止めるのも大変です。中央のボタンが無効化されているので「Ok,Google とめて!」って3回ぐらい言わないと止まってくれません)

手軽に開発を始める

これはググるとたくさん出てくることなのですが、便利なライブラリが公開されているみたいです。
よく使われているのは下記のNode.jsのライブラリですね。
google-home-notifier

簡単に使い方を説明します。

google-home-notifierのインストール

$ # package.jsonを作ります
$ npm init

$ # google-home-notifierを入れます
$ npm install google-home-notifier

$ # yarn の方は下記のようにします。
$ yarn add google-home-notifier

サンプルコードで喋らせる

google-home-notifierのGithubに書いてあるサンプルコードを使うことで簡単に喋らせることができます。

普通に喋らせる

何箇所か変えて下記のコードで実行してみます。

main.js
const googlehome = require('google-home-notifier')
const language = 'ja';

googlehome.device('Google-Home', language); 

googlehome.notify('こんにちは。私はグーグルホームです。', function(res) {
  console.log(res);
});
$ node main.js
Device "XXX-XXX-XXXXXXXXXXXXXXXXX" at 192.168.1.6:8009
Device "Google-Home-XXXXXXXXXXXXXXXXX" at 192.168.1.7:8009
Device notified

私の家にはGoogleHome以外にも喋らせることが可能なデバイスがあったようで、2デバイス表示されています。
今回はデバイス名を Google-Homeと指定しましたので、下のデバイスが選択されGoogleHomeが「こんにちは。私はグーグルホームです」と喋りました。

ここは、デバイス名が完全に一致していなくても、指定したデバイス名が含まれているデバイスに送信されます。

音楽を鳴らす

main.js
const googlehome = require('google-home-notifier')
const language = 'ja';

googlehome.device('Google-Home', language); 

googlehome.play('MP3ファイルへのリンク', function(res) {
  console.log(res);
});

notify()play() に代わり、テキストの代わりにMP3ファイルを渡すようになっただけです。

本当は、コピペで使えるようコードにしたかったのですが音楽ファイルはいろいろ著作権などが面倒そうだったのでやめました。

google-home-notifierの仕組み

どうやって、 google-home-notifier はGoogleHomeに喋らせているのでしょうか?

実際にソースコードを覗いてみましょう。

デバイス取得

notifyplayを叩くと、下記のようにデバイス名とIPアドレスが表示されます。
どうやっているのでしょうか?

Device "XXX-XXX-XXXXXXXXXXXXXXXXX" at 192.168.1.6:8009
Device "Google-Home-XXXXXXXXXXXXXXXXX" at 192.168.1.7:8009

コードはこんな感じ。

google-home-notifier.js
var notify = function(message, callback = function() {}) {
  if (!deviceAddress){
    browser.start();
    browser.on('serviceUp', function(service) {
      console.log('Device "%s" at %s:%d', service.name, service.addresses[0], service.port);
      if (service.name.includes(device.replace(' ', '-'))){
        deviceAddress = service.addresses[0];
        getSpeechUrl(message, deviceAddress, function(res) {
          callback(res);
        });
      }
      browser.stop();
    });
  }else {
    getSpeechUrl(message, deviceAddress, function(res) {
      callback(res);
    });
  }
};

1つ1つ見ていきましょう。
まず、brwoserですが、下記のように定義されています。

var mdns = require('mdns');
var browser = mdns.createBrowser(mdns.tcp('googlecast'));

mdns というライブラリを使ってキャストできる端末を探します。
(mDNSについては、下記の方の記事がすぐでてきました。
[Signagify 3] Node.js で Sender アプリ作って mDNS + CastV2 で Chromecast とお話

google-home-notifier.js
    browser.on('serviceUp', function(service) {
      console.log('Device "%s" at %s:%d', service.name, service.addresses[0], service.port);
      if (service.name.includes(device.replace(' ', '-'))){
        deviceAddress = service.addresses[0];
        getSpeechUrl(message, deviceAddress, function(res) {
          callback(res);
        });
      }
      browser.stop();
    });

serviceUp イベントを受け取ると、IPアドレス・デバイス名などが取得できるようですね。

service.name.includes(device.replace(' ', '-')

その後、指定したデバイス名が含まれているものを検索し、一致するデバイスのIPを deviceAddress に格納し、getSpeechUrl という関数を呼び出しています。
つまりキャストできる端末を取得してます。

TTSのURLを取得 - getSpeechUrl

var onDeviceUp = function(host, url, callback) {
  var client = new Client();
  client.connect(host, function() {
    client.launch(DefaultMediaReceiver, function(err, player) {

      var media = {
        contentId: url,
        contentType: 'audio/mp3',
        streamType: 'BUFFERED' // or LIVE
      };
      player.load(media, { autoplay: true }, function(err, status) {
        client.close();
        callback('Device notified');
      });
    });
  });

  client.on('error', function(err) {
    console.log('Error: %s', err.message);
    client.close();
    callback('error');
  });
};

var getSpeechUrl = function(text, host, callback) {
  googletts(text, language, 1).then(function (url) {
    console.log(url);
    onDeviceUp(host, url, function(res){
      callback(res)
    });
  }).catch(function (err) {
    console.error(err.stack);
  });
};

googletts というのを呼び出していますね。

var googletts = require('google-tts-api');

googletts というのは、Google Text To Speachの略です。
つまり、入力した文字を音声ファイルにしてくれます
どうやら、このライブラリはGoogle翻訳の読み上げ機能から音声ファイルを取得しているようです。

取得した音声を再生 - onDeviceUp

google-home-notifier.js
var onDeviceUp = function(host, url, callback) {
  var client = new Client();
  client.connect(host, function() {
    client.launch(DefaultMediaReceiver, function(err, player) {

      var media = {
        contentId: url,
        contentType: 'audio/mp3',
        streamType: 'BUFFERED' // or LIVE
      };
      player.load(media, { autoplay: true }, function(err, status) {
        client.close();
        callback('Device notified');
      });
    });
  });

  client.on('error', function(err) {
    console.log('Error: %s', err.message);
    client.close();
    callback('error');
  });
};

clientcastv2-client ですね。 castv2-client はChromecastのクライアントのようです。

var Client = require('castv2-client').Client;

その後は、普通のChromecast端末と同じように音声ファイルを送信します。

google-home-notifierの流れまとめ

まとめるとこんな感じです。案外シンプルですよね。

  • キャスト出来るデバイスを探す
  • 取得できたデバイス名から、指定したデバイスを探す
  • Google Text To Speachで、文字を音声ファイルのURLにする
  • 取得したURLをGoogleHomeにキャスト(送信)する

その他

google-home-notifierexample.jsがありますが、これを起動するとHTTPサーバが立ち上がりリクエストを送信すると喋ってくれます。

$ git clone https://github.com/noelportugal/google-home-notifier
$ cd google-home-notifier
$ npm install
$ node example.js
Endpoints:
    http://192.168.1.20:8091/google-home-notifier
    https://xxxxx.ngrok.io/google-home-notifier
GET example:
curl -X GET https://xxxxx.ngrok.io/google-home-notifier?text=Hello+Google+Home  - to play given text
curl -X GET https://xxxxx.ngrok.io/google-home-notifier?text=http%3A%2F%2Fdomain%2Ffile.mp3 - to play from given url
POST example:
curl -X POST -d "text=Hello Google Home" https://xxxxx.ngrok.io/google-home-notifier - to play given text
curl -X POST -d "http://domain/file.mp3" https://xxxxx.ngrok.io/google-home-notifier - to play from given url

これを利用して、IFTTTから自発的に喋らせるということをやってる人もいるみたいですね
Twitterの通知をGoogle Homeに教えてもらう

最後に

今回はNodeで試しましたが、Chromecastのライブラリを使用すればどの言語でも比較的簡単に作成できると思います。
つまり、音声ファイルをGoogleHomeに送信してあげるだけです。(たぶん)
Actions on Googleなどの記事は他の方が上げてくれると思います。

もっといい感じのライブラリでてきたら、教えてください。