Edited at
AnsibleDay 23

Playbookが成功したらGoogleHomeに褒めてもらう

Ansible Advent Calender 2018 23日目の記事です。

昨日はsugitkさんで、Ansibleをとりまくさまざまな技術について でした。

さて皆様におきましてはPlaybookが成功したらどう認識しているでしょうか?

notificationモジュールを使用してSlackやメールで通知するようにしている方もいるでしょう。

音声で認識できたらなと思い、モジュール作ってみました。

使うのは Google Home Mini です。 最近は3000円で投げ売りされてry...


下調べ

まずどうやってGoogle Home Miniを操作するの?ってことでググッて以下を見つけました。

https://github.com/balloob/pychromecast

Google Home Miniもchromecast機器の1種になるので、How to useの記載やExampleのソースでGoogle Home Miniも制御可能です。

https://github.com/harperreed/google-home-notifier-python

google-home-notifier を参考にしPythonで実装したようです。

ローカルでWebサーバを立ち上げてGoogleHomeにmp3ファイルのURLを渡して再生させています。

上記例を参考にして、まずmp3ファイルを再生させるモジュールを作りました。


googlehome_mp3.py

#!/usr/bin/python3

# -*- coding: utf-8 -*-

from __future__ import absolute_import, division, print_function
__metaclass__ = type

from ansible.module_utils.basic import AnsibleModule

ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}

import pychromecast
import time

def main():

ansible_facts = dict()
module = AnsibleModule(
argument_spec=dict(
device_name=dict(type='str', required=True),
mp3=dict(type='str', required=True)
)
)
device = module.params['device_name']
mp3_url = module.params['mp3']
casts = pychromecast.get_chromecasts()
cast = next(cc for cc in casts if cc.device.friendly_name == device)
time.sleep(1)
if not cast.is_idle:
cast.quit_app()
time.sleep(5)

cast.play_media((mp3_url), "video/mp3")
time.sleep(2)
module.exit_json(msg="OK", changed=False)

if __name__ == '__main__':
main()


で↑に対してこんなyamlを書いて実行すると、


googlehome_mp3.yml

---

- hosts: localhost
connection: local
gather_facts: False

tasks:
- name: Google home mp3
googlehome_mp3:
device_name: "1号機"
mp3: "https://s3.us-east-2.amazonaws.com/xxxxxxx/serenade.mp3"


mp3が再生されます。

※セレナーデは寝台特急で流れるオルゴールのやつ。

pi@raspberrypi:an $ ansible-playbook -i hosts googlehome_mp3.yml

PLAY [localhost] ****************************************************************************************************

TASK [Google home mp3] **********************************************************************************************
ok: [localhost]

PLAY RECAP **********************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0

pi@raspberrypi:an $


テキスト→音声の作成

mp3の再生はできました。

次は引数で渡したセリフを音声にする必要があります。

これには Google Cloud Text-to-Speech を使用して、mp3ファイルを作成します。

https://cloud.google.com/text-to-speech/

https://cloud.google.com/text-to-speech/docs/create-audio#text-to-speech-ssml-python

このAPI使うために以下の設定が必要となります。

・GCPの利用登録

・APIの有効化

・認証情報の作成

こちらのページを参考に設定をします。

https://blog.apar.jp/web/9893/

利用するための設定が終了したらサンプルのコードを落としてきて動かしてみます。

https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/texttospeech/cloud-client

$ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

$ python3 -m pip install -r python-docs-samples/texttospeech/cloud-client/requirements.txt

設定とインストールが完了したら、サンプルのquickstart.pyを実行してみます。

実行すると、output.mp3が作成されます。

pi@raspberrypi:cloud-client $ python3 quickstart.py

Audio content written to file "output.mp3"
pi@raspberrypi:cloud-client $ ls output.mp3
output.mp3
pi@raspberrypi:cloud-client $

デフォルトでは英語のVoiceで作成されますが、日本語も対応しています。

quickstart.py の language_code='ja_JP'にすると日本語の音声で作成されます。

対応している音声の言語はサンプルのlist_voics.pyで取得できます。


googlehome_speechモジュールを作成

quickstart.pyのコードをgooglehome_mp3.pyに付け足して、任意のセリフを喋らせることができるモジュールを作ります。

ソースはこんな感じになりました。


googlehome_speech.py

#!/usr/bin/python3

# -*- coding: utf-8 -*-

from __future__ import absolute_import, division, print_function
__metaclass__ = type

from ansible.module_utils.basic import AnsibleModule

ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}

import pychromecast
import time

def create_mp3(mp3_file, mesg):
from google.cloud import texttospeech
client = texttospeech.TextToSpeechClient()

synthesis_input = texttospeech.types.SynthesisInput(text=mesg)
voice = texttospeech.types.VoiceSelectionParams(
language_code='ja_JP',
ssml_gender=texttospeech.enums.SsmlVoiceGender.NEUTRAL)

audio_config = texttospeech.types.AudioConfig(
audio_encoding=texttospeech.enums.AudioEncoding.MP3)

response = client.synthesize_speech(synthesis_input, voice, audio_config)

with open(mp3_file, 'wb') as out:
out.write(response.audio_content)

def main():

ansible_facts = dict()
module = AnsibleModule(
argument_spec=dict(
device_name=dict(type='str', required=True),
mp3_server=dict(type='str', required=True),
mp3_folder=dict(type='str', required=True),
mp3_file=dict(type='str', required=True),
texttospeech=dict(type='str', required=True)
)
)

device = module.params['device_name']
mp3_server = module.params['mp3_server']
mp3_folder = module.params['mp3_folder']
mp3_file = module.params['mp3_file']
texttospeech = module.params['texttospeech']

file_path = mp3_folder + "/" + mp3_file
create_mp3(file_path, texttospeech)

casts = pychromecast.get_chromecasts()
cast = next(cc for cc in casts if cc.device.friendly_name == device)
time.sleep(1)
if not cast.is_idle:
cast.quit_app()
time.sleep(5)

mp3_path = mp3_server + "/" + mp3_file
cast.play_media((mp3_path), "video/mp3")
time.sleep(2)
module.exit_json(msg="OK", changed=False)

if __name__ == '__main__':
main()


mp3ファイルをGoogle Homeが取得できる場所に置く必要があるので、ラズパイにnginxを入れてフォルダを公開しておきます。

image.png

このフォルダにmp3ファイルが生成されるようにPlaybook内で指定します。

Google Homeにここに生成されたmp3ファイルのURLを渡すことで、音声が再生されます。

Playbookはこんな感じにして、前のタスクが成功したらGoogle Homeで褒めてもらうようにして実行します。


googlehome_speech.yml

---

- hosts: localhost
connection: local
gather_facts: False

tasks:
- name: command
command: hostname
register: result

- name: Google home speech
googlehome_speech:
device_name: "1号機"
mp3_server: "http://xxx.xxx.xxx.xxx/mp3"
mp3_folder: "/xxx/mp3"
mp3_file: "output.mp3"
texttospeech: "おめでとうPlaybookが成功したよ"
when: result is succeeded


前のタスクが成功するとGoogle Homeにおめでとうと言ってもらえます。

pi@raspberrypi:an $ ansible-playbook -i hosts googlehome_speech.yml 

PLAY [localhost] *****************************************************************************************

TASK [command] *******************************************************************************************
changed: [localhost]

TASK [Google home speech] ********************************************************************************
ok: [localhost]

PLAY RECAP ***********************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0

pi@raspberrypi:an $


おわりに

また、つまらぬモジュールを作ってしまいました。

Ansibleユーザの皆さまに置かれましては何とぞ大目に見て頂きたくお願いします。 :bow_tone1:

ソースは以下に置いておきます。

https://github.com/sato-ken/mymodules

Goole Homeではなく、早見沙織さんの音声で褒められたいsatokenでした。