Raspberry Pi と Python を使って【天気予報】を喋らせる

electric

今回は、ボタンを押したら、
地元の天気予報を喋ってもらおうと思います。
楽しそうだったら作ってみて♪

この記事では以下が学べます。

  • ボタン制御
  • スピーカー出力
  • Python
  • WebAPI(外部情報取得)
  • 音声合成(発話)

やりたいこと

・ボタンを押したら、
・地元の天気予報をスピーカーから喋らせる

システム構成図

やることリスト

上記の「やりたいこと」をみて、
どんな作業が必要か、自分で項目を考えてみてください。
これを考えることで、「プログラミング的思考」が身に付いていきます。

作業項目備考
部品の準備
ボタンが押されたことを判断する
天気予報の情報(文字列)の取得WebAPI
文字列を音声に変換し、スピーカーから音声出力音声合成

部品の準備

今回のシステムに必要な部品です。
不足している部品があれば購入下さい。

部品名備考
Raspberry Pi別途、電源・SDカード・HDMIケーブルが必要です。
ブレッドボード(※1)
ジャンパー線(※1)オスーメス:2本
ボタン(※1)タクトスイッチ:1個
スピーカーダイソーのUSBミニスピーカー(300円)がお薦めです。

購入に必要な部品を、
Raspberry Pi 関連に記載しています。
※1)「電子工作キット」内に全て含まれています。

ラズパイは、電源を入れただけでは起動しません。
ラズパイの起動手順の記事を参照ください。

ボタンが押されたことを判断する

回路

回路図

回路図の説明をします。

ボタンが押されていない時は、
ラズパイ内部のプルダウン(端子とグランドの間に抵抗を入れて接続)を使うことで、
電圧0Vが GPIO 24の端子に入り、GPIO 24の端子は “Low”と判断します。

ボタンが押された時は、
電圧3.3Vが GPIO 24の端子に入り、GPIO 24の端子は “High”と判断します。

配線図

部品の説明

ブレッドボード

ブレッドボードは、ソケット(穴)に部品を挿し込むだけで簡単に電子回路が作れる便利なものです。
各ソケットは、薄い緑色の線の方向に内部で繋がっています。
なので、部品とジャンパー線、部品と部品が繋がっていなくても、電気が流れます。

タクトスイッチ

スイッチを押すと、同じ側面に付いた足どうしが内部で繋がり、電流が流れます。
反対の側面に付いた足どうしは、常に内部で繋がっているので、電流は流れっ放しになります。

ソフト

ピンの制御にRPi.GPIOパッケージを使用する為、以下コマンドでインストールする。

sudo pip3 install rpi.gpio

プログラム

以下ディレクトリ通り、ディレクトリとファイルを作成する。
この章では、以下赤字のファイルを修正する。

/home/pi/work/weather/
└app.py
# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
import time
import sys

# LED_GPIO 変数に 24をセット
SW_GPIO = 24

# GPIO.BCMを設定することで、GPIO番号で制御出来るようになります。
GPIO.setmode(GPIO.BCM)

# GPIO.INを設定することで、入力モードになります。
# pull_up_down=GPIO.PUD_DOWNにすることで、内部プルダウンになります。
GPIO.setup(SW_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

# ボタン押し / 離し 動作確認用コード
while True:
    try:
        # GPIO24の値を読み込み、その値を出力します。
        # ボタンを押すと"1"(High)、離すと"0"(Low)が表示されます。
        print(f'button: {GPIO.input(SW_GPIO)}')
        time.sleep(1)   # 1秒間待つ
    # Ctrl+Cキーを押すと処理を停止
    except KeyboardInterrupt:
        # ピンの設定を初期化
        # この処理をしないと、次回 プログラムを実行した時に「ピンが使用中」のエラーになります。
        GPIO.cleanup()
        sys.exit()

実行

コマンドラインから、先程作成した app.py のディレクトリに移動し、
以下コマンドでプログラムを実行する。

python3 app.py

ボタンを押していないと、
1秒周期で
“button: 0”
が表示され、
ボタンを押すと、
“button: 1”
が表示されます。

プログラムを終了する場合は、
Ctrl+Cキー を押すと終了します。

天気予報の取得

今回は、インターネットから天気予報の情報を取得するサービスとして、
OpenWeatherMap を使用します。

無料プランの特徴
・5日後までの3時間毎の天気予報を取得可能
・1分間に天気予報を取得出来るのは60回

API keyの取得

OpenWeatherMapのAPIを使用する為には、API key を取得する必要があります。
API keyとは、APIを利用する為の認可証だと思ってください。
API keyを取得するには、
以下OpenWeatherMapの「Create New Account」URLにアクセスし、
アカウントを作成します。
https://home.openweathermap.org/users/sign_up

アカウント作成後、

●「How and where will you use our API?」というダイアログが出ます。
記入してもしなくても(cancelでも)大丈夫です。

●先程登録したメールアドレス宛に
表題:「OpenWeatherMap Account confirmation」のメールが届きます。
メールの中ほどの、「Verify your email」ボタンを押すと、メールでの認証が完了します。

上記のメール認証までが完了後、
以下画面の「API keys」タブを押すと、API keyが表示されます。

このAPI keyは、プログラムで使用するので、メモしておいてください。

プログラム

以下ディレクトリ通り、ディレクトリとファイルを作成する。
この章では、以下赤字のファイルを修正する。

/home/pi/work/weather/
└weather.py

以下コマンドでラズパイにrequestsをインストールする。

pip install requests

weather.py

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

import requests

WEATHER_API_KEY = '{上記で取得した API key を入力}'
# 地元の都市名を入れる
WEATHER_CITY_NAME = 'Tokyo'


def get_weather():

    base_url = 'http://api.openweathermap.org/data/2.5/weather'
    url = f'{base_url}?q={WEATHER_CITY_NAME}&appid={WEATHER_API_KEY}'
    # HTTP通信用ライブラリを使って、openweatherサーバから情報を取得する。
    response = requests.get(url)
    if response.status_code != requests.codes.ok:
        return None

    # json文字列を辞書に変換
    data = response.json()
    temp = round(data["main"]["temp"] - 273.15, 1)
    weather = {
        'city_name': WEATHER_CITY_NAME,
        'weather': f'{data["weather"][0]["main"]}',
        'temperature': f'{temp}度',
    }

    return weather


if __name__ == '__main__':
    weather = get_weather()
    if weather != None:
        print(f'都市名: {weather["city_name"]}')
        print(f'天気: {weather["weather"]}')
        print(f'温度: {weather["temperature"]}')

実行

コマンドラインから、先程作成した weather.py のディレクトリに移動し、
以下コマンドでプログラムを実行する。

python3 weather.py

結果として、以下のような値が表示されます。

都市名: Tokyo
天気: Clouds
温度: 15.5度

参考

地元の都市名を探す

OpenWeatherMapで天気予報が取得出来る都市は、
以下URLの「city.list.json.gz」ファイルから探すことが出来ます。
http://bulk.openweathermap.org/sample/

プログラム中の WEATHER_CITY_NAME = ‘Tokyo’
の右側の都市名を変更すると、その都市の天気情報が取得出来ます。

OepnWeather API仕様

本プログラム中で使用しているOpenWeather APIの仕様は、
以下URLから知ることが出来ます。
https://openweathermap.org/current

本APIで取得出来る情報は、
天気や温度以外にも、
湿度、気圧、風速なども取得出来ますので、
色々試してみてください。

文字列を音声に変換し、スピーカーから音声出力

今回は、無料の音声合成ソフトウェアである、
「Open JTalk」を使って、文字列を音声データに変換します。

スピーカーから音を出す方法が分からなければ、以下記事を参照ください。

Open JTalkのインストール

sudo apt install open-jtalk open-jtalk-mecab-naist-jdic hts-voice-nitech-jp-atr503-m001

プログラム

以下ディレクトリ通り、ディレクトリとファイルを作成する。
この章では、以下赤字のファイルを修正する。

/home/pi/work/weather/
└talk.py

talk.py

# -*- coding: utf-8 -*-
import subprocess

DICT_PATH = '/var/lib/mecab/dic/open-jtalk/naist-jdic/'
VOICE_PATH = '/usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice'


def talk(text: str):

    with open('talk.txt', 'w') as f:
        f.write(text)
    subprocess.run(['open_jtalk', '-x', DICT_PATH, '-m', VOICE_PATH, '-ow', 'talk.wav', 'talk.txt'])
    subprocess.run(['aplay', 'talk.wav'])


if __name__ == '__main__':
    talk('布団が吹っ飛んだ')

実行

コマンドラインから、先程作成した talk.py のディレクトリに移動し、
以下コマンドでプログラムを実行する。

python3 talk.py

結果として、
talk()に入力した
‘布団が吹っ飛んだ’
がスピーカーから音声出力されます。

音声出力する内容を変えたければ、
‘布団が吹っ飛んだ’ の所に、好きな言葉を入れて試してみてください♪

音声を女性の声に変える

Open JTalkをインストールしても、男性の声しか入っていません。
でも安心してください。
女性の声(メイちゃん)にも変更できます。

音響モデルのダウンロード

以下URLから、音声ファイル「MMDAgent_Example-1.8.zip」をダウンロードします。
https://ja.osdn.net/projects/sfnet_mmdagent/releases/

以下コマンドで、ラズパイ内の音響モデルを格納ているディレクトリにコピーします。

unzip MMDAgent_Example-1.8.zip
sudo cp -r MMDAgent_Example-1.8/Voice/mei /usr/share/hts-voice/

プログラム変更

上記、talk.py プログラムファイル中の、
VOICE_PATH = ‘*’
の値を、以下のように変更します。
上記の実行の章を行い、女性の声が出たら成功です。

VOICE_PATH = '/usr/share/hts-voice/mei/mei_happy.htsvoice'

蛇足ですが、メイちゃんの音響モデルには、
5つの感情が用意されています。
上記の例では、mei_happy を使っています。

  • mei_normal
  • mei_angry
  • mei_bashful
  • mei_happy
  • mei_sad

しゃべる内容に応じて、音響モデルを変えるとよりリアルな会話が楽しめそうですね。

まとめ

まとめです。
これまで作成した上記機能を組み合わせて、
ボタンを押して、【天気予報】を喋らせる
を実現します。

プログラム

この章では、以下赤字のファイルを修正します。

/home/pi/work/weather/
├app.py
├talk.py
└weather.py

app.py

# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
import time
import sys
import weather
import talk

# LED_GPIO 変数に 24をセット
SW_GPIO = 24

# GPIO.BCMを設定することで、GPIO番号で制御出来るようになります。
GPIO.setmode(GPIO.BCM)

# GPIO.INを設定することで、入力モードになります。
# pull_up_down=GPIO.PUD_DOWNにすることで、内部プルダウンになります。
GPIO.setup(SW_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

while True:
    try:
        # ボタン押しで発話
        if GPIO.input(SW_GPIO) == 1:
            weather = weather.get_weather()
            if weather:
                talk.talk(f'東京の天気は、{weather["weather"]}です。気温は、{weather["temperature"]}です。')
        time.sleep(0.5)   # 0.5秒間待つ
    # Ctrl+Cキーを押すと処理を停止
    except KeyboardInterrupt:
        # ピンの設定を初期化
        # この処理をしないと、次回 プログラムを実行した時に「ピンが使用中」のエラーになります。
        GPIO.cleanup()
        sys.exit()

実行

コマンドラインから、app.py のディレクトリに移動し、
以下コマンドでプログラムを実行する。

python3 app.py

ボタンを押すと、
天気予報がスピーカーから音声出力されます!

プログラムを終了する場合は、
Ctrl+Cキー を押すと終了します。

最後に

如何だったでしょうか?

ボタンを押したか判断出来た時、
ネット上から天気予報の情報が取れた時、
天気予報を喋った時、
ワクワクしましたよね♪

作ったものが動くって楽しいですよね♪

今後も、Raspberry Pi と Python を使ってワクワクするモノを作って行きます。
楽しみにしていてくださいね。

不明な点があればページTOPの「お問い合わせ」にてご連絡下さい。

タイトルとURLをコピーしました