AWS IoT & kintone ハンズオン ~基本編~

イントロダクション

ハンズオンシナリオ

シナリオ: センサーデータの送信

Ginga BLEペリフェラルから、IoT GWを通して、AWS IoTのトピックに温度センサーのデータを送信し、AWS IoTでルールに基づきkintoneへの保存を行います。また、しきい値を下回った場合、E-mailでアラートを送信するようにルールを設定します。本ハンズオンにより、センサーからのデータ取得および時系列データの保存、しきい値に対するアクションの手順を確認することができます。

_images/senario1.png

利用するデバイス、アプリケーション、サービス

GINGA BLE ペリフェラル

ネビラボ社が提供するBLEセンサーです。本ハンズオンではセンサーからのデータ取得、AWS IoTへのデータ送信に利用します。

http://nebulab.co.jp/products/sensornet.html

ペリフェラルには、温度センサー、湿度センサー、加速度センサーが実装されてます。 今回のハンズオンでは、温度センサーと湿度センサーを定期的(10秒間隔)にアップロードされます。 クラウドに上がってくるフォーマットは、以下のとおりです。

key value
device デバイス名
sensor センサータイプ(temp = 温度、humid = 湿度)
timestamp デバイス側タイムスタンプ
value センサーの値

kintone開発者ライセンス

ライセンスをお持ちでない方は、30日間無料お試しもしくは開発者ライセンスをお申込みください。 開発者ライセンスは発行に2、3日要しますので、余裕を持ってお申込みください。


AWSアカウント

AWSコマンドラインでiotおよびiot-dataを実行できるようにご利用のPCの設定をお願いします。 インストールの手順はこちらのとおりです。


AWS IoT

接続されたデバイスが安全かつ簡単にクラウドアプリケーションやその他のデバイスとやりとりするためのマネージド型プラットフォームです。本ハンズオンではデバイスからのデータ受信、デバイスのリモート制御などで利用します。
https://aws.amazon.com/jp/iot/

Amazon SNS

Amazon SNSは、モバイルおよびエンタープライズメッセージングの pub-sub サービスで、Mobile Pushやメール、HTTPコールなど複数プロトコルによるメッセージの配信ができます。

ハンズオン準備

ハンズオンを始めるにあたり、事前の準備設定を行います。

ハンズオン用CloudFormationのスタック作成

ハンズオンで利用するIAMユーザを作成を自動化するために、CloudFormationのスタックを作成します。IAMユーザはデバイスの証明書を作成するための権限を与えるために作成します。 今回のハンズオンでは、セントラルゲートウェイ側でAWS IoTへの処理を行うため、スタッフ側で証明書生成の実行を行います。スタッフが代わりに実行するためスタッフに作成したIAMユーザのAPI Keyを 渡してください。本ユーザは、必ず、ハンズオン終了後に削除してください。 作成されるユーザは、署名要求ができる権限のみ付与しております。


マネージメントコンソールのサービス一覧から”Cloud Formation”をクリックします。

_images/2-cf-1.png

“Choose a template”から”Specify an Amazon S3 template URL”にチェックを入れ、以下のパスを入力し、[Next]をクリックします。

http://toshiake-iot-handson.s3.amazonaws.com/AWSIoT/cf/awsiothandson.template


_images/2-cf-2.png

“Stack Name”に”AWSIoTHandsonStack”と入力し、[Next]をクリックします。

_images/2-cf-3.png

“Options”で何も入力せずに[Next]をクリックします。

_images/2-cf-4.png

“Resource”の画面を下にスクロールし、”Capabilities”で”I acknowledge that this template...”にチェックを入れ、[Create]をクリックします。

_images/2-cf-5.png

Cloud Formationのスタックの一覧に作成したスタックが表示されるのを確認します。Statusは”CREATE_IN_PROGRESS”から”CREATE_COMPLETE”になるのを確認します。

_images/2-cf-6.png

_images/2-cf-7.png

画面下の”Output”タブをクリックし、AccessKeyとSecretKeyが表示されていることを確認し、こちらの内容をスタッフの支持に従って渡してください。

_images/2-cf-8.png

【スタッフ用】サンプルコードの準備

証明書を取得するためのスクリプトの設定を行います。各デバイスごとのフォルダ{device-id}以下のcertsディレクトリに移動し、config.jsonの先ほどコピーしたCloudFormationのOutputのAccessKey/SecretKeyを入力します。

root:~# cd {device-id}/certs
root:~/{device-id}/certs# vi config.json

{
  "accessKeyId": "<your access key>",        ←<your access key>にAccessKeyを入力
  "secretAccessKey": "<your secret key>",    ←<your secret key>にSecretKeyを入力
  "region": "ap-northeast-1"
}

証明書作成のスクリプトを実行します。certsディレクトリにプライベートキー(privatekey.pem)とCSR(cert.csr)がある前提です。なければ、作成してください。CSRの内容を元に証明書を作成しています。出力されるcertificateIdの英数字文字列をデバイス保有者に渡してください。次章のAWS IoTの設定の中で証明書を特定するために利用します。

 root@edison:~/{device-id}/certs# node create_cert.js
 ~
 { certificateArn: 'arn:aws:iot:ap-northeast-1:xxxxxxxxxxxxxx:cert/<英数字文字列>',
certificateId: '<英数字文字列>',
~

証明書ファイル(cert.pem)がcertsディレクトリ内に存在することを確認します。

root@edison:~/{device-id}/certs# ls
cert.csr        config.json     node_modules    rootca.crt
cert.pem        create_cert.js  privatekey.pem

AWS IoT基本設定

デバイスの作成

AWSマネージメントコンソールへログインし、画面右上のメニューから東京リージョンを選択します。 サービス一覧から”AWS IoT”をクリックします。

_images/3-servicemenu.png

“Get Startedが表示される場合はそちらをクリックします。

_images/3-getstart.png

デバイス(Thing)を作成します。メニューの”Create a thing”をクリックします。Nameに指定されたデバイスIDを入力し、[Create]をクリックします。 (注意)画面でデバイスIDがedisonになっております。

_images/3-create-thing.png

リソースの一覧で作成したデバイスが表示されます。

_images/3-thing.png

ポリシーの作成

デバイスに対して、AWS IoTの各種操作を許可するためのポリシーを作成します。メニューの”Create a policy”をクリックします。フォームにそれぞれ以下のパラメータを入力し、[Create]をクリックします。

項目
Name awsiot-handson-policy
Action iot:*
Resource
  • (アスタリスク)

_images/3-create-policy.png

作成したポリシーがリソースの一覧に表示されます。

_images/3-policy.png

先ほど作成した証明書をポリシーに割当てます。リスト中の証明書をクリックし、[Actions]-[Attach a policy]をクリックしてください。(3章で証明書を作成したときのcertificateIdの証明書をリソースから選択してください。)

_images/3-attach-policy.png

“Confirm”の画面で、フォームにポリシー名”awsiot-handson-policy”を入力し、[Attach]をクリックします。

_images/3-attach-policy-2.png

次に、デバイスと証明書の関連付けを行います。作成した証明書をリソース一覧の中から選択し、[Actions]-[Attach a thingクリックします。

_images/3-attach-thing.png

“Thing Name”にデバイス名: 指定されたデバイスIDを入力し、[Attach]をクリックします。

_images/3-attach-thing-2.png

Amazon SNSの設定

IAMの設定

AWS IoTからSNSを呼び出すためのロールを設定します。 サービス一覧から”IAM”をクリックします。

_images/4-iam-console.png

左ペインの”ロール”をクリックします。 右ペインの”新しいロールの作成”をクリックします。

_images/4-iam-create-role.png

ロール名に”iot_hands_on”を入力し、”次のステップ”をクリックします。

_images/4-iam-role-name.png

ロールタイプの選択画面で、ロール一覧をスクロールし、AWS IoTの”選択”ボタンをクリックします。

_images/4-iam-select-type.png

ポリシーのアタッチ画面では、特に選択せず、”次のステップ”をクリックしします。 確認画面で確認し、”ロールの作成”をクリックします。

_images/4-iam-skip-policy.png

_images/4-iam-confirm.png

ロールの一覧画面から、先ほど作成したロールを選択します。ロール数が多い方は、検索窓に”iot_“などをいれると絞込ができます。


_images/4-iam-select-created-role.png

ロールの詳細画面から”ポリシーのアタッチ”をクリックします。


_images/4-iam-policy-attach.png

SNSに対するアクセス許可を与えるためにポリシーをアタッチします。ハンズオンでは、SNSのFullAccess権限を付与します。 プロダクションで利用する場合は、細かい権限設定をすることを推奨します。


_images/4-iam-policy-attach-sns.png

次のハンズオンで、Lambdaの実行を行いますので、ここでLambdaに対する実行権限も付与します。


_images/4-iam-policy-attach-lambda.png

アタッチされていることを確認します。


_images/4-iam-done.png

Amazon SNSの設定

Amazon SNSでは、指定したメールにメッセージを転送することができます。 受け付けることができるメールアドレスを準備してください。 携帯電話のメールアドレスで、迷惑メールフィルタをかけている方は注意が必要です。

サービス一覧から”SNS”をクリックします。

_images/4-sns-console.png

SNS Home画面の中から”Create Topic”を選択します。

_images/4-sns-create-topic.png

Topic名を入力する画面がポップアップされるので、両方の入力欄に”IoTHandson”を入力してください。 入力後、”Create topic”ボタンをクリックしてください。

_images/4-sns-create-topic.png

_images/4-sns-create-topic-2.png

Topic Detailの画面に遷移します。サブスクリプション(今回はご自身のメールアドレス)を設定するので、”Create Subscription”をクリックします。


_images/4-sns-create-subscriptions.png

サブスクリプションを設定する画面がポップアップされるので、ProtocolをEmailにして、Endpointにご自身のメールアドレスを入力してください。 入力後、”Create Subscription”ボタンをクリックします。

_images/4-sns-create-subscriptions-2.png

Topic Detailの画面に遷移され、登録したサブスクリプションが”PendingConfirmation”でサブスクリプション一覧にあることを確認します。

_images/4-sns-pending.png

登録したメールアドレスに、確認用のメールがSNSから発信されてますので、メーラーなどで確認してください。 メール本文に、Confirm subscriptionのリンクがありますので、クリックします。

_images/4-sns-confirm-mail.png

クリックするとブラウザが起動し、Confirmationが完了した画面が表示されます。

_images/4-sns-confirm-site.png

これで登録が完了されました。SNSのTopic Detailの画面に戻り、画面内のリロードボタンをクリックするとサブスクリプション一覧の情報のみ更新されます。 Subscriotion IDが設定されていることを確認してください。

_images/4-sns-confirm-done.png

AWS IoTのルール作成

IAMとSNSの設定し、それらの情報をルールとして設定します。 AWS IoTのコンソール画面に遷移し、”create a resource”をクリックします。 作成するリソース一覧から”Create a rule”を選択します。

_images/4-iot-select-rule.png

ルール作成画面が表示されますので、各項目に必要事項を入力または選択します。

項目
Name iot_handson_sns
Description IoT Handson SNS
Attribute
  • (アスタリスク)
Topic Filter {ご自身のデバイスID}/ginga
Condition sensor = “temp” AND value > 25

Choose an actionでSNSを選択します。

SNS Targetを選択する項目が表示されるので、先ほど作成した、SNS Topic”IoTHandson”を選択します。 選択後、Roleを指定する項目が表示されますので、これも先ほど作成した、ロール”iot_hands_on”を選択します。

この状態で、”Add Action”をクリックします。

_images/4-iot-create-rule.png

SNSのアイコンが表示されたあと、”Create”ボタンをクリックします。

_images/4-iot-rule-done.png

これで、ルール設定は終了です。 Gingaセンサーを手で覆うなどして温度を上げることで、ルールが起動し、メールが発砲されます。 10秒に1回センサーからデータを読み取り、AWS IoTにデータを送信するので、10秒程度おまちください。

ルールのConditionをご自身で操作してみてください。あまりに低い値ですとメールが都度送信されるので注意が必要です。

AWS IoTのルール停止

都度メールが来るとメールボックスが溢れる可能性があるため、ある程度動作確認ができたら、停止いたします。 AWS IoTの画面から作成したルールのチェックボックスをクリックし、ActionsのリストからDisableを選択することで、ルールの起動が停止します。

_images/4-iot-rule-disable.png

kintoneの設定

ユースケース

センサーの故障管理ををkintoneを使って実現することを想定しております。 センサーデータの値に応じてAWS IoTのルールが発動し、異常データをLambda経由で、kintoneにいれます。

前提条件

Lambdaからkintoneにデータを挿入するために以下の情報が必要になります。

項目
サブドメイン https://{subdomain}.cybozu.com/
X-Cybozu-Authorization {BASE64-encoded “id:password”}
Authorization Basic {BASE64-encoded “id:password”}

上記の情報は、次のハンズオンで使います。この段階で確認しましょう。 Base64エンコーディングは、ネット上にある、Base64エンコーディングするサイトなどを利用して取得しましょう。 #セキュリティ上は好ましくないですが。

kintoneの障害管理アプリ

ご自身のkintoneにログインし、ポータル画面に行きます。 すべてのアプリの”作成”をクリックします。

_images/5-kintone-portal.png

kitoneアプリストアの画面がポップアップされるので、”アプリストアから選ぶ”ボタンをクリックします。

_images/5-kintone-select-app-method.png

kitoneアプリストアから情報システム -> 障害対応管理アプリを探し、”このアプリを追加”をクリックします。

_images/5-kintone-select-app.png

これで、障害対応管理アプリが追加されました。Lambdaからデータを挿入する際に、アプリIDが必要になるため、アプリ管理から追加したアプリのIDを 取得し、メモ帳などでメモを取っておいてください。

_images/5-kintone-app-mng.png

アプリを起動してデータが入って入ってないことを確認しましょう。

_images/5-kintone-app.png

AWS Lambdaの設定

コードの修正

以下のサイトからコードをダウンロードします。

https://github.com/ToshiEna/kintone-aws-iot-handson-2015/raw/master/download/sample.zip

zipをunzipなどで解凍します。 index.jsのノートパッドなどのツールで開きます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  var moment = require('moment');
  var APP_ID = '<<アプリID>>';
  var SUBDOMAIN = '<<サブドメイン>>';

  exports.handler = function(event, context) {
    var dueDate = moment().add(1, 'd').format('YYYY-MM-DD');
    var acceptNum = moment();
    console.log(dueDate);


      record = {
          '受付番号': { value: acceptNum },
          'タイトル': { value: event.title },
          'インシデント': { value: 'アラート' },
          '作業期限': { type: 'DATE', value: dueDate },
          '内容': { value: event.value }
      };

      request({
          method: 'POST',
          url: "https://" + SUBDOMAIN + "/k/v1/record.json",
          headers: {
              'X-Cybozu-Authorization': '<<Auth情報>>',
              'Authorization': 'Basic <<Auth情報>>',
              'Content-Type': 'application/json'
          },
          json: {
              'app': APP_ID,
              'record': record
          }
      }, function(err, response, body) {
          if (err) {
              consle.log("err : " + util.inspect(err));
          }
          if (response.statusCode === 200) {
              console.log('RESULT: ');
              context.succeed();
          } else {
              console.log("response error: " + response.statusCode + ", " + err);
              console.log("response error: " + body.message);
          }
      });
  };

アプリIDアプリ、サブドメイン(cybozu.comまで含む)、Auth情報(同一のデータ)を編集して、保存します。

編集後、AWS Lambdaにコードをアップロードするためにサイドzipで圧縮します。

$ zip -r index.zip index.js node_module

AWS Lambdaの設定

AWS Lambdaのコンソールをサービス一覧から選択し、起動します。 改めて東京リージョンであることを確認してください。 “Create a Lambda Function”を選択します。

_images/6-lambda-create-lambda.png

Select blueprintは、スキップします。

_images/6-lambda-skip-blueprint.png

Configure Function画面で名前の入力などを行います。Uploadボタンをクリックし、上記で作成したZipファイルを選択します。 RoleのリストからBasic execution roleを選択します。

_images/6-lambda-conf-func-role.png

ロールを作成する画面に遷移するので、内容を確認して、”許可”ボタンをクリックします。

_images/6-lambda-create-role.png

画面が元のConfiguration Functionに戻り、Timeoutを59秒にして、”Next”ボタンをクリックします。

_images/6-lambda-conf-func-param.png

確認画面で確認して、”Create Function”をクリックします。

_images/6-lambda-confirm.png

_images/6-lambda-done.png

AWS IoTのルール設定

Lambdaの登録が終わったので、先ほどのSNSと同様の手段で、Lambdaを設定します。 手順は、SNSとほぼ同等で、Lambdaを選択する部分のみことなります。

_images/6-iot-lambda-rule.png

これで準備は整いました。 SNSの時と同様10秒単位でセンサーデータがAWS IoTにPublishされてます。 設定がうまく行っていれば、kintoneの障害対応アプリ内にデータが蓄積されます。

その他の設定(オプション)

CloudWatch Logsの設定

AWS IoTのログはCloudWatch Logsで取得可能です。 詳細な手順はこちらに掲載されています。

http://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/cloud-watch-logs.html

まず、メニュー画面から”Identity & Access Management”をクリックし、IAMの設定画面を表示します。画面左のメニューから”Roles”をクリックし、[Create New Role]をクリックします。

_images/7-logs-1.png

“Role Name”にロール名を入力し、[Next Step]をクリックします。

_images/7-logs-2.png

“Select Role Type”で”AWS IoT”の[Select]をクリックします。

_images/7-logs-3.png

“Attach Policy”で”AWSIoTLogging”のビルトインポリシーにチェックを入れ、[Next Step]をクリックします。

_images/7-logs-4.png

内容を確認します。次の手順のコマンドラインでARNが必要になるため、”Role ARN”の文字列をコピーしておきます。問題なければ[Create Role]をクリックしてください。

_images/7-logs-5.png

以下のaws cliコマンドを実行し、aws iotに作成したロールを割当てます。

aws iot set-logging-options --logging-options-payload roleArn=”arn:aws:iam::<your-aws-account-num>:role/IoTLoggingRole”,logLevel=”INFO”

証明書の作成

本ハンズオンではあらかじめプライベートキーとCSR(Certificate Signing Request)を作成し、そちらを元に証明書を取得しています。プライベート鍵とCSRを作成する手順は以下のとおりです。

以下のopensslコマンドでプライベートキーを作成します。

$ openssl genrsa -out privatekey.pem 2048
Generating RSA private key, 2048 bit long modulus
................................................................................+++
..........+++e is 65537 (0x10001)

次に、作成したプライベートキーを元にCSRを作成します。

$ openssl req -new -key privatekey.pem -out cert.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Meguro
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Amazon Web Services Japan K.K.
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

ハンズオン終了後

ハンズオン終了後には以下の設定を削除してください。

AWS IoTのリソース削除

AWS IoTの証明書、ポリシー、デバイスを削除するためには、削除前にアタッチされているリソースをデタッチする必要があります。(ルールは他のリソースとの関連性はありません)

  • マネージメントコンソールのサービス一覧から[AWS IoT]をクリックします。
  • リソース一覧から削除したい証明書を選択します。
  • 右の詳細画面より、関連付けられているデバイスおよびポリシーを選択し、[Detach]をクリックします。
_images/8-detach-1.png

  • リソース一覧から削除したいリソースを選択し、”Actions”のメニューから[Revoke]をクリックします。

CloudFormationスタックの削除

  • マネージメントコンソールのサービス一覧から[CloudFormation]をクリックします。
  • リストから”AWSIoTHandsonStack”のスタックを選択し、”Actions”から[Delete Stack]をクリックします。
_images/8-delete-cf-stack-1.png

その他のリソースの削除

  • Amazon SNSのトピック
  • AWS LambdaのFunction

それぞれのコンソールに移り、対象リソースを選択し、削除してください。

AWS IoT Device SDK解説

本ハンズオンで利用したゲートウェイ側のサンプルコードになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
var noble = require('noble');
var awsIot = require('aws-iot-device-sdk');
var moment = require('moment');

var deviceName = 'devXX';
var topic = deviceName + '/ginga';
var myAddress = "****";

var device = awsIot.device({
   keyPath: './certs/private.pem',
  certPath: './certs/cert.pem',
    caPath: './certs/root.pem',
  clientId: deviceName,
    region: 'ap-northeast-1'
});

function publish_data(sensorType, value) {
     var record = {
        "device": deviceName,
        "sensor": sensorType,
        "timestamp": moment().toISOString(),
        "value": value
      };
      console.log("Publish: " + message);
      device.publish(topic, message);
}

function temp(data){
  var v1 = parseInt(data[0]);
  var v2 = parseInt(data[1]) / 100;
  publish_data('temp',v1 + v2);
}

function humid(data){
  var v1 = parseInt(data[2]);
  var v2 = parseInt(data[3]) / 100;
  publish_data('humid',v1 + v2);
}

noble.on('stateChange', function(state) {
  if (state === 'poweredOn') {
    noble.startScanning();
  } else {
    noble.stopScanning();
  }
});

noble.on('discover', function(peripheral) {
  noble.stopScanning();
  //console.log('Local Name: ' + peripheral.advertisement.localName);
  if(myAddress == peripheral.address){
      var serviceUUID = peripheral.advertisement.serviceUuids[0];
      console.log('Service UUID: ' + serviceUUID);
      peripheral.connect(function(error){
        if (error) console.log('connect error: ' + error);
        console.log('connected to ' + peripheral.uuid);
        peripheral.discoverServices([serviceUUID],
          function (error, services){
            if (error) console.log('discoverServices error: ' + error);
            console.log('services.length: ' + services.length);
            var service = services[0];
            service.discoverCharacteristics(null,function(error, characteristicss
){
              if (error) console.log('discoverCharacteristics error: ' + error);
              console.log('characteristics.length: ' + characteristics.length);
              characteristics[0].notify(true, function(error){
                if (error) console.log('notify error: ' + error);
                setInterval(function(){
                  characteristics[0].read(function(error, data){
                    if (data){
                      //console.log( data );
                      humid(data);
                      temp(data);
                     }
                   });
                }, 10000);
              });
            });
          }
        );
      });
  } else {
    console.log("not device");
  }
});

device
  .on('connect', function() {
    console.log('Connected to Message Broker.');
  });

本書はAWS IoTおよびAWSの各サービスを利用してIoTの基本的なシステムを構築するためのハンズオン手順について記述しております。 本ハンズオンでは、GINGA BLE ペリフェラルを利用します。

前提条件

  • kintoneの最低限の知識があること
  • インテルEdisonまたはRaspberry Piなどの機器で開発経験がある方
  • IoTを活用したアプリケーション構築をご検討されているデベロッパーの方
  • AWSクラウドを活用したシステム・アプリケーション開発に従事されている方
  • UNIXの基本的なコマンドの利用経験がある方

注意事項

  • kintoneの開発者アカウントがあること
  • AWSのサービス利用料金は受講者の方にご負担いただきますよう、ご了承ください。
  • ハンズオンに必要な機材は貸出品となりますので、終了後は必ず返却をお願いします。

事前準備

スタッフから必要なセンサーデバイスの貸出をうけてください。

サンプルプログラム

本ハンズオンで利用するサンプルプログラムです。

https://github.com/ToshiEna/kintone-aws-iot-handson-2015/raw/master/download/sample.zip

よくあるトラブル

参考情報

ハッシュタグ

Twitterのハッシュタグはこちらになります。 #AWS_IoT_JP