MacrodroidというAndroidアプリとRaspberry piを使って、スマホの通知をゆっくりボイスが喋ってくれるシステムを作ってみました。
概要
MacrodroidはAndroidでタスク自動化ができるアプリです。
Androidでの何らかのイベントをトリガーに様々なアクションを自動で実行できます。
これとラズパイに立てた簡易webサーバーとを連携させ、通知が来たらその内容をwebサーバーに送りAquesTalkPiで音声を出力します。
環境
- Android10
- Raspberry pi 3b (Raspbian stretch)
- dockerインストール済み
- 3.5mmイヤホンジャックスピーカー
ラズパイ側の設定
ラズパイを使っていると、SDカードを交換して環境を作り直すことがあります。そんなときDockerfileがあると、いちいち環境構築の方法を思い出さずに済みます。
ということで簡易webサーバーをDockerで動かします。
(今回はコード量も殆ど無いのでDockerは大げさな気もしますが)
今回作成したDockerfileは次の通りです。
FROM balenalib/rpi-raspbian:buster
RUN apt-get update && \
apt-get -y install --no-install-recommends alsa-utils python3 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# https://www.a-quest.com/products/aquestalkpi.htmlのプログラム使用許諾を読んだ上で下記のダウンロードを行う
RUN mkdir /root/bin && \
curl -kL "https://www.a-quest.com/cgi-bin/download.php?download=1&readed=yes" -o /tmp/aquestalk.tgz && \
tar xzvf /tmp/aquestalk.tgz -C /tmp && \
mv /tmp/aquestalkpi/AquesTalkPi /root/bin && \
mv /tmp/aquestalkpi/aq_dic /root/bin && \
rm /tmp/aquestalk.tgz && rm -r /tmp/aquestalkpi
ADD ./softalk_server.py /root/bin
EXPOSE 8000
CMD ["python3", "/root/bin/softalk_server.py"]
また簡易webサーバーはPythonで動かしました。
# -*- coding:utf-8 -*-
from http.server import HTTPServer, SimpleHTTPRequestHandler
from urllib import parse
import subprocess
KEYS = ["app", "title", "message"]
# textをゆっくりボイスにしゃべってもらう
def talk(text):
p1 = subprocess.Popen(
["/root/bin/AquesTalkPi", text],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
p2 = subprocess.Popen(
["aplay"],
stdin=p1.stdout, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
)
p1.stdout.close() # SIGPIPE if p2 exits.
p2.communicate()[0]
# [app, title, messa]のキーからなる辞書text_dicをもとに
# 発話メッセージを用意する
def format_message(text_dic):
if text_dic['title'] is None:
return None
if text_dic['message'] is None:
return None
if len(text_dic['message']) < 40:
formatted = '{app}から{title}というタイトルのメッセージです。{message}'.format(
**text_dic
)
else:
formatted = '{app}から{title}というタイトルのメッセージです。'.format(
**text_dic
)
return formatted
# 簡易webサーバー
# GETリクエストを受け取ったら、そのパラメータをもとに
# スピーカーからゆっくりボイスを再生する
class RequestHandler(SimpleHTTPRequestHandler, object):
def do_GET(self):
query = parse.urlparse(self.path).query
query_dic = parse.parse_qs(query)
self.send_response(200)
for key in KEYS:
if key not in query_dic:
query_dic[key] = None
else:
query_dic[key] = query_dic[key][0]
print('query = {}'.format(query_dic))
formatted = format_message(query_dic)
# GETリクエストのパラメータが想定されているものと
# 違う場合はformattedはNoneになり音声は再生されない
if formatted is not None:
talk(formatted)
self.end_headers()
if __name__ == '__main__':
text = '通知サーバを開始しました'
talk(text)
httpd = HTTPServer(("", 8000), RequestHandler)
httpd.serve_forever()
そしてDockerfile
とsoftalk_server.py
があるディレクトリで以下のコマンドを実行します。
$ docker build -t softalk_notification .
$ docker run -d --name notification_server --device /dev/snd -p 8000:8000 --restart=always softalk_notification
--restart=always
のオプションをつけることで、再起動したときにも(dockerデーモンが停止したときにも)自動でコンテナを立て直すようになり便利です。
また、ALSAを使ってスピーカーの音を再生するためにdev/snd
を--device
に渡しています。
加えてwebサーバーのポートはコンテナもホストも8000
に設定しています。
うまくいっていたら次のGETリクエストでゆっくりが喋ってくれるはずです。
$ curl localhost:8000 --get --data-urlencode 'app=ゆっくり' --data-urlencode 'title=テスト' --data-urlencode 'message=ゆっくりしていってね'
Android側の設定
続いてAndroidに通知が来たときにwebサーバにGETリクエストを出しましょう。これはMacrodroidで実現できます。
Google PlayからMacrodroidをインストールしたら、以下のマクロを作成します。
-
トリガー
- 「機器のイベント」 > 「通知」 をタップ
- 「通知が表示された時」 > 「どれかのアプリ」 > OK をタップ (場合によっては通知領域に関する権限設定が必要)
-
アクション
- 「アプリケーション」 > 「Webサイトを開く / HTTP GET」をタップ
- 「エンコード・パラメータURL」にチェック
-
URLを入力
の部分に以下を入力(ラズパイのIPアドレスが192.168.0.2の場合)して右下のOK
をタップ
URL
192.168.0.2:8000?app=[not_app_name]&title=[not_title]&message=[notification]
トリガーとアクションの設定が終わったら画面右下のチェックマークをタップ。カテゴリーやマクロ名は適当に入力してください。
以上で設定は終了です。
# おわりに
今回は最低限の設定ですので実用的には細かな微調整が必要かなと思います。以下は現状で思い浮かぶ設定項目です。
- 全てのアプリの通知を読み上げるのか : Macrodroid側である程度指定可能
- 常に読み上げを行うのか: Macrodroidの時刻のトリガー(Nature remoと組み合わせて明るさで判定するのも面白そう)
興味を持たれた方は試してみてはいかがでしょうか。