0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS×Pythonで天気予報LINEBotを作ってみた

Last updated at Posted at 2024-12-31

前置き

毎朝、帰宅時間の18時に雨が降るかどうかをLINEで通知するBotを作成しました。この記事では、その作成手順を解説します。

GitHub

0. 記事の構成

  1. 天気予報API(livedoor天気互換)の動作確認
  2. 天気予報APIで降水確率をPythonで取得する
  3. LINE Messaging APIの設定
  4. AWS Lambdaの設定
  5. AWS Lambdaのテスト
  6. 天気予報APIの結果をLINEで通知する
  7. AWS EventBridgeの設定
  8. まとめ
  9. 参考文献
    • []の数字は参考文献です。

1. 天気予報API(livedoor天気互換)の動作確認[1][2]

天気予報APIのリクエストURLは以下の通りです:

リクエストパラメータ
https://weather.tsukumijima.net/api/forecast/city/<場所のID>

動作確認手順

  1. APIドキュメントに従い、リクエストURLに場所のIDを指定します。
    • 場所のIDは全国の地点定義表[3]に記載されています。
  2. 福井市(ID: 180010)を指定して実行します。

実行結果

以下は、福井市の天気予報を取得した際のレスポンス例です。

福井市
https://weather.tsukumijima.net/api/forecast/city/180010

天気予報API_livedoor天気互換の動作確認2.png

レスポンス例 JSON
{
    "publicTime": "2024-12-27T13:00:00+09:00",
    "publicTimeFormatted": "2024/12/27 13:00:00",
    "publishingOffice": "福井地方気象台",
    "title": "福井県 福井 の天気",
    "link": "https://www.jma.go.jp/bosai/forecast/#area_type=offices&area_code=180000",
    "description": {
        "publicTime": "2024-12-27T10:41:00+09:00",
        "publicTimeFormatted": "2024/12/27 10:41:00",
        "headlineText": "",
        "bodyText": " 日本付近は冬型の気圧配置となっています。\n\n 福井県は、おおむね雨や雪となっています。\n\n 27日は、冬型の気圧配置が続く見込みです。\n このため、嶺北は雪か雨、嶺南は雨か雪で、共に雷を伴う所があるでしょう。\n\n 28日は、引き続き冬型の気圧配置となる見込みです。\n このため、雪か雨で、雷を伴う所があるでしょう。",
        "text": " 日本付近は冬型の気圧配置となっています。\n\n 福井県は、おおむね雨や雪となっています。\n\n 27日は、冬型の気圧配置が続く見込みです。\n このため、嶺北は雪か雨、嶺南は雨か雪で、共に雷を伴う所があるでしょう。\n\n 28日は、引き続き冬型の気圧配置となる見込みです。\n このため、雪か雨で、雷を伴う所があるでしょう。"
    },
    "forecasts": [
        {
            "date": "2024-12-27",
            "dateLabel": "今日",
            "telop": "雪か雨",
            "detail": {
                "weather": "雪か雨 所により 雷 を伴う",
                "wind": "北の風 やや強く 後 南の風 やや強く 海上 では 西の風 強く",
                "wave": "4メートル"
            },
            "temperature": {
                "min": {
                    "celsius": null,
                    "fahrenheit": null
                },
                "max": {
                    "celsius": "8",
                    "fahrenheit": "46.4"
                }
            },
            "chanceOfRain": {
                "T00_06": "--%",
                "T06_12": "--%",
                "T12_18": "90%",
                "T18_24": "90%"
            },
            "image": {
                "title": "雪か雨",
                "url": "https://www.jma.go.jp/bosai/forecast/img/400.svg",
                "width": 80,
                "height": 60
            }
        },
        ・・・
    ],
    "location": {
        "area": "中部",
        "prefecture": "福井県",
        "district": "嶺北",
        "city": "福井"
    },
    "copyright": {
        "title": "(C) 天気予報 API(livedoor 天気互換)",
        "link": "https://weather.tsukumijima.net/",
        "image": {
            "title": "天気予報 API(livedoor 天気互換)",
            "link": "https://weather.tsukumijima.net/",
            "url": "https://weather.tsukumijima.net/logo.png",
            "width": 120,
            "height": 120
        },
        "provider": [
            {
                "link": "https://www.jma.go.jp/jma/",
                "name": "気象庁 Japan Meteorological Agency",
                "note": "気象庁 HP にて配信されている天気予報を JSON データへ編集しています。"
            }
        ]
    }
}

出力結果より

JSON
"chanceOfRain": {
                "T00_06": "--%",
                "T06_12": "--%",
                "T12_18": "90%",
                "T18_24": "90%"
            }

ここで、chanceOfRainプロパティのT12_18部分を使用して18時の降水確率を取得します。

2. 天気予報APIで降水確率をPythonで取得する[4][5]

以下のPythonコードを使用してAPIから降水確率を取得します。

python
import requests

url = requests.get("https://weather.tsukumijima.net/api/forecast/city/180010")
data = url.json()

chanceOfRain = data["forecasts"][0]["chanceOfRain"]["T12_18"]

print(f"T12_18の降水確率: {chanceOfRain}")

実行結果

powershell
$ \WeatherLine> python3 .\get_chanceOfRain.py
T12_18の降水確率: 90%

改良版:例外処理と条件分岐を追加

以下のコードでは、降水確率が50%以上の場合のみ結果を出力します。

python
import requests

try:
    response = requests.get("https://weather.tsukumijima.net/api/forecast/city/180010",timeout=5)
    response.raise_for_status()

    data = response.json()

    chanceOfRain_str = data["forecasts"][0]["chanceOfRain"]["T12_18"].strip("%")
    chanceOfRain = int(chanceOfRain_str)
    
    if chanceOfRain >= 50:
        print(f"T12_18の降水確率は{chanceOfRain}%です。雨の可能性があります。")

except requests.exceptions.Timeout:
    print("リクエストがタイムアウトしました。")

except requests.exceptions.HTTPError as e:
    print(f"HTTPエラーが発生しました: {e.response.status_code} {e.response.reason}")

except requests.exceptions.RequestException as e:
    print(f"リクエスト中にエラーが発生しました: {e}")

実行結果(福井市の場合)

PowerShell
$ \WeatherLine> python3 .\get_chanceOfRain.py
T12_18の降水確率は90%です。雨の可能性があります。

これで動作確認とローカル環境で設定が終わったため、あとはLINE Messaging APIの設定とAWS Lambdaの設定をしクラウドで動作確認を行います。

3. LINE Messaging APIの設定

  1. LINE Developersでプロバイダーを作成[6]
  2. Messaging APIチャンネルを作成
  3. チャネルアクセストークンを発行

LINE公式アカウントを使用し、Messaging APIの設定をする。

4. AWS Lambdaの設定

1. AWS Management ConsoleでLambda関数を作成

  • 関数名: WeatherLine
  • ランタイム: Python 3.13

Lambda設定1.png

2. 必要なライブラリ(requests)をインストールし、レイヤーとしてアップロード

  • レイヤーの準備(ローカル)

    $ pip install requests -t ./python
    $ zip -r python.zip ./python
    
  • 名前を「requests」にして、「python.zip」をアップロード
    Lambda設定3.png

ハマったところ No module named 'requests' [9]
フォルダ名は必ず"python.zip"とすること。
他のフォルダ名だとエラーがでて使えない!!

3. 環境変数にLINEチャネルアクセストークンを設定[7]

Lambda設定2.png

5. AWS Lambdaのテスト[8]

以下は、LINEで固定メッセージを送信するテストコードです。

python
import os
import requests

def lambda_handler(event, context):
    # 環境変数の取得
    CHANNEL_ACCESS_TOKEN = os.environ['CHANNEL_ACCESS_TOKEN']
    
    # LINEの返信APIにメッセージを送信
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {CHANNEL_ACCESS_TOKEN}'
    }

    # メッセージ内容の作成
    body = {
        "messages": [
            {
                "type": "text",
                "text": "TEST Message!!"  # LINEに送信するメッセージ
            }
        ]
    }

    # リクエストの送信
    response = requests.post(
        'https://api.line.me/v2/bot/message/broadcast',
        headers=headers,
        json=body
    )

    return {
        'statusCode': response.status_code,
        'body': response.text
    }

実行結果:LINE

LINEに「テストメッセージ」が送信されます。
LINE_test1.png

6. 天気予報APIの結果をLINEで通知する

天気予報APIから取得した降水確率をLINEで通知するLambda関数です。

python
import os
import requests

def lambda_handler(event, context):
    # 環境変数の取得
    CHANNEL_ACCESS_TOKEN = os.environ['CHANNEL_ACCESS_TOKEN']
    
    # LINE APIのヘッダー
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {CHANNEL_ACCESS_TOKEN}'
    }

    # 天気予報APIを呼び出して降水確率を取得
    message = ""
    try:
        # タイムアウトを5秒に設定
        response = requests.get("https://weather.tsukumijima.net/api/forecast/city/180010", timeout=5)
        response.raise_for_status()

        data = response.json()

        # 降水確率を取得(T12_18の値を取得)
        chanceOfRain_str = data["forecasts"][0]["chanceOfRain"]["T12_18"].strip("%")
        
        if chanceOfRain_str == "--":
            message = "T12_18の降水確率が未設定または不明です。"
        else:
            chanceOfRain = int(chanceOfRain_str)
            if chanceOfRain >= 50:
                message = f"本日18時の降水確率は{chanceOfRain}%です。雨の可能性があります。"
            else:
                message = f"本日18時の降水確率は{chanceOfRain}%です。雨の可能性は低いです。"

    except requests.exceptions.Timeout:
        message = "天気予報の取得に失敗しました(タイムアウト)。"
    except requests.exceptions.HTTPError as e:
        message = f"天気予報の取得に失敗しました(HTTPエラー: {e.response.status_code} {e.response.reason})。"
    except requests.exceptions.RequestException as e:
        message = f"天気予報の取得中にエラーが発生しました: {str(e)}"

    # LINEにメッセージを送信
    body = {
        "messages": [
            {
                "type": "text",
                "text": message  # 天気予報の結果をLINEに送信
            }
        ]
    }

    try:
        line_response = requests.post(
            'https://api.line.me/v2/bot/message/broadcast',
            headers=headers,
            json=body
        )
        line_response.raise_for_status()
    except requests.exceptions.RequestException as e:
        return {
            'statusCode': 500,
            'body': f"Error sending message to LINE: {str(e)}"
        }

    # 正常終了
    return {
        'statusCode': line_response.status_code,
        'body': line_response.text
    }

実行結果:LINE

LINE_test2.png

7. AWS EventBridgeの設定[10]

  1. AWS Management ConsoleでEventBridgeを開き、新規ルールを作成
  2. スケジュール式に以下を設定
    (日本時間、平日8時に実行)
cron(0 8 ? * MON-FRI *)

Amazon EventBridge設定1.png
3. Lambda関数をターゲットに設定

実行結果:LINE

Amazon EventBridge設定2.png

8. まとめ

この記事では、天気予報APIを活用して、帰宅時間18時の降水確率をLINEで通知するBotを作成する手順を解説しました。今後は、降水確率が高い場合に雨雲レーダー情報を追加通知する機能の実装を検討しています。

9. 参考文献

[1]

[2]

[3]

[4]

[5]

[6]

[7]

[8]

[9]

[10]

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?