Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8691

ペアリングしてステレオ化したGoogle Home(Nest)にボイスコマンドでPodcastを流してもらう

$
0
0

2台をペアリングしてステレオスピーカー化したGoogle Nest mini(Google Home miniの新型)にボイスコマンドでPodcastをしゃべってもらおうと思ったら、意外とハマりどころが多く、結構な苦戦を強いられました。
苦労の末、どうにかやりたいことはできるようになったので、今回はその辺の話を書きたいと思います。
実現のためにいくつかのクラウドサービスを利用していますが、無料枠の範囲内で大丈夫です。

この辺の記事を参考にしています。

Google Homeで好きなポッドキャストをスマートに再生する
google-home-notifier で スピーカーグループを喋らせる

やりたいこと

google homeに「ok google、~~~を流して」とお願いすると、あらかじめ指定しておいたpodcastの最新話を再生してくれる。

必要なもの

  • IFTTTのアカウント
  • firebaseのプロジェクト(無料プランで大丈夫です)
  • 自宅のLAN内で常時インターネットに接続されていてnodejsが動作するPCなど
    • 僕はRaspberry pi を使っています

動作させる仕組み

  • Google home(Google Assistant)へのボイスコマンド入力を、IFTTTでフックする。
  • IFTTTのアクションでfirebaseのRealtime Databaseを更新する。
  • nodejsで組んだスクリプトでfirebaseの更新を監視しておき、更新を検知したらPodcastのRSSを取得&パースし、最新話のMP3のURLをGoogle Homeに渡す。
  • Google Homeが、受け取ったMP3を再生してくれる

実現手順

大まかな手順は「Google Homeで好きなポッドキャストをスマートに再生する」に書かれている通りですが、いくつか修正した方がよい箇所があります。

元記事からの変更点

環境によっては、いくつかの修正が必要です。

mdnsモジュールの一部機能がRaspberryPiで動かない問題の修正

依存ライブラリのgoogle-home-notifierの内部で利用されている「mdns」モジュールが、Raspberrypiでは正しく動作しないため、修正が必要です。

121行目を以下のように修正します

変更前

~/node_modules/mdns/lib/browser.js
,'DNSServiceGetAddrInfo'indns_sd?rst.DNSServiceGetAddrInfo():rst.getaddrinfo()

変更後

~/node_modules/mdns/lib/browser.js
,'DNSServiceGetAddrInfo'indns_sd?rst.DNSServiceGetAddrInfo():rst.getaddrinfo({families:[4]})

※ 引数に {families:[4]} を追加しています。

元記事に掲載されているRaspberrypiで動かすnodejsスクリプトの修正

podcastを再生するGoogle HomeをIP Addressで指定していますが、スピーカーのペアリングやグループ化をしているとうまく動きません。

IPアドレス指定ではなく、google-home-notifierは、対象のgoogle homeデバイスをIPアドレス指定ではなく内部名で指定することもできるようになっているため、内部名で指定するように変更します。

まず、再生したいGoogle Home(Nest)の内部名を調べます。

internal_name.js
varmdns=require('mdns');varbrowser=mdns.createBrowser(mdns.tcp('googlecast'));browser.start();browser.on('serviceUp',function(service){console.log('Device "%s" at %s:%d',service.name,service.addresses[0],service.port);});

実行結果は以下のようになります(デバイスの内部名の一部を伏字にしています)。

*** WARNING *** The program 'node' uses the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/blog/projects/avahi-compat.html>
*** WARNING *** The program 'node' called 'DNSServiceRegister()' which is not supported (or only supported partially) in the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/blog/projects/avahi-compat.html>
Device "AQUOS-TV***************" at 192.168.0.111:8009
Device "Google-Home-Mini***************" at 192.168.0.22:8009
Device "Google-Nest-Mini***************" at 192.168.0.20:8009
Device "Google-Cast-Group***************" at 192.168.0.20:32000
Device "Google-Nest-Mini***************" at 192.168.0.21:8009

出力が終わったらCtrl+Cで終了

(グループ化・ペアリングしたスピーカーの場合には、Google-Cast-Group-**** のような名前になります)

上で取得した情報をもとに、引用元記事で書かれているraspberrypiで動かすスクリプトを以下のように修正&保存します(nodeのバージョンにもよるかもしれませんが、実行時エラーが出たのでそこも修正しています)。

raspberrypi.js
varFeedParser=require('feedparser');varfirebase=require('firebase');vargoogleHome=require('google-home-notifier');varrequest=require('request');constlang='ja';// const ip = '192.168.0.20'; //再生したいGoogle HomeのIPアドレス// googleHome.ip(ip, lang);constdeviceName='Google-Cast-Group*************';googleHome.device(deviceName,lang);constconfig={apiKey:'hoge',authDomain:'fuga.firebaseapp.com',databaseURL:'https://**************.firebaseio.com',projectId:'fuga',storageBucket:'',messagingSenderId:'piyo'};firebase.initializeApp(config);vardb=firebase.database();varref=db.ref('/');ref.on('child_changed',function(snapshot){// var url = ref.child('url').val();varurl=snapshot.val();if(url){playLatestPodcast(url);}ref.update({'podcast_url':''});// 変更をリセット});functionplayLatestPodcast(url){varreq=request(url);varparser=newFeedParser();varitems=[];req.on('response',function(res){this.pipe(parser);});parser.on('readable',function(){while(item=this.read()){items.push(item);}});parser.on('end',function(){googleHome.play(getLatestPodcastUrl(items),function(notifyRes){});});}functiongetLatestPodcastUrl(items){for(itemofitems){for(enclosureofitem.enclosures){varurl=enclosure['url'];if(url){returnurl;}}}return"";}

グループ化したスピーカーに対応させる。

再生するデバイスが1台のgoogle homeの場合には、これでうまくいきますが、Google homeがグループ化されていたり、ペアリングしているステレオ化されたスピーカーで再生しようとしている場合はうまく動きません。

google-home-notifier で スピーカーグループを喋らせる」の記事を参考に、~/node_modules/google-home-notifier/google-home-notifier.jsを修正します。

変更前

~/node_modules/google-home-notifier/google-home-notifier.js
deviceAddress=service.addresses[0];

変更後

~/node_modules/google-home-notifier/google-home-notifier.js
deviceAddress={};deviceAddress.host=service.addresses[0];deviceAddress.port=service.port;

※ 修正が必要な個所は2か所あります。

これで、作業はすべて完了です。

IFTTTで設定した「ok google、~~~~を流して」というフレーズを言えば、目的のpodcastの最新話が自動で再生されるかと思います。

同じ仕組みを利用して、miniDLNAなどで組んだDLNAサーバのプレイリストURLをgoogle homeに渡してあげれば、「ok google、NASの音楽を流して」という音声コマンドでNASに保存した音楽をシャッフル再生してくれるような仕組みなども作れそうです。

機会があればやってみたいと思います。


Viewing all articles
Browse latest Browse all 8691

Trending Articles