DynamoDBに保存したIPアドレスをLambda関数で呼び出す

published_with_changes 更新日:

labelamazon alexa labelBlynk labelIoT labelRaspberry pi

【追記 2025/03/03】
月が変わって、AWSからの請求が来て気づきました。API Gateway を使うと費用が発生します。

API Gateway の無料利用枠について

  • 12 か月間の無料利用枠:
    • AWS アカウント作成後 12 か月間有効
    • 一定量までの API コール、データ転送が無料
  • 12 か月経過後:
    • 無料枠終了後は利用量に応じて課金

重要なポイント:

  • 12か月を超えると無料利用枠は適用されない

Alexaスキル「アレクサ、部屋の温度を教えて」を実現のための第9歩になります。(最終章だと思います。)

Raspberry Pi でグローバルIPを取得し、AWS Lambda に送信する手順 でルータのIPアドレスを自動で取得することに成功しました。しかし、問題があります。
  • 1つ目の問題は、Lambda関数がセッション終了後にIPアドレスを保持できず、スキルがエラーになることです。
  • 2つ目は、Lambda関数が常に動作していないと、Alexaスキルが正常に動作しないことです。

本記事はこの解決策を作った記録です。Google Gemini Logoを使いました。

Lamda関数はスキルを呼び出すと動きだします。常に動いていることはありません。自動で取得したルータのグローバルIPアドレスを使って、Blynk serverにリクエストする流れは、今までどうりです。


目次
  1. 最新のIPアドレスを維持するメカニズム
  2. 手順:DynamoDBの利用
  3. 1. Pythonスクリプト(評価用)
  4. 2. Lambda関数の変更
    1. 2.1 DynamoDBテーブルの作成:
    2. 2.2 Lambda Layerを作成
      1. 2.2.1 Node.js環境の構築
      2. 2.2.2 AWS SDKのインストール:
      3. 2.2.3 zipファイルの作成手順
      4. 2.2.4 Layerの作成:
      5. 2.2.5 レイヤーの関連付け方法
      6. 2.2.6 IAMロールの作成
    3. 3. Lambda関数の作成

最新のIPアドレスを維持するメカニズム


現状の課題は、Raspberry PiからLambda関数に渡されたIPアドレスが、Lambda関数の実行終了とともに消失してしまうことです。このため、次のIPアドレスが送信されるまでの間、AlexaスキルからLambda関数を呼び出すとエラーが発生します。また、Lambda関数が常に実行されている必要があり、リソースの無駄が発生しています。

これらの課題を解決するためには、次の方法が考えられます。
  • IPアドレスを保管する場所(データベース)を設け、取得したIPアドレスをこれに格納する。
  • スキルが呼ばれ、Lambda関数がIPアドレスを必要なときに格納からIPアドレスを取り出す。
この時の格納場所としては、以下が考えられます。
  • Raspberry pi が取得したIPアドレスのログ記録
  • AWSのDynamoDBに最新のIPアドレスを格納

Lambda関数と同列に構築できるので、DynamoDBを使用することにします。

方法 メリット デメリット
SSHで接続 シンプルで直感的
リアルタイムアクセス可能
デバッグが容易
セキュリティリスク
(公開鍵、秘密鍵)
IPアドレスの変更に依存
スケーラビリティに制限
DynamoDBを使用 永続的なデータ保存
高い可用性とスケーラビリティ自動化とスクリプト化が可能
コストが発生する場合がある
設定と管理が複雑
若干のラグタイム


手順:DynamoDBの利用

  1. Raspberry PiのPythonスクリプトの変更:DynamoDBへのIPアドレス保存
  2. Lambda関数の変更:DynamoDBから最新のIPアドレスを取得
    1. DynamoDBテーブルの作成:IPアドレスを保存するためのテーブルを作成
    2. Lambda Layerを作成する
      1. Node.js環境の構築:
      2. aws-sdkのインストール: Lambda関数のデプロイパッケージにaws-sdkを追加
      3. zipファイルの作成: aws-sdkのインクルード
      4. Layerの作成: aws-sdkを含むパッケージをLambdaにアップロード
      5. Lambda関数へのLayerの関連付け
      6. IAMロールの作成
    3. Lambda関数の作成

1. Pythonスクリプト(評価用)

元のPython スクリプトの report_ip.py を大幅に変更して、report_ip2.py を作ります。なお、ファイルのエンコーディングが UTF-8 以外の形式で保存されている場合は、このブログ記事:(2-5) エラーの修正 2に沿ってエンコードします。
  • IPアドレスをpayloadに含めてLambda関数に送信。
  • 送信日時とIPアドレス、レスポンスコードをログに出力するように変更。

※ コードは評価用としてwhileループと time.sleep で10分毎に出力させています。Lambda関数が完成して正規に運用するときはこのループを削除します。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
import json
import datetime
import time

# AWS API Gateway のエンドポイントと API キー
LAMBDA_ENDPOINT = "https://your-api-gateway-url.amazonaws.com/prod/ip-report"
API_KEY = "YOUR_API_KEY"  # 実際の API キーに置き換えてください

def get_global_ip():
    """checkip.amazonaws.com からグローバル IP アドレスを取得する"""
    try:
        response = requests.get("https://checkip.amazonaws.com")
        return response.text.strip()
    except Exception as e:
        print(f"Error getting global IP: {e}")
        return None

def send_ip_to_lambda(ip):
    """取得した IP アドレスを Lambda に送信する"""
    try:
        payload = {
            'session': {
                'new': True,
                'sessionId': 'SessionId',
                'application': {
                    'applicationId': 'amzn1.ask.skill.[unique-value-here]'
                },
                'attributes': {},
                'user': {
                    'userId': 'amzn1.ask.account.[unique-value-here]'
                }
            },
            'request': {
                'type': 'LaunchRequest',
                'requestId': 'EdwRequestId',
                'locale': 'ja-JP'
            },
            'ip': ip # IPアドレスをpayloadに含める
        }
        headers = {'Content-Type': 'application/json', 'x-api-key': API_KEY}
        response = requests.post(LAMBDA_ENDPOINT, json=payload, headers=headers)
        log_message = f"{datetime.datetime.now()} - Sent IP: {ip}, Response: {response.status_code}"
        print(log_message) # ログを標準出力
    except Exception as e:
        log_message = f"{datetime.datetime.now()} - Error sending IP to Lambda: {e}"
        print(log_message) # ログを標準出力

if __name__ == "__main__":
    while True:# 評価用、繰り返し
        ip = get_global_ip()
        if ip:
            send_ip_to_lambda(ip)
        time.sleep(600)  # 評価用、10分ごとに実行
Python

このスクリプトは、Alexa スキルが Lambda 関数を呼び出す際に送信するイベントを模倣したペイロードを作成し、IP アドレスをそのペイロードに含めて Lambda 関数に送信するものです。

applicationId と userId は、Alexa スキルとユーザーを識別するための ID です。

applicationId

  • Alexa スキルを識別するための ID です。
  • Alexa Developer Console でスキルを作成した際に発行されます。
  • 通常は amzn1.ask.skill.[skillId] のような形式です。
  • [unique-value-here] の部分を実際のスキル ID に置き換えてください。

userId

  • Alexa ユーザーを識別するための ID です。
  • Amazon アカウントに紐づけられています。
  • 通常は amzn1.ask.account.[accountId] のような形式です。
  • [unique-value-here] の部分を実際のユーザーアカウント ID に置き換えてください。

注意点

  • payload は、Alexa スキルから Lambda 関数に送信されるデータの塊です。
  • applicationId と userId は、Alexa スキルとユーザーを識別するための ID です。
  • これらの ID は、必須ではありませんが、スキルの機能を拡張するために利用されます。

今回のスクリプトでは、IP アドレスを Lambda 関数に送信することが主な目的であるため、applicationId と userId を設定しなくても、スキルは問題なく動作します。

2. Lambda関数の変更

2.1 DynamoDBテーブルの作成:

DynamoDBを使用するには、IPアドレスを保存するためのテーブルを作成する必要があります。以下にDynamoDBのテーブルを設定し、IPアドレスを保存・取得するための具体的な手順を示します

  1. AWS Management Consoleにログインし、「DynamoDB」を選択します。
  2. 「テーブルを作成」をクリックします。
  3. テーブル名を「IPTable」とし、パーティションキーを「id」とします。パーティションキーのタイプは「strings」に設定します。
  4. テーブルの作成を完了します。


2.2 Lambda Layerを作成

Lambda Layerは、Lambda関数が利用できるライブラリや依存関係をまとめたものです。AWS SDKをLayerとして作成し、Lambda関数に関連付けることで、この問題を解決できます。

2.2.1 Node.js環境の構築

まず、Node.jsをインストールする必要があります。以下の手順に従って、Node.jsをインストールしてください。

  1. Node.jsのダウンロードとインストール:

    • Node.jsの公式ウェブサイトにアクセスし、最新のLTSバージョンをダウンロードします。

    • インストーラーを実行して、画面の指示に従ってインストールします。

    • </
  2. 環境変数の設定:
  • インストールが完了したら、コマンドプロンプトを再度開き、npmコマンドが認識されるか確認します。

PS C:\WINDOWS\system32> node -v
PS C:\WINDOWS\system32> npm -v
PowerShell

  1. エラー対応:
このようなエラーが出ることがあります。
PS C:\WINDOWS\system32> node -v
v22.14.0
PS C:\WINDOWS\system32> npm -v
npm : このシステムではスクリプトの実行が無効になっているため、ファイル C:\Program Files\nodejs\npm.ps1 を読み込むことが
できません。詳細については、「about_Execution_Policies」(https://go.microsoft.com/fwlink/?LinkID=135170) を参照してくだ
さい。
発生場所 行:1 文字:1
+ npm -v
+ ~~~
    + CategoryInfo    : セキュリティ エラー: (: ) []、PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess
Cmd


スタートメニューからPowerShellを検索し、「管理者として実行」を選択して起動します。

実行ポリシーの変更: 以下のコマンドを実行して、現在の実行ポリシーを確認します。

PS C:\WINDOWS\system32> Get-ExecutionPolicy
PowerShell

実行ポリシーがRestricted(制限あり)になっている場合は、以下のコマンドを実行して実行ポリシーを変更します。

PS C:\WINDOWS\system32> Set-ExecutionPolicy RemoteSigned -Force
PowerShell
このコマンドを実行すると、ローカルで作成したスクリプトは実行可能になりますが、インターネットからダウンロードしたスクリプトは署名が必要になります。
PS C:\WINDOWS\system32> npm -v
PowerShell
の再実行:

実行ポリシーを変更したら、PowerShellを再起動するか、以下のコマンドを実行して環境を更新します。

PS C:\WINDOWS\system32> $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine");
PowerShell

その後、npm -vを再度実行してnpmのバージョンが表示されることを確認してください。
PS C:\WINDOWS\system32> npm -v
10.9.2
PowerShell

2.2.2 AWS SDKのインストール:

任意のディレクトリ(たとえば、lambda_function)に移動し、以下のコマンドを実行してAWS SDKをインストールします。
PS C:\WINDOWS\system32> mkdir lambda_function
PS C:\WINDOWS\system32> cd lambda_function
PS C:\WINDOWS\system32\lambda_function> mkdir node_modules
PS C:\WINDOWS\system32\lambda_function> npm install aws-sdk --save-dev
PowerShell

このコマンドを実行すると、node_modulesというディレクトリが作成され、AWS SDKがその中にインストールされます。

2.2.3 zipファイルの作成手順

  1. nodejsディレクトリの作成:
    node_modulesディレクトリと同じ階層に、nodejsという名前のディレクトリを作成します。
  1. node_modulesディレクトリの移動:
    node_modulesディレクトリをnodejsディレクトリの中に移動します。
  1. nodejsディレクトリの圧縮:
    nodejsディレクトリをzipファイルに圧縮します。
    コマンド例:
Compress-Archive -Path nodejs -DestinationPath aws-sdk-layer.zip
PowerShell

上記手順で作成したzipファイルの構成を示します。圧縮は \nodejs フォルダを圧縮し、楚々の構成は、\nodejs\node_modules\aws-sdk です。


  • 2.2.4 Layerの作成:

    1. AWSコンソールにログインし、Lambda > Layers > Create layer に移動します。
    2. Layer nameに適当な名前(例: aws-sdk-layer)を入力します。
    3. Upload .zip fileを選択し、先ほど作成した nodejs ディレクトリを圧縮したzipファイルをアップロードします。
    4. Compatible runtimesで、Lambda関数で使用しているランタイム(例: nodejs2.2.x)を選択します。
    5. Create layerをクリックしてLayerを作成します。



    2.2.5 レイヤーの関連付け方法

    1. Lambda > Functions に移動し、該当のLambda関数を選択します。
    2. 「コード」タブを選択します。
    3. 画面下部の「レイヤー」パネルまでスクロールします。
    4. 「レイヤーの追加」をクリックします。
    5. 「ARNを指定」のテキストボックスに、作成したレイヤーのARNを直接入力します。
    6. レイヤーのARNは、Lambda > Layers で確認できます。
    7. ARNの形式は arn:aws:lambda:<リージョン>:<アカウントID>:layer:<レイヤー名>:<バージョン> です。
    8. 「追加」をクリックします。
    9. 画面右上の「保存」をクリックして設定を保存します。


    2.2.6 IAMロールの作成

    ルートユーザーでLambda関数を使用する場合のIAMロールの設定手順は、以下の通りです。

    Lambda関数に付与するIAMロールを作成します。このロールには、Lambda関数の実行に必要な権限(AWS SDKへのアクセス権限、DynamoDBへのアクセス権限など)を付与します。

    1. AWSコンソールにログインし、IAM > ロール > ロールを作成 に移動します。
    2. 「Lambda」を選択し、「次のステップ」をクリックします。
    3. 必要なポリシーを選択します。
    4. AWS SDKへのアクセス権限: AWSLambdaBasicExecutionRole
    5. DynamoDBへのアクセス権限: AmazonDynamoDBFullAccess (必要に応じて適切なポリシーを選択)
    6. ロール名を入力し、「ロールを作成」をクリックします。

    3. Lambda関数の作成

    既報で作成したLambda関数を元にして、DynamoDBを使うための変更を加えたコードを示します。新たに作成したコードで、元コードを上書きします。

    'use strict';
    
    const AWS = require('aws-sdk');
    const dynamoDb = new AWS.DynamoDB.DocumentClient();
    const tableName = 'IPTable'; // DynamoDBのテーブル名
    const http = require('http');
    
    // --------------- Helpers that build all of the responses -----------------------
    
    // ... (buildSpeechletResponse, buildResponse関数は変更なし)
    function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
        return {
            outputSpeech: {
                type: 'PlainText',
                text: output,
            },
            card: {
                type: 'Simple',
                title: `SessionSpeechlet - ${title}`,
                content: `SessionSpeechlet - ${output}`,
            },
            reprompt: {
                outputSpeech: {
                    type: 'PlainText',
                    text: repromptText,
                },
            },
            shouldEndSession,
        };
    }
    
    function buildResponse(sessionAttributes, speechletResponse) {
        return {
            version: '1.0',
            sessionAttributes,
            response: speechletResponse,
        };
    }
    
    // --------------- Functions that control the skill's behavior -----------------------
    
    // ... (getWelcomeResponse, handleSessionEndRequest, createLocationAttributes関数は変更なし)
    function getWelcomeResponse(callback) {
        const sessionAttributes = {};
        const cardTitle = 'Welcome';
        const speechOutput = "二階の温度を教えてなどと問いかけると、それを答えます。";
        const repromptText = "私はこの部屋を見てるわよっ!何が知りたいのっ!   ってかっ";
        const shouldEndSession = false;
    
        callback(sessionAttributes,
            buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
    }
    
    function handleSessionEndRequest(callback) {
        const cardTitle = 'Session Ended';
        const speechOutput = 'Thank you for trying the Alexa Skills Kit sample. Have a nice day!';
        const shouldEndSession = true;
    
        callback({}, buildSpeechletResponse(cardTitle, speechOutput, null, shouldEndSession));
    }
    
    function createLocationAttributes(location) {
        return { location };
    }
    
    
    async function readTemperatureInSession(intent, session, callback) {
        const cardTitle = intent.name;
        const LocationSlot = intent.slots.Location;
        const MeasurementSlot = intent.slots.Measurement;
        let repromptText = '';
        let sessionAttributes = session.attributes || {};
        const shouldEndSession = false;
        let speechOutput = '';
        let body = '';
        const blynkport = '8080';
        let blynkAuthToken;
        let blynkPin;
    
        let location = LocationSlot.value || sessionAttributes.location || '二階';
        sessionAttributes.location = location;
    
        let ip;
    
        try {
            // DynamoDBからIPアドレスを取得
            const params = {
                TableName: tableName,
                Key: {
                    id: 'globalIP' // パーティションキーは固定値
                }
            };
            const data = await dynamoDb.get(params).promise();
            const item = data.Item;
    
            if (!item || !item.ipAddress) {
                console.error('IPアドレスがDynamoDBに存在しません。');
                speechOutput = 'IPアドレスが取得できませんでした。';
                repromptText = 'もう一度お試しください。';
                callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
                return;
            }
    
            ip = item.ipAddress; // DynamoDBから取得したIPアドレス
    
        } catch (error) {
            console.error(`DynamoDBからIPアドレスを取得中にエラーが発生しました: ${error}`);
            speechOutput = 'IPアドレスの取得中にエラーが発生しました。';
            repromptText = 'もう一度お試しください。';
            callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
            return; // エラー発生時は処理を中断
        }
    
    
        switch (location) {
            case '二階':
                blynkAuthToken = '********************************';
                break;
            case '仏間':
                blynkAuthToken = '********************************';
                break;
            case '屋根裏':
                blynkAuthToken = '********************************';
                break;
            default:
                speechOutput = '指定された場所が見つかりませんでした。';
                repromptText = '他の場所を指定してください。';
                callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
                return;
        }
    
        let measurement = MeasurementSlot.value || '温度';
        switch (measurement) {
            case '何度':
            case '気温':
            case '室温':
            case '温度':
                blynkPin = 'V0';
                break;
            case '湿気':
            case '湿度':
                blynkPin = 'V1';
                break;
            case '大気圧':
            case '気圧':
                blynkPin = 'V2';
                break;
            case '熱中度指数':
            case '熱中度':
            case '暑さ指数':
            case '暑さ度':
            case '暑さ':
                blynkPin = 'V4';
                break;
            default:
                speechOutput = '指定された測定項目が見つかりませんでした。';
                repromptText = '他の測定項目を指定してください。';
                callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
                return;
        }
    
        try {
            console.log(`Sending request to Blynk server with Auth Token: ${blynkAuthToken}, Pin: ${blynkPin}, IP: ${ip}`);
    
            const httpPromise = new Promise((resolve, reject) => {
                http.get({
                    host: ip,
                    path: `/${blynkAuthToken}/get/${blynkPin}`,
                    port: blynkport,
                }, (response) => {
                    response.on('data', (d) => {
                        body += d;
                    });
                    response.on('end', () => {
                        resolve('Done Sending');
                    });
                }).on('error', (e) => {
                    reject(e); // エラーをreject
                    console.error(`Blynkサーバーへのリクエストエラー: ${e}`); // エラーログ
                });
            });
    
            await httpPromise;
    
            console.log(`Received response from Blynk server: ${body}`);
    
            let info;
            try {
                info = parseFloat(JSON.parse(body)); // パースを試みる
            } catch (parseError) {
                console.error(`JSONパースエラー: ${parseError}, body: ${body}`);
                info = NaN; // パースに失敗したらNaNを設定
            }
    
            if (isNaN(info)) {
                speechOutput = '温度の取得に失敗しました。';
                repromptText = 'もう一度お試しください。';
                callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
            } else {
                // ... (温度表示処理)
                speechOutput = location + 'の ' + measurement + 'は ';
                repromptText = speechOutput;
                switch (measurement) {
                    default:
                    case '何度':
                    case '気温':
                    case '室温':
                    case '温度':
                        speechOutput += `${info.toFixed(1)}度 です。`;
                        repromptText += `${info.toFixed(1)}℃です。`;
                        break;
                    case '湿気':
                    case '湿度':
                        speechOutput += `${info.toFixed(1)}パーセント です。`;
                        repromptText += `${info.toFixed(1)}%です。`;
                        break;
                    case '大気圧':
                    case '気圧':
                        speechOutput += `${info.toFixed(0)}ヘクトパスカル です。`;
                        repromptText += `${info.toFixed(0)}hPaです。`;
                        break;
                    case '熱中度指数':
                    case '熱中度':
                    case '暑さ指数':
                    case '暑さ度':
                    case '暑さ':
                        let annotation = '';
                        if (info >= 31) {
                            annotation = '危険! ブラックです。';
                        } else if (info >= 28) {
                            annotation = '厳重警戒! レッドです。';
                        } else if (info >= 25) {
                            annotation = '警戒! オレンジです。';
                        } else if (info >= 21) {
                            annotation = '注意です。';
                        }
                        speechOutput += `${info.toFixed(0)}度 です。${annotation}`;
                        repromptText += `${info.toFixed(0)}℃です。${annotation}`;
                        break;
                }
                callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
            }
    
        } catch (error) {
            console.error(`温度取得処理全体のエラー: ${error}`);
            speechOutput = '温度の取得中にエラーが発生しました。';
            repromptText = 'もう一度お試しください。';
            callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
        }
    }
    
    
    // ... (onSessionStarted, onLaunch, onIntent, onSessionEnded関数は変更なし)
    function onSessionStarted(sessionStartedRequest, session) {
        console.log(`onSessionStarted requestId=${sessionStartedRequest.requestId}, sessionId=${session.sessionId}`);
    }
    
    function onLaunch(launchRequest, session, callback) {
        console.log(`onLaunch requestId=${launchRequest.requestId}, sessionId=${session.sessionId}`);
        getWelcomeResponse((sessionAttributes, speechletResponse) => {
            callback(sessionAttributes, speechletResponse);
        });
    }
    
    function onIntent(intentRequest, session, callback) {
        console.log(`onIntent requestId=${intentRequest.requestId}, sessionId=${session.sessionId}`);
        const intent = intentRequest.intent;
        const intentName = intentRequest.intent.name;
    
        if (intentName === 'GetMeasurement') {
            readTemperatureInSession(intent, session, callback);
        } else if (intentName === 'AMAZON.HelpIntent') {
            getWelcomeResponse((sessionAttributes, speechletResponse) => {
                callback(sessionAttributes, speechletResponse);
            });
        } else if (intentName === 'AMAZON.StopIntent' || intentName === 'AMAZON.CancelIntent') {
            handleSessionEndRequest((sessionAttributes, speechletResponse) => {
                callback(sessionAttributes, speechletResponse);
            });
        } else {
            throw new Error('Invalid intent');
        }
    }
    
    function onSessionEnded(sessionEndedRequest, session) {
        console.log(`onSessionEnded requestId=${sessionEndedRequest.requestId}, sessionId=${session.sessionId}`);
        // callbackを呼び出す必要はありません。
        // context.succeed()も不要です。
    }
    
    exports.handler = (event, context) => {
        try {
            console.log('Event:', JSON.stringify(event));
    
            let globalIP;
            if (event.session && event.session.attributes && event.session.attributes.globalIP) {
                globalIP = event.session.attributes.globalIP;
                console.log(`Using globalIP from session attributes: ${globalIP}`);
                continueProcessing(event, context); // IPアドレス取得後に実行したい処理
            } else {
                console.log("globalIP not found in session attributes. Retrieving from DynamoDB or IP");
                // IPアドレスの取得処理 (DynamoDB or event.ip)
                if (event.ip) {
                    globalIP = event.ip;
                    event.session.attributes.globalIP = globalIP; // セッション属性に保存
                    console.log(`IP from event: ${globalIP}`);
                    continueProcessing(event, context); // IPアドレス取得後に実行したい処理
                } else {
                    getIPAddressFromDynamoDB(event, context);
                }
            }
    
        } catch (e) {
            console.error(`Exception: ${e}`);
            context.fail(`Exception: ${e}`);
        }
    };
    
    function updateIPAddress(event, context) {
        const params = {
            TableName: tableName,
            Item: {
                id: 'globalIP',
                ipAddress: event.ip
            }
        };
    
        dynamoDb.put(params).promise()
            .then(() => {
                console.log(`Successfully updated IP address in DynamoDB: ${event.ip}`);
                event.session.attributes.globalIP = event.ip;
                console.log(`Updated globalIP to: ${event.ip}`);
                continueProcessing(event, context);
            })
            .catch(err => {
                console.error(`Error updating IP address in DynamoDB: ${err}`);
                context.fail(`Error updating IP address: ${err}`);
            });
    }
    
    function getIPAddressFromDynamoDB(event, context) {
        const params = {
            TableName: tableName,
            Key: {
                id: 'globalIP'
            }
        };
    
        dynamoDb.get(params).promise()
            .then(data => {
                if (data.Item) {
                    const ipAddress = data.Item.ipAddress;
                    event.session.attributes.globalIP = ipAddress;
                    console.log(`Retrieved IP address from DynamoDB: ${ipAddress}`);
                    continueProcessing(event, context);
                } else {
                    console.error('IP address not found in DynamoDB.');
                    context.fail('IP address not found.');
                }
            })
            .catch(err => {
                console.error(`Error retrieving IP address from DynamoDB: ${err}`);
                context.fail(`Error retrieving IP address: ${err}`);
            });
    }
    
    function continueProcessing(event, context) {
        if (event.session && event.session.new) {
            onSessionStarted({ requestId: event.request.requestId }, event.session);
        }
        if (event.request && event.request.type) {
            if (event.request.type === 'LaunchRequest') {
                onLaunch(event.request, event.session, (sessionAttributes, speechletResponse) => {
                    context.succeed(buildResponse(sessionAttributes, speechletResponse));
                    console.log('LaunchRequest succeeded');
                });
            } else if (event.request.type === 'IntentRequest') {
                onIntent(event.request, event.session, (sessionAttributes, speechletResponse) => {
                    context.succeed(buildResponse(sessionAttributes, speechletResponse));
                    console.log('IntentRequest succeeded');
                });
            } else if (event.request.type === 'SessionEndedRequest') {
                onSessionEnded(event.request, event.session);
                context.succeed();
                console.log('SessionEndedRequest succeeded');
            }
        } else {
            console.error('event.request が見つかりません。');
            context.fail('event.request が見つかりません。');
        }
    }
    
    // ... (onSessionStarted, onLaunch, onIntent, onSessionEnded, buildResponse, buildSpeechletResponseなどの関数は省略)
    Python

    == 文末 ==

    Powered by Blogger | Designed by QooQ

    keyboard_double_arrow_down

    keyboard_double_arrow_down