I'm implementing an Alexa Smart Home skill and I want to know if a user is still using the app after a while.
Google Home, for example, sends a request when I unlink my app from the Google Smarthome app. I need to know it to disable sending updates to Amazon Alexa gateway if a user isn't using the skill anymore.
What the best way of doing it? Alexa documentation doesn't talk about it.
Can I rely on just checking if the user has a expired OAuth tokens? E.g. if expired for more than a day, mark user as inactive.
Another thing I'm going to test out tomorrow is just see the gateway response after having unlinked the skill. But for my case it wouldn't be good option anyway, as I will only know the user state after a physical change and trying to submit it and have it possibly fail. Which can happen after days or weeks, so it isn't that reliable.
You can integrate with Alexa Skill Events and get notification when user disables the Skill.
https://developer.amazon.com/docs/smapi/skill-events-in-alexa-skills.html#skill-disabled-event.
The SkillDisabled event only contains user_id (i.e. no access token). So you would also need to listen for the SkillAccountLinked event so you can link that user_id with your own user identifier.
Your Smart Home Skill manifest should look like this:
{
"manifest": {
"publishingInformation": {
"locales": {
"en-US": {
"summary": "...",
"examplePhrases": [
"Alexa, ...",
"Alexa, ...",
"Alexa, ..."
],
"keywords": [],
"name": "...",
"smallIconUri": "...",
"description": "...",
"largeIconUri": "..."
}
},
"isAvailableWorldwide": false,
"testingInstructions": "...",
"category": "SMART_HOME",
"distributionCountries": [
"US"
]
},
"apis": {
"smartHome": {
"endpoint": {
"uri": "arn:aws:lambda:..."
},
"protocolVersion": "3"
}
},
"manifestVersion": "1.0",
"permissions": [
{
"name": "alexa::async_event:write"
}
],
"privacyAndCompliance": {
"allowsPurchases": false,
"locales": {
"en-US": {
"termsOfUseUrl": "...",
"privacyPolicyUrl": "..."
}
},
"isExportCompliant": true,
"containsAds": false,
"isChildDirected": false,
"usesPersonalInfo": false
},
"events": {
"endpoint": {
"uri": "arn:aws:lambda:..."
},
"subscriptions": [
{
"eventName": "SKILL_ENABLED"
},
{
"eventName": "SKILL_DISABLED"
},
{
"eventName": "SKILL_PERMISSION_ACCEPTED"
},
{
"eventName": "SKILL_PERMISSION_CHANGED"
},
{
"eventName": "SKILL_ACCOUNT_LINKED"
}
],
"regions": {
"NA": {
"endpoint": {
"uri": "arn:aws:lambda:..."
}
}
}
}
}
}
Related
The skill in question asks for one permission when enabling in Web or app (Outbound Notification). But, when implemented Skill Enabled Event it's not asking user to give notification permission or not. Skill enablement works itself but permission is by default No. How to make alexa to ask for permission when enabling via voice?
Can Alexa prompt them via voice to enable the outbound notification?
skill.json
{
"manifest": {
"publishingInformation": {
"locales": {
"en-US": {
"summary": "test skill summary",
"examplePhrases": [
"Alexa, launch test skill",
"Alexa, open test skill",
"Alexa, start test skill"
],
"keywords": [
"test skill"
],
"name": "test skill",
"description": "test skill Description",
"smallIconUri": "",
"largeIconUri": "",
"updatesDescription": ""
}
},
"isAvailableWorldwide": true,
"testingInstructions": "n/a",
"category": "EVENT_FINDERS",
"distributionCountries": [],
"automaticDistribution": {
"isActive": false
}
},
"apis": {
"custom": {
"endpoint": {
"uri": "arn:aws:lambda:us-east-1:"
},
"interfaces": []
}
},
"manifestVersion": "1.0",
"privacyAndCompliance": {
"allowsPurchases": false,
"locales": {
"en-US": {
"privacyPolicyUrl": "",
"termsOfUseUrl": ""
}
},
"isExportCompliant": true,
"containsAds": false,
"isChildDirected": false,
"usesPersonalInfo": false
},
"events": {
"endpoint": {
"uri": "arn:aws:lambda:us-east-1:"
},
"publications": [
{
"eventName": "AMAZON.MessageAlert.Activated"
},
{
"eventName": "AMAZON.MediaContent.Available"
}
],
"regions": {
"NA": {
"endpoint": {
"uri": "arn:aws:lambda:us-east-1:",
"sslCertificateType": "Trusted"
}
}
},
"subscriptions": [
{
"eventName": "SKILL_PROACTIVE_SUBSCRIPTION_CHANGED"
},
{
"eventName": "SKILL_ENABLED"
},
{
"eventName": "SKILL_DISABLED"
},
{
"eventName": "SKILL_PERMISSION_ACCEPTED"
},
{
"eventName": "SKILL_PERMISSION_CHANGED"
},
{
"eventName": "SKILL_ACCOUNT_LINKED"
}
]
},
"permissions": [
{
"name": "alexa::devices:all:notifications:write"
}
]
}
}
Thank you for the help
There may be a different way, but once you are in the skill I believe you will need to send an ask for permissions card. As I understand it the idea is to make sure that Amazon is involved as a third party permissions granter. This will pop a permissions request in the Alexa app on the users phone. This added layer of security just makes sure the customer saw exactly what permissions they were granting.
You can do this a few different ways in your skill. You could check the first time that the user connects and keep track of that first connection in a persistent customer data layer. Or you could just check if the user has permission when you go to use that part of the skill. If they don't respond telling the customer you sent them a card to grant permissions.
Here is more info on permission cards:
https://developer.amazon.com/en-US/docs/alexa/custom-skills/request-customer-contact-information-for-use-in-your-skill.html#permissions-card-for-requesting-customer-consent
To run reminders via a lambda, other permissions are probably the same format.
const CreateReminderIntent = {
canHandle(handlerInput) {
const { request } = handlerInput.requestEnvelope;
return request.type === 'IntentRequest' && request.intent.name === 'CreateReminderIntent';
},
async handle(handlerInput) {
const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;
const consentToken = requestEnvelope.context.System.user.permissions
&& requestEnvelope.context.System.user.permissions.consentToken;
if (!consentToken) {
return handlerInput.responseBuilder
.addDirective({
type: "Connections.SendRequest",
name: "AskFor",
payload: {
"#type": "AskForPermissionsConsentRequest",
"#version": "1",
"permissionScope": "alexa::alerts:reminders:skill:readwrite"
},
token: "<string>"
})
.getResponse();
}
try {
const speechText = "Great! I've scheduled a reminder for you";
const ReminderManagementServiceClient = serviceClientFactory.getReminderManagementServiceClient();
const reminderPayload = {
"trigger": {
"type": "SCHEDULED_RELATIVE",
"offsetInSeconds": "10",
"timeZoneId": "Europe/London"
},
"alertInfo": {
"spokenInfo": {
"content": [{
"locale": "en-GB",
"text": "Wash the dog"
}]
}
},
"pushNotification": {
"status": "ENABLED"
}
};
await ReminderManagementServiceClient.createReminder(reminderPayload);
return responseBuilder
.speak(speechText)
.getResponse();
} catch (error) {
console.error(error);
return responseBuilder
.speak('Uh Oh. Looks like something went wrong.')
.getResponse();
}
}
};
I am playing with a sample Alexa Smart Home skill - I am not talking to any real hardware or back-end, just trying to get message flow working. I have set up a simple switch/plug/light that can just support turning On/Off - and I have account linked working and the skill enabled. When I try looking at it via the Alexa app on phone or web (with debug enabled) it always says the device isn't responding, or it's "Failed to Retrieve State". I can definitely see the messages in Cloud Watch as follows.
Any idea why I'd be chronically getting such a response??
Request:
"directive": {
"endpoint": {
"cookie": {},
"endpointId": "endpoint-003",
"scope": {
"token": "<<<SUPRESSING>>",
"type": "BearerToken"
}
},
"header": {
"correlationToken": "<<SHORTENED>>",
"messageId": "50397414-bb9d-412f-8a2c-15669978ab64",
"name": "ReportState",
"namespace": "Alexa",
"payloadVersion": "3"
},
"payload": {}
}
}
Response:
{
"context": {
"properties": [
{
"name": "connectivity",
"namespace": "Alexa.EndpointHealth",
"timeOfSample": "2020-06-29T16:49:59.00Z",
"uncertaintyInMilliseconds": 0,
"value": "OK"
},
{
"name": "powerState",
"namespace": "Alexa.PowerController",
"timeOfSample": "2020-06-29T16:49:59.00Z",
"uncertaintyInMilliseconds": 0,
"value": "ON"
}
]
},
"event": {
"endpoint": {
"endpointId": "endpoint-003",
"scope": {
"token": "Alexa-access-token",
"type": "BearerToken"
}
},
"header": {
"correlationToken": "<<SHORTENED>>",
"messageId": "7a8b9a71-adda-41b8-acba-4d3855374845",
"name": "Response",
"namespace": "Alexa",
"payloadVersion": "3"
},
"payload": {}
}
}
Problem was: The "name" in my header response should have been "ReportState". "Response" is only used for things that set/change values.
My general advice is to always verify that THREE things are good:
Initial "Discovery"
"Response" messages
General "ReportState" queries.
By this - I mean that:
Anything you advertised as should be reported in "discovery" better be reported in other ("ReportState") messages. If you advertise a "PowerController" - if your ReportStates don't contain status for that, you'll either not see the status, or it'll keep retrying forever (continuing to look for it) - or you might get some sort of an error.
If you CHANGED your discovery stuff - make sure that you really removed, re-discovered, and that the states (above) for the new additions/removals are okay
Always make sure that "EndpointHealth" is being reported.
I have custom skill that calls web service i created. I am able to launch and get other intent, but i am not getting notification when permission for notification is changed by user of my skill. I need he notification event to get user id for sending push notifications later by other service.
Below is my json file:
{
"manifest": {
"apis": {
"custom": {
"endpoint": {
"uri": "https://pathToMyService",
"sslCertificateType": "Wildcard"
},
"interfaces": []
}
},
"events": {
"publications": [
{ "eventName": "AMAZON.TrashCollectionAlert.Activated" },
{ "eventName": "AMAZON.MessageAlert.Activated" }
],
"subscriptions": [
{ "eventName": "SKILL_PROACTIVE_SUBSCRIPTION_CHANGED" },
{ "eventName": "SKILL_ENABLED" },
{ "eventName": "SKILL_DISABLED" },
{ "eventName": "SKILL_PERMISSION_ACCEPTED" },
{ "eventName": "SKILL_PERMISSION_CHANGED" },
],
"regions": {
"NA": {
"endpoint": {
"uri": "https://pathToMyService",
"sslCertificateType": "Wildcard"
}
}
},
"endpoint": {
"uri": "https://pathToMyService",
"sslCertificateType": "Wildcard"
}
},
"manifestVersion": "1.0",
"permissions": [
{ "name": "alexa::devices:all:notifications:write" }
],
"publishingInformation": {
"locales": {
"en-US": { "name": "Test Events" }
}
}
}
}
Below is the Launch request: I have truncated applicatioId, userID, consentToken, deviceId, apiAccessToken
{"version":"1.0","session":{"new":true,"sessionId":"amzn1.echo-api.session.60ad1e76-0872-4e10-b79d-7144cdf3e1c9","application":{"applicationId":"amzn1.ask.skill.59d60703"},"user":{"userId":"amzn1.ask.account.AGB7EOY","permissions":{"consentToken":"eyJ0eXAiOiJKV1"}}},"context":{"System":{"application":{"applicationId":"amzn1.ask.skill.59d60703"},"user":{"userId":"amzn1.ask.account.AGB7EOY","permissions":{"consentToken":"eyJ0eXAiOiJKV1Qi"}},"device":{"deviceId":"amzn1.ask.device.AFNXDZOAEMFDFKK","supportedInterfaces":{}},"apiEndpoint":"https://api.amazonalexa.com","apiAccessToken":"eyJ0eXAiOiJKV1Qi"}},"request":{"type":"LaunchRequest","requestId":"amzn1.echo-api.request.adb318af-1977-4b36-b8ad-0bb4352fa563","timestamp":"2020-03-22T23:37:55Z","locale":"en-US","shouldLinkResultBeReturned":false}}
Thanks
I resolved the issue: When I updated by skill.json file using
ask api update-skill -s amzn1.ask.skill.59d6 -f Test.json
it didn't update properly. I noticed today when I got latest
ask api get-skill -s amzn1.ask.skill.59d6 >Test2.json
the event section was missing. I added back and reapplied and it's working now.
Hi, I am creating a chatbot. I developed a IBM cloud function(action) in IBM.
This is the action code..
{
"context": {
"my_creds": {
"user": "ssssssssssssssssss",
"password": "sssssssssssssssssssssss"
}
},
"output": {
"generic": [
{
"values": [
{
"text": ""
}
],
"response_type": "text",
"selection_policy": "sequential"
}
]
},
"actions": [
{
"name": "ssssssssssss/user-detail",
"type": "server",
"parameters": {
"name": "<?input.text?>",
"lastname": "<?input.text?>"
},
"credentials": "$my_creds",
"result_variable": "$my_result"
}
]
}
Now my action user detail is giving response when i am invoking the code.
But when i am checking the output with my chatbot I am getting execution of cloud functions action took too long.
There is currently a 5 second limitation on processing time for a cloud function being called from a dialog node. If your process will need longer than this, you'll need to do it client side through your application layer.
When using the "Send To Messenger" plugin, the response received is:
{
"object": "page",
"entry": [
{
"id": "410441912660258",
"time": 1506529761355,
"messaging": [
{
"recipient": {
"id": "410441912660258"
},
"timestamp": 1506529761355,
"sender": {
"id": "1388094137927363"
},
"optin": {
"ref": "login"
}
}
]
}
]
}
However, when I interact with Messenger using the same Messenger Account, Facebook sends:
{
"originalRequest": {
"source": "facebook",
"data": {
"sender": {
"id": "1271682282961502"
},
"recipient": {
"id": "1818762375111057"
},
"message": {
"mid": "mid.$cAAZ2J6JWBDZk9XGKQVexCxoKu27Y",
"text": "hi",
"seq": 17289
},
"timestamp": 1506529788481
}
}
}
Note that, despite using the same Messenger account, the sender/recipient IDs are different. So I can't match any users up from the Messenger Chat vs the Send To Messenger button.
I believe this is because the "Send To Messenger" button is using the Page Scoped User ID of the relevant Facebook Page, instead of the Facebook App. Is there any way to match these two IDs or, to tell the Send To Messenger button to use the APP ID instead of the Page ID?
You can use the ID matching API
https://developers.facebook.com/docs/messenger-platform/identity/id-matching