Related
I am currently developing a smart home skill for my blinds, however I am unable to discover device. Is there a way for me to validate my Discovery response message? I'm thinking this is some logical error in the JSON.
I'm using a Lambda function to perform the requests to my API using node-fetch and async/await, thus I have tagged all JS function as async, this could be another potential cause of this issue. I don't get any errors in CloudWatch either.
This is the response my Lambda function is sending:
{
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover.Response",
"payloadVersion": "3",
"messageId": "0a58ace0-e6ab-47de-b6af-b600b5ab8a7a"
},
"payload": {
"endpoints": [
{
"endpointId": "com-tobisoft-rollos-1",
"manufacturerName": "tobisoft",
"description": "Office Blinds",
"friendlyName": "Office Blinds",
"displayCategories": [
"INTERIOR_BLIND"
],
"capabilities": [
{
"type": "AlexaInterface",
"interface": "Alexa.RangeController",
"instance": "Blind.Lift",
"version": "3",
"properties": {
"supported": [
{
"name": "rangeValue"
}
],
"proactivelyReported": true,
"retrievable": true
},
"capabilityResources": {
"friendlyNames": [
{
"#type": "asset",
"value": {
"assetId": "Alexa.Setting.Opening"
}
}
]
},
"configuration": {
"supportedRange": {
"minimumValue": 0,
"maximumValue": 100,
"precision": 1
},
"unitOfMeasure": "Alexa.Unit.Percent"
},
"semantics": {
"actionMappings": [
{
"#type": "ActionsToDirective",
"actions": [
"Alexa.Actions.Close"
],
"directive": {
"name": "SetRangeValue",
"payload": {
"rangeValue": 100
}
}
},
{
"#type": "ActionsToDirective",
"actions": [
"Alexa.Actions.Open"
],
"directive": {
"name": "SetRangeValue",
"payload": {
"rangeValue": 1
}
}
},
{
"#type": "ActionsToDirective",
"actions": [
"Alexa.Actions.Lower"
],
"directive": {
"name": "AdjustRangeValue",
"payload": {
"rangeValueDelta": 10,
"rangeValueDeltaDefault": false
}
}
},
{
"#type": "ActionsToDirective",
"actions": [
"Alexa.Actions.Raise"
],
"directive": {
"name": "AdjustRangeValue",
"payload": {
"rangeValueDelta": -10,
"rangeValueDeltaDefault": false
}
}
}
],
"stateMappings": [
{
"#type": "StatesToValue",
"states": [
"Alexa.States.Closed"
],
"value": 100
},
{
"#type": "StatesToRange",
"states": [
"Alexa.States.Open"
],
"range": {
"value": 0
}
}
]
}
},
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
}
]
}
]
}
}
}
Thanks for any help.
Is there a way for me to validate my Discovery response message?
Yes, you could use the Alexa Smart Home Message JSON Schema. This schema can be used for message validation during skill development, it validates Smart Home skills (except the Video Skills API).
This is the response my Lambda function is sending
I've validated your response following this steps, the result: no errors found, the JSON validates against the schema. So, there's probably another thing going on. I suggest getting in touch with Alexa Developer Contact Us
I'm creating my infrastructure using CloudFormation.
I'm hoping to create the API using "API Gateway Extensions to OpenAPI"
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions.html
Relevant code segment looks like this.
"MorningApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Description": {
"Fn::Sub": "${Stage}-MorningApi"
},
"Name": {
"Fn::Sub": "${Stage}-MorningApi"
},
"EndpointConfiguration": {
"Types": [
"REGIONAL"
]
},
"BodyS3Location": {
"Bucket" : "cf-morning",
"Key" : "nested-templates-stack/MorningApiStatusStackSwagger.json"
}
}
},
"MorningApiloadBalancer": {
"Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
"Properties": {
"Name": {
"Fn::Sub": "${Stage}-MorningApiloadBalancer"
},
"Subnets": [
{
"Ref": "PrivateASubnet"
},
{
"Ref": "PrivateBSubnet"
},
{
"Ref": "PrivateCSubnet"
}
],
"Type": {
"Ref": "ELBType"
},
"Scheme": "internal",
"IpAddressType": {
"Ref": "ELBIpAddressType"
}
}
}
I need to pass "DNSName" of the "MorningApiloadBalancer" to the swagger file located in the S3 location. I cannot find a way to do this.
Any help is appreciated.
I haven't tried using swagger with API gateway before.
Using Fn::Transform
Using the Swagger file stored in S3 using the Fn::Tranform macro, it basically takes the content of the swagger file and tranforms into cloudformation.
{
"APIGateway": {
"Type": "AWS::ApiGateway::RestApi",
"Name": "myapi",
"Properties": {
"Body": {
"Fn::Transform": {
"Name": "AWS::Include",
"Parameters": {
"Location": {
"Fn::Sub": "s3://${AWS::AccountId}-swagger-files/${SwaggerFile}"
}
}
}
}
}
}
}
Reference:
https://medium.com/#nabtechblog/integrating-swagger-with-aws-lambda-and-api-gateway-using-cloud-formation-macro-functions-7432dec50dd
Inline swagger definition
I saw an example where the swagger definition is embedded into the cloudformation template. If you do so, you can use intrinsic functions inside the swagger definition. In your case, you can use Ref to get the dns name of the load balancer.
"GreetingApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "Greeting API",
"Description": "API used for Greeting requests",
"FailOnWarnings": true,
"Body": {
"swagger": "2.0",
"paths": {
"/greeting": {
"get": {
"x-amazon-apigateway-integration": {
"uri": {
"Fn::Join": [
"",
[
"arn:aws:apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"GreetingLambda",
"Arn"
]
},
"/invocations"
]
]
}
}
}
}
}
}
}
}
Reference:
https://blog.jayway.com/2016/09/18/introduction-swagger-cloudformation-api-gateway/
Getting DNS Name
I think you know this already.
"Fn::GetAtt" : [ "MorningApiloadBalancer" , "DNSName" ]
Hope this helps.
I have written an Alexa smart home skills.
When I try to discover the device using the Alexa test or from the mobile app, the lambda is triggered.
The lambda is getting successfully executed, but I get below error in App or test in Alexa console.
I couldn't find any new Smart Home devices. If you’ve n't already,
please enable the smart home skill for your device from the Alexa App.
What could be the possible issue?
Since the lambda is getting successfully executed, I don't think there is any issue with language (English(IN)) or AWS region (EU-WEST-1) , where the lambda is deployed.
I didn't see any logs on Alexa developer console
Any pointers?
Response from Lambda function -
header =
{
namespace: 'Alexa.Discovery',
name: 'Discover.Response',
payloadVersion: '3',
messageId: '785f0173-6ddb-41d8-a785-de7159c7f7ca'
}
payload =
{
"endpoints": [
{
"endpointId": "d4b87cbe6c8e490493733f260b8c2c25",
"friendlyName": "Kitchen",
"description": "Demo",
"manufacturerName": "Man1",
"displayCategories": [
"LIGHT"
],
"cookie": {
"owner": "Owner1"
},
"capabilities": [
{
"type": "AlexaInterface",
"version": "3",
"interface": "Alexa"
},
{
"type": "AlexaInterface",
"version": "3",
"interface": "Alexa.PowerController",
"properties": {
"supported": [
{
"name": "powerState"
}
],
"proactivelyReported": true,
"retrievable": true
}
},
{
"type": "AlexaInterface",
"version": "3",
"interface": "Alexa.BrightnessController",
"properties": {
"supported": [
{
"name": "brightness"
}
],
"proactivelyReported": true,
"retrievable": true
}
}
]
}
]
}
We are wrapping header and payload in the response event.
context.succeed({ event: { header: header, payload: payload } });
So far I haven't found a way to view the logs either.
I had the same problem and I realized that I was putting wrong values in some properties or schema entities like ids.
In the same way, another thing that solved me on some occasion was to place the scheme in the following way:
context.succeed({
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover.Response",
"payloadVersion": "3",
"messageId": header.messageId
},
"payload": {
"endpoints": [
{
"endpointId": "demo_id",
...
,
"cookie": {},
"capabilities": [
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
},
...
]
}
]
}
}
});
I'm trying out the HTTP passthrough functionality in API gateway, passing through a resource method to another API. I want to pass through the path parameters from the API gateway URL to the backend API that also needs those path parameters.
I have the following simple Swagger document trying to test this out:
{
"swagger": "2.0",
"info": {
"version": "2017-09-15T03:33:48Z",
"title": "api-gateway-http-test"
},
"schemes": [
"https"
],
"paths": {
"/subresource/{name}": {
"get": {
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "200 response",
"schema": {
"$ref": "#/definitions/Empty"
}
}
},
"x-amazon-apigateway-integration": {
"uri": "http://my.web.service.url/subresource/{name}",
"passthroughBehavior": "when_no_match",
"httpMethod": "GET",
"type": "http_proxy",
"requestParameters": {
"integration.request.path.name": "method.request.path.name"
}
}
}
}
},
"definitions": {
"Empty": {
"type": "object",
"title": "Empty Schema"
}
}
}
When I try deploying this to API Gateway via CloudFormation, API Gateway gives me this error:
Unable to put integration on 'GET' for resource at path '/subresource/{name}':
Invalid mapping expression specified:
Validation Result:
warnings : [], errors : [Invalid mapping expression parameter specified: method.request.path.name]
I've looked at various sources online, and this way of configuring the "requestParameters" section seems to be the recommended way to pass through path parameters to the backend API.
What am I missing here that would cause this to not work?
It is missing parameter definitions.
Check it out with the below,
{
"swagger": "2.0",
"info": {
"version": "2017-09-15T03:33:48Z",
"title": "api-gateway-http-test"
},
"schemes": [
"https"
],
"paths": {
"/subresource/{name}": {
"get": {
"produces": [
"application/json"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "200 response",
"schema": {
"$ref": "#/definitions/Empty"
}
}
},
"x-amazon-apigateway-integration": {
"uri": "http://google.com/subresource/{name}",
"passthroughBehavior": "when_no_match",
"httpMethod": "GET",
"type": "http_proxy",
"requestParameters": {
"integration.request.path.name": "method.request.path.name"
}
}
}
}
},
"definitions": {
"Empty": {
"type": "object",
"title": "Empty Schema"
}
}
}
I deployed CloudFoundry on top of vSphere using BOSH (full BOSH with CF manifest file) with attribute srv_api_uri: http://api.cf.epam.by
When I trying to login into my CloudFoundry instance I got error
vmc login
target: http://api.cf.epam.by
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol
For more information, see ~/.vmc/crash
result of vmc login -t is
target: http://api.cf.epam.by
>>>
REQUEST: GET /info
REQUEST_HEADERS:
accept : application/json
user-agent : Ruby
content-length : 0
RESPONSE: [200]
RESPONSE_HEADERS:
date : Fri, 04 Jan 2013 09:51:24 GMT
server : nginx
content-type : application/json; charset=utf-8
etag : "35acd28a7b24338237a8a1025d78f6ca"
cache-control : max-age=0, private, must-revalidate
x-ua-compatible : IE=Edge,chrome=1
transfer-encoding : chunked
{
"name": "vcap",
"build": 2222,
"support": "http://support.cloudfoundry.com",
"version": "0.999",
"description": "VMware's Cloud Application Platform",
"allow_debug": false,
"frameworks": {
"sinatra": {
"name": "sinatra",
"runtimes": [
{
"name": "ruby18",
"version": "1.8.7p357",
"description": "Ruby 1.8"
},
{
"name": "ruby19",
"version": "1.9.2p180",
"description": "Ruby 1.9"
}
],
"detection": [
{
"*.rb": "\\s*require[\\s\\(]*['\"]sinatra(/base)?['\"]"
},
{
"config/environment.rb": false
}
]
},
"play": {
"name": "play",
"runtimes": [
{
"name": "java",
"version": "1.6.0_24",
"description": "Java 6"
},
{
"name": "java7",
"version": "1.7.0_04",
"description": "Java 7"
}
],
"detection": [
{
"lib/play.*.jar": true
}
]
},
"standalone": {
"name": "standalone",
"runtimes": [
{
"name": "java",
"version": "1.6.0_24",
"description": "Java 6"
},
{
"name": "java7",
"version": "1.7.0_04",
"description": "Java 7"
},
{
"name": "ruby18",
"version": "1.8.7p357",
"description": "Ruby 1.8"
},
{
"name": "ruby19",
"version": "1.9.2p180",
"description": "Ruby 1.9"
},
{
"name": "node",
"version": "0.4.12",
"description": "Node.js"
},
{
"name": "node06",
"version": "0.6.8",
"description": "Node.js"
},
{
"name": "node08",
"version": "0.8.2",
"description": "Node.js"
}
],
"detection": [ ]
},
"rack": {
"name": "rack",
"runtimes": [
{
"name": "ruby18",
"version": "1.8.7p357",
"description": "Ruby 1.8"
},
{
"name": "ruby19",
"version": "1.9.2p180",
"description": "Ruby 1.9"
}
],
"detection": [
{
"config.ru": true
},
{
"config/environment.rb": false
}
]
},
"node": {
"name": "node",
"runtimes": [
{
"name": "node",
"version": "0.4.12",
"description": "Node.js"
},
{
"name": "node06",
"version": "0.6.8",
"description": "Node.js"
},
{
"name": "node08",
"version": "0.8.2",
"description": "Node.js"
}
],
"detection": [
{
"*.js": "."
}
]
},
"spring": {
"name": "spring",
"runtimes": [
{
"name": "java",
"version": "1.6.0_24",
"description": "Java 6"
},
{
"name": "java7",
"version": "1.7.0_04",
"description": "Java 7"
}
],
"detection": [
{
"*.war": true
}
]
},
"lift": {
"name": "lift",
"runtimes": [
{
"name": "java",
"version": "1.6.0_24",
"description": "Java 6"
},
{
"name": "java7",
"version": "1.7.0_04",
"description": "Java 7"
}
],
"detection": [
{
"*.war": true
}
]
},
"rails3": {
"name": "rails3",
"runtimes": [
{
"name": "ruby18",
"version": "1.8.7p357",
"description": "Ruby 1.8"
},
{
"name": "ruby19",
"version": "1.9.2p180",
"description": "Ruby 1.9"
}
],
"detection": [
{
"config/application.rb": true
},
{
"config/environment.rb": true
}
]
},
"java_web": {
"name": "java_web",
"runtimes": [
{
"name": "java",
"version": "1.6.0_24",
"description": "Java 6"
},
{
"name": "java7",
"version": "1.7.0_04",
"description": "Java 7"
}
],
"detection": [
{
"*.war": true
}
]
},
"grails": {
"name": "grails",
"runtimes": [
{
"name": "java",
"version": "1.6.0_24",
"description": "Java 6"
},
{
"name": "java7",
"version": "1.7.0_04",
"description": "Java 7"
}
],
"detection": [
{
"*.war": true
}
]
}
},
"authorization_endpoint": "https://uaa.cf.epam.by"
}
<<<
>>>
REQUEST: GET /login
REQUEST_HEADERS:
accept : application/json
user-agent : Ruby
content-length : 0
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol
For more information, see ~/.vmc/crash
Why it's trying to use SSL?
Why "authorization_endpoint": "https://uaa.cf.epam.by" used https rather http? ( http://uaa.cf.epam.by is available but not a https://uaa.cf.epam.by)
P.S. I open such discussion at Google Groups https://groups.google.com/a/cloudfoundry.org/forum/#!topic/vcap-dev/OAZcsFiZ3LA%5B1-25-false%5D but on this moment I have nothing. Can somebody help me to figure out what is wrong?
The current cf-release jobs have cloud_controller.yml.erb with a hard-coded https URL for the UAA. This is definitely mandatory in production, but I can see why you might want to change it in a dev environment. There are other places where the protocol is configured or guessed, e.g. in login.yml.erb:
<% if !properties.login || !properties.login.uaa_base
# Fix this to https when SSL certs are working in dev and staging
protocol = (properties.login && properties.login.protocol) ? properties.login.protocol : "http"
uaa_base = "#{protocol}://uaa.#{properties.domain}"
else
uaa_base = properties.login.uaa_base
end %>
You could modify the cloud_controller.yml.erb to do something similar and re-deploy.
There is yet-to-be merged patch available for cf-release to allow http-only uaa endpoints. Perhaps try this out and comment on the gerrit patch.
http://reviews.cloudfoundry.org/#/c/13137/