AWS Lambdaで傘予報LINE BOTをつくってみた

# はじめに
外出時に雨が降ることを知らずに傘を忘れてしまった経験はありませんか？
私はよく傘を忘れます。。。
そこでAWS Lambdaで傘予報をしてくれるLINE BOTをつくってみたいと思います。

# アーキテクチャ
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689353/a7ed5ee2-fed9-6557-b74b-acc7be545cd6.png width="720">

#### ①スケジュール
Amazon EventBridgeを使用して、毎日AM 6:00にAWS Lambdaを起動するようスケジュールします。

#### ②天気予報取得
OpenWeatherMapのAPIを使用して、天気予報情報を取得します。

#### ③プッシュメッセージ
天気予報情報から傘予報を行い、LINE BOTにプッシュメッセージを送信します。

# OpenWeatherMap
現在の天気や予報などの気象データを提供しているサービスです。
傘予報をする為に天気予報情報を取得します。

OpenWeatherMap APIを使用する為の事前準備などについては、
公式サイト「[How to start using Weather API](https://openweathermap.org/guide)」を参照ください。

# LINE BOT
傘予報を通知する為にLINE BOTを作成します。

LINE Massaging APIを使用する為の事前準備などについては、
公式サイト「[Messaging APIを始めよう](https://developers.line.biz/ja/docs/messaging-api/getting-started/)」を参照ください。

# AWS Lambda
OpenWeatherMap APIで天気予報を取得して、LINE BOTにMessaging APIでプッシュメッセージを送信するLambda関数を作成します。

## OpenWeatherMap API
OpenWeatherMapの次のAPIを使用して、天気予報の降水量（daily.rain）を取得します。

#### ***One Call API***

***URL***
https://api.openweathermap.org/data/2.5/onecall

***パラメーター***

|パラメータ  |必須  |説明  |
|---|---|---|
|lat, lon	|required	|Geographical coordinates (latitude, longitude)|
|appid	|required|	Your unique API key (you can always find it on your account page under the "API key" tab)|
exclude|	optional|	By using this parameter you can exclude some parts of the weather data from the API response.<br> It should be a comma-delimited list (without spaces).<br>Available values:<br>・current<br>・minutely<br>・hourly<br>・daily<br>・alerts|
|units	|optional	|Units of measurement. standard, metric and imperial units are available.<br> If you do not use the units parameter, standard units will be applied by default.|
|lang|	optional	|You can use the lang parameter to get the output in your language.|

***レスポンス***

- daily Daily forecast weather data API response
    - daily.dt Time of the forecasted data, Unix, UTC
    - daily.sunrise Sunrise time, Unix, UTC
    - daily.sunset Sunset time, Unix, UTC
    - daily.temp Units – default: kelvin, metric: Celsius, imperial: Fahrenheit. How to change units used
        - daily.temp.morn Morning temperature.
        - daily.temp.day Day temperature.
        - daily.temp.eve Evening temperature.
        - daily.temp.night Night temperature.
        - daily.temp.min Min daily temperature.
        - daily.temp.max Max daily temperature.
    - daily.feels_like This accounts for the human perception of weather. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit. How to change units used
        - daily.feels_like.morn Morning temperature.
        - daily.feels_like.day Day temperature.
        - daily.feels_like.eve Evening temperature.
        - daily.feels_like.night Night temperature.
    - daily.pressure Atmospheric pressure on the sea level, hPa
    - daily.humidity Humidity, %
    - daily.dew_point Atmospheric temperature (varying according to pressure and humidity) below which water droplets begin to condense and dew can form. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
    - daily.wind_speed Wind speed. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour. How to change units used
    - daily.wind_gust (where available) Wind gust. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour. How to change units used
    - daily.wind_deg Wind direction, degrees (meteorological)
    - daily.clouds Cloudiness, %
    - daily.uvi Midday UV index
    - daily.pop Probability of precipitation
    - <font color=red>daily.rain (where available) Precipitation volume, mm</font>
    - daily.snow (where available) Snow volume, mm
    - daily.weather
        - daily.weather.id Weather condition id
        - daily.weather.main Group of weather parameters (Rain, Snow, Extreme etc.)
        - daily.weather.description Weather condition within the group (full list of weather conditions). Get the output in your language
        - daily.weather.icon Weather icon id. How to get icons

## LINE Messaging API
Messaging APIを使用して、LINE BOTに傘予報のプッシュメッセージを送信します。
今回は、ライブラリ（line-bot-sdk）を使用します。

***URL***
https://api.line.me/v2/bot/message/push

***パラメーター***

|パラメータ  |必須  |説明  |
|---|---|---|
|to	             |必須|送信先のID。<br>Webhookイベントオブジェクトで返される、<br>userId、groupId、またはroomIdの値を使用します。<br>LINEに表示されるLINE IDは使用しないでください。|
|message	     |必須|送信するメッセージ<br>最大件数：5|
|notificationDisabled|任意|true：メッセージ送信時に、ユーザーに通知されない。<br>false：メッセージ送信時に、ユーザーに通知される。<br>ただし、LINEで通知をオフにしている場合は通知されません。<br>デフォルト値はfalseです。|

***レスポンス***
ステータスコード200と空のJSONオブジェクトを返します。

## Lambda関数
OpenWeatherMap APIで取得した降水量（daily.rain）が0以上であれば、
Messaging APIでLINE BOTに傘予報を通知するLambda関数を作成します。

~~~ python
import json
import requests
from datetime import date
from linebot import LineBotApi
from linebot.models import TextSendMessage
from linebot.exceptions import LineBotApiError

LINE_USER_ID = '*****'               # LINEユーザーID
LINE_CHANNEL_ACCESS_TOKEN = '*****'  # LINEアクセストークン

OPEN_WEATHER_FORECAST_URL = 'https://api.openweathermap.org/data/2.5/onecall'
OPEN_WEATHER_API_KEY = '*****'       # APIキー

def create_message(forecast):
    return date.today().strftime("%m/%d") + 'は雨の予報です。' + '\n' + \
           '外出時は傘を忘れずに！' + '\n' + \
           '天気：' + str(forecast['weather'][0]['description']) + '\n' + \
           '降水量：' + str(forecast['rain']) + 'mm'

def push_message(message):
    try:
        line_bot_api = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN)
        line_bot_api.push_message(LINE_USER_ID, TextSendMessage(text=message))
    except LineBotApiError as e:
        print(e)

def lambda_handler(event, context):
    try:
        params = {
            'lat': '*****', # 予報場所（緯度）
            'lon': '*****', # 予報場所（経度）
            'units': 'metric',
            'lang': 'ja',
            'appid': OPEN_WEATHER_API_KEY
        }
        response = requests.get(OPEN_WEATHER_FORECAST_URL, params=params)
        print(json.dumps(response.json()['daily'], indent=2, ensure_ascii=False))
        today_forecast = response.json()['daily'][0]
        if 'rain' in today_forecast:
            push_message(create_message(today_forecast))
    except requests.exceptions.RequestException as e:
        print(e)
~~~

# デプロイ
Lambda関数のデプロイパッケージを作成して、デプロイします。
以下のライブラリをデプロイパッケージに含めます。

- line-bot-sdk

次にLambda関数のトリガーに「EventBridge (CloudWatch Events)」を追加します。

これで雨の日のAM6:00にLINE BOTへ傘予報が通知されるようになりました。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689353/c63f27ba-c5e3-8abe-47d7-2df95171dc05.png width="360">

# さいごに
AWS Lambdaを使用して傘予報のLINE BOTを作成してみましたが、
想像していたより簡単に完成することができました。
AWS Lambdaは無料枠内でも色々と出来るので、本当に便利ですね。
これで傘を忘れなくなるかな…
最後まで読んでいただきありがとうございました。

※ AWS Lambda 初心者なので、至らない点があればコメントいただけると幸いです。