Sigfox Shield for ArduinoのデータをAWSに送信する

Sigfox Shield for ArduinoのデータをAWSに送信してみました。
スイッチサイエンス社では在庫が無かったので、SORACOMさんから購入しました。
様々なセンサーがこのシールドには搭載されています。
単体でネットワークに繋がるので、直ぐにIoTを試すことが出来ます。

IMG_0364.png

搭載センサー

  • 加速度センサ(MMA8451Q)
  • 温湿度・気圧センサ(BME280)

必要なもの

準備

SORACOM社から購入しているので、購入後セットアップは下記を参照してください。
https://dev.soracom.io/jp/start/sigfox_hw_unashield-v2s/#_ga=2.210765397.1366760851.1509329125-812912311.1499217908

DynamoDBテーブル作成

まずデータを保存するためのテーブルをAWSのDynamoDBに作成します。

s100.png

s101.png

項目
テーブル名 SigfoxDemo
プライマリキー timestamp(数値型)

s102.png

Lambdaの作成

続いてLambdaの作成を行います。関数の作成をクリックしてください。
s103.png

一から作成をクリック
s104.png

好きなロール名を入力してください。
s105.png

IAMのインラインポリシーを下記のように設定しました。
Resourceのテーブル名はIDは各々の設定を入力してください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "dynamodb:PutItem"
            ],
            "Resource": "arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXX:table/SigfoxDemo",
            "Effect": "Allow"
        }
    ]
}

関数コードを入力

関数が出来たら、関数コードを入力部分をクリックしてコードを追加しましょう

s118.png

// initialize SDK and document client
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();

exports.handler = function(event, context) {

  // SORACOMから送られてくるタイムスタンプ取得
  event.item.timestamp = event.timestamp;

  // build API parameter
  var params = {
    Item: event.item,
    TableName: 'SigfoxDemo'    /*対象のテーブル名*/
  };

  // call PutItem operation
  docClient.put(params, function(err, data){
    if (err)
      context.fail(err);
    else
      context.succeed({Item: event.item, Result:'success'});
  });
};

API Gatewayの設定

APIの作成をクリックしてください。

s107.png

好きなAPI名を入力してください
s108.png

メソッドの作成をクリックしてください
s109.png

POSTを選択しましょう
s110.png

POSTのセットアップ

s111.png

OKをクリックしましょう
s112.png

メソッドリクエストをクリック
s113.png

ヘッダーの追加をクリックして、SORACOMから送られてくる「X-SORACOM-TIMESTAMP」を設定します。
s114.png

APIキーの必要性をtrueにする
s115.png

総合リクエストをクリック
s116.png

本文マッピングテンプレートにあるマッピングテンプレートの追加をクリックして
Content-Typeにapplication/jsonを入力
s117.png

送られてくるデータをこれで取得する

{
    "timestamp":$input.params('X-SORACOM-TIMESTAMP'),
    "item":$input.json('$')
}

テスト

これでうまくDynamoDBに書き込まれるかテストを行ってみます。

s119.png

s120.png

これでDynamoDBに書き込まれたはずです。
ここで書き込まれなかった場合はロールの設定を見直してみましょう。DBアクセス権限が無い場合があります。

s121.png

デプロイする

作成したAPIをデプロイしましょう

s122.png

ステージ名を「prod」にしてデプロイボタンをクリック
s123.png

APIキー作成

APIキーを作成しましょう。

s124.png

好きなAPI名を入力して保存ボタンをクリック
s125.png

「使用量プランに追加」をクリック
s126.png

作成ボタンをクリック
s127.png

2つのチェックを外してください
s128.png

対象のAPIをステージ名を選択します
s129.png

最終的にこうなっていればOK
s130.png

AWSとSORACOM Beamを紐付ける

ここからは、SORACOMさんの管理画面から操作していき、作成したAWSと紐付けていきます。
管理画面のSigfoxグループをクリックしてください。

s131.png

適当にグループ名を入力しましょう
s132.png

SORACOM Air for Sigfox 設定

シールドから送られてくるバイナリデータをパースする為の設定です。
s133.png

SORACOM Beam 設定

HTTPSのエントリポイントを設定します
s134.png

s135.png

事前共有鍵の設定

s136.png

カスタムヘッダを追加

s137.png

s138.png

最終的には下記のような感じです
s139.png

Sigfoxデバイス管理

s140.png

s141.png

s142.png

実行する

ここまで完了したら、Sigfox Shield for Arduinoに電源を繋いで起動してみましょう
するとDynamoDBにセンサー値が書き込まれるかと思います。

s143.png

まとめ

比較的簡単にAWSとの接続が出来ました。しかも1年間は通信料が無料という特典付きです!
USBの電池ボックスとケースを作成すればサーバーの温度を測れる簡易センサーが作れると思います。
是非お試しあれ!

続きを読む

SORACOM Funnelを利用してKinesis FirehoseにJSONを送信してS3にPUTする(ついでにDynamoDBに書き込む)

はじめに

今頃Kinesis Firehoseとか今更感がありますがちゃんと使ってみたかったってのと、FunnelからFirehoseにJSONを投げたいという要望が舞い込んできたので、あんまりニーズはないと思いますが記事にしてみた

処理フロー

※点線部分はおまけ

funnel_firehose.PNG

Create S3

FirehoseがPUTするためのS3を作成しておきます。(作成する方法は省略します)

Create Kinesis Firehose

コンソールからFirehoseの画面へ移動して「Create delivery stream」からFirehoseを作成します
まだ東京リージョンで利用することはできないので、オレゴンリージョンで作成しました

  1. 「Delivery stream name」に任意の文字列を入力し、そのまま「next」をクリック
  2. FirehoseからLambdaをキックすることはしないのでそのまま「next」をクリック
  3. 「Destination」でS3を選択し(おそらくデフォルトで選択されています)、PUTするバケットを選択
  4. 「S3 buffer conditions」の「Buffer interval」を最小の「60」に設定。これで60秒待ってからS3にPUTします
  5. その他のデータを圧縮するか、暗号化するかなどのを任意に設定して、IAMroleを作成します
  6. 新しいIAMroleを作成すると今までの設定で必要な権限がついているIAMroleが作成されます
  7. 「Status」が「ACTIVE」になれば作成完了です

これでFirehoseにPUTRecordされたデータはS3にPUTObjectされます

※AWS-CLIでテストを行う

aws firehose put-record --delivery-stream-name deliveryStreamName --record Data="test"

SORACOM Funnelの設定

新しくSIMグループを作成し、Funnelの設定を行っていきます

  1. 「転送先サービス」から「Amazon Kinesis Firehose」を選択
  2. 「転送先URL」に「https://firehose.[region].amazonaws.com/[deliveryStreamName] 」を入力
  3. 「認証情報」には、Kinesis Firehoseの実行権限があるKey情報を持ったものを作成し、適用します
  4. 「送信データ形式」には「JSON」を選択します

これで、「http://funnel.soracom.io」にリクエストを送るとFirehoseにデータが送信されます

さぁテストの時間だ

先ほど設定したSIMグループのSIMが刺さったデバイスからPOSTメソッドを送信します

 curl -X POST --data @test.json -H "Content-Type: application/json" http://funnel.soracom.io

送信後S3にデータが保存されていれば成功です

おまけ

S3にPUTが行われたときにLambdaをキックしてDynamoDBにデータを保存する
おおまかなフロー
1. Funnel経由でFirehoseにJSONを送信
2. FirehoseがS3にPutRecord
3. S3がLambdaをキック
4. LambdaがS3にPutされたJSONを取得しDynamoDBにPut

Lambda

LambdaのロールにはDynamoDBへの権限を持たせておきます

index.js
const AWS = require("aws-sdk");
const co = require("co");

const dynamodb = new AWS.DynamoDB.DocumentClient({
  region: "us-west-2"
});
const s3 = new AWS.S3();

const dynamoPutData = require("./lib/dynamo_put_data");
const s3GetObject = require("./lib/s3_get_object");


exports.handler = (event, context, callback) => {
  console.log(JSON.stringify(event));
  co(function *() {
    // S3のBucketNameとPUTされたJSONのKey情報を取得
    const bucketName = event["Records"][0]["s3"]["bucket"]["name"];
    const objectKey = event["Records"][0]["s3"]["object"]["key"];
    // S3からJSONファイルを取得
    const s3GetData = yield s3GetObject.getObject(s3, bucketName, objectKey);
    const item = {
      id: "test",
      payloads: s3GetData
    };
    return yield dynamoPutData.putDynamoDB(dynamodb, item);
  }).then(() => {
    console.log("success");
  }).catch((err) => {
    console.log(err);
  });

};
s3_get_object.js
class s3GetObject {

  /**
   * S3からObjectを取得する
   * @param s3
   * @param bucket
   * @param key
   * @returns {Promise}
   */
  static getObject(s3, bucket, key) {
    return new Promise((resolve, reject) => {
      const params = {
        Bucket: bucket,
        Key: key
      };
      s3.getObject(params, (err, data) => {
        if(err) {
          return reject(err);
        } else {
          const getData = JSON.parse(data.Body.toString());
          return resolve(getData["payloads"]);
        }
      });
    });
  }
}

module.exports = s3GetObject;
dynamo_put_data.js
class dynamoPutData {

   /**
   * DynamoDBにデータを保存する(Put)
   * @param {DocumentClient} dynamoDB
   * @param item
   * @returns {Promise}
   */
  static putDynamoDB(dynamoDB, item) {
    return new Promise((resolve, reject) => {
      const params = {
        TableName: "tableName",
        Item: item
      };
      return dynamoDB.put(params, (err, data) => {
        if (err) {
          console.log(err);
          return reject(err);
        } else {
          console.log(data);
          return resolve(data);
        }
      });
    });
  }
}

module.exports = dynamoPutData;

S3

  1. S3のコンソール画面からプロパティ⇒Eventsを選択
  2. 「Add notification」を選択
  3. 「Name」には任意の文字列、「Events」はPut、「Send to」は「Lambda Function」を選択し、先ほど作成したLambdaを選択します

これで作業完了です。
Funnel経由でJSONを送信し、S3やDynamoDBにデータが保存されているか確認してください

まとめ

とりあえずFirehoseがどうしても1分データを保持してしまうのでStreamに比べたら処理時間がかかってしまうようです
というかリアルタイム性がほしければStream使おうかってなりますよねー
あと早く東京に上陸してくれないだろうかって感じですね

ではまた!

続きを読む

SORACOM BeamでバイナリデータをAPIGateway経由でS3にアップロードする

はじめに

あるお客様からLTEモジュールからS3に画像ファイルをアップロードしたとの要望があったので、いろいろな方法を模索したのですが、AWS-CLIなんて積めないし、HTTPリクエストのヘッダーに必要なAWS認証情報を作成できないし、といった感じでどうやって実現しようかと悩んでいました。(AWS-CLIやAWS-SDKのすばらしさに感動したw)
そんなとき「SORACOM Beamを使ってAPIGateway経由で何とかならんかね?バイナリデータのサポートもされたことだし」という神のお告げが降ってきたので実装してみた

どんな感じ?

apigateway_post.PNG

SORACOM Beamって?

下記公式ページから抜粋

SORACOM Beam(以下、Beam)は、IoT デバイスにかかる暗号化等の高負荷処理や接続先の設定を、クラウドにオフロードできるサービスです。
Beam を利用することによって、クラウドを介していつでも、どこからでも、簡単に IoT デバイスを管理することができます。
大量のデバイスを直接設定する必要はありません。

(参考:https://soracom.jp/services/beam/)

S3バケットの作成

まず画像ファイルをアップロードするバケットを作成しましょう
詳しい手順は割愛しますが、バケットポリシーを設定しないとPutObjectできないのでこんな感じで設定しておきます

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::[Bucket Name]/*"
        }
    ]
}

APIGatewayの作成

次にAPIGatewayを作成します

  1. APIGatewayのコンソール画面を開き、「Create API」をクリックします
  2. 「API name」に任意の文字列を入力し「Create API」で作成します
  3. リソースを作成します。「Actions」から「Create Resource」を選択し「upload」というリソースを作成します
  4. 「/upload」の子階層に「/{key}」といリソースを作成します。「/{key}」はURLパスパラメータとなり、今回はS3にPutする際のKey情報となります
  5. 「/{key}」を選択した状態で「Actions」から「Create method」を選択し「POST」メソッドを作成します。画面はこのような感じになっていると思います。この時点で「/upload/{key}」に対してPOSTメソッドを受け付けるように設定されています
    apigateway_post_test.PNG
  6. 「Integration type:HTTP」「HTTP method:PUT」「Endpoint URL:S3のエンドポイント(ex:https://s3-ap-northeast-1.amazonaws.com/[Bucket Name]/{key})」を選択・入力し「save」をクリックします。そうするとPOSTメソッドが作成されます
    apigateway_post_method.PNG
    「Method Request」を選択して「API Key Required」を「ture」に変更します
  7. 「Actions」から「Deploy API」を選択し、APIをデプロイします。初めての場合は[New Stage]を選択して新しいステージを作成してください。「Invoke URL」を控えておいてください
  8. バイナリデータを受け取る設定をします。「Binary Support」を選択し、「Edit」をクリックして「application/octet-stream」と「image/png」を追加します
  9. 次にSORACOM BeamからAPIGatewayを利用するにあたってAPIキーが必要になるので、APIキーを作成してAPIGatewayと紐付けます。
  10. 「API Keys」を選択し、「Actions」から「Create API Key」をクリック。「Name」に任意の文字列を入力し、「Save」をクリックします。これでAPIキーが作成されました。「API Key」の文字列をどこかに控えておいてください
  11. 「Usage Plans」を選択し、「Create」をクリック。各必須項目に任意の値を入力して「next」をクリック
  12. 「Add API Stage」をクリックして、先ほどデプロイしたAPIGatewayを選択し「Next」をクリック
  13. 「Add API Key to Usage Plan」を選択し、先ほど作成したAPIキーを入力し「Done」をクリック
  14. これで、APIGatewayとAPIキーが結びつきました

SORACOM Beamの設定

最後にSORACOM Beamの設定をします
1. SORACOMのコンソール画面を開きグループを作成します
2. 作成したグループのBeam設定を開き、プラスのアイコンから「HTTPエントリポイント」を選択します
3. 下記内容を入力・設定していきます

設定名:任意の文字列
エントリポイント
  パス:/
転送先
  ホスト名:APIGatewayのInvoke URL
  パス:/upload/test.png
ヘッダ操作
  IMSIヘッダ付与:ON
  署名ヘッダ付与:ON
  事前共有鍵:作成しておいたものを選択。新たに作成する場合は後ほど記述します
カスタムヘッダ:「アクション:置換」「ヘッダ名:X-API-KEY」「値:APIキーの文字列」

※事前共有鍵の作成
「認証情報ID」と「事前共有鍵」に任意の文字列を入力し「登録」をクリックしてください
soracom_key.PNG

これで「http://beam.soracom.io:8888/ 」に対してリクエストを送信すると、APIGatewayにPOSTメソッドが送信されます

送信テスト

SIMのグループをBeamが設定されているグループに変更し、デバイスにSSHでログインします
テスト送信用のpngファイル(下記コマンドでは「test.png」)があるディレクトリに移動し、下記コマンドを入力しS3に画像がアップロードされているかを確認してください

curl -X POST --data-binary "@test.png" -H  "Content-Type: application/octet-stream" http://beam.soracom.io:8888/

成功していれば、S3の対象バケット内に「test.png」がアップロードされていると思います

まとめ

最近よくIoT案件に関わらせていただいているのですが、そもそもセキュアな通信を前提としていないデバイスをクラウドなどと接続したいという要望が増えてきているように感じてきました
SORACOMさんのようなSIMに認証情報を持たせてセキュアな通信を担保してくれるようなサービスを最大限に活用してそういった要望にこたえていきたいと思う今日この頃でした
ただクラウド側での処理が複雑になればなるほどどこかで破綻するんじゃないかなーとも感じていたりいなかったり

あと、SORACOMBeamでAPIGatewayのパスを変数的に持たせることってできないんだろうか
APIGateway側でURLパスパラメータを使ってS3へアップロードするキー名を決めているので、今回のように固定にしてしまうと、アップロードされる画像がずっと上書きされてしまうので、あまりよろしくない・・・
S3のイベントで画像がアップロードされたタイミングでLambdaキックしてリネームしてアップロードしなおすという手もあるけど・・・
Beamの仕様を漁るか・・・
もし、何かよい方法があればコメント等で教えてください!

ではまた!

続きを読む