Particle for alexa smart home skill (2)

上一章介紹了開發所需的基本軟硬件,從這一章開始介紹每一步的過程。



第2章、如何建立 Lambda 功能


1) 打開 aws.amazon.com, 登入到控制臺 (賬號區域需要選擇US East (N. Virginia) 才可以正常使用)

  


2) 選擇 Lambda

  


  3) 點擊 Create Lambda function

  


4) 輸入篩選字符  smart , 點擊 alexa-smart-home-skill-adapter

  


5) 配置觸發器, 這一欄填 alexa skill 的 application id, 但目前我們還沒有建好 alexa skill , 所以先隨便輸入 test001,直接點 Next.

  


6) 配置 Lambda 服務, 輸入名稱, Rutime 欄位選 Node.js 4.3 


7) 將以下代碼填入 CODE 區域, 用來提供基礎框架(發現設備、控制設備的命令清單)和 2個燈泡名稱 Bedroom light 和 Kitchen light,

語言類別:NodeJS

var https = require('https');

var kitchenLightApplianceId = "A146-3456-b31d-8ec4c146c5ea";
var bedroomLightApplianceId = "A146-3456-b31d-8ec4c146c5eb";

var particleServer = "api.particle.io";
var particlePath = "/v1/devices/";

/**
 * Main entry point.
 * Incoming events from Alexa Lighting APIs are processed via this method.
 */
exports.handler = function(event, context) {

    log('Input', event);

    switch (event.header.namespace) {
        
        /**
         * The namespace of "Discovery" indicates a request is being made to the lambda for
         * discovering all appliances associated with the customer's appliance cloud account.
         * can use the accessToken that is made available as part of the payload to determine
         * the customer.
         */
        case 'Alexa.ConnectedHome.Discovery':
            handleDiscovery(event, context);
            break;

            /**
             * The namespace of "Control" indicates a request is being made to us to turn a
             * given device on, off or brighten. This message comes with the "appliance"
             * parameter which indicates the appliance that needs to be acted on.
             */
        case 'Alexa.ConnectedHome.Control':
            handleControl(event, context);
            break;

            /**
             * We received an unexpected message
             */
        default:
            log('Err', 'No supported namespace: ' + event.header.namespace);
            context.fail('Something went wrong');
            break;
    }
};

/**
 * This method is invoked when we receive a "Discovery" message from Alexa Connected Home Skill.
 * We are expected to respond back with a list of appliances that we have discovered for a given
 * customer. 
 */
function handleDiscovery(accessToken, context) {

    /**
     * Crafting the response header
     */
    var headers = {
        namespace: 'Alexa.ConnectedHome.Discovery',
        name: 'DiscoverAppliancesResponse',
        payloadVersion: '2'
    };

    /**
     * Response body will be an array of discovered devices.
     */
    var appliances = [];

    var kitchenLight = {
        applianceId: kitchenLightApplianceId,
        manufacturerName: 'KRV',
        modelName: 'ParticleLight',
        version: 'VER01',
        friendlyName: 'Kitchen Light',
        friendlyDescription: 'Particle light in kitchen',
        isReachable: true,
        actions:[
            "incrementPercentage",
            "decrementPercentage",
            "setPercentage",
            "turnOn",
            "turnOff"
        ],
        additionalApplianceDetails: {
            /**
             * OPTIONAL:
             * We can use this to persist any appliance specific metadata.
             * This information will be returned back to the driver when user requests
             * action on this appliance.
             */
            fullApplianceId: '2cd6b650-c0h0-4062-b31d-7ec2c146c5ea',
            deviceId: "39003d000447343232363230"
        }
    };
    
    var bedroomLight = {
        applianceId: bedroomLightApplianceId,
        manufacturerName: 'KRV',
        modelName: 'ParticleLight',
        version: 'VER01',
        friendlyName: 'Bedroom Light',
        friendlyDescription: 'Particle light in bedroom',
        isReachable: true,
        actions:[
            "incrementPercentage",
            "decrementPercentage",
            "setPercentage",
            "turnOn",
            "turnOff"
        ],
        additionalApplianceDetails: {
            /**
             * OPTIONAL:
             * We can use this to persist any appliance specific metadata.
             * This information will be returned back to the driver when user requests
             * action on this appliance.
             */
            fullApplianceId: '2cd6b650-c0h0-4062-b31d-7ec2c146c5eb',
            deviceId: "39003d000447343232363230"
        }
    };
    
    appliances.push(kitchenLight);
    appliances.push(bedroomLight);

    /**
     * Craft the final response back to Alexa Connected Home Skill. This will include all the 
     * discoverd appliances.
     */
    var payloads = {
        discoveredAppliances: appliances
    };
    var result = {
        header: headers,
        payload: payloads
    };

    log('Discovery', result);

    context.succeed(result);
}

/**
 * Control events are processed here.
 * This is called when Alexa requests an action (IE turn off appliance).
 */
function handleControl(event, context) {
    if (event.header.namespace === 'Alexa.ConnectedHome.Control') {

        /**
         * Retrieve the appliance id and accessToken from the incoming message.
         */
        var accessToken = event.payload.accessToken;
        var applianceId = event.payload.appliance.applianceId;
        var deviceid = event.payload.appliance.additionalApplianceDetails.deviceId;
        var message_id = event.header.messageId;
        var param = "";
        var index = "0";
        var state = 0;
        var confirmation;
        var funcName;
        
        log("Access Token: ", accessToken);
        log("DeviceID: ", deviceid);

        if(event.header.name == "TurnOnRequest"){
            state = 1;
            confirmation = "TurnOnConfirmation";
            funcName = "onoff";
        }
        else if(event.header.name == "TurnOffRequest"){
            state = 0;            
            confirmation = "TurnOffConfirmation";
            funcName = "onoff";
        }
        else if(event.header.name == "SetPercentageRequest"){
            state = event.payload.percentageState.value;
            confirmation = "SetPercentageConfirmation";
            funcName = "setvalue";
        }
        else if(event.header.name == "IncrementPercentageRequest"){
            var increment = event.payload.deltaPercentage.value;
            
            state += increment;
            
            if(state > 100){
                state = 100;
            }
            
            confirmation = "IncrementPercentageConfirmation";
            funcName = "setvalue";
        }
        else if(event.header.name == "DecrementPercentageRequest"){
            var decrement = event.payload.deltaPercentage.value;
            
            state -= decrement;
            
            if(state < 0){
                state = 0;
            }
            
            confirmation = "DecrementPercentageConfirmation";
            funcName = "setvalue";
        }
        
        log('applianceId', applianceId);
        
        if(applianceId == kitchenLightApplianceId){
            index = "0";
        }
        else if(applianceId == bedroomLightApplianceId){
            index = "1";
        }
        
        param = index + "=" + state;
        
        var options = {
            hostname: particleServer,
            port: 443,
            path: particlePath + deviceid + "/" + funcName,
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };
        
        log(options);
        accessToken = "35311bb780d44f27724e58d66353e3c1d1f9c7e4";
        var data = "access_token=" + accessToken + "&" + "args=" + param;
        
        log(data);

        var serverError = function (e) {
            log('Error', e.message);
            context.fail(generateControlError('TurnOnRequest', 'DEPENDENT_SERVICE_UNAVAILABLE', 'Unable to connect to server'));
        };

        var callback = function(response) {
            var str = '';

            response.on('data', function(chunk) {
                str += chunk.toString('utf-8');
            });

            response.on('end', function() {
                log('Return Value');
                log(str);
                
                var headers = {
                    namespace: 'Alexa.ConnectedHome.Control',
                    name: confirmation,
                    payloadVersion: '2',
                    messageId: message_id
                };
                var payloads = {
                    
                };
                var result = {
                    header: headers,
                    payload: payloads
                };

                context.succeed(result);
            });

            response.on('error', serverError);
        };

        var req = https.request(options, callback);
            
        req.on('error', serverError);
        
        req.write(data);
        req.end();
    }
}

/**
 * Utility functions.
 */
function log(title, msg) {
    console.log(title + ": " + msg);
}

function generateControlError(name, code, description) {
    var headers = {
        namespace: 'Control',
        name: name,
        payloadVersion: '1'
    };

    var payload = {
        exception: {
            code: code,
            description: description
        }
    };

    var result = {
        header: headers,
        payload: payload
    };

    return result;
}

8) Role 選擇 lambda_basic_execution, 高級設置不做修改, 點擊 Next

  


9) 點擊 Create function


10) 模擬測試, 點擊 Test 

  


11)Sample event template 選擇 Alexa Smart Home - Control, 將 "namespace" 的值改為 Alexa.ConnectedHome.Control

  


  以下畫面表示 Alexa.ConnectedHome.Control 輸入測試OK, 當然可也可以測試 Alexa.ConnectedHome.Discovery, (通過修改 "namespace" 的值)

  


  建立完成后, 在Lambda  function 列表中可以看到 


  到此, Lambda 功能建立完成, 其中的觸發器我們暫時命名為 test001, 要等建立好 alexa skill 后重新進行綁定.

  另外需要保存 ARN 的值,等到建立 alexa skill 的時候要用到.  


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值