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































新しいトピック
最新:10/01 12:07


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






管理人へMAIL

プライバシーポリシー

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

スマートホームスキルとAWS Lambdaを作っていきます


4.4 Alexaスマートホームスキルを作る

 Alexaのスキルを作っていきます。途中まではカスタムスキルを作ったときの手順と同じですが、「4. スキル情報」から変わってきます。

  1. Amazon開発者コンソールにサインインします
  2. 「ALEXA」をクリックし、Alexa Skills Kitの「始める>」ボタンをクリック
  3. 「新しいスキルを追加する」ボタンをクリック
  4. スキル情報を以下のように設定します
    • スキルの種類:スマートホームスキルAPI
    • 言語:Japanese
    • スキル名:今回は「IRKitスマート照明」とでもしましょう
    • ペイロードのバージョン:v3(推奨)
    設定したら「保存」ボタンをクリックします。アプリケーションIDが割り付けられたら「次へ」をクリック。
  5. 対話モデル
    スマートホームスキルでは対話モデルを作る必要がないので、何もせず「次へ」ボタンをクリックします。
  6. 設定
    サービスエンドポイントのタイプは、スマートホームスキルの場合、必ずAWS LambdaのARN (Amazonリソースネーム)になります。
    デフォルトの欄にはまだ入力せず、ここで例によって一旦止めてAWS Lambdaの作成に移ります。開発者コンソールは開きっ放しにしておきます。

4.5 スマートホームスキルのLambdaを作成する

 以下の手順でLambda関数を作成します。

  1. AWSコンソールにサインインします
  2. リージョンを「アジアパシフィック(東京)」から「米国西部(オレゴン)」に変更します
    スマートホームスキルの言語が日本語の場合は、まだ「アジアパシフィック(東京)」リージョンではダメで、「米国西部(オレゴン)」にする必要があります(ワタシはこれでハマりました)。詳しいことがスマートホームスキルの作成手順Lambda関数を作成して追加するに書いてあるのですが、これをうっかり見落とすとスキルにLambdaのARNが設定できないという罠に落ちます。
  3. AWSサービスでLambdaを選択
  4. 「関数の作成」ボタンをクリック
  5. 「設計図」を基に関数を作成します
    「設計図」を選択し、設計図のフィルターに「alexa」と入力します。すると「alexa-smart-home-skill-adapter」が出てきますので、これを選択し「設定」ボタンをクリックします。
  6. 基本的な情報を設定します
    • 名前:今回は"MyIRKit_SmartLight"としましょうか
    • ロール:「既存のロールを選択」
    • 既存のロール:lambda_basic_execution
    • アプリケーション ID「4.4 Alexaスマートホームスキルを作る」で作成したスキルのアプリケーションIDを入力
    • トリガーの有効化:チェックを入れる
    情報を設定したら「関数の作成」ボタンをクリックします。関数が作成されるとトリガーに「Alexa Smart Home」が設定されているはずです。
  7. Lambdaのコードを編集します
    「関数コード」の「コードエントリタイプ」は「コードをインラインで編集」を選択してください。「ランタイム」は「Node.js 4.3」になっていると思いますので、これを「Node.js 6.10」に変えます。
    コード("index.js")の編集画面に、後述のLambdaコードをコピペします。
  8. 環境変数を設定します
    • My_IRKit_NAME:自分のIRKitの名前
    • My_DeviceID :カスタムスキルを作成した際にも使用したIRKitの deviceid です
    • My_ClientKey:カスタムスキルを作成した際にも使用したIRKitの clientkey です
  9. ARNをコピーします
    スキルと紐付けるため、ARNをコピーして控えておきます。

【Lambdaコード】

// IRKitデバイス情報
const IRKit_DEVICE = process.env.My_IRKit_NAME;
const clientkey = process.env.My_ClientKey;
const deviceid = process.env.My_DeviceID;
const IRKit_EndPoint_ID = IRKit_DEVICE + "-light-" + deviceid;  // 照明デバイスの識別子

// エラー情報
const sendError = Error("Send error");
const unknownError = Error("Unknown error");

// リモコン信号(*2)
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]
  },
};

exports.handler = function (request, context, callback) {
    var header = request.directive.header;
    var req_name = header.name;
    if (header.namespace === 'Alexa.Discovery' &&
        req_name === 'Discover') {
        log("DEGUG:", "Discover request", JSON.stringify(request));
        handleDiscovery(request, context, "");
    }
    else if (header.namespace === 'Alexa.PowerController') {
        var endpoint = request.directive.endpoint;
        var deviceId = endpoint.endpointId;         // 電源操作対象のデバイス識別子
        if (req_name === 'TurnOn' || req_name === 'TurnOff') {
            log("DEBUG:", "TurnOn or TurnOff Request", JSON.stringify(request));
            log("DEBUG:", "endpointId=", deviceId);
            handlePowerControl(request, context, callback);
        }
    }

    function handleDiscovery(request, context) {
        var payload = {
            "endpoints":
            [
                {
                    "endpointId": IRKit_EndPoint_ID,
                    "manufacturerName": "IRKit",
                    "friendlyName": "リビングの照明",	// このデバイス名で検出されます(*1)
                    "description": "リビングの照明をIRKitで操作できます。",
                    "displayCategories": ["LIGHT"],		// 照明器具
                    "cookie": {
                    },
                    "capabilities":
                    [
                        {
                          "type": "AlexaInterface",
                          "interface": "Alexa",
                          "version": "3"
                        },
                        {
                            "interface": "Alexa.PowerController",
                            "version": "3",
                            "type": "AlexaInterface",
                            "properties": {
                                "supported": [{
                                    "name": "powerState"	// 電源のオン・オフが可能
                                }],
                                "retrievable": true
                            }
                        }
                    ]
                }
            ]
        };
        var header = request.directive.header;
        header.name = "Discover.Response";
        log("DEBUG:", "Discovery Response: ", JSON.stringify({ header: header, payload: payload }));
        context.succeed({ event: { header: header, payload: payload } });
    }

    function log(message, message1, message2) {
        console.log(message + message1 + message2);
    }

    // リモコン信号の送信
    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) {
            var result = res.statusCode;
            if (result == 200) {
                console.log("res.statusCode=" + result);    // ログ出力
                callback(null, "success");                  // 送信成功
            }
            else {
                console.log(postData);                      // ログ出力
                console.log("res.statusCode=" + result);    // ログ出力
                callback(sendError);                        // 送信エラーを通知
            }
        });
        req.write(postData);
        req.end();
    }

    function handlePowerControl(request, context, callback) {
        // get device ID passed in during discovery
        var requestMethod = request.directive.header.name;
        // get user token pass in request
        //var requestToken = request.directive.endpoint.scope.token;
        var responseHeader = request.directive.header;
        var endpoint = request.directive.endpoint;
        var deviceId = endpoint.endpointId;         // 電源操作対象のデバイス識別子
        var powerResult;
        var ir;

        if (requestMethod === "TurnOn") {
            ir = LightIR.on;
            powerResult = "ON";
        }
        else if (requestMethod === "TurnOff") {
            ir = LightIR.off;
            powerResult = "OFF";
        }
        var contextResult = {
            "properties": [{
                "namespace": "Alexa.PowerController",
                "name": "powerState",
                "value": powerResult,
                "timeOfSample": "2017-12-24T16:20:50.52Z",
                "uncertaintyInMilliseconds": 0
            }]
        };
        responseHeader.namespace = "Alexa";
        responseHeader.name = "Response";
        responseHeader.messageId = responseHeader.messageId + "-R";
        var response = {
            context: contextResult,
            event: {
                header: responseHeader,
                endpoint: {
                    "endpointId": deviceId,
                }
            },
            payload: {}
        };
        sendIR(ir, function (error) {
            log("DEBUG:", "Alexa.PowerController ", JSON.stringify(response));
            if (error) {
                callback(error);
            }
            else {
                context.succeed(response);
            }
        });
    }
};
備考1:
このLambdaでは、デバイス名が「リビングの照明」になります。
備考2:
リモコン信号はご自分の家電の信号で書き換えてください。
備考3:
照明器具の場合、電源のオン・オフ以外にも輝度や色、色調を調整するような操作も可能にできます。詳しくは照明用のスマートホームスキルを構築するを参照してください。


< 過去の記事 [ 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.