LambdaでLine Notifyを使って予定通知をやってみた

Lambda(Python3.6.0を使用)からDynamoDBとS3から必要な情報を取得し、Line Notifyを利用して予定通知を行います。また、CloudWatchEventsを設定し12:00に通知されるよう設定します
2020.08.24

こんにちはデータアナリティクス事業本部の下地です。

予定をlineに通知できないかなと調べると、Line Notifyを使うと出来そうですので実装してみたいと思います。

全体像

実装する全体像としては図のようになります。

流れとしては、以下のようになります。

  1. CloudWatchEventsで定時刻にLambdaを起動
  2. DynamoDBから予定取得、S3から画像取得
  3. lineに通知

前準備

作成前に以下の内容について準備します(DynamoDBには予定がすでに入っておりS3にも画像がある状態を想定し進めます)。

  1. Line Notifyトークン取得
  2. DynamoDBの予定確認
  3. ポリシー追加
  4. requestsをレイヤーに追加
  5. Lambda環境変数を設定

1. LINE Notifyトークン取得

こちらのサイト(LINE Notifyをnode.jsで利用する)を参考にLINE Notifyの登録を行いトークンを取得します。

  • マイページよりトークンを発行をクリックします。トークン名を記入し、1:1でLINE Notifyから通知を受け取るを選択します。
  • トークンが発行されるので控えます。

2. DynamoDBの予定確認

DynamoDBには以下のデータが入っています。

3. ポリシー追加

LambdaからDynamoDBとS3へ接続するためAmazonS3FULLAccessAmazonDynamoDBFullAccessの管理ポリシーを追加します。

4. requestsをレイヤーに追加

Lambdaでrequestsを使用するため、以下のリンクを参考にLambdaレイヤーに追加するための作業を行います。

pandasをLambdaのLayerとして追加する

Amazon Linux と Ubuntu に pyenv を入れて Python 3.6.0 の環境を作る方法

  1. EC2にPython3.6.0の環境構築を行う
  2. EC2でrequestsをzip化する
  3. Python3.6.0環境構築後に以下の手順でrequestsをzip化します。

    	$ mkdir requests
    	$ pip install -t ./requests requests
    	$ zip -r req.zip requests
  4. zipファイルをS3にupload
  5. EC2からexitし、下記scpコマンドを使用しrequests.zipをダウンロードします。

    	$ scp -i ~/.ssh/***.pem ec2-user@**.***.*.*:/home/ec2-user/requests/requests.zip ./requests.zip
  6. Lambdaレイヤーに追加
  7. ローカルにダウンロードしたrequests.zipをS3にアップロードします。そしてLambdaのレイヤーから選択し追加します。

5. Lambda環境変数を設定

Line Notifyのトークンなど必要な情報を、Lamdbaの環境変数に設定します。

実装

Line Notifyを使ってみる

まずは実行するとlineに通知するだけの機能を実装します。コードは以下のようになります。

lambdaに以下のコードを記入します。

lambda_function.py

import os
import requests

# Line Notify
ACCESS_TOKEN = os.environ["access_token"]
HEADERS = {"Authorization": "Bearer %s" % ACCESS_TOKEN}
URL = "https://notify-api.line.me/api/notify"

def lambda_handler(event, context):
    data = {'message': "send_test"}
    #lineに通知
    requests.post(URL, headers=HEADERS, data=data)

では送信します。

lineに送信されたことが確認できました。

予定と画像を送信するコードを追加

次にDynamoDBから試験日の取得を行い、S3から画像を取得しlineに送信するために以下のようにコードを追加します。

lambda_function.py

import os
import requests
import boto3
from boto3.dynamodb.conditions import Key, Attr

KEY_PICTURE= os.environ["key_picture"]
DOWNLOAD_PATH = os.environ["download_path"]

# Line Notify
ACCESS_TOKEN = os.environ["access_token"]
HEADERS = {"Authorization": "Bearer %s" % ACCESS_TOKEN}
URL = "https://notify-api.line.me/api/notify"

DYNAMO_DB = boto3.resource('dynamodb')
DYNAMO_TABLE = DYNAMO_DB.Table(os.environ["table_name"])
S3_RESOURCE = boto3.resource("s3")
BUCKET = S3_RESOURCE.Bucket(os.environ["bucket_name"])


def lambda_handler(event, context):
    #scanを使用して全件取得する。Dynamoからデータを取得し通知メッセージを作成
    itemdata = DYNAMO_TABLE.scan(ConsistentRead=True)
    message = '日付:試験'
    for item in itemdata["Items"]:
        message += '\n' + item['date'] + '(' + item['day'] + "):" + item['exam']
    print(message)
    data = {'message': message}
    
    # s3の画像を一時フォルダにアップロードし、画像ファイルを取得する
    BUCKET.download_file(KEY_PICTURE, DOWNLOAD_PATH)
    files = {'imageFile': open(DOWNLOAD_PATH, 'rb')}

    #予定と画像をlineに通知する
    requests.post(URL, headers=HEADERS, data=data, files=files)

CWEventsを設定

上記のコードを毎日12:00に通知するために、以下図のようにcron式と、作成したLambda名を設定しCWEventsを登録します。

結果

12:00に予定通知されました!

まとめ

Line Notifyを使用した通知が出来ました!DynamoDBのデータ取得やLambdaでrequestsを使う方法など少し回り道をしましたが通知ができるようになったので今後も使っていきたいと思います。ただ、今回作成した内容が試験日の通知ですので毎日気を引き締めて勉強しようと思いました。。最後まで読んでくれてありがとうございます。

参考URL