AWS IoTボタンでTwitter APIを呼び出してみる

プログラミング
Amazon IoTボタン

AWS IoTボタンを入手してみました。Amazonダッシュボタンが特定の製品を1-clickで注文できるのに対して、こちらのボタンは任意のアクションを設定できる優れものです。その分値段もちょっとお高めでamazonで2500円です。

ボタンアクションにはシングルクリック、ダブルクリック、長押しの3種類があり、プログラム側でクリック種別毎に異なる動作をさせることができます。

ネット上で使い道を調べてみると、トイレボタンというのが多くみつかりました。トイレにボタンを設置しておいて、用を足すたびにボタンを押すと、Googleスプレッドシートなどに日時と種別を記録するというような感じのものです。

せっかくなので、少し違った切り口でプログラムの試作をしてみようと思います。玄関のドアに設置しておいて、ボタンを押すと最寄りの路線の情報を収集して、自分のEmailアドレスにそれを送り、事前に電車の混雑情報を把握しておく、というものを作ります。情報源はtwitterとします。

Amazon IoTボタン

AWS IoTボタンの仕組み

このボタンはAWS IoT 1-clickサービスと連動しています。ボタンを押すと、1-clickサービス上に設置したAmazon Lambdaのハンドラによりアクションを定義することができます。

作成したLambdaプログラム

AWS IoT 1-clickサービスには、ボタンを押すとSNSにメッセージを投げる、ボタンを押すとEmailにメールを送信する、という2種類が最初から用意されています。今回は後者のEmailにメールを送信するプログラムをベースに、twitter APIを実行するコードを追加することにします。

作成したプログラムはこうです。

from __future__ import print_function

import boto3
import json
import logging
from requests_oauthlib import OAuth1Session

consumer_key = 'XXXXXXXX'
consumer_secret = 'XXXXXXXX'
access_token = 'XXXXXXXX'
access_token_secret = 'XXXXXXXX'

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

ses = boto3.client('ses')

def check_email(email):
    result = ses.get_identity_verification_attributes(Identities=[email])
    attr = result['VerificationAttributes']
    if (email not in attr or attr[email]['VerificationStatus'] != 'Success'):
        logging.info('Verification email sent. Please verify it.')
        ses.verify_email_identity(EmailAddress=email)
        return False
    return True

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

    twitter = OAuth1Session(consumer_key,
                            consumer_secret,
                            access_token,
                            access_token_secret)
    params = {
        "q": "西武池袋線",
        "lang": "ja",
        "results_type": "recent",
        "count": "10"
    }
    req = twitter.get("https://api.twitter.com/1.1/search/tweets.json?", params = params)
    timeline = json.loads(req.text)
    message = ""
    for tweet in timeline["statuses"]:
        message = message + 40 * "-" + "\n" + tweet["created_at"] + "\n" + tweet["text"] + "\n"

    attributes = event['placementInfo']['attributes']
    from_address = attributes['email']
    to_address = attributes['email']
    subject = attributes['subject']

    if not check_email(from_address):
        logging.error('From email is not verified')
        return

    if not check_email(to_address):
        logging.error('To email is not verified')
        return

    ses.send_email(Source=from_address,
                   Destination={'ToAddresses': [to_address]},
                   Message={'Subject': {'Data': subject}, 'Body': {'Text': {'Data': message}}})

    logger.info('Email has been sent')

twitter APIを使うためには、事前にtwitter開発アカウントとAPIを使うための鍵情報 が必要です。入手した鍵情報はプログラム中で以下のように定義しておきます(XXXXXXXXの部分は実際に入手した文字列)。

consumer_key = 'XXXXXXXX'
consumer_secret = 'XXXXXXXX'
access_token = 'XXXXXXXX'
access_token_secret = 'XXXXXXXX'

ボタンを押すとAmazon Lambdaからlambda_handler()が呼び出されるので、この中にtwitter APIを呼び出すコードを書きます。今回は最寄りの路線名を検索キーとして、最新の10件のツイートを検索することとします。

    twitter = OAuth1Session(consumer_key,
                            consumer_secret,
                            access_token,
                            access_token_secret)
    params = {
        "q": "西武池袋線",
        "lang": "ja",
        "results_type": "recent",
        "count": "10"
    }
    req = twitter.get("https://api.twitter.com/1.1/search/tweets.json?", params = params)
    timeline = json.loads(req.text)

あとは得られた結果からメッセージを組み立てれば良いです。メールの送信先アドレスやメールタイトルは、AWS IoT 1-Clickサービス側で定義したものを参照するようにします。

完成したらAmazon Lambdaにアップロードすれば良いのですが、ここで2点注意があります。私もこれでしばらくハマりました。

追加モジュールがあるローカルフォルダにコピーする

標準で用意されているPython版Lambaハンドラでは、boto3、json、loggingの3つのモジュールがimportされるようになっています。今回はtwitter APIを呼び出すために、requests_oauthlibモジュールを追加でimportしました。AWS側で用意されていないモジュールを使う場合は、これも含めてLambdaに登録しないといけないようです。そこで作成したtimeline.pyファイルと同じ階層で以下を実行して、依存関係のあるモジュールを含めすげてダウンロードして、zipファイルを作成します。

$ pip install requests_oauthlib -t .
$ zip -r * ../timeline.zip

zipファイルを送信した場合はハンドラ関数を正しく指定する

単にzipファイルをアップロードしただけだと、zip内のどのpyファイルでハンドラ関数を定義しているかわからないため、Lambdaサービス内でファイル名とハンドラ関数を指定します(下図の枠内)。指定の仕方は、「ファイル名のベース.ハンドラ関数名」です。ファイル名がtimeline.pyでハンドラ関数がlambda_handlerなら、「timeline.lambda_handler」となります。

 

結果

うまく動くようになったのでボタンを押してみます。ボタンを押すとLEDが白く点滅したのち5秒ほどで緑に点灯します。すると数秒後にEmailが届きました。

うまくいきました! ただこのままだとリツイートの情報も拾ってしまうので、目的からするとノイズとなる情報が多いです。まだ改良の余地があることが分かりました。

コメント

タイトルとURLをコピーしました