【Python】無料で使える天気予報APIで降水確率を取得する

今回は天気予報APIから降水確率を取得してみる。

この記事を書こうと思った元々の目的は「良い天気予報APIを見つけたからみんなにぜひ共有したい!!」という気持ちからなのだが、APIを見つけてしまったからには実際に使って何か作りたいというエンジニア精神が溢れ出てしまいました。
お暇があればお付き合い下さい..。

目次

無料で使える天気予報API

無料で使える天気予報APIで有名なのがOpenWeatherMapというサービスなのだが、アカウント登録が必要だったり、APIの使用回数に制限があったり...そもそも僕がやりたかった降水確率の取得はできない。
(情報の信用性に関しては高いので、目的によってはこちらを使うほうが良かったりもする..)

そこで、天気予報 API(livedoor 天気互換)をおすすめしたい。
もちろん無料だし、アカウントの作成も必要ない。取得できるデータも割と豊富で僕の取得したかった降水確率も得ることができる。

天気予報 API(livedoor 天気互換)を使ってみる

使い方も簡単。
https://weather.tsukumijima.net/api/forecast/city/
の後ろに取得したいcityコードを付加するだけ。

cityコードはこちらを参照していただけるとすぐ分かると思う。
https://weather.tsukumijima.net/primary_area.xml

例えば、僕が最近旅行に行きたい石川県(金沢市)の天気を取得したい場合は以下のURLからjson形式で天気情報を取得することが出来る。

https://weather.tsukumijima.net/api/forecast/city/170010

降水確率は0-6時,6-12時,12-18時,18-24時毎の情報を取得できる
しかも、直近3日の天気予報を取得できるので、非常に親切なAPIですね。
(他にも取得できる情報はこちらを参考に https://weather.tsukumijima.net/primary_area.xml)

PythonでAPIを叩いてみる

あーうずうずしてきましたよ。PythonでAPI叩いたろ。
降水確率をLINEで通知するbotを作りたいとかいう需要があれば使えますね。

import requests
import re
from datetime import datetime

city_code = "440010" # 石川県(金沢市)のcityコード
url = "https://weather.tsukumijima.net/api/forecast/city/" + city_code

try:
    response = requests.get(url)
    response.raise_for_status()     # ステータスコード200番台以外は例外とする
except requests.exceptions.RequestException as e:
    print("Error:{}".format(e))

else:
    weather_json = response.json()
    print(weather_json['forecasts'][0]['chanceOfRain']) # 0:今日 1:明日 2:明後日
   # 現在の時間の降水確率を取得していく
    now_hour = datetime.now().hour
    if 0 <= now_hour and now_hour < 6:
        cor = weather_json['forecasts'][0]['chanceOfRain']['T00_06']
    elif 6 <= now_hour and now_hour < 12:
        cor = weather_json['forecasts'][0]['chanceOfRain']['T06_12']
    elif 12 <= now_hour and now_hour < 18:
        cor = weather_json['forecasts'][0]['chanceOfRain']['T12_18']
    else:
        cor = weather_json['forecasts'][0]['chanceOfRain']['T18_24']

    print("現在の降水確率 {}".format(cor))


# 以下出力
現在の降水確率 20%

サクッとAPIで現在時刻の降水確率を取得してみた。

うーん、なんだか満足しないな。よし、ラズパイに組み込んだろ

傘持ち出しアラート装置

今日は傘いる?いらない?をわざわざ天気予報で見たりしなくても良いように現時刻の降水確率の表示と、雨が降りそうなときはLED点灯を行うような装置をラズパイで作ってみた。
降水確率は5分周期でAPIを叩き更新を行う。

これを玄関に置いておけば傘の持ち出しの必要性がすぐ分かる!
かなりアナログな装置だが、意外と使い物になるのでは?

ラズパイのモジュールを組み込む

今回使用するモジュールはLEDモジュールと、4Digit-LED-Displayモジュールです。

LEDモジュール
4Digit-LED-Displayモジュール

方針は、4Digit-LED-Displayモジュールで降水確率を表示し、降水確率30%以上となった場合は「傘を持ち出せ」というアラートの意味でLEDモジュールを点灯させるようにしてみた。

オシャレさもない見た目になった..。まぁかっこいいじゃん。

傘持ち出しアラート装置

一応コーディング結果も貼っておきます。
10数分でサクッと書いた程度なのでキレイではないでが...。

#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
import requests
import re
from datetime import datetime
import threading

# 7色LEDのpin
ledpin = 40

# 4Digit-LEDのpin
pins = {'pinA':3, 'pinB':5, 'pinC':21, 'pinD':8, 'pinE':10, 'pinF':11, 'pinG':12, 'pinDP':13, 'pin_1':15, 'pin_2':16, 'pin_3':18, 'pin_4':19}

# API (石川県(金沢市)の天気情報取得)
url = "https://weather.tsukumijima.net/api/forecast/city/440010"

# 降水確率初期値
cor = None

# この降水確率より大きい場合はアラート用LED点灯
RAINY_ALERT = 30

# 降水確率取得
def get_weather_cor():
    cor = None
    try:
        response = requests.get(url)
        response.raise_for_status()     # ステータスコード200番台以外は例外とする
    except requests.exceptions.RequestException as e:
        print("Error:{}".format(e))

    else:
        weather_json = response.json()
        print(weather_json['forecasts'][0]['chanceOfRain'])
        now_hour = datetime.now().hour
        if 0 <= now_hour and now_hour < 6:
            cor = weather_json['forecasts'][0]['chanceOfRain']['T00_06']
        elif 6 <= now_hour and now_hour < 12:
            cor = weather_json['forecasts'][0]['chanceOfRain']['T06_12']
        elif 12 <= now_hour and now_hour < 18:
            cor = weather_json['forecasts'][0]['chanceOfRain']['T12_18']
        else:
            cor = weather_json['forecasts'][0]['chanceOfRain']['T18_24']

        cor = re.sub("\\D", "", cor)    # %除去

        print("現在の降水確率 {}%".format(cor))

    return cor

# 初期化
def init():
    GPIO.setmode(GPIO.BOARD)
    # 7色LEDのセットアップ
    GPIO.setup(ledpin, GPIO.OUT)
    # 4Digit-LEDのセットアップ
    for i in pins:
        GPIO.setup(pins[i], GPIO.OUT)

# 4Digit-LED 点灯桁数
def digitSelect(digitNum):
    if digitNum == 1:
        GPIO.output(pins['pin_1'], GPIO.LOW)
        GPIO.output(pins['pin_2'], GPIO.HIGH)
        GPIO.output(pins['pin_3'], GPIO.HIGH)
        GPIO.output(pins['pin_4'], GPIO.HIGH)
    elif digitNum == 2:
        GPIO.output(pins['pin_1'], GPIO.HIGH)
        GPIO.output(pins['pin_2'], GPIO.LOW)
        GPIO.output(pins['pin_3'], GPIO.HIGH)
        GPIO.output(pins['pin_4'], GPIO.HIGH)
    elif digitNum == 3:
        GPIO.output(pins['pin_1'], GPIO.HIGH)
        GPIO.output(pins['pin_2'], GPIO.HIGH)
        GPIO.output(pins['pin_3'], GPIO.LOW)
        GPIO.output(pins['pin_4'], GPIO.HIGH)
    elif digitNum == 4:
        GPIO.output(pins['pin_1'], GPIO.HIGH)
        GPIO.output(pins['pin_2'], GPIO.HIGH)
        GPIO.output(pins['pin_3'], GPIO.HIGH)
        GPIO.output(pins['pin_4'], GPIO.LOW)
    else:
        GPIO.output(pins['pin_1'], GPIO.LOW)
        GPIO.output(pins['pin_2'], GPIO.LOW)
        GPIO.output(pins['pin_3'], GPIO.LOW)
        GPIO.output(pins['pin_4'], GPIO.LOW)

# 4Digit-LED全ハイフン表示
def display_all_haihun():
    digitSelect(0)  # 4桁すべて点灯
    GPIO.output(pins['pinA'], GPIO.LOW)
    GPIO.output(pins['pinB'], GPIO.LOW)
    GPIO.output(pins['pinC'], GPIO.LOW)
    GPIO.output(pins['pinD'], GPIO.LOW)
    GPIO.output(pins['pinE'], GPIO.LOW)
    GPIO.output(pins['pinF'], GPIO.LOW)
    GPIO.output(pins['pinG'], GPIO.HIGH)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 0表示
def display_0():
    GPIO.output(pins['pinA'], GPIO.HIGH)
    GPIO.output(pins['pinB'], GPIO.HIGH)
    GPIO.output(pins['pinC'], GPIO.HIGH)
    GPIO.output(pins['pinD'], GPIO.HIGH)
    GPIO.output(pins['pinE'], GPIO.HIGH)
    GPIO.output(pins['pinF'], GPIO.HIGH)
    GPIO.output(pins['pinG'], GPIO.LOW)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 1表示
def display_1():
    GPIO.output(pins['pinA'], GPIO.LOW)
    GPIO.output(pins['pinB'], GPIO.HIGH)
    GPIO.output(pins['pinC'], GPIO.HIGH)
    GPIO.output(pins['pinD'], GPIO.LOW)
    GPIO.output(pins['pinE'], GPIO.LOW)
    GPIO.output(pins['pinF'], GPIO.LOW)
    GPIO.output(pins['pinG'], GPIO.LOW)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 2表示
def display_2():
    GPIO.output(pins['pinA'], GPIO.HIGH)
    GPIO.output(pins['pinB'], GPIO.HIGH)
    GPIO.output(pins['pinC'], GPIO.LOW)
    GPIO.output(pins['pinD'], GPIO.HIGH)
    GPIO.output(pins['pinE'], GPIO.HIGH)
    GPIO.output(pins['pinF'], GPIO.LOW)
    GPIO.output(pins['pinG'], GPIO.HIGH)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 3表示
def display_3():
    GPIO.output(pins['pinA'], GPIO.HIGH)
    GPIO.output(pins['pinB'], GPIO.HIGH)
    GPIO.output(pins['pinC'], GPIO.HIGH)
    GPIO.output(pins['pinD'], GPIO.HIGH)
    GPIO.output(pins['pinE'], GPIO.LOW)
    GPIO.output(pins['pinF'], GPIO.LOW)
    GPIO.output(pins['pinG'], GPIO.HIGH)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 4表示
def display_4():
    GPIO.output(pins['pinA'], GPIO.LOW)
    GPIO.output(pins['pinB'], GPIO.HIGH)
    GPIO.output(pins['pinC'], GPIO.HIGH)
    GPIO.output(pins['pinD'], GPIO.LOW)
    GPIO.output(pins['pinE'], GPIO.LOW)
    GPIO.output(pins['pinF'], GPIO.HIGH)
    GPIO.output(pins['pinG'], GPIO.HIGH)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 5表示
def display_5():
    GPIO.output(pins['pinA'], GPIO.HIGH)
    GPIO.output(pins['pinB'], GPIO.LOW)
    GPIO.output(pins['pinC'], GPIO.HIGH)
    GPIO.output(pins['pinD'], GPIO.HIGH)
    GPIO.output(pins['pinE'], GPIO.LOW)
    GPIO.output(pins['pinF'], GPIO.HIGH)
    GPIO.output(pins['pinG'], GPIO.HIGH)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 6表示
def display_6():
    GPIO.output(pins['pinA'], GPIO.HIGH)
    GPIO.output(pins['pinB'], GPIO.LOW)
    GPIO.output(pins['pinC'], GPIO.HIGH)
    GPIO.output(pins['pinD'], GPIO.HIGH)
    GPIO.output(pins['pinE'], GPIO.HIGH)
    GPIO.output(pins['pinF'], GPIO.HIGH)
    GPIO.output(pins['pinG'], GPIO.HIGH)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 7表示
def display_7():
    GPIO.output(pins['pinA'], GPIO.HIGH)
    GPIO.output(pins['pinB'], GPIO.HIGH)
    GPIO.output(pins['pinC'], GPIO.HIGH)
    GPIO.output(pins['pinD'], GPIO.LOW)
    GPIO.output(pins['pinE'], GPIO.LOW)
    GPIO.output(pins['pinF'], GPIO.LOW)
    GPIO.output(pins['pinG'], GPIO.LOW)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 8表示
def display_8():
    GPIO.output(pins['pinA'], GPIO.HIGH)
    GPIO.output(pins['pinB'], GPIO.HIGH)
    GPIO.output(pins['pinC'], GPIO.HIGH)
    GPIO.output(pins['pinD'], GPIO.HIGH)
    GPIO.output(pins['pinE'], GPIO.HIGH)
    GPIO.output(pins['pinF'], GPIO.HIGH)
    GPIO.output(pins['pinG'], GPIO.HIGH)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 9表示
def display_9():
    GPIO.output(pins['pinA'], GPIO.HIGH)
    GPIO.output(pins['pinB'], GPIO.HIGH)
    GPIO.output(pins['pinC'], GPIO.HIGH)
    GPIO.output(pins['pinD'], GPIO.HIGH)
    GPIO.output(pins['pinE'], GPIO.LOW)
    GPIO.output(pins['pinF'], GPIO.HIGH)
    GPIO.output(pins['pinG'], GPIO.HIGH)
    GPIO.output(pins['pinDP'], GPIO.LOW)

# 4Digit-LED 点灯番号選択
def pickNum(number):
    if(number == 0):
        display_0()
    elif(number == 1):
        display_1()
    elif(number == 2):
        display_2()
    elif(number == 3):
        display_3()
    elif(number == 4):
        display_4()
    elif(number == 5):
        display_5()
    elif(number == 6):
        display_6()
    elif(number == 7):
        display_7()
    elif(number == 8):
        display_8()
    elif(number == 9):
        display_9()
    else:
        display_all_haihun()

# 降水確率の表示
def Display_cor():
    global cor
    if cor is not None:
        for i, num in enumerate(reversed(cor)):
            # 1の位から埋めていく
            digitSelect(4 - i)
            pickNum(int(num))
            time.sleep(0.01)
    else:
        # 降水確率が取得できない場合はオールハイフン表示
        display_all_haihun()
        time.sleep(0.1)

# 降水確率の更新
def update_weather_cor():
    global cor

    while True:
        cor = get_weather_cor()

        # 降水確率30%以上はLED点灯させる
        if cor is not None:
            if int(cor) >= RAINY_ALERT:
                GPIO.output(ledpin, GPIO.HIGH)
            else:
                GPIO.output(ledpin, GPIO.LOW)
        # 降水確率は5分周期で更新
        time.sleep(300)


if __name__ == '__main__':
    try:
        init()
        # 降水量の更新はスレッドで実行する
        update_thread = threading.Thread(target=update_weather_cor)
        update_thread.setDaemon(True)
        update_thread.start()
        while True:
            Display_cor()

    except:
        GPIO.cleanup()

長っ!!!。

ラズパイで動かしてみる

こちらは降水確率が10%の場合
雨がほぼ振らないということで、アラート用のLEDは点灯しない。

降水確率10%

そして、こちらは降水確率が80%の場合
雨が降りそうなので、アラート用のLEDを点灯

降水確率80%

(これは、個人的な偏見なのですが、なんとなくフィーリングで降水確率20%までは雨が降らないと勝手に思っている.。なので30%でアラート発行とした。)

この傘持ち出しアラート装置を玄関に置いておけば、LEDが点灯している日は傘を持っていこう!!と教えてくれます。こうして、ちょっと便利な装置が出来たのでした〜。
APIの紹介をするついでにラズパイで作ってみちゃいました。

お子さんの夏休みの自由研究なんかに作ってみてもおもしろいですね。ぜひ参考に。ばいちゃ

今回使用したモジュールはこちらのキットを購入するとすべて付いています。(僕もこれ買いました)

他にもラズパイセンサーキットのおすすめ紹介しています

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!

コメント

コメントする

目次
閉じる