一,前期準備材料
二,技能創建
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的列子
最後聲明,本文章純屬原創,未經允許禁止轉載。謝謝。。。