Atom's tech blog

AWS API Gateway/Lambda Functionを使用してIoT Coreへメッセージ送信してみた!

f:id:iAtom:20201208120006j:plain

最終目標は 「 スマホ-> 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関数に適用でいけました。


dev.classmethod.jp


正式にはIoT CoreのATSエンドポイント指定することで対応可能なようです。 すみません。自分は確認していません。ご了承ください。

dev.classmethod.jp

AWS構成図


f:id:iAtom:20201214163659j:plain

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」となります。

個人的に下記リンクがわかりやすかったので載せておきます。

aws.amazon.com

Lambda function作成

Lambdaコンソールを起動します。


f:id:iAtom:20201207202403j:plain


「関数の作成」ボタンをクリックします。


f:id:iAtom:20201207202723j:plain


関数はPythonを使用します。

関数名 : testApi 」 、「 ランタイム:Python3.7 、「 実行ロール:基本的なLambdaアクセス権限で新しいロールを作成 」を設定します。


f:id:iAtom:20201207203236j:plain


最後に「 関数の作成 」ボタンをクリックし関数を作成します。


f:id:iAtom:20201207203812j:plain


作成が完了すると、画面の下の方に関数コードがありますので、そちらに下記ソースコードをコピぺしてください。


f:id:iAtom:20201207203911j:plain


最初にlambda_functionのタブのソースコード内容を消して、貼り付けしてください。

次に「 File 」-> 「 save 」し、最後に「 デプロイ」ボタンをクリックすることで変更内容が反映されます。


f:id:iAtom:20201207204156j:plain


ソースコードは下記です。

IoT Coreへpubulishするtopicは「 topic/apigateway 」にしています。 topicはあとで受信確認するときに使用します。


boto3ライブラリドキュメントはこちら

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」関数 が動作するイメージです。


f:id:iAtom:20201207205805j:plain
ここでLambda functionが作成しましたが、まだ「 Lambdaのロールアタッチ 」と、「 IoT Coreに送信するポリシー登録 」するまで完了していません。

それでは「Lambdaのロールアタッチ 」と「ポリシー登録」します。

Lambdaのロールアタッチとポリシー登録

Lambda function作成時に自動でロールが作成されています。Lambda function画面の「 アクセス権限 」タブを選択し、ロール名をクリックしてください。


f:id:iAtom:20201207210556j:plain

IAMコンソールが起動します。

左メニューから「 ポリシー 」を選択し、「 ポリシーの作成 」ボタンをクリックします。 ここで作成するポリシーは、IoT Coreへ送信するための登録です。


f:id:iAtom:20201207210807j:plain


ポリシーの作成画面の遷移し、サービスで「 IoT 」選択します。


f:id:iAtom:20201207211113j:plain


アクションは「 Publish 」を入力し、チェックボックスをクリックします。


f:id:iAtom:20201207211446j:plain


リソースは「 すべてのリソース 」のラジオボタンをクリックし、「 ポリシーの確認 」ボタンをクリックします。


f:id:iAtom:20201207211651j:plain


ポリシーの画面確認で名前を入力し、「 ポリシーの作成 」ボタンをクリックします。。ここでは「testapi_policy」としています。


f:id:iAtom:20201207212124j:plain

ロールの画面に移動し、「 ポリシーをアタッチします 」ボタンをクリックします。


f:id:iAtom:20201207212530j:plain


ロールに「testapi_policy」がアタッチしたことが表示されます。


f:id:iAtom:20201207212751j:plain


Lambda functionコンソールに戻り「 アクセス権限 」タブのリソース概要に「 IoT Core 」が関連付けされていることが確認できます。


f:id:iAtom:20201207213112j:plain


これでLambda function 登録が完了です!!

次はAWS API Gatewayに新しいAPIを作成します。

AWS API Gateway作成

次はAPIの作成です。AWS API Gatewayコンソールにいきます。


f:id:iAtom:20201208084054j:plain

API」入力、「 エンドポイントタイプ」を選択します。ここではAPI名は「testAPI」、「リージョン」を指定し、「 APIの作成 」ボタンをクリックします。

エンドポイントにリージョンを選択すると、外部から指定するURLに「リージョン名」を付与しているアドレスになるイメージです。

下記のリージョン名は、「ap-northeast-1」です。尚、リージョン名は「メソッド作成」箇所で選択します。 (https:xxxxxxxxxxxxxxxxxxxx.ap-northeast-1.amazonaws.com/xxxxxxxxxxxxxx)


f:id:iAtom:20201208084619j:plain


アクション 」ボタンをクリックし「 リソースの作成 」を選択します。


f:id:iAtom:20201208084930j:plain


リソース名 」を入力し、「 リソースの作成 」をクリックし、リソースを作成します。 「リソース名」は「リソースパス」欄に自動挿入されます。

「リソースパス」とは、外部から指定するURL(https:................/test )のアドレスとして扱われます。ここでは「リソース名」を「test」としているため、パスにtestが入ります。


f:id:iAtom:20201208085700j:plain


アクションボタン 」をクリックし、「 メソッドの作成 」を選択します。

「メソッド」とは、HTTPメソッドのことです。 HTTPメソッドとは、リソースに対して実行したいアクションを示すもので、メソッドには「GET」、「POST」、「PUT」などがあり、HTTPサーバー(今回はAWSがサーバー)へ指定する時に使用します。

AWS API Gatewayは、一つのメソッドに一つのLambda functionを登録できますので、メソッド毎にLambda functionを登録し、別の処理を行うことができます。


f:id:iAtom:20201208090002j:plain


プルダウンリストからHTTPリクエストメソッド「 POST 」を選択します。選択完了後は、「 チェックマーク 」をクリックします。


f:id:iAtom:20201208093105j:plain


左側のツリー表示から「POST」を選択し、POSTのセットアップをします。 統合タイプは「 Lambda関数 」のラジオボタンで選択、「 Lambdaリージョン 」を選択します。最後に「 Lambda関数 」に関数名を入力&選択し、「 保存 」ボタンをクリックします。

Lambda関数名は、本投稿で作成した「testApi」です。キーボードで登録したい関数名を入力すると、作成済みのLambda関数が表示されますので、対象の関数があったらそれを選択しましょう。


f:id:iAtom:20201208093853j:plain


Lambda関数に権限を追加する 」のダイアログが表示されます。「 OK 」ボタンをクリックします。


f:id:iAtom:20201208094141j:plain


テストで実際にLambda関数を起動、IoT Coreにメッセージを送信の結果を確認することもできますが、すみませんが割愛します。

ここからが「 外部からアクセスするためにURLを公開」する登録です。

ただし、APIをデプロイした時点で外部に公開され、誰でもアクセスできてしまいます。 Webブラウザからアクセスするブログなどのサイトではないので、誰からもアクセスできないようAPIキーを使用して認証を行うようにします。

先にAPIキーを作成し、APIリクエスト時に認証を行うようにします。

左メニューから「 APIキー 」を選択。「 アクションボタン 」をクリックし、「 APIキーの作成 」を選択します。


f:id:iAtom:20201208095335j:plain


名前 」を入力し、「 APIキー 」は自動生成とし、「 保存ボタン 」をクリックします。


f:id:iAtom:20201208095630j:plain


作成が完了すると、APIキーが生成されます。このAPIキーは、外部からアクセスするときに使用します。「 表示 」をクリックでキー情報を確認できます。


f:id:iAtom:20201208095953j:plain


APIキーをメソッドと関連付けさせます。左ツリー表示の「 POST 」を選択し、右画面の「 メソッドリクエス 」をクリックします。


f:id:iAtom:20201216144834j:plain


APIキーの必要性 」が「 false 」になっていますので、プルダウンで「 true 」を選択し、「 チェックボタン 」をクリックします。


f:id:iAtom:20201208100601j:plain


「true」になったことを確認した後、APIをデプロイします。

アクションボタン 」をクリックし、「 APIのデプロイ 」を選択します。


f:id:iAtom:20201208101054j:plain


APIのステージを登録します。

このステージは、実際の使用する時エンドポイントを分けて使用することができます。例えば開発用、評価が終わって正式公開用などのようにもできます。

今回はお試しなので「 デプロイされるステージ 」を「新しいステージ」、「 ステージ名 」を「development」とし、「 デプロイ 」ボタンをクリックし、デプロイします。

このステージ名がURL(https:xxxxxxxxxxxxx/development/test)に割り当てられます。


f:id:iAtom:20201208101927j:plain


デプロイ 」が完了するとステージまでのURLアドレスが表示されます。これに「 リソース名」(今回はtest)が追加されたアドレスがアクセスアドレスになります。


f:id:iAtom:20201208102631j:plain


使用量プランを設定します。作成したAPIの使用量を測定することに使用されます。 左メニュー画面から「 使用プラン 」を選択し、「 作成 」ボタンをクリックします。


f:id:iAtom:20201208103510j:plain


プラン「 名前 」を入力し、「ロットリングの有効化 」「 クォータを有効する 」のチェックボックスのチェック外して、「 次へ 」のボタンをクリックします。


f:id:iAtom:20201208103956j:plain


APIステージと使用プランを関連付けます。下記画像の「 APIステージの追加 」ボタンが非Active化(グレー表示)なっていますが、実際はボタンはActive化状態となっていますので、ご了承ください。

APIステージの追加 」ボタンをクリックし、「 API 」、「 ステージ 」を選択し、「 チェックマーク 」をクリックします。


f:id:iAtom:20201208104624j:plain

完了すると、「 次へ 」ボタンがActive化されますので、ボタンをクリックします。


f:id:iAtom:20201208104916j:plain

APIキーと使用プランを関連付けします。下記画像の「 APIキーを使用プランに追加 」ボタンが非Active化(グレー表示)なっていますが、実際はボタンはActive化状態となっていますので、ご了承ください。

名前のテキストボッククス 」に、APIキー名を入力すると選択表示が出ますので選択します。「 チェックマーク 」をクリックします。


f:id:iAtom:20201208105141j:plain


完了すると、「 完了 」ボタンがActive化されますので、ボタンをクリックします。


f:id:iAtom:20201208105507j:plain


長くなりましたが、これで外部から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 」を入力し、「 トピックへのサプクライブ 」ボタンをクリックします。


f:id:iAtom:20201208112901j:plain


これで受信準備ができました。

外部から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で正常に受信できると以下のメッセージを出力します。


f:id:iAtom:20201208113625j:plain


以上でIoT Coreまでの動作が確認できました。

本投稿は基本的なものだけなので、もう少し具体的なサービスも考えた上で開発が必要ですね。 もっと勉強が必要。