Python 3 から Google Home に喋らせる(低遅延)
はじめに
Google Home にプッシュで喋らせる場合、google-home-notifier がよく使われると思います。
しかし、なんか大げさな気がする・・・
軽い方法として、Python で pychromecast を使ってしゃべらせる方法があります。
しかし使ってみたら、スクリプトを起動してから喋るまで10秒近くかかっちゃいます。
そこで、できるだけ早く喋り始めさせる方法を模索しました。
pychromecast のキホン
pychromecast は、音声データのある適当なURLをぶち込むと、それを再生してくれます。(それ以外にもいろいろできますが、ここでの使い方はそれを想定しています)
音声データはどこかのWebサーバに置いておく必要があります。任意の言葉をしゃべらせる場合は、テキスト→音声変換が別途必要になりますね。
喋らせる内容が固定であれば、固定の音声ファイルをWebサーバに置いておけばよいです。
ここでは、 http://192.168.0.100/test.mp3
に音声ファイルがある前提で進めます。(Google Home から見える場所であれば、ローカルネットワーク内でもインターネット上でもどちらでもいいです。)
基本的な使い方は以下のようになります。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pychromecast
mp3url = 'http://192.168.0.100/test.mp3';
#Chromecastデバイス(Google Homeも)を探す
chromecasts = pychromecast.get_chromecasts()
if len(chromecasts) == 0:
print("Google Homeが見つかりませんω")
exit()
#固定で1個目を使う
googleHome = chromecasts[0]
if not googleHome.is_idle:
print("Killing current running app")
googleHome.quit_app()
time.sleep(5)
#喋らせる
googleHome.wait()
googleHome.media_controller.play_media(mp3url, 'audio/mp3')
googleHome.media_controller.block_until_active()
Google Home が複数台ある場合はどうなるでしょうか?
たまたま最初に見つかったGoogle Homeがしゃべります。
仮にGoogle Homeが1台だけでも、Chromecastが存在する場合はそっちが選ばれてしまう可能性があります。
ほとんどのご家庭では実用になりませんね!!!
で、次。名前でGoogle Homeを特定する方法。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pychromecast
mp3url = 'http://192.168.0.100/test.mp3';
#Chromecastデバイス(Google Homeも)を探す
chromecasts = pychromecast.get_chromecasts()
if len(chromecasts) == 0:
print("Google Homeが見つかりませんω")
exit()
#名前で探す
googleHome = next(cc for cc in chromecasts if cc.device.friendly_name == 'リビング')
if not googleHome.is_idle:
print("Killing current running app")
googleHome.quit_app()
time.sleep(5)
#喋らせる
googleHome.wait()
googleHome.media_controller.play_media(mp3url, 'audio/mp3')
googleHome.media_controller.block_until_active()
違いは
#固定で1個目を使う
googleHome = chromecasts[0]
が
#名前で探す
googleHome = next(cc for cc in chromecasts if cc.device.friendly_name == 'リビング')
になっただけです。
簡単ですね。
ちなみに、モデル名を使って
#モデル名で探す
googleHome = next(cc for cc in chromecasts if cc.device.model_name == 'Google Home Mini')
のように探すこともできます。
ただこれらの方法、しゃべり始めるまでに10秒ぐらいかかります。
どこで時間がかかっているかというと、pychromecast.get_chromecasts()
のところです。つまり、デバイス一覧を作るところです。pychromecast のソースを見てみたところ、一覧作成時に5秒の待ちがあります。
一覧の作成は飛ばしたい。
IPアドレス指定でやる
IPアドレス指定でイケる方法が絶対あるはずだ。そう思って調べた結果が以下のソースになります。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pychromecast
mp3url = 'http://192.168.0.100/test.mp3';
#IPアドレスで特定する
googleHome = pychromecast.Chromecast('192.168.0.22')
if not googleHome.is_idle:
print("Killing current running app")
googleHome.quit_app()
time.sleep(5)
#喋らせる
googleHome.wait()
googleHome.media_controller.play_media(mp3url, 'audio/mp3')
googleHome.media_controller.block_until_active()
これだと割とすぐ喋ってくれます。
ちなみに、ubuntu 18.04 で apt install python3-pychromecast
でインスコした pychromecast ではエラーが出てしまいます。pip で最新をインスコしましょう。
これで低遅延で喋らせることができましたが、IPアドレスを直接指定するのは嫌だ! やっぱり名前で指定したい!!
一覧の作成はせず、名前で指定する
名前指定で探して、見つかったら可及的速やかにそいつに喋らせる。不可能ではないはずだ。そう思って5時間ぐらいかけて作ったコードが以下です。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pychromecast
import time
from threading import Event
from zeroconf import ServiceBrowser, Zeroconf
googleHomeName = 'リビング'
mp3url = 'http://192.168.0.100/test.mp3'
class MyListener(object):
def add_service(self, zeroconf, type, name):
global ip
info = zeroconf.get_service_info(type, name)
if info.properties[b'fn'].decode() == googleHomeName :
#見つかった機器に割り振られているIPアドレスの最初のIPを採用(IPv6の場合もあるかも)
ip = info.parsed_addresses()[0]
#見つかったことを通知
discover_complete.set()
discover_complete = Event() #待ち合わせ用
zeroconf = Zeroconf()
listener = MyListener()
# GoogleHomeを探す(非同期実行)
browser = ServiceBrowser(zeroconf, "_googlecast._tcp.local.", listener)
# 見つかるかタイムアウトするまで待ち
discover_complete.wait(5)
googleHome = pychromecast.Chromecast(ip)
if not googleHome.is_idle:
print("Killing current running app")
googleHome.quit_app()
time.sleep(5)
#喋らせる
googleHome.wait()
googleHome.media_controller.play_media(mp3url, 'audio/mp3')
googleHome.media_controller.block_until_active()
zeroconfを使って探索を開始し、指定された名前のが見つかったらすぐにそいつに喋らせます。
探索は非同期実行なので、Event の set() wait() を使っているところがミソです。
まとめ
- pychromecast を普通に使うとデバイス一覧作成で時間がかかる
- IPアドレス直指定だと低遅延で喋らせることができる
- さらに、zeroconfと組み合わせて、名前指定でも低遅延で喋らせることができる!
Author And Source
この問題について(Python 3 から Google Home に喋らせる(低遅延)), 我々は、より多くの情報をここで見つけました https://qiita.com/rukihena/items/8af9b8baed49542c033d著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .