0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Serverless(2)Advent Calendar 2016

Day 21

AWS IoT の Thing Shadow と AWS Lambda の Schedule Event で Crystal Signal Pi に通知する

Last updated at Posted at 2016-12-21

Raspberry Pi で作る LED 警告灯ソリューション、Crystal Signal Pi のプリント基板キットが届いたので早速組み立て、AWS IoT の Thing Shadow と AWS Lambda の Schedule Event で通知するところまでやってみました。

crystalsignalpi.gif

Schedule Event で Lambda 関数が実行される毎に点灯の仕方を変えています。

Crystal Signal Pi とは

詳しくは Crystal Signal Pi 公式サイトを参照ください。

事前準備

本記事では主に AWS CLI を使ってリソースを作成していきます。

AWS CLI をアップデート
$ sudo pip install --upgrade awscli
バージョン確認
$ aws --version
aws-cli/1.11.32 Python/2.7.12 Darwin/15.6.0 botocore/1.4.89

AWS IoT 側の準備

Thing を作成
$ aws iot create-thing --thing-name crystalSignalPi
Shadow を登録
$ aws iot-data update-thing-shadow --thing-name crystalSignalPi  \
  --payload '{"state": {"desired" : {"blinkColor" : "green"}}}' \
  outfile.json

AWS Lambda 側の準備

今回の AWS Lambda 関数作成に必要なものから作成していきます。

assume ロールの決定
$ cat << EOF > lambdaExecution.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
IAM ロールの作成
$ aws iam create-role \
        --role-name lambdaExecution \
        --assume-role-policy-document file://lambdaExecution.json
ポリシーの適用
$ aws iam attach-role-policy \
        --role-name lambdaExecution \
        --policy-arn arn:aws:iam::aws:policy/AWSIoTDataAccess
Lambda 関数
$ cat << EOF > changeBlinkColor.js
console.log('Loading function');
var aws = require('aws-sdk');

var endpoint  = 'XXXXXXXXXXXXX.iot.ap-northeast-1.amazonaws.com';
var thingName = 'crystalSignalPi';

exports.handler = function(event, context) {
    var iotdata = new aws.IotData( { endpoint: endpoint } );
    var params = { thingName: thingName };
    iotdata.getThingShadow(params, function (err, data) {
        if (!err) {
            var payload = JSON.parse(data.payload);
            var currentBlinkColor = payload.state.desired.blinkColor;
            console.log("Current Color : " + currentBlinkColor);
 
            var desiredBlinkColor;
            if(currentBlinkColor == 'red') {
                desiredBlinkColor = 'green';
            } else {
                desiredBlinkColor = 'red';
            }
            var desiredState = {
                state: {
                    desired: {
                        blinkColor: desiredBlinkColor
                    },
                    reported: {
                        blinkColor: currentBlinkColor
                    }
                }
            };
             
            var params = {
                thingName: thingName,
                payload: JSON.stringify(desiredState)
            };
            iotdata.updateThingShadow(params, function (err, data) {
                if (!err) {
                    context.succeed();
                } else {
                    context.fail(err);      
                }
            });
        } else {
            context.fail(err);      
        }
    });
};
EOF
$ zip changeBlinkColor.zip changeBlinkColor.js
Lambda 関数の作成
$ aws lambda create-function \
        --function-name changeBlinkColor \
        --zip-file fileb:///path/to/changeBlinkColor.js.zip \
        --runtime nodejs4.3 \
        --role arn:aws:iam::XXXXXXXXXXXX:role/lambdaExecution \
        --handler changeBlinkColor.handler
Schedule 作成
$ aws lambda add-permission \
        --function-name changeBlinkColor \
        --statement-id "changeBlinkColor00" \
        --action 'lambda:InvokeFunction' \
        --principal events.amazonaws.com \
        --source-arn arn:aws:events:ap-northeast-1:XXXXXXXXXXXX:rule/changeColorBatch
Event のルールを設定
$ aws events put-rule \
        --name "changeColorBatch" \
        --schedule-expression "cron(*/5 * * * ? *)" \
        --state ENABLED
$ aws events put-targets \
        --rule "changeColorBatch" \
        --targets Arn=arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:changeBlinkColor,Id=XXXXX

Crystal Signal Pi を組み立てる

公式サイトのマニュアルを見ながら Crystal Signal Pi を組み立て、設定していきます。

Raspberry Pi と AWS IoT の連携

pip のインストール
$ sudo apt-get install python-pip
AWS IoT Device SDK for Pythonのインストール
$ sudo pip install AWSIoTPythonSDK
git のインストール
$ sudo apt-get install git
サンプルコードのダウンロード
$ git clone https://github.com/aws/aws-iot-device-sdk-python.git
$ cd aws-iot-device-sdk-python
$ sudo python setup.py install
IAM ユーザーの作成

デバイス用に IAM ユーザーを作成、Managed policy AWSIoTFullAccess をアタッチ

アクセスキーの設定

クレデンシャル情報を設定

サンプルコードをコピー
$ mkdir -p crystal-signal-pi
$ cd crystal-signal-pi
$ cp ../samples/basicShadow/basicShadowDeltaListener.py ./shadowDeltaListener.py
証明書の準備、配置

コピーしたサンプルコードと同じディレクトリに配置

コードを編集
shadowDeltaListener.py
# coding: utf-8
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient
import sys
import logging
import time
import json
import getopt
import pycurl

# Shadow JSON schema:
#
# Name: Bot
# {
#	"state": {
#		"desired":{
#			"property":<INT VALUE>
#		}
#	}
#}

# Custom Shadow callback
def customShadowCallback_Delta(payload, responseStatus, token):
	# payload is a JSON string ready to be parsed using json.loads(...)
	# in both Py2.x and Py3.x
	print(responseStatus)
	payloadDict = json.loads(payload)
	print("++++++++DELTA++++++++++")
	property = "blinkColor"
	blinkColor = str(payloadDict["state"][property])
	print("property: " + blinkColor)
	#print("version: " + str(payloadDict["version"]))
	print("+++++++++++++++++++++++\n\n")
	if blinkColor == "red":
		url = "http://localhost/ctrl/?color=100,0,0&mode=1&repeat=0&period=250&json=1"
	else:
		url = "http://localhost/ctrl/?color=0,80,0&mode=1&repeat=0&period=1000&json=1"

	curl = pycurl.Curl()
	curl.setopt(pycurl.URL, url)
	curl.setopt(pycurl.CUSTOMREQUEST, 'GET')
	curl.perform()

# Read in command-line parameters
useWebsocket = True
host = "XXXXXXXXXXXXX.iot.ap-northeast-1.amazonaws.com"
rootCAPath = "rootCA.pem"
certificatePath = "XXXXXXXXXX-certificate.pem.crt"
privateKeyPath = "XXXXXXXXXX-private.pem.key"
thingName = "crystalSignalPi"

# Configure logging
logger = logging.getLogger("AWSIoTPythonSDK.core")
logger.setLevel(logging.DEBUG)
streamHandler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
streamHandler.setFormatter(formatter)
logger.addHandler(streamHandler)

# Init AWSIoTMQTTShadowClient
myAWSIoTMQTTShadowClient = None
myAWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient("basicShadowDeltaListener", useWebsocket=True)
myAWSIoTMQTTShadowClient.configureEndpoint(host, 443)
myAWSIoTMQTTShadowClient.configureCredentials(rootCAPath)

# AWSIoTMQTTShadowClient configuration
myAWSIoTMQTTShadowClient.configureAutoReconnectBackoffTime(1, 32, 20)
myAWSIoTMQTTShadowClient.configureConnectDisconnectTimeout(10)  # 10 sec
myAWSIoTMQTTShadowClient.configureMQTTOperationTimeout(5)  # 5 sec

# Connect to AWS IoT
myAWSIoTMQTTShadowClient.connect()

# Create a deviceShadow with persistent subscription
Bot = myAWSIoTMQTTShadowClient.createShadowHandlerWithName(thingName, True)

# Listen on deltas
Bot.shadowRegisterDeltaCallback(customShadowCallback_Delta)

# Loop forever
while True:
	pass

python-pycurl のインストール

$ sudo apt-get install python-pycurl

コードを実行

$ python shadowDeltaListener.py

おわりに

今回はまず、AWS IoT との連携までやってみました。
次回は光での通知だけでなく、Polly を使って音声と連携した使い方も試してみたいと思います。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?