[PYTHON] Use AWS Lambda + LINE Notify to notify LINE not to forget your umbrella when you get home

Introduction

Everyone has once left an umbrella in a company or school, right? If it rains the next day, I'm in despair without an umbrella. .. ..

Therefore, we have created a system that notifies LINE so that you will not forget your umbrella when you return home **!

Finished product

IMG_1366.PNG

It is based on the system introduced in the following article that notifies you to have an umbrella in the morning if it rains.

Python + AWS Lambda + Line Notify automatically notifies Line of today's weather every morning.

Implemented in addition to the above, ** Notify you to bring an umbrella in the morning if it rains ** + ** Notify you to bring your umbrella home when you get home ** Support rainy days!

System overview

Morning: Notify me to have an umbrella if it rains

reminder_1.jpg

First, launch Lambda at 7am every morning in CloudWatch Event. Lambda gets the weather information and tells LINE to have an umbrella if it rains today. Up to this point, you can create it with above article.

The difference is that if it rains, it will create a file in S3. This is used for notification when returning home.

When returning home: Notify you to bring your umbrella home

reminder_2.jpg

This is the main part added in this article. First, launch Lambda every day when you get home with CloudWatch Event. Lambda will check S3, and if the file was created on today's date, it will determine that you have an umbrella in the morning and will notify LINE to bring it back.

It's very simple! Let's actually make it!

Get LINE Notify token

Get the LINE Notify token by referring to the following articles. https://qiita.com/iitenkida7/items/576a8226ba6584864d95

Preparing for S3

Create an appropriate directory in your S3 bucket. In this article, we created the weather directory.

スクリーンショット 2020-01-28 21.12.20.png

In the system of this article, the following files will be generated in the directory created above. In addition, since the deletion process is not implemented, it is convenient to set the life cycle rule and delete it automatically after a few days!

スクリーンショット 2020-01-28 21.12.10.png

Lambda creation

Create a new Lambda function. This time, the runtime is Python 3.8.

Edit the default generated lambda_function.py and paste the code below.

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("rain" in weather_json['forecasts'][0]['telop']):
            send_info("\n☔☔☔☔☔☔☔☔\n It will rain today.\n Don't forget your umbrella!\n☔☔☔☔☔☔☔☔" + msg)
            put_s3()
    elif(event['event_type'] == "evening" and was_it_raining()):
        send_info("\n☂️☂️☂️☂️☂️☂️☂️☂️\n Let's take an umbrella home!\n☂️☂️☂️☂️☂️☂️☂️☂️")
    
    return {
        'statusCode': 200,
        'body': json.dumps('function finished')
    }

kankyo.png

Create a CloudWatch Event

Create two triggers in your CloudWatch Event to launch your Lambda in the morning (7:00) and when you get home (17:00). On the Lambda function screen, click "Add Trigger" in the red frame below.

triger.png

Select CloudWatch Event and create two triggers with a scheduled expression like this:

events.png

Click the created event to display the edit screen. Then set the value to pass when triggering Lambda as follows.

target.png

This will pass the value set above to the event variable of lambda_handler when each trigger starts Lambda. In Lambda of this article, by conditional branching with this value, the morning processing and the processing at the time of returning home are separated as follows. Convenient!

def lambda_handler(event, context):
    if(event['event_type'] == "morning"):
        #Morning processing
    elif(event['event_type'] == "evening"):
        #Processing when returning home

That's it! Let's wait for a rainy day!

result

IMG_1366.PNG

Notifications came to LINE on rainy days, morning and when I got home! Thanks to that, I feel that I'm less likely to forget my umbrella and leave it on the go.

You can make it with the AWS free frame, so please give it a try.

Recommended Posts

Use AWS Lambda + LINE Notify to notify LINE not to forget your umbrella when you get home
Use AWS lambda to scrape the news and notify LINE of updates on a regular basis [python]
ImportError when trying to use gcloud package with AWS Lambda Python version
When you want to use it as it is when using it with lambda memo
Creating a LINE BOT to notify you of additional AtCoder contests using AWS
How to remember when you forget a word
Summary of studying Python to use AWS Lambda
Let's use AWS Lambda to create a mechanism to notify slack when the value monitored by CloudWatch is exceeded on Python
I tried to get an AMI using AWS Lambda
[Python] When you want to import and use your own package in the upper directory
What to do if you get an Undefined error when trying to use pip with pyenv