Writing a Personal Automation API: Part 4 - Your First Integration

Posted by Matthew Watkins on December 23, 2016

In my previous post, I outlined how to add authentication to the personal automation API we’ve been building using Google Apps Script. Now I’ll talk about how to start harnessing the power of the Maker channel on IFTTT to connect our API to anything and everything we want to, starting with Nest as an example.

Building an HTTP Utility

Before we get started building the latest and greatest integrations to any of those APIs you’ve been eyeing, we’ll need to create a utility to send HTTP requests. I just created an object a wrapper around the Google’s UrlFetchApp. There isn’t a whole lot going on here, but having this thin layer wrapping things up makes life a bit easier:

/*
 * Enum for HTTP request method types
 */
var HttpRequestMethod = {
  GET: 'GET',
  POST: 'POST'
};

/*
 * "Constructor" for the HttpUtility
 */
function HttpUtility() {
  /*
   * Issues a request and returns the contents as text
   */
  this.issueTextRequest = function(method, url, body, headers, ignoreInvalidSslCerts) {
    return this.issueRequest(method, url, body, headers, ignoreInvalidSslCerts).getContentText();
  };
  
  /*
   * Issues a request and returns the HTTP response object
   */
  this.issueRequest = function (method, url, body, headers, ignoreInvalidSslCerts) {
    return UrlFetchApp.fetch(url, {
      muteHttpExceptions: true,
      method: method,
      payload: body,
      headers: headers || {},
      validateHttpsCertificates: !ignoreInvalidSslCerts
    });
  };
}

Integrating with the IFTTT Maker channel

Once you enable the maker channel integration on your IFTTT account, you unlock nearly infinite power over IFTTT’s connected services. With a little bit of configuration on your IFTTT portal, you can basically turn your Maker integration into a proxy API for anything.

Setting things up on IFTTT

First you’ll need to setup the Maker and Nest thermostat channels on IFTTT. Once you’ve done that if you go to the settings page for your IFTTT Maker channel, you’ll see that you are assigned a URL with long access key in it to use in URLs for Maker applets. Copy that key down since you’ll need it later. Paste the URL into your browser’s address bar and you end up at the documentation for how to trigger events in the Maker channel. We’ll use that knowledge in just a minute in our API code.

Creating a Maker to Nest applet

Next I created an applet that configured IFTTT to set the temperature range in my home Nest when it receives a certain type of web request to the URL from the Maker channel:

Trigger: Maker receives a web request Event name: nest.temp.set-range Action: Nest Thermostat sets temperature range

Select your device. Set the ingredient for the Low temperature to Value1 and the High temperature to Value2.

Once finished, you can test it if you want to by visiting the documentation URL I mentioned earlier. It contains a tool to issue Maker requests from your browser.

Building the IFTTT Utilities

We’ll use that knowledge from the previously mentioned maker documentation page to write an IftttUtility that uses the HttpUtility we wrote a minute ago to issue web requests:

/*
 * "Constructor" for the IftttUtility
 */
function IftttUtility() {
  /*
   * Triggers the specified maker event with the values passed in
   */
  this.triggerMakerEvent = function(event, val1, val2, val3) {
    var fullURL = 'https://maker.ifttt.com/trigger/' + event + '/with/key/' + this.getMakerAccessToken();
    var result = new HttpUtility().issueTextRequest(HttpRequestMethod.POST, fullURL, {
      value1: val1,
      value2: val2,
      value3: val3
    });
    if (result !== 'Congratulations! You\'ve fired the ' + event + ' event') {
      throw new WebApiException(ErrorCode.IFTTT_ERROR, result);
    }
  };
  
  /*
   * Sets the access token for the IFTTT maker service in the "database"
   */
  this.setMakerAccessToken = function(token) {
    return new DbUtility().setObject('IftttUtility.MakerAccessToken', { text: token });
  }
  
  /*
   * Gets the access token for the IFTTT maker service in the "database"
   */
  this.getMakerAccessToken = function() {
    return new DbUtility().getObject('IftttUtility.MakerAccessToken').text;
  }
}

And now we’ll create a small utility specifically to trigger the Nest applet we wrote:

/*
 * "Constructor" for the NestUtility
 */
function NestUtility() {
  /*
   * Sets the range of the Nest. Note: per https://ifttt.com/nest_thermostat,
   * this works only when Nest is set to Home.
   */
  this.setTemperatureRange = function(low, hi) {
    new IftttUtility().triggerMakerEvent('nest.temp.set-range', low, hi);
  };
}

A note on IFTTT and Nest Home/Away

You’ll see in the note that this only works if your Nest is already in Home mode. If it’s not already in mode then IFTTT will silently succeed the request. And there is no way to force your Nest to Home or Away mode via IFTTT right now. In my case this isn’t a problem because I disabled Nest’s Home/Away detection. It kept switching to away mode while I was upstairs and took too long to switch to away mode once everyone left the house. I wanted something more precise– something not controlled by motion in front of the thermostat but by location of cell devices (I’ll be talking about how I hooked all that up in a future post).

Adding a new controller to your API

Now let’s make it all official and add a controller to allow us to set nest temperature ranges from our API in a new SmartHomeController:

/*
 * "Constructor" for the SmartHomeController
 */
function SmartHomeController() {
  this.name = 'SMART_HOME';
  this.actions = [
    // Sets the home temperature range
    new ControllerAction('SET_TEMP_RANGE', function(data) {
      new NestUtility().setTemperatureRange(data.low, data.hi); 
    })
  ];
}

Currently the controller only has one action, but we’ll be adding more as we think of new smart home devices we want to control.

Testing it all out

Once we deploy our API, if we issue the appropriate web request…

{
  "auth_token": "your-api-code",
  "action": "SMART_HOME.SET_TEMP_RANGE",
  "data": {
    "low": 62,
    "hi": 73
  }
}

… then you should see a successful response:

{
  "success": true,
  "data": {},
  "error": null
}

If you check your IFTTT applet activity log, you should see that your applet ran successfully and your home Nest should be updated within a few seconds (assuming it has good network connectivity of course).

In the next post I’ll cover adding more services and integrations.

This post first appeared on Another Dev Blog