はじめに
いつでもゴミ出していいマンションから引っ越して、「ゴミの日覚えられん!」となりLINEbotを作成しました。
【前編】では、LINE Messaging API・AWS Lambda・Amazon EventBridgeを使って、ゴミの日の前日21時にリマインドが送られてくる機能を実装します。
【後編】では、LINE Messaging API・AWS Lambda・API Gatewayを使って、ユーザーが「燃えるゴミ」と送ったら「【収集日】毎週火曜日と金曜日」と返するような機能を実装します。
使用技術
・Python3.9
・LINE Messaging API
・AWS Lambda
・Amazon EventBridge
簡単な機能の説明
1.EventBridgeが定期的にLambda関数を実行する
2.Lambda関数が実行され、現在日時がゴミの日の前日の場合はLINEbotからメッセージが届く
手順
LINE公式アカウントの作成とLINE Messaging APIの設定
こちらの記事を参考にしました。料金のことについても記載があります。
【LINE Messaging API】を使ってブロードキャストメッセージを送信する
今回は同居人にもメッセージを送りたかったので、上記記事と同じく、ブロードキャストメッセージ(作成したLINEアカウントと友だちになっているすべてのユーザーに送信するメッセージ)を送信します。
チャンネルアクセストークンは後程使いますので、発行の上控えておいてください。
Lambda関数作成
実行したいことは以下の3つです。
・現在日時を取得して、「第〇週の〇曜日」と変換する
・明日がゴミの日である場合、「明日は〇〇ゴミの日です」というメッセージを定義する
(例)毎週火曜日が燃えるゴミの日の場合、今日が月曜日であれば、「明日は燃えるゴミの日です」というメッセージを定義する
・定義された送信メッセージを送信する
1つずつ分けて説明します。
① 現在日時を取得して、「第〇週の〇曜日」と変換する
from datetime import datetime, timedelta, timezone
# 「第n週」か取得
def get_nth_week(day):
return (day - 1) // 7 + 1
# 「第n(週)X曜日」か取得
# datetime.weekdayは月曜が0、日曜が6で返す
def get_nth_dow(year,month,day):
nth_week = get_nth_week(day)
nth_day = datetime(year,month,day).weekday()
return {"nth_week" : nth_week, "nth_day" : nth_day}
# 現在日時を取得する
JST = timezone(timedelta(hours=+9), 'JST')
current_at = datetime.now(JST)
year = current_at.year
month = current_at.month
day = current_at.day + 1 # 前日にLINEを送るため、+1をする
nth_week = get_nth_dow(year,month,day)["nth_week"]
nth_day = get_nth_dow(year,month,day)["nth_day"]
これで変数nth_weekに「第〇週」、変数nth_dayに「〇曜日」が代入されている状態になりました。
コードの書き方はこちらの記事を参考にしました。
Pythonで任意の日付がその月の第何週目・何曜日かを取得
② LINEbotからメッセージを送信するための設定をする
from linebot import (LineBotApi, WebhookHandler)
from linebot.models import (MessageEvent, TextMessage, TextSendMessage)
from linebot.exceptions import (LineBotApiError, InvalidSignatureError)
# LINEbotの送信先設定をする
def notify_lastnight(body):
line_bot_api = LineBotApi(channel_access_token = "控えたチャンネルアクセストークン")
line_bot_api.broadcast(TextSendMessage(text = body))
今回はline-bot-sdk-pythonを使ってみました。
公式リファレンスはこちら
コードの書き方はこちらの記事を参考にしました。
Python、LINE BOTで一斉送信
③ 明日がゴミの日である場合、「明日は〇〇ゴミの日です」というメッセージを定義する
条件式がちょっと多いですし、居住地域モロバレになってしまうので、フェイクを入れて一部だけコードを載せます。
# ゴミ出しの曜日のパターンと送信メッセージの定義
# 毎週火曜日と金曜日は燃えるゴミ
if (nth_day == 1) or (nth_day == 4):
body = "明日は燃えるゴミの日です。準備をしましょう!"
notify_lastnight(body)
# 第2・第4水曜日は空き缶・空きびん
if ((nth_week == 2) and (nth_day == 2)) or ((nth_week == 4) and (nth_day == 2)):
body = "明日は空き缶・空きびんの日です。準備をしましょう!"
notify_lastnight(body)
①で取得した「第〇週」「〇曜日」という情報を条件式に組み込んで、現在日時に応じてメッセージを変えます。
条件式がtrueであった場合に②で作成した関数notify_lastnight()
を呼び出しています。これによって、明日がゴミの日でない場合は、LINEメッセージを送らないようになります。
①~③のコードを組み合わせると、下記のようになります。
from datetime import datetime, timedelta, timezone
from linebot import (LineBotApi, WebhookHandler)
from linebot.models import (MessageEvent, TextMessage, TextSendMessage)
from linebot.exceptions import (LineBotApiError, InvalidSignatureError)
# 「第n週」か取得
def get_nth_week(day):
return (day - 1) // 7 + 1
# 「第n(週)X曜日」か取得
# datetime.weekdayは月曜が0、日曜が6で返す
def get_nth_dow(year,month,day):
nth_week = get_nth_week(day)
nth_day = datetime(year,month,day).weekday()
return {"nth_week" : nth_week, "nth_day" : nth_day}
# LINEbotの送信先設定をする
def notify_lastnight(body):
line_bot_api = LineBotApi(channel_access_token = "控えたチャンネルアクセストークン")
line_bot_api.broadcast(TextSendMessage(text = body))
def lambda_handler(event, context):
# 現在の日時を取得する
JST = timezone(timedelta(hours=+9), 'JST')
current_at = datetime.now(JST)
year = current_at.year
month = current_at.month
day = current_at.day + 1 # 前日にLINEを送るため、+1をする
nth_week = get_nth_dow(year,month,day)["nth_week"]
nth_day = get_nth_dow(year,month,day)["nth_day"]
# ゴミ出しの曜日のパターンと送信メッセージの定義
# 毎週火曜日と金曜日は燃えるゴミ
if (nth_day == 1) or (nth_day == 4):
body = "明日は燃えるゴミの日です。準備をしましょう!"
notify_lastnight(body)
# 第2・第4水曜日は空き缶・空きびん
if ((nth_week == 2) and (nth_day == 2)) or ((nth_week == 4) and (nth_day == 2)):
body = "明日は空き缶・空きびんの日です。準備をしましょう!"
notify_lastnight(body)
return {
"statusCode" : 200,
"body" : "ok"
}
④ Lambda Layersの設定をする
③までのステップでコードはすべて書けましたが、このままではline-bot-sdkは使えません。
line-bot-sdkのようにPythonの標準ライブラリでないものを使うには、Lambda Layers
を利用します。
Lambda Layers用のパッケージを作る手順は以下のとおりです。
pythonフォルダを作成し、そのフォルダ下にline-bot-sdkをインストールする
フォルダ名を「python」
としなければ、Lambda関数がライブラリを参照できないので要注意です。
AWS公式ドキュメントに詳しい説明があります。
作成したpythonフォルダをzip化する
ツールで圧縮しても、コードで圧縮しても、どちらでも大丈夫です。
作成したzipファイルの容量が10MBを超える場合はS3にアップロードしてください。
zipファイルをLambda Layersに登録する
① AWS Lambdaの「レイヤー」から「レイヤーの作成」を選択する
② 「レイヤー設定」
「名前」を設定し、「.zipファイルをアップロード」を選択してアップロードを行い、「互換性のあるアーキテクチャ」は「x86_64」を選択し、「互換性のあるランタイム」はLambda関数のランタイムと同じものを選択して、「作成」を押すとLambda Layerができます。
③ AWS Lambdaの「関数」から「Layers」を押す
④ 「レイヤーの追加」を押す
⑤ 「レイヤーを選択」
「カスタムレイヤー」を選択し、「カスタムレイヤー」のプルダウンから先ほど作成したLambda Layerを選び、「追加」を押します。
これでline-bot-sdkが使えるようになります!
EventBridgeでLambda関数の定期実行を設定する
実行するLambda関数の設定はできたので、それを定期実行させる設定をします。Amazon EventBridgeを使うと簡単です。
① Amazon EventBridgeの画面を開き、「ルールを作成」を押す
② 「ルールの詳細を定義」
「名前」を設定し、「イベントパス」はデフォルトのまま、「ルールタイプ」は「スケジュール」を選択して、「次へ」を押します。
③ 「スケジュールを定義」
「特定の時刻に実行されるきめ細かいスケジュール」を選択し、Cron式を設定します。Cron式の書き方は公式ドキュメントを参考にしてください。
また、スケジュールはUSTで設定されるので、JSTに合わせるためには時差を考慮してください。
【AWS】Amazon EventBridgeのcron式の時差について
「以降10回のトリガー日」で「ローカルタイムゾーン」を選ぶと、日本時間でいつ実行されるかが出てきます。
④ 「ターゲットを選択」
「ターゲットタイプ」で「AWSのサービス」を選択し、「ターゲットを選択」で「Lambda関数」を選択し、「機能」で定期実行させたいLambda関数を選択し、「次へ」を押してください。
⑤ タグの必要があれば設定し、「レビューと作成」でルールの内容を確認した後「作成」を押す。
感想
LINEが生活に欠かせなくなっている人間なので、さくっと実装できる割に得られるメリットが大きく大満足です。
AWS LambdaとLINE Messaging APIの組み合わせは、小規模利用の場合だとコストもかからないですし、初心者の学習にちょうど良いなと感じました。
後編をなるべくはやく公開できるようにがんばります!