AWS IoT Button : I am going to home button


Private Talk

I coded AWS IoT button lambda function called "I am going home" last year but I haven't release sorce code.
I was busy on 2019 due to changing my job.
Early of the year I was working as a computer engineer at so called "SIer" :P.
But at middle of the year I started my career as a car software engineer. Car is core industry in my country Japan and software such as connected technology becomes more important comporent on car. I am still enjoying my engineering life as car embedded software developper.

Let's back to a AWS Solusion

It takes about 1 hour commuting between my apartment and office by train. When I got on the return train to my home, always I email my wife about the time I will get home. It is simple task but it is a bit of work.
So I coded this AWS lambda function.

The folloings are full part of this Python function.
ImGoingHome.py
import boto3
import requests
import json
import math
from datetime import datetime, timedelta, timezone
from bs4 import BeautifulSoup 
import logging

RE = 6378.137
LANGUAGE = 'ja'
AWS_REGION='us-west-2'
AWS_ACCESS_KEY_ID=<YOUR AWS ACCESS KEY ID>
AWS_SECRET_ACESS_KEY=<YOUR AWS SECRET_ACCESS_KEY>
GEOCODE_API_KEY=<YOUR GEOCODE API KEY>

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def check_email(ses, email):
    result = ses.get_identity_verification_attributes(Identities=[email])
    attr = result['VerificationAttributes']
    print(attr)
    if (email not in attr or attr[email]['VerificationStatus'] != 'Success'):
        ses.verify_email_identity(EmailAddress=email)
        return False
    return True

def get_coordinate(lat, lng):
    h = math.radians(lat)
    t = math.radians(lng)
    x = math.cos(h) * math.cos(t)
    y = math.cos(h) * math.sin(t)
    z = math.sin(h)
    return (x, y, z)

def calc_distance(base_coordinate, lat, lng):
    coordinate = get_coordinate(lat, lng)
    ip = base_coordinate[0]*coordinate[0] 
    ip += base_coordinate[1]*coordinate[1] 
    ip += base_coordinate[2]*coordinate[2]
    return RE * math.acos(ip)

def find_near_station(base_lat, base_lng):
    tuples = list()
    base_coordinate = get_coordinate(base_lat, base_lng)
    with open('./station_data.json') as f:
        json_dict = json.load(f)
        stations = json_dict['station']
        for r in stations:
            if 'lat' in r and 'lng' in r :
                d = calc_distance(base_coordinate, r['lat'], r['lng'])
                tp = (r['name'], str(d))
                tuples.append(tp)

        sorted_tuples = sorted(tuples, key=lambda t: t[1])
    return (sorted_tuples[0][0], sorted_tuples[0][1])

def get_transfer_navitime(station_from, station_to,year,month,day,hour,minute):

    t = station_from + ' ⇒ ' + station_to + ' : '

    url = 'https://www.navitime.co.jp/transfer/searchlist?'
    url += 'orvStationName=' + station_from + '&'
    url += 'dnvStationName=' + station_to + '&'
    url += 'thrStationName1=&'
    url += 'thrStationCode1=&'
    url += 'thrStationName2=&'
    url += 'thrStationCode2=&'
    url += 'thrStationName3=&'
    url += 'thrStationCode3=&'
    url += 'month=' + year + '%2F' + month +'&'
    url += 'day=' + day +'&' 
    url += 'hour=' + hour+ '&'
    url += 'minute=' + minute + '&'
    url += 'orvStationCode=&'
    url += 'dnvStationCode=&'
    url += 'basis=1&'
    url += 'from=view.transfer.top&'
    url += 'sort=0&'
    url += 'wspeed=100&'
    url += 'airplane=1&'
    url += 'sprexprs=1&'
    url += 'utrexprs=1&'
    url += 'othexprs=1&'
    url += 'mtrplbus=1&'
    url += 'intercitybus=1&'
    url += 'ferry=1&'
    url += 'ctl=020010&'
    url += 'atr=2&'
    url += 'init='
    r = requests.get(url)

    soup = BeautifulSoup(r.text,"html.parser")

    #element 'dt'
    dt = soup.find_all("dt")

    #all elements
    for tag in dt:
        try:
            #retrieve 'class'
            string_ = tag.get("class").pop(0)
            #in case that the class value is 'left'
            if string_ in "left":
                t += tag.string
                break
        except:
            #do nothing
            pass
    return t

def lambda_handler(event, context):
    logging.info('start')
    logging.info('Received event: ' + json.dumps(event))

    # subject & body
    subject = '帰宅のお知らせ'
    body = '----お知らせ----\n'

    # retrieve parameters
    attributes = event['placementInfo']['attributes']
    from_address = attributes['emailFrom']
    to_address = attributes['emailTo']
    destination = attributes['destination']
    s3_bucket_name = attributes['s3bucket']
    s3_object_key = attributes['s3key']
    #clickType = event['deviceEvent']['buttonClicked']['clickType']

    JST = timezone(timedelta(hours=+9), 'JST')
    currentTime = datetime.now(JST).strftime("%Y%m%d%H%M")
    year = currentTime[0:4]
    month = currentTime[4:6]
    day = currentTime[6:8]
    hour = currentTime[8:10]
    minute = currentTime[10:12]

    # create boto object
    ses = boto3.client('ses',
        region_name=AWS_REGION
#        ,aws_access_key_id=AWS_ACCESS_KEY_ID
#        ,aws_secret_access_key=AWS_SECRET_ACESS_KEY
    )
    s3 = boto3.client('s3',
        region_name=AWS_REGION
#        ,aws_access_key_id=AWS_ACCESS_KEY_ID
#        ,aws_secret_access_key=AWS_SECRET_ACESS_KEY
    )

    # retrieve device information (JSON) from S3
    s3_obj = s3.get_object(Bucket=s3_bucket_name, Key=s3_object_key)
    devinfo = json.loads(s3_obj['Body'].read().decode('utf-8'))

    # retrieve street address
    lat = devinfo['latitude']
    lng = devinfo['longitude']
    apikey = GEOCODE_API_KEY
    api_base_url = 'https://maps.googleapis.com/maps/api/geocode/json?language={0}&latlng={1},{2}&key={3}&sensor=false'
    headers = {'content-type': 'application/json'}
    api_url = api_base_url.format(LANGUAGE, str(lat), str(lng), apikey)
    r = requests.get(api_url, headers=headers)
    data = r.json()
    if 'results' in data and len(data['results']) > 0 and 'formatted_address' in data['results'][0]:
        for ret in data['results']:
            body += (ret['formatted_address'] + ' らへんにいます\n')
            break
    
    #get nearest stastion
    station = find_near_station(float(lat), float(lng))
    body += ('最寄駅は' + station[0] + 'です(現在地から駅までの距離は' + str(station[1])[0:4] + 'kmくらいです)\n')
    
    #transfer info
    station_from= station[0]
    station_to = destination
    body += ('着予定は 『' + get_transfer_navitime(station_from,station_to,year,month,day,hour,minute) + '』\n')
    
    body += ('これから帰ります\n')

    #email check
    if not check_email(ses, from_address):
        return 'From email is not verified'

    if not check_email(ses, to_address):
        return 'To email is not verified'

    # send email
    ses.send_email(Source=from_address,
                   Destination={'ToAddresses': [to_address]},
                   Message={'Subject': {'Data': subject}, 
                            'Body': {'Text': {'Data': body}}})
    logging.info('end')
    return 'OK'
Profile
I have technical job experience in enbedded software development and server side infrastructure/application engineering. I'm interested in programming and computer security.
Objective
To write down my technical knowledge in the place where I can access from anywhere. To share my program source code. To train my writing skill.
Link
  • LinkedIn (preparing)

  • Twitter

  • Facebook (preparing)

  • GitHub

  • StackOverFlow (preparing)

Archives