LoginSignup
4
7

Raspberry Piに現在時刻、天気予報、ニュースを喋らせる(旧ver)

Last updated at Posted at 2021-04-11

Openwetherではなく気象庁から情報を取得できるようになったため以下のページにて書き直しました。
Raspberry Piに現在時刻+時報ボイス、天気予報、ニュースを喋らせる(2)

初めに

前回Raspberry Piに現在時刻、天気予報を喋らせるで作ったコードなんですが、引っ越した際なんと喋らなくなってしまいました。
どうやらOpenWeathermapには郵便番号から位置情報が引き出せない地域があるようで404が帰ってきてしまいました。
この問題を直すついでにニュースも読み上げれるよう改良しようかと思います。

今回新たに利用する物

・郵便番号より緯度・経度の取得

今回はHeartRailsGeo API郵便番号による住所検索 APIを利用しようかと思います。

・ニュースの取得

NHKのRSSを利用します。
このうち取得日時より二日以内の主要ニュースと政治を読み上げようかと思います。

事前準備

・下記の記事を参考にAquasTalkを利用した"atalk"コマンドを使えるようにしてください。
 raspberry piの音周り

OpenWeathermapにてアカウント登録(無料)してAPIを取得してください。

実装

適当な場所に実行させるプログラムを作ってください。

open_talkweather.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import shlex
import subprocess
from datetime import datetime
from time import time
import urllib.request
import feedparser
import json
import deg_speed

city_name = "100-0005" #郵便番号
API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxx" #APIキー
CMD_SAY = "atalk -b -s 90"
da = datetime.now()

def main():
        say_datetime()
        say_weather()
        say_news()
        say_datetime2()
        return

def say_datetime():
        if 6<= da.hour <=22:
                text = "天気予報です。%s年%s月%s日、%s時をお知らせします。" % (da.year, da.month, da.day, da.hour)
                text = CMD_SAY + ' ' + text
                print(text)
                proc = subprocess.Popen(shlex.split(text))
                proc.communicate()
                return
        else:
                exit()

def say_weather():
        url0 = "http://geoapi.heartrails.com/api/json?method=searchByPostal&postal=%s" % (city_name)
        r0 = urllib.request.urlopen(url=url0)
        obj0 = json.loads(r0.read())
        lat = obj0["response"]["location"][0]["y"]
        lon = obj0["response"]["location"][0]["x"]
        url = "https://api.openweathermap.org/data/2.5/onecall?lat=%s&lon=%s&appid=%s&units=metric&lang=ja&exclude=hourly" % (lat, lon, API_KEY)
        print(url)
        title_text = u'%sの天気'
        weather_text = u'%sは%sの風、風力%s。%s。天気は%s。降水確率は%s%です。'
        now_text = u'現在の気温は%s度、湿度%s%で体感温度は%s度です。'
        temperature_text = u'%sの予想最高気温は、%s度。予想最低気温は、%s度、湿度は%s%です。'
        try:
                r = urllib.request.urlopen(url=url)
                obj = json.loads(r.read())
                c = obj["current"]
                d = obj["daily"]
                title = obj0["response"]["location"][0]["town"]

                #today
                Nt = d[0]["temp"]
                pop = round(d[0]["pop"] * 100)
                wdn = c["wind_deg"]
                wdn = deg_speed.wdeg(wdn)
                wsn = c["wind_speed"]
                (wsn,wsna) = deg_speed.wspeed(wsn)
                today_w = d[0]["weather"][0]["description"]
                today_w_txt = weather_text % (u"今日", wdn, wsn, wsna, today_w, pop)
                today_t_txt = temperature_text % (u"今日", round(Nt["max"], 1), round(Nt["min"], 1), d[0]["humidity"])
                today_n_txt = now_text % (round(c["temp"], 1), c["humidity"], round(c["feels_like"], 1))

                #tommorow
                Nt = d[1]["temp"]
                pop = round(d[1]["pop"] * 100)
                wdt = d[1]["wind_deg"]
                wdt = deg_speed.wdeg(wdt)
                wst = d[1]["wind_speed"]
                (wst,wsna) = deg_speed.wspeed(wst)
                tommorow_w = d[1]["weather"][0]["description"]
                tommorow_w_txt = weather_text % (u"明日", wdt, wst, wsna, tommorow_w, pop)
                tommorow_t_txt = temperature_text % (u"明日", round(Nt["max"], 1), round(Nt["min"], 1), d[1]["humidity"])

                #say
                weather_str = title + ' ' + today_w_txt + ' ' + today_n_txt + ' ' + today_t_txt + ' ' + tommorow_w_txt + ' ' + tommorow_t_txt
                weather_str = weather_str.replace("-", "マイナス")
                text = '''%s '%s' ''' % (CMD_SAY, weather_str)
                print(text)
                proc = subprocess.Popen(shlex.split(text))
                proc.communicate()
        finally:
                r.close()
        return

def say_news():
        l = ["0", "4"]
        for loop in l:
                RSS_URL = 'https://www.nhk.or.jp/rss/news/cat%s.xml' % (loop)
                d = feedparser.parse(RSS_URL)
                for i, entry in enumerate(d.entries):
                        newstime = ",".join(map(str, entry.published_parsed[:5]))
                        newstime = datetime.strptime(newstime, "%Y,%m,%d,%H,%M")
                        if i == 0:
                                text = entry.summary
                        else:
                                text = "次のニュースです。" +  entry.summary
                        text = "atalk " + text
                        if da.timestamp() - newstime.timestamp() <= 172800:
                                print(text)
                                proc = subprocess.Popen(shlex.split(text))
                                proc.communicate()
        return

def say_datetime2():
        da = datetime.now()
        text = "%s時%s分です。" % (da.hour, da.minute)
        text = CMD_SAY + ' ' + text
        print(text)
        proc = subprocess.Popen(shlex.split(text))
        proc.communicate()
        return

### Execute
if __name__ == "__main__":
    main()

前回と同様に同じディレクトリ内に以下のものを作ります。

deg_speed.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-


import math

def wdeg(wd):
        obj = ["北","北北東","北東", "東北東", "東", "東南東", "南東", "南南東", "南", "南南西", "南西", "西南西", "西", "西北西", "北西", "北北西", "北"];
        wd = ((wd + 11.24) / 22.5)
        wd = math.floor(wd)
        return obj[wd]

def wspeed(ws):
        if 0 <= ws <= 0.3:
                return (0, u"静穏")
        elif 0.3 <= ws < 1.6:
                return (1, u"至軽風")
        elif 1.6 <= ws < 3.4:
                return (2, u"軽風")
        elif 3.4 <= ws < 5.5:
                return (3, u"軟風")
        elif 5.5 <= ws < 8.0:
                return (4, u"和風")
        elif 8.0 <= ws < 10.8:
                return (5, u"疾風")
        elif 10.8 <= ws < 13.9:
                return (6, u"雄風")
        elif 13.9 <= ws < 17.2:
                return (7, u"強風")
        elif 17.2 <= ws < 20.8:
                return (8, u"疾強風")
        elif 20.8 <= ws < 24.5:
                return (9, u"大強風")
        elif 24.5 <= ws < 28.5:
                return (10, u"暴風")
        elif 28.5 <= ws < 32.7:
                return (11, u"烈風")
        elif 32.7 <= ws:
                return (12, u"颶風")

if __name__ == '__main__':

        wd = input("風向(度)")
        ws = input("風速(m/s)")
        wd = int(wd)
        d = wdeg(wd)
        ws = int(ws)
        (x, y) = wspeed(ws)
        text = u"%sの風、風力%s,%s" % (d, x, y)
        print(text)

多分これで行けると思います。

注意点

郵便番号や市区町村データを取り扱うときにはまったこと
この記事を見ればわかるのですが、場所が全く異なるにもかかわらず郵便番号が同じである場合もあります。
当てはまる場合は各々でコードの修正をお願いいたします。

参考文献

Raspberry Piに現在時刻と、天気をしゃべらせてみた(Python)
raspberry piの音周り
One Call API
ビューフォート風力階級
Raspberry Piに現在時刻、天気予報を喋らせる
OpenWeatherMapで郵便番号が使えないときのアプローチ
郵便番号や市区町村データを取り扱うときにはまったこと
PythonでDatetimeからUnixtime変換
Weather condition codes
OpenWeatherMapの空模様(概況)の表現対照表

4
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
7