クラウド側からプッシュしたテキストをAndroidタブレットに読み上げさせる (MacrodroidのWebhook + Text to Speech)

## TL;DR

MacroDroidはWebhookをトリガーにすることができる。
`HTTP GET https://https://trigger.macrodroid.com/DEVICE_ID/NAME?param=ABC`
と投げ込むと MacroDroid変数 `g_param` が設定できるので、テキスト読み上げアクションの中から `[v=g_param]` と参照することでText to Speechができる。

## 概要

こんな感じで話せることが可能です。(YouTubeに飛びます)
[![Text to Speech by MacroDroid](http://img.youtube.com/vi/TX4ESvJuJmw/0.jpg)](http://www.youtube.com/watch?v=TX4ESvJuJmw)

Android OSの自動化アプリ「[MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid)」は、Androidが元々持っている音声読み上げ機能(Text to Speech; 以下 TTS)が利用できます。
そして、TTSは[MacroDroidのWebhookトリガー](https://medium.com/@macrodroid/introducing-the-webhook-trigger-a760e2ee140d)から起動できるので、クラウド側からプッシュしたテキストをAndroidに読み上げさせることが可能です。
<img src="https://docs.google.com/drawings/d/e/2PACX-1vRhcgrGlFz1_n6Y1VYPnx02nZ6TxO29gfpUg1CRycHqJQ3GbPTULHhIS6lHpmyPlCDWYVHvC_6QC3Qq/pub?w=699&amp;h=228">

### 確認環境

- TECLAST P80X (Android 9)
- MacroDroid 5.7

## MacroDroidでの手順

- 1. 変数
    - Webhook経由で送信されたテキストを保存しておくグローバル変数の作成
- 2. マクロ
    - トリガー > 接続 > Webhook
        - 識別子を入力してURLを作成、入手
    - アクション > 機器アクション > テキストを読み上げる
        - 読み上げるテキストにグローバル変数を指定

以上で準備が整います。
あとはHTTP ClientからWebhook URLに対して、読み上げさせたいテキストをパラメータとして付けてHTTP GETするとテキストが読まれます。

### MacroDroid: 変数

Webhookで投げ込まれたパラメータは、MacroDroid内の一致するグローバル変数名の値として設定できます。
ここでは `tts_text` としました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/a0305d41-06c3-d2c5-4ecf-d3ac9116cd36.png)

### MacroDroid: マクロ / トリガー > 接続 > Webhook

識別子を入力すると、最終的なWebhook URLが作成されます。このURLをメモしておいてください。
ここでは `text2speech` という識別子としました。
![Screenshot_20210101-152701.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/f7013cb2-66f3-e04c-dfc4-c5e5e6457fb6.png)

#### 注意点

1. 短縮URLでも問題なく機能しますがtinyurlはMacroDroidとは別サービスですので、経由するか否かは検討の余地があります。
2. `trigger.macrodroid.com/` の後に続く[ランダム文字列の再生成はアプリの再インストール、もしくはアプリデータの消去にて可能のようです]((https://medium.com/@macrodroid/introducing-the-webhook-trigger-a760e2ee140d))(未調査)。URL漏洩にはお気を付けください。

### MacroDroid: マクロ / アクション > 機器アクション > テキストを読み上げる

_読み上げるテキストを入力_ にMacroDroid変数を参照するようにします。
ここでは `[v=tts_text]` としています。
![Screenshot_20210101-152833.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22754/b7977b10-49b7-5a39-944e-fc973799ebbd.png)

## 実行: curl

curlコマンドで実行できます。

```console
$ curl "https://trigger.macrodroid.com/${DEVICE_ID}/text2speech?tts_text=ABC"
ok
```

「エービーシー」と話し始める事でしょう。

日本語も話させることが可能です。
UTF-8をURLエンコードします。 `--get` を使うと `--data-urlencode` をURLエンコードしつつ、QueryStringにしてくれます。

```console
$ curl --get --data-urlencode "tts_text=日本語も話せます" https://trigger.macrodroid.com/${DEVICE_ID}/text2speech
ok
$ curl --get --data-urlencode "tts_text=現在の時刻は、$(date +%H:%m)です。" https://trigger.macrodroid.com/${DEVICE_ID}/text2speech
ok
```

## 実行: AWS Lambda

URLを環境変数 `MACRODROID_WEBHOOK_URL` に設定します。
テストや呼び出しは `{"tts_text": "大丈夫だ、問題ない。"}` とすればOKです。

```python:macrodroid_webhook_invoker
# for Python 3.8
import urllib.request
import os
MACRODROID_WEBHOOK_URL = os.environ['MACRODROID_WEBHOOK_URL']

def lambda_handler(event, context):
    print(event)
    if 'tts_text' in event:
        payload = {'tts_text': event['tts_text']}
    url = f'{MACRODROID_WEBHOOK_URL}?{urllib.parse.urlencode(payload)}'
    with urllib.request.urlopen(url) as res:
        print(res.read().decode("utf-8"))
    return {'statusCode': 20
```

他のLambda関数から呼び出したい場合は `boto3.client('lambda').invoke()` で OK です。
呼び出し元のLambda関数にInvokeFunctionポリシーの付与をお忘れなく。

```python:他のLambdaから呼び出す例
import boto3
w = '晴れ'
t = {'tts_text': f'今日の天気は{w}です'}
boto3.client('lambda').invoke(FunctionName='macrodroid_webhook_invoker', InvocationType='Event', Payload=json.dumps(t))
```

## おわりに

今年もよろしくお願いします。

EoT