絖綛 N@i.jp  昨日:00015902
 今日:00014710
 総計:00151525
keywords
管理者専用
  Post   Add link   Control Panel 































新しいトピック
最新:11/14 16:41


新しいコメント
最新:07/28 16:47






管理人へMAIL

プライバシーポリシー

Alexa(amazon Echo)のIRKitスキルを作る(4)

AWS Lambdaを作ります


3.3 AWS Lambdaを作成する

 開発者コンソールの方は一旦置いといて、次はAWS Lambda(ラムダ)を作成します。AWSコンソールにサインインして、

左上のAWSサービス欄に「Lambda」と入力して行きます。すると選択可能なサービスがプルダウン表示され、「La」あたりまで入力すると「Lambda サーバーレスでコードを実行」が表示されて選択できるようになりますので、これをクリックします。

 左ペインで「関数」をクリックし、「関数の作成」ボタンをクリックします。

 関数の作成では、関数を「一から作成」することと「設計図」を基に作成することができます。ここでは「設計図」を 基に作成することにし、設計図には「alexa-skill-kit-sdk-factskill」を選択します。これはNode.js 6.10で記述されたシンプルな設計図(雛型。英語だとBlue Print (青写真) と言うようです)です。選択したら「設定」ボタンをクリックします。

 基本的な情報では以下を入力します。

  • 名前
    関数の名前です。関数名は後から変更することは出来ませんので、お試しだからと言って「Sample」とか「Test」と言った 名前は避けましょう。関数名には半角の英数字、記号が使え、大文字小文字は区別されます。
    命名規約などは特に無いようですので、ここでは「myIRKitControl」としています。
  • ロール
    ロールはこの関数の権限(アクセス権)を定義するもので、Lambda関数からAWSの資源にアクセスする場合などに必要になってきます。が、ここでは深く考えず、トレーニングの第1回で作成したロールを使うため「既存のロールを選択」を選びます。
  • 既存のロール
    既存のロールには「lambda_basic_execution」を選択します(このロールでもCloudWatchログへのアクセス権限を持っていますので、今はこれで充分です)。

 その下にはLambda関数コードが表示されていますので、ざっと眺めてみることをお勧めします。最低限必要なハンドラ、インテントや、多国語化の方法などが分かります(そして、少しだけ間違いもあります ^^;)。
 眺め終ったら、右下の「関数の作成」ボタンをクリックします。

 これでLambda関数「myIRKitControl」が作成されました。右上には本関数固有のARN識別子が表示されています。これは後に、開発者コンソールで作成したスキルと紐付けるために使います。
 次にトリガーを設定します。[左側のリストからトリガーを追加します]と書いてある枠をクリックして、左側にあるリストから「Alexa Skills Kit」を選択します。

 トリガーに「Alexa Skills Kit」が設定されたら「追加」ボタンをクリック。

 これで関数コードを作成する用意ができました。Webブラウザ上で関数コードを直接編集しても良いし、第1回のトレーニングでやったのと同じようにZIPファイルにしてアップロードすることもできます。今回は直接編集してしまいましょう。「コードをインラインで編集」を選んで、折角の設計図ですが、以下をコピペして"index.js"のコードを置き換えてしまいます(でも設計図の基本構造は保っていますよ)。

'use strict';
 
const Alexa = require('alexa-sdk');
 
const APP_ID = process.env.IRKit_APPID;  // IRKit app ID

// IRKitデバイス情報
const clientkey = process.env.My_ClientKey;
const deviceid = process.env.My_DeviceID;

// リモコン信号
const lightIR = {
  on: { "format":"raw",
        "freq":38,
        "data":[18031,8755,1190,1037,1190,3228,1190,1037,1190,1037,1190,1037,
                1190,1037,1190,1037,1190,3228,1190,3228,1190,1037,1190,3228,
                1190,3228,1190,1037,1190,3228,1190,3228,1190,1037,1190,3228,
                1190,3228,1190,3228,1190,3228,1190,3228,1190,1037,1190,1037,
                1190,1037,1190,1037,1190,1037,1190,1037,1190,1037,1190,1037,
                1190,3228,1190,3228,1190,3228,1190,65535,0,18031,18031,4400,
                1190,65535,0,65535,0,60108,17421,4400,1190]
  },
  off: {"format":"raw",
        "freq":38,
        "data":[18031,8755,1190,1037,1190,3228,1190,1037,1190,1037,1190,1037,
                1190,1037,1190,1037,1190,3228,1190,3228,1190,1037,1190,3228,
                1190,3228,1190,1037,1190,3228,1190,3228,1190,1037,1190,1037,
                1190,3228,1190,3228,1190,3228,1190,3228,1190,1037,1190,1037,
                1190,1037,1190,3228,1190,1037,1190,1037,1190,1037,1190,1037,
                1190,3228,1190,3228,1190,3228,1190,65535,0,18031,18031,4400,
                1190,65535,0,65535,0,60108,17421,4400,1190]
  }
};

// 言語リソース
const languageStrings = {
    "ja": {     // 日本語
        translation: {
            WELCOME_MESSAGE: "ようこそ、アイアールキットリモコンで家電を制御します。何をしましょうか?",
            HELP_MESSAGE:    "アイアールキットリモコンで家電を制御します。",
            CANCEL_MESSAGE:  "アイアールキットリモコンを中止します。",
            STOP_MESSAGE:    "アイアールキットリモコンを終了します。",
            UNKNOWN_MESSAGE: "すみません、分かりません。",
            RETRY_MESSAGE:   "すみません、もう一度お願いします。",
            LIGHT_ON:        "明りを点けます。",
            LIGHT_OFF:       "明りを消します。",
        },
    },
};

// リモコン信号の送信
function sendIR(ir, callback) {
    var https = require("https");
    var qs = require("querystring");
    var postData = qs.stringify({
        clientkey: clientkey,
        deviceid: deviceid,
        message: JSON.stringify(ir)
    });
    var req = https.request({
        host: "api.getirkit.com",
        path: "/1/messages",
        method: "POST",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
            "Content-Length": postData.length
        }
    }, function (res) {
        callback(null, "success");
    });
    req.write(postData);
    req.end();
}

function onLightOn(callback) {
    sendIR(lightIR.on, callback);	// 明かりを点ける
}

function onLightOff(callback) {
    sendIR(lightIR.off, callback);	// 明かりを消す
}


const handlers = {
    'LaunchRequest': function () {
        this.emit(":ask", this.t("WELCOME_MESSAGE"));
    },
    'LightControl': function () {
        // 照明インテントのハンドラ
        var session = this.event.session;			// セッション
        var apid = session.application.applicationId;	// アプリケーションID
        var now = this.event.request.timestamp;        // 日付&時刻
        var intent = this.event.request.intent;		// インテント
        var onoff = intent.slots.Switch.value;		// スロット{Switch}の値
        switch(onoff){
            case 'オン':
            case '点け':
            case '点灯':
                this.emit(":tell", this.t("LIGHT_ON"));
                onLightOn(this.callback);
                break;
            case 'オフ':
            case '消す':
            case '消し':
            case '切る':
            case '消灯':
                this.emit(":tell", this.t("LIGHT_OFF"));
                onLightOff(this.callback);
                break;
            default:
                this.emit(":ask", this.t("RETRY_MESSAGE"));
                break;
        }
    },
    'AMAZON.HelpIntent': function () {
        this.emit(":ask", this.t("HELP_MESSAGE"));
    },
    'AMAZON.CancelIntent': function () {
        this.emit(":tell", this.t("CANCEL_MESSAGE"));
        this.callback(null);
    },
    'AMAZON.StopIntent': function () {
        this.emit(":tell", this.t("STOP_MESSAGE"));
        this.callback(null);
    },
    'Unhandled': function() {
        this.emit(":ask", this.t("UNKNOWN_MESSAGE"));
    }
};

// Lambda関数ハンドラー
// パラメタ
//  event: イベントデータ
//  context: ランタイム情報
//  callback: 呼び出し元へ情報を返すためのコールバック関数
exports.handler = function (event, context, callback) {
    var session = event.session;                    // セッション
    var apid = session.application.applicationId;   // アプリケーションID
    const alexa = Alexa.handler(event, context, callback);

    alexa.appId = APP_ID;
    // To enable string internationalization (i18n) features, set a resources object.
    alexa.resources = languageStrings;  // 言語リソースを設定
    alexa.registerHandlers(handlers);   // ハンドラを登録
    alexa.execute();
};
備考1:
実は既に IRKitの作者maaash.jpさんがAmazon AlexaにエアコンをつけてもらうでIRKitのLambdaを公開されています(設計図は違うもののようです)。自分のスキル不足で肝心のリモコン信号の送信関数がうまく作れなかったので、この部分については参考にさせていただきました。
備考2:
lightIRのon/offは自分のシーリングライトのリモコン信号です。この部分は適宜お使いの家電のリモコン信号で書き換えてください。

 汎用性に乏しいプログラムですが、環境変数を使って少しでも汎用性を高める工夫をしています。関数コードの編集画面の下にある環境変数の欄に、

  • IRKit_APPID
  • My_DeviceID
  • My_ClientKey

を追加します。
 IRKit_APPIDの値には、amazon開発者コンソールで作成したスキルのアプリケーションID(スキル固有の識別子)を設定します(「3.2 Alexa Skills Kitでスキルを作成する」を参照)。
 My_DeviceID、My_ClientKeyの値には、お手持ちの IRKitの clientkey, deviceid を設定してください。IRKitの clientkey, deviceid の取得は以下の方法で行います。

  1. LAN内にあるIRKitデバイス一覧を調べる
    本家Mac使いの方は、
    $ dns-sd -B _irkit._tcp
    Browsing for _irkit._tcp
    DATE: ---Sat 09 Dec 2017---
    20:22:15.294  ...STARTING...
    Timestamp     A/R    Flags  if Domain               Service Type         Instance Name
    20:22:15.429  Add        2   9 local.               _irkit._tcp.         irkitXXXX
    20:22:15.431  Add        2   9 local.               _irkit._tcp.         iRKitYYYY
    ^C
    $ 
    WindowsでApple Bonjourをインストールしてある場合は、
    C:>c:¥Windows¥System32¥dns-sd.exe -B _irkit._tcp
    Browsing for _irkit._tcp
    Timestamp     A/R Flags if Domain                    Service Type              Instance Name
    19:48:51.329  Add     2  4 local.                    _irkit._tcp.              iRKitXXXX
    19:48:51.344  Add     2  4 local.                    _irkit._tcp.              irkitYYYYY
    ^C
    C:>
    Linuxな人はavahiをインストールして、
    # avahi-browse -alt | grep irkit
    +   eth1 IPv4 irkitXXXX                                     _irkit._tcp          local
    +   eth1 IPv4 irkitYYYY                                     _irkit._tcp          local
  2. IRKitのIPアドレスを調べる
    本家Mac使いの場合は、
    $ dns-sd -G v4 irkitXXXX.local
    DATE: ---Sat 09 Dec 2017---
    20:23:33.949  ...STARTING...
    Timestamp     A/R Flags if Hostname                               Address                                      TTL
    20:23:34.115  Add     2  9 irkitXXXX.local.                       192.168.NN.MM                                10
    ^C
    $ 
    WindowsでApple Bonjourをインストールしてある場合、
    C:>c:¥Windows¥System32¥dns-sd.exe dns-sd -G v4 iRKitXXXX.local
    Timestamp     A/R Flags if Hostname                  Address                                      TTL
    19:57:54.032  Add     2  4 irkitXXXX.local.          192.168.NN.MM                                10
    ^C
    C:>
    Linuxな人は、
    # avahi-resolve-host-name irkitXXXX.local
    irkitXXXX.local	192.168.NN.MM
  3. 目的のIRKitのclienttokenを取得する
    $ curl -i "http://192.168.NN.MM/keys" -d '' -H "X-Requested-With: curl"
    HTTP/1.0 200 OK
    Access-Control-Allow-Origin: *
    Server: IRKit/3.0.0.0.g85190b1
    Content-Type: text/plain
    
    {"clienttoken":"Axxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
    Windows, Linuxな人はcurlをインストールして行ってください。
    [備考] 稀に以下のようにIRKitからの応答が無い場合があります。
    $ curl -i "http://192.168.NN.MM/keys" -d '' -H "X-Requested-With: curl"
    curl: (52) Empty reply from server
    この場合は、IRKitから電源ケーブルを抜き挿しし、一旦IRKitを再起動させると直るようです。
  4. clienttokenからclientkey, deviceid を取得する
    $ curl -i -d "clienttoken=Axxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "https://api.getirkit.com/1/keys"
    HTTP/1.1 200 OK
    Server: openresty
    Date: Sat, 09 Dec 2017 11:26:30 GMT
    Content-Type: application/json; charset=utf-8
    Content-Length: 94
    Connection: keep-alive
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Headers: X-Requested-With
    X-Content-Type-Options: nosniff
    
    {"deviceid":"nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn","clientkey":"mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm"} 
[続く]


< 過去の記事 [ 12月の プログラミング リスト ] 新しい記事 >

2017 calendar
12月
12
3456789
10111213141516
17181920212223
24252627282930
31


掲示板
最新:08/15 17:19


GsBlog was developed by GUSTAV, Copyright(C) 2003, Web Application Factory All Rights Reserved.