AWS API Gateway/Lambda Functionを使用してIoT Coreへメッセージ送信してみた!
最終目標は 「 スマホ-> AWS API Gateway->Lambda->AWS IoT Core -> IoT Device」ルートで遠隔操作です。
本記事ではAWS API GatewayにLambda関数を登録して、AWS IoT Croreで受信ができるところまで。
少しみたところIoT Deviceを制御するには、IoT Coreで「Device shadow」を使い、API Gatewayはパラメータ設定したいので「統合リクエスト」を使うことで実現できそうです。
注意
2020/12/17からboto3でIoT CoreのDevice ShadowにアクセスするとSSLエラーが発生する事象が出ています。
AWSのcertifiライブラリが「2020.12.5」にバージョンアップされたことが原因らしく、下記サイトを参考に応急処置を行い、問題なく動作できることを確認しました。
その時のエラーメッセージです。
{"errorMessage": "SSL validation failed for https://data.iot.ap-northeast-1.amazonaws.com/things/RaspberryPi_Camera/shadow [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate
応急処置方法のサイトをリンク貼り付けます。
certifiライブラリ「2020.11.8」版をMACで作成し、その「 layer.zip 」ファイルをAWS Lambdaコンソールから「 レイヤー追加 」、対象となるLambda関数に適用でいけました。
正式にはIoT CoreのATSエンドポイント指定することで対応可能なようです。 すみません。自分は確認していません。ご了承ください。
AWS構成図
AWS API Gatwayとは
API とは、 「Application Programming Interface」の略で、サービスの提供者が自身のサービスを外部の利用者が使えるようにするために提供するインタフェース(外部との窓口)のことです。アプリケーションの開発者は、既存の API を利用することにより、同じ機能を 1 から自身で開発する必要がないため、開発コスト・期間を減らすことができます。 AWS が提供するフルマネージド型サービスの Amazon API Gateway (以降、API Gatewayと略) を使うと、 外部から AWS のバックエンドサービスや AWS 以外の HTTP ベースのサービスを利用するための窓口となる API を作成できます。※API Gateway で作成できる API は、Web からアクセスできる「Web API」となります。
個人的に下記リンクがわかりやすかったので載せておきます。
Lambda function作成
Lambdaコンソールを起動します。
「関数の作成」ボタンをクリックします。
関数はPythonを使用します。
「 関数名 : testApi 」 、「 ランタイム:Python3.7 、「 実行ロール:基本的なLambdaアクセス権限で新しいロールを作成 」を設定します。
最後に「 関数の作成 」ボタンをクリックし関数を作成します。
作成が完了すると、画面の下の方に関数コードがありますので、そちらに下記ソースコードをコピぺしてください。
最初にlambda_functionのタブのソースコード内容を消して、貼り付けしてください。
次に「 File 」-> 「 save 」し、最後に「 デプロイ」ボタンをクリックすることで変更内容が反映されます。
ソースコードは下記です。
IoT Coreへpubulishするtopicは「 topic/apigateway 」にしています。 topicはあとで受信確認するときに使用します。
import json import boto3 # AWS IoT Data Planeオブジェクトを取得 iot = boto3.client('iot-data') # lambda関数 def lambda_handler(event, context): # topicは topic/apigateway topic = 'topic/apigateway' # メッセージ内容 payload = { "message": "API Gateway to iot core message" } try: # メッセージをpubulish iot.publish( topic=topic, qos=0, payload=json.dumps(payload, ensure_ascii=False) ) return "Send Success." except Exception as e: print(e) return "Failed."
ランタイム設定のハンドラは
「 lambda_function .py」ファイルの「 def lambda_handler () 」を示しており、API GaytewayからLambda functionが起動すると、「lambda_handler」関数 が動作するイメージです。
ここでLambda functionが作成しましたが、まだ「 Lambdaのロールアタッチ 」と、「 IoT Coreに送信するポリシー登録 」するまで完了していません。
それでは「Lambdaのロールアタッチ 」と「ポリシー登録」します。
Lambdaのロールアタッチとポリシー登録
Lambda function作成時に自動でロールが作成されています。Lambda function画面の「 アクセス権限 」タブを選択し、ロール名をクリックしてください。
IAMコンソールが起動します。
左メニューから「 ポリシー 」を選択し、「 ポリシーの作成 」ボタンをクリックします。 ここで作成するポリシーは、IoT Coreへ送信するための登録です。
ポリシーの作成画面の遷移し、サービスで「 IoT 」選択します。
アクションは「 Publish 」を入力し、チェックボックスをクリックします。
リソースは「 すべてのリソース 」のラジオボタンをクリックし、「 ポリシーの確認 」ボタンをクリックします。
ポリシーの画面確認で名前を入力し、「 ポリシーの作成 」ボタンをクリックします。。ここでは「testapi_policy」としています。
ロールの画面に移動し、「 ポリシーをアタッチします 」ボタンをクリックします。
ロールに「testapi_policy」がアタッチしたことが表示されます。
Lambda functionコンソールに戻り「 アクセス権限 」タブのリソース概要に「 IoT Core 」が関連付けされていることが確認できます。
これでLambda function 登録が完了です!!
次はAWS API Gatewayに新しいAPIを作成します。
AWS API Gateway作成
次はAPIの作成です。AWS API Gatewayコンソールにいきます。
「 API名 」入力、「 エンドポイントタイプ」を選択します。ここではAPI名は「testAPI」、「リージョン」を指定し、「 APIの作成 」ボタンをクリックします。
エンドポイントにリージョンを選択すると、外部から指定するURLに「リージョン名」を付与しているアドレスになるイメージです。
下記のリージョン名は、「ap-northeast-1」です。尚、リージョン名は「メソッド作成」箇所で選択します。 (https:xxxxxxxxxxxxxxxxxxxx.ap-northeast-1.amazonaws.com/xxxxxxxxxxxxxx)
「 アクション 」ボタンをクリックし「 リソースの作成 」を選択します。
「 リソース名 」を入力し、「 リソースの作成 」をクリックし、リソースを作成します。 「リソース名」は「リソースパス」欄に自動挿入されます。
「リソースパス」とは、外部から指定するURL(https:................/test )のアドレスとして扱われます。ここでは「リソース名」を「test」としているため、パスにtestが入ります。
「 アクションボタン 」をクリックし、「 メソッドの作成 」を選択します。
「メソッド」とは、HTTPメソッドのことです。 HTTPメソッドとは、リソースに対して実行したいアクションを示すもので、メソッドには「GET」、「POST」、「PUT」などがあり、HTTPサーバー(今回はAWSがサーバー)へ指定する時に使用します。
AWS API Gatewayは、一つのメソッドに一つのLambda functionを登録できますので、メソッド毎にLambda functionを登録し、別の処理を行うことができます。
プルダウンリストからHTTPリクエストメソッド「 POST 」を選択します。選択完了後は、「 チェックマーク 」をクリックします。
左側のツリー表示から「POST」を選択し、POSTのセットアップをします。 統合タイプは「 Lambda関数 」のラジオボタンで選択、「 Lambdaリージョン 」を選択します。最後に「 Lambda関数 」に関数名を入力&選択し、「 保存 」ボタンをクリックします。
Lambda関数名は、本投稿で作成した「testApi」です。キーボードで登録したい関数名を入力すると、作成済みのLambda関数が表示されますので、対象の関数があったらそれを選択しましょう。
「 Lambda関数に権限を追加する 」のダイアログが表示されます。「 OK 」ボタンをクリックします。
テストで実際にLambda関数を起動、IoT Coreにメッセージを送信の結果を確認することもできますが、すみませんが割愛します。
ここからが「 外部からアクセスするためにURLを公開」する登録です。
ただし、APIをデプロイした時点で外部に公開され、誰でもアクセスできてしまいます。 Webブラウザからアクセスするブログなどのサイトではないので、誰からもアクセスできないようAPIキーを使用して認証を行うようにします。
先にAPIキーを作成し、APIリクエスト時に認証を行うようにします。
左メニューから「 APIキー 」を選択。「 アクションボタン 」をクリックし、「 APIキーの作成 」を選択します。
「 名前 」を入力し、「 APIキー 」は自動生成とし、「 保存ボタン 」をクリックします。
作成が完了すると、APIキーが生成されます。このAPIキーは、外部からアクセスするときに使用します。「 表示 」をクリックでキー情報を確認できます。
APIキーをメソッドと関連付けさせます。左ツリー表示の「 POST 」を選択し、右画面の「 メソッドリクエスト 」をクリックします。
「 APIキーの必要性 」が「 false 」になっていますので、プルダウンで「 true 」を選択し、「 チェックボタン 」をクリックします。
「true」になったことを確認した後、APIをデプロイします。
「 アクションボタン 」をクリックし、「 APIのデプロイ 」を選択します。
APIのステージを登録します。
このステージは、実際の使用する時エンドポイントを分けて使用することができます。例えば開発用、評価が終わって正式公開用などのようにもできます。
今回はお試しなので「 デプロイされるステージ 」を「新しいステージ」、「 ステージ名 」を「development」とし、「 デプロイ 」ボタンをクリックし、デプロイします。
このステージ名がURL(https:xxxxxxxxxxxxx/development/test)に割り当てられます。
「 デプロイ 」が完了するとステージまでのURLアドレスが表示されます。これに「 リソース名」(今回はtest)が追加されたアドレスがアクセスアドレスになります。
使用量プランを設定します。作成したAPIの使用量を測定することに使用されます。 左メニュー画面から「 使用プラン 」を選択し、「 作成 」ボタンをクリックします。
プラン「 名前 」を入力し、「 スロットリングの有効化 」「 クォータを有効する 」のチェックボックスのチェック外して、「 次へ 」のボタンをクリックします。
APIステージと使用プランを関連付けます。下記画像の「 APIステージの追加 」ボタンが非Active化(グレー表示)なっていますが、実際はボタンはActive化状態となっていますので、ご了承ください。
「 APIステージの追加 」ボタンをクリックし、「 API 」、「 ステージ 」を選択し、「 チェックマーク 」をクリックします。
完了すると、「 次へ 」ボタンがActive化されますので、ボタンをクリックします。
APIキーと使用プランを関連付けします。下記画像の「 APIキーを使用プランに追加 」ボタンが非Active化(グレー表示)なっていますが、実際はボタンはActive化状態となっていますので、ご了承ください。
「 名前のテキストボッククス 」に、APIキー名を入力すると選択表示が出ますので選択します。「 チェックマーク 」をクリックします。
完了すると、「 完了 」ボタンがActive化されますので、ボタンをクリックします。
長くなりましたが、これで外部からAPIキーを使用したURLアクセスができるようになりました。 作成手順を簡単に整理すると、
- LambdaコンソールからLambda functionの作成
- Lambda functionで使用するPythonコードを作成
- IoT Coreへアクセスするポリシー作成、Lambda functionロールにアタッチし関連付け
- API Gatewayコンソールからリソース作成とメソッド作成(Lambda fuctionを関連付け)
- APIをデプロイ
- APIキーを作成
- APIの使用量プランを設定
API動作確認
外部からPOSTアクセスし、API Gatewayに登録したLambda functionのPythonコードが実行され、IoT Coreにtopic 「 topic/apigateway 」が受信できることを確認します。
IoT Core受信設定
それではIoT Coreでメッセージ受信ができることを確認するための設定です。
AWS IoT Coreコンソールで「 テスト 」を選択し、トピックのサブスクリプションに「 topic/apigateway 」を入力し、「 トピックへのサプクライブ 」ボタンをクリックします。
これで受信準備ができました。
外部からAPI発行
外部からAPI(URLアクセス)発行をします。自分はMACを使用します。当然ながらインターネットに接続できていることが前提です 。
少し説明します。 コマンドは「 curl 」コマンドを使用します。
x-api-key:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx の < xxxx > 部には APIキーを指定してください。
httpsアドレスは本投稿で説明した「 APIステージまでのURL+リソース名 」となります。
--header はヘッダーを追加して送信でき、ここではAPIキー番号を入力します。
$curl -X POST --header "x-api-key:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" https://xxxxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/development/test
IoT Core受信結果
IoT Coreで正常に受信できると以下のメッセージを出力します。
以上でIoT Coreまでの動作が確認できました。
本投稿は基本的なものだけなので、もう少し具体的なサービスも考えた上で開発が必要ですね。 もっと勉強が必要。