FlashAirからAmazon AWSに接続する2(実行編)
このチュートリアルではFlashAirに保存されたデータを、インターネット経由で直接AWSに送信する方法を解説します。準備編はこちらをご覧下さい。
AWSの設定
実際にAWSアカウント作成からバケット作成、FlashAirから画像をアップロードするところまで実行してみましょう。AWS内での設定のほとんどは公式サイトに詳しい説明があるので、本チュートリアルでは簡易的にまとめています。
既にアカウント作成済み、S3に他アプリからアップロードを行ったことがある場合はFlashAirの設定に進んでください。
AWSアカウントを作成
AWS アカウントの作成からアカウントを作成を行います。
連絡先情報、クレジットカード情報登録、アカウント認証、AWSサポートプランの選択を行いアカウントを作成します。詳細はAWS アカウント作成の流れをご覧ください。
必要に応じてAWS
セキュリティの認証情報
__等を設定してください。
S3にバケットを作成する
Amazon S3にログインし、「Amazon S3 の使用を開始する」を選択します。画面の指示通りに進みます。
「バケットを作成する」ボタンをクリックします。
ダイアログからバケットを作成します。任意のバケット名、リージョンを入力し「作成」ボタンをクリックします。
- 例
- flashair-bkt
- アジアパシフィック(東京)
S3へファイルをアップロードするために必要なアクセスキーとシークレットキーを取得します。
AWSメニューバーからアカウント名をクリックし、「セキュリティ認証情報」をクリックします。
IAM ユーザーのアクセスキーの管理を参考に、アクセスキー、シークレットキーを取得、控えておきます。これらの情報は取扱に注意し、他人と共有しないようにしてください。
これでS3の準備が完了しました。
FlashAirの設定
FlashAirの設定を行います。FlashAirをステーションモードにして無線LAN子機として使用します。ステーションモードの詳細はステーションモードの利用をご覧ください。
CONFIGの設定
CONFIGを編集するには、/SD_WLAN/CONFIG
をエディタ等で開き、前述のパラメータを編集します。
このフォルダは隠しフォルダとなっていますので、隠しフォルダを扱う事が出来るツールを使いましょう。
(Macの場合は/Volumes/(ボリュームラベル名)/SD_WLAN/CONFIG
です。)
CONFIG内で以下の3つの情報を変更する必要があります。 括弧内は CONFIGの対応するパラメータ名です。 パラメータが存在しない場合は新しく行を追加してください。 パラメータの順序は問いません。
動作モード (APPMODE)
パラメータに5
を指定し、インフラストラクチャ・モードのステーション動作に変更します。
無線LAN SSID (APPSSID)
接続先無線LANのSSIDを指定します。
無線LAN ネットワークパスワード (APPNETWORKKEY)
接続先無線LANのネットワークキーを指定します。
編集後は、たとえば下記のようになります。
APPMODE=5 APPNAME=flashair APPSSID=FOOSSID APPNETWORKKEY=password0123 CIPATH=/DCIM/100__TSB/FA000001.JPG VERSION=F15DBW3BW4.00.03 CID=02544d535730384708c00b7d7800d201 PRODUCT=FlashAir VENDOR=TOSHIBA MASTERCODE=18002d4ff0a2 LOCK=1
ファイルの設置、設定
ページ下部のサンプルコードをダウンロードし、FlashAirのルートフォルダ内に展開します。
s3-put.lua
をテキストエディタで開きます。
3-6行目をバケット作成時のリージョン、バケット名、「S3にバケットを作成する」で取得したアクセスキー、シークレットキーで上書きします。
s3-put.lua
local s3Util = require("s3-util")
local REGION = "ap-northeast-1" --リージョン名
local ACCESS_KEY = "AKIAIXXXXXXXXXXXXXXX" --アクセスキー
local SECRET_KEY = "/id3EXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+" --シークレットキー
local BACKET = "flashair-bkt" --バケット名
保存するファイルについて
- DATAフォルダ
アップロードするファイルを格納するフォルダです。 - s3-exec.lua
sendtime.dat
ファイルに保存されている日付以降に作成されたファイルがDATAフォルダ内に見つかった場合、s3-put.lua
ファイルのS3Putクラスにファイルパスとファイル名を引渡します。10秒ごとにフォルダ内をチェックします。 - s3-put.lua
S3のバケットにファイルをアップロードします。 - s3-util.lua
ユーティリティクラスです。現在時刻、ハッシュ値等を、計算・取得します。 - sendtime.dat
s3-exec.lua
でファイルを検索した後に現在日付を保存します。
注意 ファイルがアップロードされない場合は、ファイル内に1
を記入(ファイル検索用日時の初期化)し上書き保存してから再度DATAフォルダにファイルを作成、コピーしてください。
それでは、サンプルプログラムがどのように動作するかをみていきます。
s3-exec.lua
local s3Put = require("s3-put")
local dir = "/DATA"
- 3行目
s3-put.luaをインクルードします。 - 5行目
アップロードするファイルの格納フォルダを指定します。変更する場合は"/DATA"
を任意の場所に修正してください。function readSendTime() local sendtime = 0 local file = io.open(timefile, "r") if file ~= nil then sendtime = file:read() file.close() else debug("file == nil") end if sendtime == nil then debug("sendtime == nil") sendtime = 0 end debug("r = " .. sendtime) return sendtime end
sendtime.datファイルの内容を読み込み、内容を返します。
function writeSendTime(sendtime) local file = io.open(timefile, "w+") if file ~= nil then file:write(sendtime) file:close() debug("w = " .. sendtime) end end
sendtime.datファイルにファイル検索を行った日時を書き込みます。
function getFilePath(sendtime) local filepath, filename = nil local result, filelist, sendtime = fa.search("file", dir, sendtime) if result == 1 or filelist ~= nil then filepath = string.match(filelist, "(.-),") if filepath ~= nil then filename = string.match(filepath, "[^/]*$") end end return filepath, filename, sendtime end
fa.searchで、引数sendtimeと更新日時が一致するファイル、若しくは引数sendtimeより新しいファイルのうち最も古いファイル(指定された日時の次に新しいファイル)のファイルを取得し、返します。
function execute() local temptime = readSendTime() if temptime == 0 then print("temptime == 0") return end local sendtime = tonumber(readSendTime()) + 1 local filepath, filename, time = getFilePath(sendtime) if filepath == nil then return end writeSendTime(time) debug("filepath = " .. filepath .. ", filename = " .. filename) local s3 = s3Put:new(filepath, filename) s3:put() end
- 47行目
sendtime.datファイルを読み込みます。日時が取得できなかった場合は終了します。 - 52-53行目
sendtime.datに保存されている日時の0.5秒後以降のファイルを検索します。 - 57行目
該当ファイルが見つかった場合、ファイルの更新日付をsendtime.datに書き込みます。 - 59行目
S3Putクラスにファイルパスとファイル名を引き渡します。function debug(msg) --print(msg) end
デバッグメッセージを表示します。必要な場合はコメントを削除してください。
while(1) do execute() sleep(10000) collectgarbage("collect") end
sleepを使用し、10秒毎にファイル検索を行います。
s3-put.lua
local s3Util = require("s3-util")
s3-util.luaをインクルードします。
local S3Put = {}
S3Put.new = function(self, fpath, fname)
local this = {}
local SERVICE = "s3"
local METHOD = "PUT"
local PAYLOAD_HASH = "UNSIGNED-PAYLOAD"
local ALGORITHM = "AWS4-HMAC-SHA256"
local CONTENT_TYPE = "image/jpeg"
local util = s3Util:new()
local filepath = fpath
local filename = fname
local nowtime = util:currentTime()
local date = os.date('!%Y%m%d', nowtime)
local datetime = os.date('!%Y%m%dT%H%M00Z', nowtime)
local dataPath = "/" .. filename
local host = SERVICE .. "-" .. REGION .. ".amazonaws.com"
local canonicalURI = "/" .. BACKET .. dataPath
local endpoint = "https://" .. host
local canonicalQuery = ""
local signedHeader = "content-type;host;x-amz-content-sha256;x-amz-date"
local credentialScope = date .. "/" .. REGION .. "/" .. SERVICE .. "/" .. "aws4_request"
function this:getSignatureKey()
local kDate = util:sha256Hmac("AWS4" .. SECRET_KEY, date)
debug("kDate=" .. kDate)
kDate = util:hex2Bytes(kDate)
local kRegion = util:sha256Hmac(kDate, REGION)
debug("kRegion=" .. kRegion)
kRegion = util:hex2Bytes(kRegion)
local kService = util:sha256Hmac(kRegion, SERVICE)
debug("kService=" .. kService)
kService = util:hex2Bytes(kService)
local kSigning = util:sha256Hmac(kService, "aws4_request")
debug("kSigning=" .. kSigning)
kSigning = util:hex2Bytes(kSigning)
return kSigning
end
function this:getStringToSign()
local canonicalHeader = "content-type:" .. CONTENT_TYPE .. "\n" .. "host:" .. host .. "\n" .. "x-amz-content-sha256:" .. PAYLOAD_HASH .. "\n" .. "x-amz-date:" .. datetime .. "\n"
local canonicalRequest = METHOD .. "\n" .. canonicalURI .. "\n" .. canonicalQuery .. "\n" .. canonicalHeader .. "\n" .. signedHeader .. "\n" .. PAYLOAD_HASH
debug("canonicalRequest=" .. canonicalRequest)
local stringToSign = ALGORITHM .. "\n" .. datetime .. "\n" .. credentialScope .. "\n" .. util:sha256(canonicalRequest)
debug("----stringToSign----")
debug(stringToSign)
debug("----------")
return stringToSign
end
function this:getAuthorizationHeader()
local signingKey = this:getSignatureKey()
local signingSign = this:getStringToSign()
local signature = util:sha256Hmac(signingKey, signingSign)
local authorizationHeader = ALGORITHM .. " " .. "Credential=" .. ACCESS_KEY .. "/" .. credentialScope .. ", " .. "SignedHeaders=" .. signedHeader .. ", " .. "Signature=" .. signature
debug("----authorizationHeader----")
debug(authorizationHeader)
debug("----------")
return authorizationHeader
end
function this:put()
local filesize = lfs.attributes(filepath, "size")
local headers = {["content-type"]=CONTENT_TYPE, ["content-length"]=filesize, ["x-amz-date"]=datetime, ["x-amz-content-sha256"]=PAYLOAD_HASH, ["Authorization"]=this:getAuthorizationHeader()}
local requestURL = endpoint .. canonicalURI
local body, code, header = fa.request{
url=requestURL,
method="PUT",
headers=headers,
file=filepath,
body='<!--WLANSDFILE-->',
bufsize=1460*10,
}
debug("resultCode=" .. code)
debug("headers=" .. cjson.encode(header))
debug("body=" .. body)
end
return this
end
S3Putクラスを定義します。
- 35-49行目
シークレットキー、リージョン等から署名を暗号化するためのキーを作成します。署名キーの詳細はこちらをご覧ください。 - 51-60行目
正規リクエストを作成します。正規リクエストの詳細はこちらをご覧ください。 - 62-71行目
署名キーと正規リクエストを用いて、署名バージョン4の署名文字列を作成し、正規ヘッダーを作成します。 - 73-89行目
fa.requestを使用してAWS APIへリクエストを送信します。
実行、結果
FlashAirの設定が終わったら、FlashAirを抜き差しして修正を反映させます。
PCなどのSDメモリカードホスト側のOSがSDメモリカードの内容をキャッシュしていると、その変更をOSが認識する事が出来ません。
その為、SDメモリカードホスト機器とLuaやCGIから同時に変更を行うとFAT不整合が起きる可能性があります。
ブラウザから http://flashair/s3-exec.lua
を実行します。
DATAフォルダにファイルを作成またはコピーします。
アップロードが行われたか確認します。
「S3にバケットを作成する」で作成したバケット名をクリックします。
DATAフォルダ内のファイルがアップロードされていることが確認できました。
応用
準備編で解説したLambda、Rekognition、QuickSightを使用すると、取得したデータを加工、可視化、共有することが出来ます。
今回は、動体検知カメラで撮影した顔写真から年齢や性別、笑顔の有無などをRekognitionにより判定し、QuickSightで可視化してみました。
Lambda内でS3にファイルが追加されたらRekognitionの顔認識処理を呼び出す関数を作成します。関数の作成方法はLambda 関数を作成するをご覧ください。
あらかじめS3内に解析結果を格納するためのバケットを準備しておきます。Rekognitionの解析処理を取得したらS3に解析結果を解析バケットに格納する関数も用意します。
QuickSightでは、上記で作成した解析バケットのデータを用いてグラフを作成することが出来ます。QuickSightの使用方法はAmazon QuickSight とはをご覧ください。
Lambda
QuickSight
サンプルコード
advanced_tutorial_08.zip (4KB)
このサイトのサンプルコードは二条項BSDライセンスで提供されています。