一,前期准备材料
二,技能创建
https://developer.amazon.com/zh/alexa 登录上述网址,并登录您的账号,在下图选择你的技能创建
进去之后,点击create skill,技能名称输入您的技能名,语言默认(也可以选择你自己喜欢的语言,然而并不支持中文,所以。。。),模型选择 智能家居,然后点击创建技能。
三,技能设置
2.1 AWS Lambda ARN 设置 Your Skill ID 点击复制到文本,方便后面使用
2.2 Default endpoint* 这个是你在创建aws lambda函数时对应的表达式,在后面会给出具体的位置。
2.3 下面三个复选框 只是为了让你给不同的地区选择不同的区域,为了使用不同的语言版本用户时能够得到更好的体验
此处只使用默认的端点,不勾选其它的。
3.完成以上设置,请点击保存按钮。
四,lambda 函数的创建
1.登录您的lambda控制台,如果找不到lambda函数的具体位置,请点击aws-->计算-->选择lambda,或者直接搜索。
2.进入lambda控制台,点击创建功能,选择从新开始,输入名称,因为笔者是用java开发的,所以运行的哪一块就选择 java8
3.选择角色,若没有点击创建,具体流程就不再介绍了,https://developer.amazon.com/docs/smarthome/steps-to-build-a- smart-home-skill.html#create-an-iam-role-for-lambda
4.进行lambda配置(在配置前请确保右上角你的地区选择,因为有的地区的触发器没有smart home 选项),
在左侧的触发器,里面选择 alexa smart home,然后点击它,并进行配置,复制你的技能id,并添加。
5.点击右上角的保存
五,配置你的账户关联
在配置账户关联之前请确保2.2 步骤的默认端点已填写你刚才创建的lambda函数,
六,关于如何通过lambda向本地进行测试
如果我们在一个项目里面写业务逻辑,然后再进行上传jar包到lambda函数的话,有很多的确点,一方面就意味着你要重复的上传代码,如果你的网络允许你这样做的话,当我没说。另一方面,如果代码上传完你需要调试的话会很麻烦。
所以,我们可以这么做
// -*- coding: utf-8 -*- // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // Licensed under the Amazon Software License (the "License"). You may not use this file except in // compliance with the License. A copy of the License is located at // http://aws.amazon.com/asl/ // or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific // language governing permissions and limitations under the License. import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.Charset; import java.util.Scanner; import org.json.JSONObject; import com.amazonaws.services.lambda.runtime.Context; public class AlexaHandler { public static void handler(InputStream inputStream, OutputStream outputStream, Context context) { String request; try { System.out.println("----开始请求"); request = getRequest(inputStream); //System.out.println("Request:"); System.out.println("请求参数:"+request); String reqURL = "https://www.******/rest/alexa/S_Alexa_Gateway/postGateway"; // url参数转换 String url = UrlEncoderUntil.GetRealUrl(reqURL + "?request=" + request); // 响应内容 String responseData= GetSample(url); System.out.println("----结束请求"); System.out.println(responseData); outputStream.write(responseData.getBytes(Charset.forName("UTF-8"))); } catch (Exception e) { e.printStackTrace(); } } /** * 说明: 发送请求到后台(请求转发) 方法名: GetSample * * @param url * @return */ private static String GetSample(String url) { StringBuilder sb = new StringBuilder(); try { URL iurl = new URL(url); HttpURLConnection c = (HttpURLConnection) iurl.openConnection(); c.connect(); int status = c.getResponseCode(); switch (status) { case 200: case 201: case 202: BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); String line; while ((line = br.readLine()) != null) { sb.append(line + "\n"); } br.close(); } } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } @SuppressWarnings("unused") private static JSONObject GetResponse(String json) { InputStream inputStream = new ByteArrayInputStream(json.getBytes(Charset.forName("UTF-8"))); OutputStream outputStream = new OutputStream() { private StringBuilder sb = new StringBuilder(); @Override public void write(int b) throws IOException { this.sb.append((char) b); } public String toString() { return this.sb.toString(); } }; String responseString = outputStream.toString(); return new JSONObject(responseString); } /** * 说明:判断请求的是否有值,若没有值返回空 方法名: getRequest * * @param is * @return */ static String getRequest(java.io.InputStream is) { Scanner s = new Scanner(is).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; } }
import java.net.URLEncoder; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.StringTokenizer; public class UrlEncoderUntil { public static void main(String[] args)throws Exception { String str="http://nufm.dfcfw.com/EM_Finance2014NumericApplication/JS.aspx?type=CT&cmd=C._A&sty=FCOIATA&sortType=C&sortRule=-1&page=1&pageSize=70&js=var%20quote_123%3d{rank:[(x)],pages:(pc)}&token=7bc05d0d4c3c22ef9fca8c2a912d779c&jsName=quote_123&_g=0.5927966693718834"; String result=GetRealUrl(str); System.out.println(result); } //对url中的参数进行url编码 public static String GetRealUrl(String str) { try { int index = str.indexOf("?"); if (index < 0) return str; String query = str.substring(0, index); String params = str.substring(index + 1); Map map = GetArgs(params); //Map map=TransStringToMap(params); String encodeParams = TransMapToString(map); return query + "?" + encodeParams; } catch (Exception ex) { System.out.println(ex.getMessage()); } return ""; } //将url参数格式转化为map public static Map GetArgs(String params) throws Exception{ Map map=new HashMap(); String[] pairs=params.split("&"); for(int i=0;i<pairs.length;i++){ int pos=pairs[i].indexOf("="); if(pos==-1) continue; String argname=pairs[i].substring(0,pos); String value=pairs[i].substring(pos+1); value= URLEncoder.encode(value,"utf-8"); map.put(argname,value); } return map; } //将map转化为指定的String类型 public static String TransMapToString(Map map){ java.util.Map.Entry entry; StringBuffer sb = new StringBuffer(); for(Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) { entry = (java.util.Map.Entry)iterator.next(); sb.append(entry.getKey().toString()).append( "=" ).append(null==entry.getValue()?"": entry.getValue().toString()).append (iterator.hasNext() ? "&" : ""); } return sb.toString(); } //将String类型按一定规则转换为Map public static Map TransStringToMap(String mapString){ Map map = new HashMap(); java.util.StringTokenizer items; for(StringTokenizer entrys = new StringTokenizer(mapString, "&"); entrys.hasMoreTokens(); map.put(items.nextToken(), items.hasMoreTokens() ? ((Object) (items.nextToken())) : null)) items = new StringTokenizer(entrys.nextToken(), "="); return map; } }
通过以上的代码,你就可以轻松的把请求转发到你的本地去,那样就方便多了。
后台接收lambda请求的方法。。。
package com.cn.whirlpool.services.alexaIot; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.ext.Provider; import org.apache.commons.lang3.StringUtils; import org.codehaus.jettison.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import com.cn.whirlpool.services.DbService; import com.cn.whirlpool.services.RedisService; import Utils.UicJsonUtils; import antlr.Token; /** * 说明: S_DingDong_Gateway * @author author * @date 2018年9月10日 */ @SuppressWarnings("unused") @Transactional @Component @Provider @Path("/alexa/S_Alexa_Gateway") public class S_Alexa_Gateway { @Autowired private AlexaResponse alexaResponse; @Autowired private S_Alexa_Discovery s_Alexa_Discovery; @Autowired private S_Alexa_Controller s_Alexa_Controller; private static Logger log = LoggerFactory.getLogger(S_Alexa_Gateway.class); DbService redis=RedisService.getInstance(); @SuppressWarnings("unused") @GET @Path("/postGateway/") public JSONObject postGateway(@Context HttpServletRequest request, @Context HttpServletResponse response) throws Exception { JSONObject jsonObject =new JSONObject(); //打印请求的参数,这样方便查看,后面删掉 showParams(request); // 用来接收返回信息的对象信息 AlexaResponse alexaResponse = null; //处理接收的参数 String requestParam = request.getParameter("request"); // 接收请求信息 JSONObject jsonRequest = new JSONObject(requestParam); JSONObject directive = (JSONObject) jsonRequest.get("directive"); JSONObject header = (JSONObject) directive.get("header"); JSONObject payload = (JSONObject) directive.get("payload"); String namespace = header.optString("namespace", "INVALID"); String correlationToken = header.optString("correlationToken", "INVALID"); //客户的授权码 String code = null; //客户的访问令牌 String token = null; if (payload.has("grant")) { JSONObject grant = (JSONObject) payload.get("grant"); code = grant.optString("code", "INVALID"); } if (payload.has("grantee")) { JSONObject grantee = (JSONObject) payload.get("grantee"); token = grantee.optString("token", "INVALID"); } switch(namespace) { case "Alexa": //状态报告 log.info("Found Alexa Namespace"); alexaResponse = s_Alexa_Discovery.StateReport(jsonRequest); break; case "Alexa.Authorization": //向alexa发送网关事件,主要是事件验证使用 log.info("Found Alexa.Authorization Namespace"); alexaResponse = new AlexaResponse("Alexa.Authorization","AcceptGrant.Response"); JSONObject payloads = new JSONObject("{}"); alexaResponse.SetPayload(payloads.toString()); //alexaResponse = new AlexaResponse("Alexa.Authorization","AcceptGrant", "INVALID", "INVALID", correlationToken); break; case "Alexa.Discovery": //发现设备的命令 log.info("Found Alexa.Discovery Namespace"); alexaResponse = s_Alexa_Discovery.Discovery(jsonRequest); log.info("发现设备的响应参数:"+alexaResponse.toString()); break; case "Alexa.PowerController": //开关设备的指令 System.out.println("Found Alexa.PowerController Namespace"); alexaResponse = s_Alexa_Controller.Controller(jsonRequest,namespace); log.info("控制设备开关的响应参数:"+alexaResponse.toString()); break; case "Alexa.ThermostatController": //温度控制指令 System.out.println("Found Alexa.ThermostatController Namespace"); alexaResponse = s_Alexa_Controller.Controller(jsonRequest,namespace); log.info("控制设备温度的响应参数:"+alexaResponse.toString()); break; //以下功能未实现 case "Alexa.ModeController": //模式设置的指令(暂时不支持,该功能只有预览版才有) System.out.println("Found Alexa.ModeController Namespace"); alexaResponse = s_Alexa_Controller.Controller(jsonRequest,namespace); log.info("控制设备模式的响应参数:"+alexaResponse.toString()); break; case "Alexa.RangeController": //温度范围设置的指令(暂时不支持,该功能只有预览版才有) System.out.println("Found Alexa.RangeController Namespace"); alexaResponse = s_Alexa_Controller.Controller(jsonRequest,namespace); log.info("控制设备温度范围的响应参数:"+alexaResponse.toString()); break; default: System.out.println("INVALID Namespace"); alexaResponse = new AlexaResponse(); break; } jsonObject = new JSONObject(alexaResponse.toString()); log.info(jsonObject.toString()); return jsonObject; } @SuppressWarnings({ "unused", "rawtypes", "unchecked" }) private void showParams(HttpServletRequest request) { Map map = new HashMap(); Enumeration paramNames = request.getParameterNames(); while (paramNames.hasMoreElements()) { String paramName = (String) paramNames.nextElement(); String[] paramValues = request.getParameterValues(paramName); if (paramValues.length == 1) { String paramValue = paramValues[0]; if (paramValue.length() != 0) { map.put(paramName, paramValue); } } } Set<Map.Entry<String, String>> set = map.entrySet(); System.out.println("------------------------------"); for (Map.Entry entry : set) { System.out.println(entry.getKey() + ":" + entry.getValue()); } System.out.println("------------------------------"); } }
响应的方法
package com.cn.whirlpool.services.alexaIot; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; import java.util.TimeZone; import java.util.UUID; import javax.ws.rs.ext.Provider; import org.apache.commons.lang3.StringUtils; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Transactional @Component @Provider public class AlexaResponse { private JSONObject response = new JSONObject("{}"); private JSONObject event = new JSONObject("{}"); private JSONObject header = new JSONObject("{}"); private JSONObject endpoint = new JSONObject("{}"); private JSONObject payload = new JSONObject("{}"); private String CheckValue(String value, String defaultValue) { if (value.isEmpty()) return defaultValue; return value; } public AlexaResponse() throws JSONException { this("Alexa", "Response", "INVALID", "INVALID", null); } public AlexaResponse(String namespace, String name) throws JSONException { this(namespace, name, "INVALID", "INVALID", null); } public AlexaResponse(String namespace, String name,String errType,String errMessage) throws JSONException { header.put("namespace", CheckValue(namespace, "Alexa")); header.put("name", CheckValue(name,"Response")); header.put("messageId", UUID.randomUUID().toString()); header.put("payloadVersion", "3"); event.put("header", header); event.put("endpoint", endpoint); if (StringUtils.isNotBlank(errType)) { payload.put("type", CheckValue(errType, "INVALID")); payload.put("message", CheckValue(errMessage, "INVALID")); } event.put("payload", payload); response.put("event", event); } public AlexaResponse(String namespace, String name, String endpointId, String token, String correlationToken) throws JSONException { header.put("namespace", CheckValue(namespace, "Alexa")); header.put("name", CheckValue(name,"Response")); header.put("messageId", UUID.randomUUID().toString()); header.put("payloadVersion", "3"); if (correlationToken != null) { header.put("correlationToken", CheckValue(correlationToken, "INVALID")); } JSONObject scope = new JSONObject("{}"); scope.put("type", "BearerToken"); scope.put("token", CheckValue(token, "INVALID")); endpoint.put("scope", scope); endpoint.put("endpointId", CheckValue(endpointId, "INVALID")); event.put("header", header); event.put("endpoint", endpoint); event.put("payload", payload); response.put("event", event); } public AlexaResponse(String namespace, String name, String endpointId, String token, String correlationToken,String errType,String errMessage) throws JSONException { header.put("namespace", CheckValue(namespace, "Alexa")); header.put("name", CheckValue(name,"Response")); header.put("messageId", UUID.randomUUID().toString()); header.put("payloadVersion", "3"); if (StringUtils.isBlank(correlationToken)) { header.put("correlationToken", CheckValue(correlationToken, "INVALID")); } JSONObject scope = new JSONObject("{}"); scope.put("type", "BearerToken"); scope.put("token", CheckValue(token, "INVALID")); endpoint.put("scope", scope); endpoint.put("endpointId", CheckValue(endpointId, "INVALID")); event.put("header", header); event.put("endpoint", endpoint); if (StringUtils.isNotBlank(errType)) { payload.put("type", CheckValue(errType, "INVALID")); payload.put("message", CheckValue(errMessage, "INVALID")); } event.put("payload", payload); response.put("event", event); } public AlexaResponse(String namespace, String name, String endpointId, String token, String correlationToken,String errType,String errMessage,String validRange) throws JSONException { header.put("namespace", CheckValue(namespace, "Alexa")); header.put("name", CheckValue(name,"Response")); header.put("messageId", UUID.randomUUID().toString()); header.put("payloadVersion", "3"); if (StringUtils.isBlank(correlationToken)) { header.put("correlationToken", CheckValue(correlationToken, "INVALID")); } JSONObject scope = new JSONObject("{}"); scope.put("type", "BearerToken"); scope.put("token", CheckValue(token, "INVALID")); endpoint.put("scope", scope); endpoint.put("endpointId", CheckValue(endpointId, "INVALID")); event.put("header", header); event.put("endpoint", endpoint); if (StringUtils.isNotBlank(errType)&&StringUtils.isNotBlank(validRange)) { payload.put("type", CheckValue(errType, "INVALID")); payload.put("message", CheckValue(errMessage, "INVALID")); payload.put("validRange", new JSONObject(validRange)); } event.put("payload", payload); response.put("event", event); } public void AddCookie(String key, String value) throws JSONException { JSONObject endpointObject = response.getJSONObject("event").getJSONObject("endpoint"); JSONObject cookie; if (endpointObject.has("cookie")) { cookie = endpointObject.getJSONObject("cookie"); cookie.put(key, value); } else { cookie = new JSONObject(); cookie.put(key, value); endpointObject.put("cookie", cookie); } } public void AddPayloadEndpoint(String friendlyName, String endpointId, String capabilities) throws JSONException { JSONObject payload = response.getJSONObject("event").getJSONObject("payload"); if (payload.has("endpoints")) { JSONArray endpoints = payload.getJSONArray("endpoints"); endpoints.put(new JSONObject(CreatePayloadEndpoint(friendlyName, endpointId, capabilities, null))); } else { JSONArray endpoints = new JSONArray(); endpoints.put(new JSONObject(CreatePayloadEndpoint(friendlyName, endpointId, capabilities, null))); payload.put("endpoints", endpoints); } } public void AddContextProperty(String namespace, String name, String value, int uncertaintyInMilliseconds) throws JSONException { JSONObject context; JSONArray properties; try { context = response.getJSONObject("context"); properties = context.getJSONArray("properties"); } catch (JSONException jse) { context = new JSONObject(); properties = new JSONArray(); context.put("properties", properties); } properties.put(new JSONObject(CreateContextProperty(namespace, name, value, uncertaintyInMilliseconds))); response.put("context", context); } public String CreateContextProperty(String namespace, String name, String value, int uncertaintyInMilliseconds) throws JSONException { JSONObject property = new JSONObject(); try { property.put("namespace", namespace); property.put("name", name); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'"); TimeZone tz = TimeZone.getTimeZone("UTC"); sdf.setTimeZone(tz); String timeOfSample = sdf.format(new Date().getTime()); property.put("timeOfSample", timeOfSample); property.put("uncertaintyInMilliseconds", uncertaintyInMilliseconds); /* property.put("value", value);*/ property.put("value", new JSONObject(value)); } catch (Exception je) { property.put("value", value); } return property.toString(); } public String CreatePayloadEndpoint(String friendlyName, String endpointId, String capabilities, String cookie) throws JSONException{ JSONObject endpoint = new JSONObject(); endpoint.put("capabilities", new JSONArray(capabilities)); //设备的描述(暂时写死) endpoint.put("description", "Whirlpool smart home"); //没有找到对应的类型,暂时全部为other JSONArray displayCategories = new JSONArray("[\"OTHER\"]"); endpoint.put("displayCategories", displayCategories); //设备制造商的名称 endpoint.put("manufacturerName", "Whirlpool Corporation"); if (endpointId == null) endpointId = "endpoint_" + 100000 + new Random().nextInt(900000); endpoint.put("endpointId", endpointId); if (friendlyName == null) friendlyName = "Sample Endpoint"; endpoint.put("friendlyName", friendlyName); if (cookie != null) endpoint.put("cookie", new JSONObject(cookie)); return endpoint.toString(); } public String CreatePayloadEndpointCapability(String type, String interfaceValue, String version, String properties, String configuration) throws JSONException { JSONObject capability = new JSONObject(); capability.put("type", type); capability.put("interface", interfaceValue); capability.put("version", version); if (properties != null) capability.put("properties", new JSONObject(properties)); if (configuration!=null) { capability.put("configuration", new JSONObject(configuration)); } return capability.toString(); } public void SetPayload(String payload) throws JSONException { response.getJSONObject("event").put("payload", new JSONObject(payload)); } @Override public String toString() { return response.toString(); } }
后面的话可根据请求的不同类型进行不同的方法。
关于java如何请求响应请查看亚马逊alexa的列子
最后声明,本文章纯属原创,未经允许禁止转载。谢谢。。。