天気をAPI使って取得してRaspberry Piに発話させる！

前回はwebスクレイピングで取得した情報を発話させました。
今回は天気情報をRaspberry PiにopenJtalkを使って発話させます！
#この記事でできること
- 天気情報をAPI使って取得
- 天気をRaspberryPiに発話させる

#前提
・Raspberry PiでPython3とOpenJtalkが使える状態
(OpenJtalkのインストールはこの記事で解説しているのでまだの方はどうぞ！)
#動作環境
・Raspberry P i3 model B
・OS: Raspbian
・Python ver3.7
#天気情報をAPiで取得
今回の記事では、
https://openweathermap.org/
の提供しているAPIを使います。
これの使い方については、先人がやってくれているので以下の記事を参照して登録してください。
記事1: https://qiita.com/syunyo/items/b408b8d61f9f73b21da7
記事2: https://qiita.com/nownabe/items/aeac1ce0977be963a740

#openJtalkをpythonスクリプトから動かす
ここからはOpen weather mapのAPI登録が完了しているという前提で話を進めていきます。
適当にディレクトリを作ります。

```
$ mkdir weatherapi
$ cd weatherapi
```
まずopenJtalkをPythonスクリプトと動かせるように以下のコードを作成します。

```
$ vi jtalk.py
```

iを押して編集モードにしてから以下をコピペしてください。

```python:jtalk.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import subprocess
from datetime import datetime

def jtalk(t):
    open_jtalk=['open_jtalk']
    mech=['-x','/var/lib/mecab/dic/open-jtalk/naist-jdic']
    htsvoice=['-m','/usr/share/hts-voice/mei/mei_normal.htsvoice']
    speed=['-r','1.0']
    outwav=['-ow','open_jtalk.wav']
    cmd=open_jtalk+mech+htsvoice+speed+outwav
    c = subprocess.Popen(cmd,stdin=subprocess.PIPE)
    c.stdin.write(t.encode())
    c.stdin.close()
    c.wait()
    aplay = ['aplay','-q','open_jtalk.wav']
    wr = subprocess.Popen(aplay)

def say_datetime():
    d = datetime.now()
    text = '%s月%s日、%s時%s分%s秒' % (d.month, d.day, d.hour, d.minute, d.second)
    jtalk(text)

if __name__ == '__main__':
    say_datetime()
```
上のコードでは、openJtalkのデフォルトではない女性の音声を使っています。openJtalkのインストールだけしかやっていない人は
`htsvoice=['-m','/usr/share/hts-voice/mei/mei_normal.htsvoice']`
を
`htsvoice=['-m','/usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice]`
に変更してください。

#API叩いて取得した天気情報を発話
次に同じディレクトリにAPIを叩いて発話させるコードを作成します。
同じように

```
$ vi weather_api_jtalk.py
```

iを押して編集モードにしてから以下をコピペしてください。

```python:weather_api_jtalk.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#open weather map & openJtalkを使って天気を音声出力する
#Reference: https://qiita.com/syunyo/items/b408b8d61f9f73b21da7

#API import
import requests
import json

### jtalk import
import jtalk
import time

# API key
apikey = "your api key" #ここにあなたのapi keyを入れてください

# 天気を調べたい都市の一覧 
#cities = ["Sendai,JP", "London,UK", "New York,US"]
cities = ["Sendai,JP"] #今回は仙台だけ
# APIのひな型
api = "http://api.openweathermap.org/data/2.5/weather?q={city}&APPID={key}"

# 温度変換(ケルビン→摂氏)
k2c = lambda k: k - 273.15

# 各都市の温度を取得する
for name in cities:
    # APIのURLを得る
    url = api.format(city=name, key=apikey)
    # 実際にAPIにリクエストを送信して結果を取得する
    r = requests.get(url)
    
    # 結果はJSON形式なのでデコードする json -> dictionary
    data = json.loads(r.text)    
    
    # 結果を出力
    
    jtalk.jtalk("ここんにちは、今日の天気は")
    time.sleep(2)
    print("+ 都市=", data["name"])
    print("| 天気=", data["weather"][0]["description"])
    if "rain" in data["weather"][0]["description"]:
        jtalk.jtalk("雨です。")
    else:
        jtalk.jtalk("雨ではありません")
    time.sleep(2)
    print("| 最低気温=", k2c(data["main"]["temp_min"]))
    jtalk.jtalk("最低気温は、摂氏"+str(k2c(data["main"]["temp_min"]))+"どです。")
    time.sleep(4)
    print("| 最高気温=", k2c(data["main"]["temp_max"]))
    jtalk.jtalk("最高気温は、摂氏"+str(k2c(data["main"]["temp_max"]))+"どです。")
    #print("| 湿度=", data["main"]["humidity"])
    #print("| 気圧=", data["main"]["pressure"])
    #print("| 風向き=", data["wind"]['deg'])
    #print("| 風速度=", data["wind"]["speed"])
    #print("")
    #print("missing some requested data or some error occurs")

```

#実行

```
$ python weather_api_jtalk.py
```

どうでしょうか？
私は、いつも自転車で通勤しているので雨かどうか知りたいだけなので雨なら"雨です" それ以外なら"雨ではありません"と発話します。
その次に、最低気温、最高気温を知らせてくれます。

#ここで一つ注意があります。
ここで自分は少しハマったので強調して書いておきます。

```python
jtalk.jtalk("ここんにちは、今日の天気は")
time.sleep(2)
```
ここでわかるようにjtalkで発話させている間にsleep関数を使って実行を停止させています。これを行わないと話している途中に次に出力させる音声情報が入ってきてしまうため、発話が途切れてしまいます。
なので、話すのにかかる時間と同程度の停止時間をjtalk.jtalk()の後に
time.sleep(発話にかかるであろう時間くらい)
を挟んでください。

#まとめ
今回は、天気をAPIを叩いて取得してOpenJtalkを使って音声出力させました。自然対話APIを使えば会話もできるようになると思います。
では！