AWS Lambda + LINE Notify で帰宅時に傘を忘れないようにLINEへ通知する

# はじめに
誰でも一度は、会社や学校に傘を置き忘れてしまった経験ありますよね？
もし翌日に雨が降ったら傘がなくて絶望です。。。

そこで、**帰宅時に傘を忘れないようにLINEに通知してくれるシステム**を作りました！

# 完成物

![IMG_1366.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329009/8ac2cb08-a85c-9824-ec7f-b11fd69200e6.png)


以下の記事で紹介されている、雨だったら朝に傘を持つように通知するシステムをベースにさせていただきました。

[Python + AWS Lambda + Line Notify で自動で毎朝Lineに本日のお天気を通知してみた。](https://qiita.com/Yougurut/items/6c5f2bd6f3f29b1ae465)

上記に追加する形で実装し、**雨だったら朝に傘を持つように通知** ＋ **帰宅時に傘を持ち帰るように通知** という二段構えで雨の日をサポートします！

# システム概要
## 朝：雨だったら傘を持つように通知する

![reminder_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329009/ab4a738f-1703-024b-3954-43d301262ed0.jpeg)

まず、CloudWatch Eventで毎朝7時にLambdaを起動させます。
Lambdaはお天気情報を取得し、もし今日雨が降るなら傘を持つようにLINEに通知します。
ここまでは[上記記事](https://qiita.com/Yougurut/items/6c5f2bd6f3f29b1ae465)で作成できます。

異なる点は、雨だったらS3にファイルを作成する点です。こちらは帰宅時の通知に使用します。

## 帰宅時：傘を持ち帰るように通知する

![reminder_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329009/5857b936-e091-eafb-0840-ddd5e35dd1dd.jpeg)


ここが本記事で主に追加した部分です。
まず、CloudWatch Eventで毎日帰宅時にLambdaを起動させます。
LambdaはS3を確認し、今日の日付でファイルが作成されていたら、朝に傘を持ったと判定して、LINEに傘を持ち帰るように通知します。

とてもシンプルですね！それでは実際に作ってみましょう！

# LINE Notify トークン取得

以下の記事などを参考にLINE Notifyのトークンを取得しておきます。
https://qiita.com/iitenkida7/items/576a8226ba6584864d95

# S3の準備

S3バケットに適当なディレクトリを作成しておきます。
本記事では`weather`ディレクトリを作成しました。

![スクリーンショット 2020-01-28 21.12.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329009/389f36ab-260b-be18-fba9-b4a422db4bef.png)

本記事のシステムでは、上記で作成したディレクトリに以下のようなファイルが生成されます。なお、削除処理は実装していないので、ライフサイクルルールを設定して数日したら自動で消すようにしておくと便利です！

![スクリーンショット 2020-01-28 21.12.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329009/3b7d3eda-21aa-f284-963a-8cde2dc181fe.png)


# Lambda作成

Lambda関数を新規作成します。
今回、ランタイムはPython3.8にしました。

デフォルトで生成される`lambda_function.py`を編集し、以下のコードを貼り付けてください。

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

import json
import sys
import urllib.parse
import urllib.request
import datetime
import os
import boto3

# weather's API
WEATHER_URL="http://weather.livedoor.com/forecast/webservice/json/v1?city=%s"
CITY_CODE="130010" # TOKYO
TODAY=0

# LINE notify's API
LINE_TOKEN = os.environ['LINE_TOKEN']
LINE_NOTIFY_URL = "https://notify-api.line.me/api/notify"

S3_BUCKET_NAME = os.environ['S3_BUCKET_NAME']
S3_PREFIX = "weather/"
s3 = boto3.resource('s3')
s3Client = boto3.client('s3')

def get_weather_info():
    try:
        url = WEATHER_URL % CITY_CODE
        html = urllib.request.urlopen(url)
        html_json = json.loads(html.read().decode('utf-8'))
    except Exception as e:
        print ("Exception Error: ", e)
        sys.exit(1)
    return html_json

def set_weather_info(weather_json, day):
    min_temperature = None
    max_temperature = None
    try:
        date = weather_json['forecasts'][day]['date']
        weather = weather_json['forecasts'][day]['telop']
        max_temperature = weather_json['forecasts'][day]['temperature']['max']['celsius']
        min_temperature = weather_json['forecasts'][day]['temperature']['min']['celsius']
    except TypeError:
        # temperature data is None etc...
        pass
    msg = "%s\nweather: %s\nmin: %s\nmax: %s" % \
               (date, weather, min_temperature, max_temperature)
    return msg

def send_info(msg):
    method = "POST"
    headers = {"Authorization": "Bearer %s" % LINE_TOKEN}
    payload = {"message": msg}
    try:
        payload = urllib.parse.urlencode(payload).encode("utf-8")
        req = urllib.request.Request(
            url=LINE_NOTIFY_URL, data=payload, method=method, headers=headers)
        urllib.request.urlopen(req)
    except Exception as e:
        print ("Exception Error: ", e)
        sys.exit(1)
        
def put_s3():
    now = datetime.datetime.now() + datetime.timedelta(hours=9) ## UTC+9
    obj = s3.Object(S3_BUCKET_NAME, S3_PREFIX + now.strftime('%Y-%m-%d'))
    obj.put()
        
def was_it_raining():
    now = datetime.datetime.now() + datetime.timedelta(hours=9) ## UTC+9
    contents = s3Client.list_objects(Bucket=S3_BUCKET_NAME, Prefix=S3_PREFIX)["Contents"]
    if contents:
        for content in contents:
            if content.get("Key") == S3_PREFIX + now.strftime('%Y-%m-%d'):
                return True
    return False
        
def lambda_handler(event, context):
    if('event_type' not in event):
        return {
            'statusCode': 400,
            'body': json.dumps('event_type does not exist in event')
        }
    
    if(event['event_type'] == "morning"):
        weather_json = get_weather_info()
        msg = set_weather_info(weather_json, TODAY)
        if("雨" in weather_json['forecasts'][0]['telop']):
            send_info("\n☔☔☔☔☔☔☔☔\n今日は雨が降ります。\n傘を忘れずに！\n☔☔☔☔☔☔☔☔" + msg)
            put_s3()
    elif(event['event_type'] == "evening" and was_it_raining()):
        send_info("\n☂️☂️☂️☂️☂️☂️☂️☂️\n傘を持ち帰りましょう！\n☂️☂️☂️☂️☂️☂️☂️☂️")
    
    return {
        'statusCode': 200,
        'body': json.dumps('function finished')
    }
```

* CITY_CODEは東京になってますが、お好きな都市コードを指定してください。ここから調べることができます：http://weather.livedoor.com/forecast/rss/primary_area.xml
* LINE NotifyのトークンとS3バケット名を環境変数から取るようにしてます。以下の図のように設定してください。

![kankyo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329009/e6c127c7-464b-16f3-fe05-293f849eb76c.png)

# CloudWatch Eventの作成

朝(7:00)と帰宅時(17:00)にLambdaを起動するため、CloudWatch Eventで2つのトリガーを作成します。
Lambda関数の画面で、以下の赤枠の「トリガーの追加」をクリックします。

![triger.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329009/9d679f21-9fce-b68a-6089-b48f9131f5f7.png)

CloudWatch Eventを選択し、スケジュール式で以下のような2つのトリガーを作成します。

* EveryMorning : `cron(0 22 * * ? *)` → 毎日7:00(UTC22時)に起動
* EveryEvening : `cron(0 8 * * ? *)` → 毎日17:00(UTC8時)に起動

![events.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329009/f815e74b-794b-cb62-a999-f8be4e7248cf.png)

作成したイベントをクリックし、編集画面を表示します。
そして以下のようにLambdaをトリガーする際に渡す値を設定します。

* EveryMorning : `{"event_type": "morning"}`
* EveryEvening : `{"event_type": "evening"}`

![target.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329009/660bfe48-7ee2-5f3b-3db8-5349b475deac.png)

これにより、各トリガーがLambdaを起動する際に、lambda_handlerのevent変数に上記で設定した値が渡されます。
本記事のLambdaでは、この値で条件分岐することで、以下のように朝の処理と帰宅時の処理を分けています。便利！

```py
def lambda_handler(event, context):
    if(event['event_type'] == "morning"):
        # 朝の処理
    elif(event['event_type'] == "evening"):
        # 帰宅時の処理
```

以上で完成です！雨の日を待ちましょう！

# 結果

![IMG_1366.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329009/8ac2cb08-a85c-9824-ec7f-b11fd69200e6.png)

雨の日、朝と帰宅時にそれぞれLINEへ通知が来ました！
おかげで傘を忘れる＆外出先に置き忘れることが少なくなったと実感しています。

AWSの無料枠で作れるので、是非試してみてください。