MESHを使ってゆっくりを喋らせてみた

# はじめに
プログラミング歴が浅いが、IoTデバイスを触ってみたいと思い切って[MESH](http://meshprj.com/jp/)の人感センサーを購入しました。
人感センサーなので反応する度何か喋ってほしいなと考えていました。
さらに、__喋るならゆっくりに喋ってほしい…__と思いでカスタムタグを作成したので、備忘録として載せます。

# そもそもMESHってなに？
MESHとは「無線でつながるIoTデバイス」であり、主な特徴としては以下が挙げられます。[(MESH公式サイト)](http://meshprj.com/jp/)

* ビジュアルプログラミングアプリがあり、プログラミングが分からなくても簡単にMESHの挙動フロー(MESHレシピ)が作成できる
これはアプリで作成したMESHレシピになるのですが、タグと呼ばれるものを繋げて挙動を決定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/245399/ac71c616-b3b1-b7bf-d375-7923c25a3820.png)

* SDKがあり、独自のコード(カスタムタグ)を作成できる
* MESH HubによりRaspberry Piからコードを動かすことができる

# MESHに反応があるとゆっくりに喋るようになるまで
MESH Hubを使ってMESHの人感センサーに反応があるたびにRaspberry Piからゆっくりが喋るカスタムタグを作成してみました。

ざっくりとした流れはこちら
1. Raspberry PiからWebAPIサーバを起動する
2. MESHのカスタムタグからWebAPIへHTTPリクエストを発行する
3. WebAPIの中でsubprocessによりAquesTalkコマンドを実行する

主に[Sony MESH Hubでミクさんにおかえりを言ってもらった](http://kikei.github.io/smart-home/2018/03/12/raspberrypi-echo.html)を参考にしています。
ゆっくりに喋ってもらいたかったので、__OpenJTalkを使う所はAquesTalkに変えています。__

ラズパイからゆっくりに喋ってもらう部分は[Raspberry pi で音声会話をする](https://qiita.com/what_is_your_name/items/ecf9488039eb93babf5e)を参考にしました。


```js:start.py
#!/usr/bin/perl
# -*- coding:utf-8 -*-

import subprocess

from flask import Flask, request
app = Flask(__name__)

def aquestalk(speech):
  cmd = '/home/pi/aquestalkpi/AquesTalkPi -s 80 ' + speech.decode('utf-8') + '| aplay';
  
  // コマンドを実行する
  // 実行が成功すると0が返り、失敗するとCalledProcessErrorが生じる 
  // 詳しくは https://docs.python.jp/3/library/subprocess.html
  output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
  print(str(output))
  return True

def say(speech):
  aquestalk(speech)
  return speech

// ルーティングをしてURLとPOSTメソッドを紐づける
@app.route('/talk', methods=['POST'])
def handleSay():
  speech = request.form['speech'].encode('utf-8')
  return say(speech)

def main():
  // WebAPIサーバーを起動する
  app.run('127.0.0.1')

if __name__ == '__main__':
  main()

```

カスタムタグの作り方は[Sony MESH Hubでミクさんにおかえりを言ってもらった](http://kikei.github.io/smart-home/2018/03/12/raspberrypi-echo.html)が詳しいため割愛。
Executeメソッドの実装時に__routeデコレーターの引数とPropertyの設定__を合わせる必要があります。

__カスタムタグのProperty__
![image.png](https://qiita-image-store.s3.amazonaws.com/0/245399/870ef8cf-520d-13b6-4576-11884e12307c.png)

__カスタムタグのExecuteメソッド__

```js:Execute
// AjaxでアクセスするURL
// routeデコレーターの引数と合わせる
var url = "http://localhost:5000/talk";

// URLに送信したいデータオブジェクト
// PropatyのRefarence Nameと合わせる
var speech = {
    "speech" : properties.talk,
};

// Ajaxで非同期通信を行う
// 詳しくは https://meshprj.com/sdk/doc/ja/
ajax({
	url: url,
	type: 'post',
	data: speech,
	timeout: 5000,
	success: function(success) {
		log(success);
		callbackSuccess({
			resultType: 'continue' // 次のメソッドを呼ぶ
		});
	},
	error: function(request, error) {
		log(error);
		callbackSuccess({
			resultType: 'continue' // 次のメソッドを呼ぶ
		});
	}
});

// Ajaxは非同期通信であるためイベントハンドラが実行されるまで待つ
return {
	resultType: 'pause' // 次のメソッドを呼ばない
};

```


完成したゆっくりが喋るタグがこちら。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/245399/55aeaee6-0fc6-0745-3867-50c9ea533ee5.png)

レシピはお試しでシンプルに喋るだけにしました。
Propertyを設定しておくことでレシピのタグから喋る内容が変えられるようになります。

![mesh_yukkuri.PNG](https://qiita-image-store.s3.amazonaws.com/0/245399/daca2176-df53-882a-1f51-c1456493b2d9.png)

以下のコマンドを叩いてMESHの人感センサーを反応させるとゆっくりが喋ります。ヤッター！

```
$ python start.py
```

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">MESHとラズパイを使ってゆっくりを喋らせてみた <a href="https://t.co/lE7cWc2Mhx">pic.twitter.com/lE7cWc2Mhx</a></p>&mdash; nori (@nori0__) <a href="https://twitter.com/nori0__/status/1051333211622494209?ref_src=twsrc%5Etfw">2018年10月14日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# ハマった点
* MESH HubはRaspbian(Stretch)でしか動かない  
(久々ラズパイを動かしたのでRaspbian Jessieで止まっていていたため```sudo apt-get update```を何度も実行しました…)
* MESH Hubを使う場合、iOS版のMESHアプリでしか対応していない(2018/9/12現在)  
* ```subprocess.check_output```の引数をリストにした場合、CalledProcessErrorが生じる

```py

# CalledProcessError：Command return non-zero exit status 154が発生
cmd = '/home/pi/aquestalkpi/AquesTalkPi -s 80 ' + speech.decode('utf-8') + '| aplay';
  output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, shell=True)
```
[subprocess で shell=True でリストを与えたときの挙動](https://qiita.com/yoichi22/items/5afa8b3b39c723acb359)によると、shell=Trueを指定した場合、リストではなく文字列を指定しないと適切に引数が渡らないようです。

# 課題
* 「python start.py」を打ってWebAPIを起動させるのは面倒くさい問題
* ゆっくりが最初の4文字分ほどを喋ってくれない問題  
(PropertyのValueに「ゆっくりしていってね」と入れると「していってね」と聞こえてしまい、ラズパイがゆっくりしてくれない)  
よって、PropertyのValueが「ゆっくりゆっくりしていってね」にすると「ゆっくりしていってね」と聞こえる。  
~~自身の環境の問題かもしれないが解決策が分からない。~~