How to Add a Timer to an Alexa Skill: Part Two

Anand Kumar Oct 07, 2021
Share:
Build Alexa-Hosted Skills
Blog_Header_Post_Img

In part 1 of a two-part series we have covered how to use voice permission and call the Timer API to set timers in Alexa skill. Now in this second part, we will cover how you can perform read, pause, resume and delete operations to Timer API.

How to Read the Specific Timer

To perform read operations you need to have permission enabled in your skill. Whenever a skill creates a timer using the Timer API, a unique “id” is sent back to your skill in response. This “id” will be used to identify the specific timer set in Alexa device.

Now we will use this “id” to perform all read, delete, pause and resume operations.

Below is a sample request used to call the Read Timer API:

Copied to clipboard
GET /v1/alerts/timers/{id}
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json

No request body is needed to call this API.

This API call then returns a response, which will contain the timer id, status, duration, triggerTime, createdTime and updatedTime.

Example response:

Copied to clipboard
{ 
    "id": "a3aac326-c504-458b-8520-15fd048f086a", 
    "status": "ON", 
    "duration": "PT10M", 
    "triggerTime": "2021-08-13T10:25:30Z", 
    "createdTime": "2021-08-13T10:15:30Z", 
    "updatedTime": "2021-08-13T10:15:30Z" 
}

If the created timer has been previously paused, then the “remainingTimeWhenPaused” property will be added in the response. Here is an example where the timer has three minutes and three seconds left:

Copied to clipboard
{ 
      "id": "a3aac326-c504-458b-8520-15fd048f086a", 
      "status": "PAUSED", 
      "duration": "PT5M", 
      "timerLabel": "Pizza", 
      "createdTime": "2019-12-03T10:15:30Z", 
      "updatedTime": "2019-12-03T10:12:03Z", 
      "remainingTimeWhenPaused": "PT3M3S" 
}

How to Read All TImers 

Get timers for a specified customer. Timers that are created within the skill will be visible on all devices associated with the Alexa account, and are returned, sorted in order from the timer with the shortest duration to the longest duration.

Copied to clipboard
GET /v1/alerts/timers
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json

No request body is needed to call this API.

This API will return details for all timers created for this user through the skill.

Example response where one timer is active and another one is paused:

Copied to clipboard
{ 
    "timers": [ 
        { 
            "id": "a3aac326-c504-458b-8520-15fd048f086a", 
            "status": "ON", 
            "duration": "PT10M", 
            "triggerTime": "2019-12-03T10:25:30Z", 
            "createdTime": "2019-12-03T10:15:30Z", 
            "updatedTime": "2019-12-03T10:15:30Z", 
        }, 
        { 
            "id": "a3aac326-c504-458b-8520-15fd048f086a", 
            "status": "PAUSED", 
            "duration": "PT5M", 
            "timerLabel": "Pizza", 
            "createdTime": "2019-12-03T10:15:30Z", 
            "updatedTime": "2019-12-03T10:12:03Z", 
            "remainingTimeWhenPaused": "PT3M3S" 
        } 
    ], 
    "totalCount": 2, 
    "nextToken": null 
}

We also provide ASK SDK support to perform read operation so you don’t have to worry about API calls.

Copied to clipboard
async handle(handlerInput) {
    const {serviceClientFactory} = handlerInput;
    try {
        const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
        // getTimers() will send list of all timers created.
        const timersList = await timerServiceClient.getTimers();
        console.log('Read timers: ' + JSON.stringify(timersList));
        const totalCount = timersList.totalCount;
        if(timerId || totalCount > 0) {
            timerId = timerId ? timerId : timersList.timers[0].id; 
            // getTimer(timerId) will send details of specific timer as per "id" provided in "timerId".
            let timerResponse = await timerServiceClient.getTimer(timerId);       
            console.log('Read timer: ' + JSON.stringify(timerResponse));
            const timerStatus = timerResponse.status;
            return handlerInput.responseBuilder
                .speak("Read timer operation completed")
                .getResponse();
        } else {
            return handlerInput.responseBuilder
                .speak("No timer was created")
                .getResponse();
        }
    } catch (error) {
        console.log('Read timer error: ' + JSON.stringify(error));
        // If error code is passed 401 then send voice permission to user to grant Timer permission.
        if(error.statusCode === 401) {
            console.log('Unauthorized!');
            // we send a request to enable by voice
            // note that you'll need another handler to process the result, see AskForResponseHandler
            return handlerInput.responseBuilder
                .addDirective({
                type: 'Connections.SendRequest',
                'name': 'AskFor',
                'payload': {
                    '@type': 'AskForPermissionsConsentRequest',
                    '@version': '1',
                    'permissionScope': TIMERS_PERMISSION
                },
                token: 'verifier'
            }).getResponse();
        }
        else
            return handlerInput.responseBuilder
                        .speak("You haven't set a timer. Try saying, set a timer.")
                        .getResponse();
    }
}

How to Delete a Specified Timer

This API is invoked to delete a specific timer for the current device. “id” is the unique identifier of specific timer.

Copied to clipboard
DELETE /v1/alerts/timers/{id}
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json

No request body is needed to call this API.

How to Delete All Timers

This API will delete all timers created by user.

Copied to clipboard
DELETE /v1/alerts/timers
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json

No request body is needed to call this API.

You can also use the ASK SDK here to form delete operations like below:

Copied to clipboard
async handle(handlerInput) {
    const {serviceClientFactory} = handlerInput;

    try {
        const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
        const timersList = await timerServiceClient.getTimers();
        console.log('Read timers: ' + JSON.stringify(timersList));
        const totalCount = timersList.totalCount;
        if(totalCount === 0) {
            return handlerInput.responseBuilder
                .speak("No timer has created.")
                .getResponse();
        }
            // warning, since there's no timer id we cancel all timers by the user
            await timerServiceClient.deleteTimers();
        
        console.log('Timer deleted!');
        return handlerInput.responseBuilder
            .speak("All created timers deleted")
            .getResponse();
    } catch (error) {
        console.log('Delete timer error: ' + JSON.stringify(error));
        if(error.statusCode === 401) {
            console.log('Unauthorized!');
            // we send a request to enable by voice
            // note that you'll need another handler to process the result, see AskForResponseHandler
            return handlerInput.responseBuilder
                .addDirective({
                type: 'Connections.SendRequest',
                'name': 'AskFor',
                'payload': {
                    '@type': 'AskForPermissionsConsentRequest',
                    '@version': '1',
                    'permissionScope': TIMERS_PERMISSION
                },
                token: 'verifier'
            }).getResponse();
        }
        else
            return handlerInput.responseBuilder
                .speak("Something went wrong in performing delete operation")
                .getResponse();
    }
}

How to Pause a Specified Timer

You can only pause a timer that is scheduled but has not started yet. The timer's remaining time is frozen and saved. For example, if you pause a timer that is due to go off in 45 minutes, then the timer will go off 45 minutes from when you resume the timer.

Copied to clipboard
POST /v1/alerts/timers/{id}/pause
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json

No request body is needed to call this API.

Below are the details on how you can use ASK SDK to perform a pause operation for a specific timer:

Copied to clipboard
async handle(handlerInput) {
        const {serviceClientFactory} = handlerInput;
        
        try {
            const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
            const timersList = await timerServiceClient.getTimers();
            console.log('Read timers: ' + JSON.stringify(timersList));
            const totalCount = timersList.totalCount;

            if(totalCount === 0) {
                return handlerInput.responseBuilder
                    .speak("No timer has created.")
                    .getResponse();
            }
            // pauses all timers
            for(const timer of timersList.timers ) {
                if(timer.status === 'ON'){
    // This will pause specific timer provided in “timer.id”.
                    await timerServiceClient.pauseTimer(timer.id);
                }
            };
            return handlerInput.responseBuilder
                .speak("Timer has been paused.")
                .getResponse();
        } catch (error) {
            console.log('Pause timer error: ' + JSON.stringify(error));
            if(error.statusCode === 401) {
                console.log('Unauthorized!');
                // we send a request to enable by voice
                // note that you'll need another handler to process the result, see AskForResponseHandler
                return handlerInput.responseBuilder
                    .addDirective({
                    type: 'Connections.SendRequest',
                    'name': 'AskFor',
                    'payload': {
                        '@type': 'AskForPermissionsConsentRequest',
                        '@version': '1',
                        'permissionScope': TIMERS_PERMISSION
                    },
                    token: 'verifier'
                }).getResponse();
            }
            else
                return handlerInput.responseBuilder
                    .speak("Something went wrong while pausing timer.")
                    .getResponse();
        }
    }

How to Resume a Specified Timer

Use this API to resume a previously paused timer. The timer will then run for the remaining time after resuming, unless it is otherwise paused or stopped.

Copied to clipboard
POST /v1/alerts/timers/{id}/resume
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json

No request body is needed to call this API.

Below are the details on how you can perform the resume operation using the ASK SDK:

Copied to clipboard
async handle(handlerInput) {
        const {serviceClientFactory} = handlerInput;
        
        try {
            const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
            const timersList = await timerServiceClient.getTimers();
            console.log('Read timers: ' + JSON.stringify(timersList));
            const totalCount = timersList.totalCount;

            if(totalCount === 0) {
                return handlerInput.responseBuilder
                    .speak("No timer has created.")
                    .getResponse();
            }
            // resumes all timers
            for(const timer of timersList.timers ) {
                if(timer.status === 'PAUSED'){
                // This will resume Timer which has been paused.
                    await timerServiceClient.resumeTimer(timer.id);
                }
            };
            return handlerInput.responseBuilder
                .speak("Timer has resumed successfully.")
                .getResponse();
        } catch (error) {
            console.log('Resume timer error: ' + JSON.stringify(error));
            if(error.statusCode === 401) {
                console.log('Unauthorized!');
                // we send a request to enable by voice
                // note that you'll need another handler to process the result, see AskForResponseHandler
                return handlerInput.responseBuilder
                    .addDirective({
                    type: 'Connections.SendRequest',
                    'name': 'AskFor',
                    'payload': {
                        '@type': 'AskForPermissionsConsentRequest',
                        '@version': '1',
                        'permissionScope': TIMERS_PERMISSION
                    },
                    token: 'verifier'
                }).getResponse();
            }
            else
                return handlerInput.responseBuilder
                    .speak("Something went wrong while resuming Timer.")
                    .getResponse();
        }
    }

Conclusion

With this blog we covered operations possible in Timer API and showcase how you can leverage the ASK SDK to call this API, and create a timer skill which will be useful for customers. If you have any question about what we’ve talked about in this blog, please visit the tech docs here.

Related Articles

How to Add a Timer to an Alexa Skill: Part 1
Optimizing Your Multimodal Experiences on the New Echo Show 15
How You Can Build with Amazon's Newest Devices & Services

Subscribe