Lambda + CloudWatch + DynamoDB + LINE Notifyでリマインダーを作る

# はじめに
DynamoDBのキャッチアップのついでに、リマインダーを作りたかったので作ってみた。
今回は時間があまりなかったので、備忘録みたいな感じ。（まだ完成していない)

構成としては以下のような感じ。
![設計図-5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396492/ae1c3c66-8ec9-ec70-a11d-8a4d08c0cd5b.jpeg)

本当は、Androidアプリを作って、プッシュ通知までもって行きたかったが時間がないので後日。
通知の部分は、簡単にできるLineNotifyを使ってLineで通知をするようにした。


## DynamoDBを立てる
1. IAMにて、ユーザーにAmazonDynamoDBFullAccessの権限をつける
2. DynamoDBのトップページにてテーブル作成を押す
3. テーブル名とパーティーションキー名(今回はDate)を入力する。
5. できたDynamoDBの構成は以下の通り
  - テーブル…データのコレクション。
  - 項目 …各テーブルには０以上の項目がある。
  - 属性 …各項目は1つ以上の属性でできている。
6. 項目の作成ボタンから指定のテーブルの項目とデータが設定できる
    今回の構成
  - remainder_id: Number ID
  - color: String 表示カラー（6進数）
  -  contents: String 内容
  -  Date: String 日付（format: 2019-12-22）
  -  time: String 時間(format: 00:00)
  -  type: Number カテゴリー

DynamoDB開発者ガイド：https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Introduction.html

## Lambdaで関数を作成する
Lambdaには3つ関数を作る予定。
   - Regist Remainder: リマインダーを登録する
   - Put Remainder: 前日にリマインダーをCloudWatchに登録する
   - Push　Remainder: リマインダーを通知する

注意点１：　関数内でDynamoDBを接続する際は、roleの設定を忘れない
　参考→　LambdaからDynamoDB見るときの権限：https://qiita.com/hellscare/items/d80c9ff0290966eb0cf8
注意点２：　パーティションキーとソートキーの関係を理解しないとデータをうまく取れない。
　参考→　DynamoDBでPythonを使って試してみた：https://qiita.com/estaro/items/b329deafdfef790aa355


### RegistRemainder関数
※あとで作る

### PutRemainder関数

※これまだうまくできていません。。

```python
import json
import boto3
import datetime
from boto3.dynamodb.conditions import Key


cloudwatch = boto3.resource('cloudwatch')
dynamodb = boto3.resource('dynamodb')
remainder_table = dynamodb.Table('Remainder')


def lambda_handler(event, context):
    # get tomorrow schedule from DB
    response= remainder_table.query(
        KeyConditionExpression=Key('Date').eq(str(datetime.date.today()))
    )
    print('Get Tommorow Data: ', response)
    
    if len(response['Items']) > 0:
        for data in response['Items']:
            print('GET Items: ', data)
            # リマインド時間取得
            remaind_date = datetime.datetime.strptime(str(data['Date'])+ " " + str(data['time']), '%Y-%m-%d %H:%M')
            print('Set Date: ', remaind_date.datetime)
            print('Set Remaind Id', data['remaind_id'])
            # Put an event
            response = cloudwatch.put_events(
                Entries=[
                    {
                        'Time': remaind_date.datetime,
                        'Resources': [
                            ‘ARN（Your AmazonResourceName）',
                        ],
                        'Detail': {"remaind_id": data['remaind_id']}
                    }
                ]
            )
            print(response['Entries'])
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```

 このLambda関数は毎日0時に起動するようにCloudWatchで設定。
 起動すると、今日のRemainderの時間をDynamoDBから探し出して、CloudWatchEventに登録する。


### PushRemainder関数

```python
import json
import boto3
import datetime
from boto3.dynamodb.conditions import Key
import requests


dynamodb = boto3.resource('dynamodb')


def lambda_handler(event, context):
    print('START lambda_handler: getParam ->', event)
    print('TODAY IS: ', str(datetime.date.today()))
    remainder_table = dynamodb.Table('Remainder')
    table_response= remainder_table.query(
        KeyConditionExpression=Key('Date').eq(str(datetime.date.today())) & Key('remaind_id').eq(event['remaind_id'])
    )
    
    print('>>>>>>Get Data: ', table_response)
    
    if len(table_response['Items']) > 0:
        for remaind_data in table_response['Items']:
            header = {'Authorization':'Bearer <access token>'}
            param = {'message': remaind_data['contents']}
            response = requests.post('https://notify-api.line.me/api/notify', headers=header, data=param,)
            print('>>>>>SEND: ', remaind_data['contents'])
            print('>>>>>>POST Response: ', response)
    
    return {
        'statusCode': 200,
        'body': json.dumps('Remaind Finish!')
    }
```
CloudWatchEventに登録されて、指定の時間になると引数が渡されて実行される関数。
実行されたら、
今日の日付と、引数で渡されたremaider_idを元にDynamoDBから検索。
取得したリマインダーデータをLineNotifyを使ってLineに通知をする。

＜LineNotifyに接続する＞
　公式Document: https://notify-bot.line.me/doc/ja/
　※LineNotifyにリクエストを送る必要があるので、Lambdaにrequestsライブラリ等の外部モジュールを設定する
　　注意点：　zipをアップロードするとき、lambda_function.pyのデータが消える可能性があるので注意！！！！！！
　　→requestsモジュールのインストール：https://qiita.com/SHASE03/items/16fd31d3698f207b42c9
   
　※Notifyのアクセストークン取得はPCサイトからしかできないので注意
　　→トークンの発行方法：https://qiita.com/iitenkida7/items/576a8226ba6584864d95

##結論
こんな感じ。
画像とかも表示できると思うので、おいおい追加していきます。
![Screenshot_20191222-165552.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396492/05880646-a987-cf78-b840-e6ba2f8367c5.png)

##終わりに
随時、進捗があったら更新します！
年末までには完成させたらいいなと思います！:relaxed: