2015年12月22日

AWS 「API Gateway」「Lambda」「SES」を使って、RaspberryPiでのセンサー検知をメール通知してみた【node.js】


◆今日のゴール

RaspberryPiに赤外線センサーを付けて、人が近づいた事を検知します。

検知をしたら、AWSの「API Gateway」「Lambda」「SES」を使って、メールで通知するようにします。

AWS.png

必要な道具
・赤外線モーションセンサー PIR Infrared Motion Sensor


AWSのアカウント
利用にあたり、AWSの利用料金がかかる場合があります。


スポンサードリンク
◆手順
  1. Amazon SES(Simple Email Service)のセットアップ
  2. AWS IAM(Identity and Access Management)でポリシー・ロールの作成
  3. AWS Lambdaの関数作成とAPI Gatewayの設定(APIキーの発行)
  4. RaspberryPiで、検知したらAPIをコールするプログラムを作成【node.js】
  5. 動かしてみる
1、Amazon SES(Simple Email Service)のセットアップ

ここでは、送信元と送信先となるeメールアドレスの認証(verify)作業を行います。
今回は、送信元と送信先を同一アドレスにしますので、1つのアドレスに対してのみ認証作業を行いますが、送信元・送信先のメールアドレスを分けたい場合や、複数の宛先に送りたい場合は、そのメールアドレスに対しても認証作業を行ってください。

【補足】SESはデフォルトで、Sandboxという環境下で動いています。SESをSandboxの外に出す申請をすることで、認証していない宛先にもメールを送信することができるようになります。

Amazon AWSのコンソール画面にログインして、SESを開きます。
今回、リージョンは、「オレゴン(us-west-2)」とします。

SESのメニューから「Email Addresses」をクリックします。
ses001.png

「Verify a New Email Address」ボタンをクリックします。
ses002.png

今回使用するメールアドレスを入力します。
ses003.png

Statusが「pending verification」(認証待ち)となっているアドレスが追加されます。
ses004.png

メールアドレス宛にAWSからメールが届きます。
「Amazon SES Address Verification Request in region US West (Oregon)‏」

ses005.png

メールの本文に記載されているURLをクリックすると、認証(verify)が完了し、更新するとステータスが「pending verification」から「verified」に変わります。
ses006.png
以上で、メールアドレスの認証は完了です。
他のメールアドレスも登録したい場合は同様の手順を繰り返してください。

2、AWS IAMでポリシー・ロールの作成

SESでメールを送信する権限をもつポリシー・ロールを定義します。
AWSコンソール画面でIAM(Identity and Access Management)を開き、メニューから「ポリシー」をクリックします。ポリシー一覧画面が開きます。「ポリシーの作成」ボタンをクリックします。
iam001.png
「独自のポリシーを作成」を「選択」します。
iam002.png
ポリシー名に「RaspiSesSendMail」
ポリシードキュメントを下記の通り、入力して「ポリシーの作成」をクリックします。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ses:SendEmail",
                "ses:SendRawEmail"
            ],
            "Resource": "*"
        }
    ]
}
iam003.png
続いて、このポリシーをアタッチしたロールを作ります。
メニューから「ロール」をクリックしロール一覧画面を開きます。
「新しいロールの作成」をクリックします。
iam005.png
ロール名に「raspiSES」と入力します。
iam006.png
ロールタイプの選択で「AWSサービスロール」>「AWS Lambda」を「選択」します。
iam007.png
ポリシーのアタッチで、先ほど作成したポリシー「RaspiSesSendMail」にチェックを入れて「次のステップ」をクリックします。
iam008.png
最後に確認画面が出ますので、「ロールの作成」をクリックします。
iam009.png
これで、「raspiSES」というロールが作られました。
iam010.png

3、AWS Lambdaの関数作成とAPI Gatewayの設定(APIキーの発行)

AWSコンソール画面でLambdaを開きます。
ブループリント(青写真)を選ぶ画面がでますが、ここでは「Skip」を押して、白紙の状態から始めます。
lam001.png

【Configure Function】Name*「raspiSendMail」、Runtime*「Node.js」とします。
lam002.png

Lambda Function Codeは下記の通り入力します。メールアドレスは手順1でverifyしたメールアドレスに書き換えてください。
console.log('Loading function');
var aws = require('aws-sdk');
var ses = new aws.SES({
    apiVersion: '2010-12-01',
    region: 'us-west-2' // SES の設定をオレゴンでおこなった場合。
});

var to = ['toAddress@hogehoge.com']; // SESでverify済みのメールアドレス。(送信元)
var from = 'fromAddress@hogehoge.com';  // SESでverify済みのメールアドレス。(送信先)

// メールの本文
var text = "\
こんにちは\n\
\n\
Raspberry piです。\n\
\n\
赤外線センサーが検知しました。\n\
このメールはSESで配信しています。\n\
\n\
\
";

exports.handler = function(event, context) {
    console.log("Incoming: ", event);

    var eParams = {
        Destination: {
            ToAddresses: to
        },
        Message: {
            Body: {
                Text: {
                    Data: text,
                    Charset: 'iso-2022-jp'
                }
            },
            Subject: {
                Data: 'RaspberryPiが人感赤外線センサーで検知しました。',
                Charset: 'iso-2022-jp'
            }
        },
        Source: from
    };

    console.log('===SENDING EMAIL===');
    var email = ses.sendEmail(eParams, function(err, data){
        if(err){
            console.log("===EMAIL ERR===");
            console.log(err);
            context.fail(new Error('mail error occured'));
            
        } else {
            console.log("===EMAIL SENT===");
            console.log(data);
            context.succeed('SUCCESS');
        }
    });
    console.log("EMAIL CODE END");
};
【Lambda function handler and role】でハンドラーとロールを下記の通り設定します。
Handler * 「index.handler」(デフォルトのまま)
Role * 「raspiSES」(手順2で作ったロールを設定します。【重要!】)

Advanced Settingsはお好みで変更してください。

「Next」をクリックします。
lam003.png

確認画面がでますので「Create function」をクリックします。
lam004.png
下記の画面に遷移しますので、「API endpoints」のタブをクリックします。
lam005.png
「Add API endpoint」をクリックします。
lam006.png
【API endpoint type】に「API Gateway」を選択します。
lam007.png

下記の通り入力し「Submit」をクリックします。(今回は、アクセスキーでAPIの認証を行います。)
【API endpoint type】API Gateway
【API name】Raspi
【Resource name】/mail
【Method】POST
【Deployment Stage】prod
【Security】Open with access key
lam008.png

「Submit」をクリックと下記の通り、「API」が作成されます。
【API endpoint URL】がAPIのendpointになります。このURLは次の手順で使用します。
lam009.png

上記画面で【Method】「POST」のリンクをクリックします。API Gatewayの管理画面に遷移します。
api001.png
メニューから「APIs」>「API Keys」をクリックします。 api002.png
新しくAPI Keyを生成します。Name「raspi」、Enabledにチェックを入れ「Save」をクリックします。
api003.png
【API Stage Association】
で下記の通り選択し「Add」をクリックします。
Select API「Raspi」
Select stage「prod」

「Add」をクリックするとStages Enabledに追加されます。
ここの画面で表示されている「API Key」は次の手順で使用します。
api004.png

AWSのセットアップはこれで終了です。
「API endpoint URL」、「API Key」は次の手順で使用します。

4、RaspberryPiで、検知したらAPIをコールするプログラムを作成【node.js】

ここからは、Raspberry Piで作業します。
APIをコールするので、node.jsを使って実装します。

下記記事を参考に、「node」と「「npm」」をインストールします。
Raspberry Piで【node.js】を使ってみる

つづいて、下記コマンドで、「node-rest-client」というREST APIのクライアントモジュールをインストールします。「node-rest-client」を使用することで、簡単にAPIを呼び出せます。
$ sudo npm install -g node-rest-client

続いて、下記の通り赤外線センサーを接続します。
VCCに「RaspberryPiの5V」
OUTに「RaspberryPiのGPIO26番」
GNDに「RaspberryPiのGND」


赤外線センサーで検知したら、APIを呼び出すプログラムを書きます。
$ sudo vi motion.js 
require.main.paths.push('/usr/local/lib/node_modules');

fs = require('fs');
path = require('path');

dir = '/sys/class/gpio/'
pin = 26;

fs.writeFileSync(path.join(dir, 'export'), pin);

gpio26 = path.join(dir, 'gpio' + pin);

fs.writeFileSync(path.join(gpio26, 'direction'), 'in');

var status = 0;
var end = 0;

console.log('press enter if you want to stop');
var reader = require('readline').createInterface({
    input: process.stdin,
    output: process.stdout
});
reader.on('line', function (line) {
    end = 1;
    reader.close();
});
reader.on('close', function () {
    end = 1;
});

var detect = function() {
    var value = fs.readFileSync(path.join(gpio26, 'value'), 'ascii');
    if(value == 1 && status == 0 ) {
        console.log('Detection');
        status = 1;
        apiCall();
    }else if (value == 0){
        status = 0;
    }

    var id = setTimeout(detect,1000);
    if (end == 1) {
        console.log('finalize');
        clearTimeout(id);
        fs.writeFileSync(path.join(dir, 'unexport'), pin);
    }
}

var invokeURL = '手順3で発行したAPI endpoint URL';
var jsonHeader = {
    'x-api-key' : '手順3で発行したAPI Key'
};

var args = {
    headers:jsonHeader,
    accepts: "application/json",
    contentType: 'application/json'
};

var apiCall = function() {
    console.log('call api');
    var Client = require("node-rest-client").Client;
    var client = new Client();
    client.post(invokeURL, args , function(data,response) {
    console.log(data);
    });
};

detect();
7行目のpinはGPIOの番号です。
18〜29行目は、標準入力から入力があった際にプログラムを終了させるようにしています。
31〜47行目で、赤外線センサーの検知があったら、apiCall()という関数を呼び出しています。
49〜67行目は、APIを呼び出す関数です。
49行目は「手順3で発行したAPI endpoint URL」に置き換えてください。
51行目は「手順3で発行したAPI Key」に置き換えてください。

5、動かしてみる

下記、コマンドでプログラムを実行します。
$ sudo node motion.js
下記の様に待機状態になります。センサーに手をかざしてみましょう。
$ sudo node motion.js
press enter if you want to stop
APIが呼び出されます。メールが届いていれば成功です!
$ sudo node motion.js
press enter if you want to stop
Detection
call api
SUCCESS
プログラムを終了させるには、エンターキーを押します。
$ sudo node motion.js
press enter if you want to stop
Detection
call api
SUCCESS
finalize

以上で終了です。
AWSを活用することで、IoTっぽくなりましたね。



posted by Raspberry Pi at 10:23 | Comment(0) | Raspberry Pi | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。