AWS IoT Buttonで"ゆれ"とツイートする

AWS IoT Buttonというものがあります。

こんなの↓

(出典:https://aws.amazon.com/jp/iotbutton/

簡単に言えばAmazon Dash Buttonの処理をカスタマイズ出来る版ってな感じのシロモノです。
これがあれば、あんなことやそんなことが出来ると夢が拡がる一方ですが、
取り敢えずはAWS IoT初体験として「押したら”ゆれ”とツイートするボタン」を試しに作ってみました。
特に意味はありません。

ちなみに2017年8月時点ではまだ日本での販売はされておらず、
今回入手したものは本家の米Amazonから購入しています。うっかり5個買っちゃった。

概観図

tweet_button1.png

Twitterのアプリ登録

Twitterへ投稿する処理を実装するためには、あらかじめアプリ登録を済ませておく必要があります。
具体的な手順は下記のとおりです(一連の手順やWebページのUIは変更される可能性有)。

  1. ボタンを押したとき呟くことになるアカウントでTwitterへログインする
  2. https://apps.twitter.com へアクセス
  3. 右上の「Create New App」を押す
  4. Name、Description、Websiteを適当に入力する
    • Websiteは必須項目なので何かしらを入力(https://twitter.com など)、Callback URLは空でOK
  5. Twitter Developer Agreementを確認してチェックを付けた後、「Create your Twitter application」を押す
  6. 登録成功した感じのページに遷移したらタブの「Keys and Access Tokens」を選択
  7. 下の方にある「Create my access token」のボタンを押す

ここまでの操作により、下に赤枠で示した4つの情報が確認できればTwitter側は準備完了です。

※Access Tokenは途中にあるハイフンも含むのでコピペの際に間違って消さないよう注意

AWS IoT Buttonのセットアップ

AWS IoT Buttonを利用するためにはAWSアカウントが必要です。
まだアカウントを作成していない場合はこちらなどから頑張ってサインアップします。

AWSコンソールへサインイン出来たら、
ここに書いてある通りにセットアップを実行します。

一つ注意点として、セットアップ手順を進めるPCが無線LANにアクセスできない端末の場合、
無線LANアクセス可能なPCへ証明書と鍵を送ってButtonの設定を完了させる必要があります。
これにもたついているとButtonへの接続が切れて入力やり直しとかになったりします。
まぁ今時そんなPCはまず無いと思いますが、念のため。
なんでこのPC無線LAN子機内蔵してないんだ……

Lambda関数の処理を実装

AWS IoT Buttonのセットアップ手順でLambda関数の作成までは行ったので、
その関数の処理をTwitterへ投稿する処理に変更します。
上でセットアップしたButtonが押されると、ここで書いた処理が実行されるという感じになるわけですね。

下記の手順は既にNode.js & npmがインストールされているという前提になります。

まず、作業ディレクトリを作成して、

mkdir iotbutton
cd iotbutton

Twitterのライブラリをインストールし、

npm install twitter

Twitterへ”ゆれ”と投稿する処理を書いてindex.jsとして保存した後、
(clientのパラメータにはTwitterでアプリ登録した際に確認したキーを指定)

const Twitter = require('twitter');

const client = new Twitter({
    consumer_key: 'xxxxxxxx',
    consumer_secret: 'xxxxxxxx',
    access_token_key: 'xxxxxxxx',
    access_token_secret: 'xxxxxxxx'
});

exports.handler = (event, context, callback) => {
    client.post('statuses/update', {status: 'ゆれ'}, function(error, tweet, response) {
        if (error) {
            console.log(error);
            callback(error);
            return;
        }
        console.log(tweet);
        callback();
    });
};

最後にnode_modulesindex.jsをzipで固めてLambda関数のコードとしてアップロードするだけです。
とっても簡単!

一度アップロードした後は、AWSコンソール上からインラインでコードの編集が出来るようになります。

動作確認

これで準備は全て整いましたので、早速試してみます。
ただし、ゆれてもいないときに一人ゆれツイートを投稿して誤爆しちゃったみたいな感じになるのは嫌なので
今だけ”This is a test tweet by Lambda.”に文言を変えています。

まずはButtonを押下。
少し間を空けてからタイムラインを更新すると……

tweet_button2.png

成功です!
これでもういつ地震が来ても大丈夫。

制限事項とか残課題とか

  • Buttonを押してから呟きが投稿されるまでに5秒~10秒くらいのタイムラグがある。自分で投稿した方が速そう
  • セットアップしたWi-Fiアクセスポイントのある場所でしか使えない。
  • 間違えて押すと悲しいことに。 → 2回押されたらキャンセル or 削除させる?

雑感

タイムラグが致命的なため、地震ツイートRTA用途には使えなさそうなのが非常に残念でした。

それはともかくとして、セットアップの容易さとAWSとの連携による汎用性の高さを併せ持つ
このButton(1個約20$)は魅力的で可能性を感じるプロダクトだと改めて実感しました。
早く日本でも販売開始してほしい。

余談ですが、国産のIoTプロダクトではMESHというのもありますね。
機会があればこっちも触ってみるかもしれません。

続きを読む

serverless frameworkを使ってデプロイ

serverless frameworkってなんなん

YAMLに設定を書いておくと、CLIでAWSのデプロイ/設定が行えます。
簡単に言うと、デプロイの自動化ができます。

環境

項目 version
node 6.10.2
serverless framework 1.19.0

インストール

serverless frameworkをglobalにインストール。

npm install -g serverless

config credentials

serverless framework docs AWS – Config Credentials

プロジェクト作成

serverless frameworkのコマンドを使用してプロジェクトを作成します。

mkdir serverless-sample
serverless create -t aws-nodejs

以下内容のファイルが作成されます。試してみたら見れますがw

handler.js
'use strict';

module.exports.hello = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    }),
  };

  callback(null, response);

  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};
serverless.yml
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
#    docs.serverless.com
#
# Happy Coding!

service: serverless-sample

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

provider:
  name: aws
  runtime: nodejs6.10

# you can overwrite defaults here
#  stage: dev
#  region: us-east-1

# you can add statements to the Lambda function's IAM Role here
#  iamRoleStatements:
#    - Effect: "Allow"
#      Action:
#        - "s3:ListBucket"
#      Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ]  }
#    - Effect: "Allow"
#      Action:
#        - "s3:PutObject"
#      Resource:
#        Fn::Join:
#          - ""
#          - - "arn:aws:s3:::"
#            - "Ref" : "ServerlessDeploymentBucket"
#            - "/*"

# you can define service wide environment variables here
#  environment:
#    variable1: value1

# you can add packaging information here
#package:
#  include:
#    - include-me.js
#    - include-me-dir/**
#  exclude:
#    - exclude-me.js
#    - exclude-me-dir/**

functions:
  hello:
    handler: handler.hello

#    The following are a few example events you can configure
#    NOTE: Please make sure to change your handler code to work with those events
#    Check the event documentation for details
#    events:
#      - http:
#          path: users/create
#          method: get
#      - s3: ${env:BUCKET}
#      - schedule: rate(10 minutes)
#      - sns: greeter-topic
#      - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
#      - alexaSkill
#      - iot:
#          sql: "SELECT * FROM 'some_topic'"
#      - cloudwatchEvent:
#          event:
#            source:
#              - "aws.ec2"
#            detail-type:
#              - "EC2 Instance State-change Notification"
#            detail:
#              state:
#                - pending
#      - cloudwatchLog: '/aws/lambda/hello'
#      - cognitoUserPool:
#          pool: MyUserPool
#          trigger: PreSignUp

#    Define function environment variables here
#    environment:
#      variable2: value2

# you can add CloudFormation resource templates here
#resources:
#  Resources:
#    NewResource:
#      Type: AWS::S3::Bucket
#      Properties:
#        BucketName: my-new-bucket
#  Outputs:
#     NewOutput:
#       Description: "Description for the output"
#       Value: "Some output value"

region設定

regionの設定を追記します。

serverless.yml
--- 省略 ---
provider:
  name: aws
  runtime: nodejs6.10
  region: ap-northeast-1
--- 省略 ---

API Gateway設定

上記ロジックを呼ぶエンドポイントの設定を追記。

serverless.yml
--- 省略 ---
functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: serverless-sample
          method: get
--- 省略 ---

デプロイ

serverless frameworkのコマンドを使用してデプロイします。
serverless.ymlに記載の内容でデプロイされます。

serverless deploy

参考

serverless

続きを読む

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の仕様を漁るか・・・
もし、何かよい方法があればコメント等で教えてください!

ではまた!

続きを読む