In this codelab, you'll build a simple web app that talks to the Works with Nest API using Node.js, Electron, and Polymer.

What you'll learn

What you'll need

How will you use this tutorial?

Read everything thoroughly Read each step and complete the exercises

How would rate your experience with building web apps?

Novice Intermediate Proficient

Get the source code

You can either download all the sample code to your computer...

Download Zip

...or clone the GitHub repository from the command line.

git clone https://github.com/googlecodelabs/nest-cloud-nodejs.git

Getting your Product ID and Product Secret

Now, navigate to developers.nest.com and sign in with your given credentials. The ‘Sign In' button may be hidden under the menu icon on some browsers. Accept the terms of service and click on the button to create a cloud product. This will bring you to a page where you can fill in product details and permissions. Give your product a unique name, such as ‘<your name> + codelab'. Make sure you include Thermostat read/write v5 permissions as they are be required for this codelab. Include more if you like. Also, if you do not have your web server, use ‘https://nest.com' for the Support URL field.

Now click on ‘Create Product'. You will see a page with your newly created product integration.

Click on your product and look for the ‘Keys' section. Here you will find your Product ID and Product Secret.

Copy these values and paste them into the productID and productSecret values in the config.json file. Don't worry about your token, we'll generate one later.

Install dependencies

This project uses NPM, Bower, and Gulp to manage dependency packages and automate the build process. You will need both npm and bower installed globally first, as well as gulp-cli. Go to the source code folder (‘nest-cloud-nodejs') in the terminal. Use the following commands to get the project ready for the next step.

npm install
bower install
gulp

Verify the installation

After gulp finishes, your folder structure should look like this. Note the newly created dist/ folder.

nest-cloud-nodejs/
    bower.json
    bower_components/
    config.json
    dist/    <------------ This was created by Gulp
    gulpfile.js
    node_modules/
    package.json
    readme.md
    src/
    Step5 (and 6 and 7)

Run the app

To preview the app using Electron, run the following command:

electron dist/main.js

The app should look like this:

As you can see, there isn't much going on here. First we need to connect to the Nest API

Select the connect button. This will open up a separate window where you can log in to the Nest portal, accept the terms and conditions, and get a Pincode. The image below shows a sample pincode.

Copy the Pincode generated by the window and paste it into the input dialog in the app. After the app connects to the API, it should look like this.

Pretty boring, huh? Let's spice it up with some devices!

The main way to interact with the Nest API in this tutorial is to use NestApplicationInterface.js. This is a wrapper class that handles all API calls. It has a network manager that handles the REST calls and a representation manager that keeps track of device representations.

Open src/app.js. This file currently does three things:

A hydrated event is fired after the Nest interface registers with the API and receives a cache of device representations. This is a good place to start. Modify the callback function so that it looks like this:

app.js

// listen for hydrated events:
  NestApplicationInterface.addHydratedListener(function(){
    console.log("hydrate event");
    // once hydrated, get the device cache
    var deviceCache = NestApplicationInterface.getAllDevices();
    // pass the device cache to the device page Polymer element
    var page = Polymer.dom(document).querySelector('#device-page');
    page.deviceObject = deviceCache;
    page.hasDevices = true;
  });

The getAllDevices() method returns an object containing device categories. Each category has a collection of devices. The page variable is a custom Polymer component that takes the returned deviceCache and displays each device according to its collection type. It renders when the hasDevices flag is set to true.

Reset the app

Now go back to the terminal. If you haven't yet quit Electron, type Ctrl + C from the terminal. Use the following command to build and run the app again:

gulp && electron dist/main.js 

Now, it should look something like this:

The Nest API exposes multiple device properties based on which permissions are enabled. For this example, we will look at both read and write properties for the thermostat. More information about the data model can be found here.

Displaying Thermostat properties

Open nest-thermostat.html inside the src/custom_elements/ directory. Add a <div> and a few <span> elements to the paper-card so that it looks like this:

nest-thermostat.html

...
<paper-card heading="{{device.name}}">

    <div class="card-content">
        <span>Can Heat: {{device.can_heat}}</span><br>
        <span>Can Cool: {{device.can_cool}}</span><br>
        <span>HVAC State: {{device.hvac_state}}</span><br>
        <span>Ambient Temp (F): {{device.ambient_temperature_f}}</span><br>
        <span>Target Temp (F): {{device.target_temperature_f}}</span>
    </div>

</paper-card>
...

These properties are read-only and pretty intuitive. Check out the documentation linked above to add more properties.

Now, quit and rebuild the app again to see the properties exposed on the UI.

Viewing a property is neat, but manipulating a device is where the real fun begins. First, add a <div>, a <paper-input>, and a <paper-button> to the card in nest-thermostat.html.

nest-thermostat.html

...
<paper-card heading="{{device.name}}">

    <div class="card-content">
        <span>Can Heat: {{device.can_heat}}</span><br>
        <span>Can Cool: {{device.can_cool}}</span><br>
        <span>HVAC State: {{device.hvac_state}}</span><br>
        <span>Ambient Temp (F): {{device.ambient_temperature_f}}</span><br>
        <span>Target Temp (F): {{device.target_temperature_f}}</span>
    </div>

    <div class="card-actions">
        <paper-input label="Target Temperature (F)" id="target-temp"></paper-input>
        <paper-button on-click="handleUpdate">Update</paper-button>
    </div>

</paper-card>
...

The input's value will be used to update the target temperature property of the thermostat. When the ‘update' button is selected, a handleUpdate() function is called. Add this function to the Polymer object as seen below:

nest-thermostat.html

...
<script>
    Polymer({
      is: 'nest-thermostat',
      properties: {
        device: Object
      },
      handleUpdate: function(){
        var NestApplicationInterface = window.NestApplicationInterface;

        var thisDevice = this.device;
        //get the value from the input box
        var targetTemp = this.$$('#target-temp').value;

        NestApplicationInterface.updateDevice(
          thisDevice,
          'target_temperature_f',
          targetTemp
        ).then(
          (success) => {
            console.log('updated', success);
          },
          (failure) => {
            console.warn('failure', failure);
          }
        );
      }
    });
</script>
...

Finally, the app needs to know what to do when it sees an update from the API. Modify the updateListener callback in app.js so that it looks like this:

app.js

...  
  // listen for update events:
  NestApplicationInterface.addUpdateListener(function(){
    console.log("update event");
    var deviceCache = NestApplicationInterface.getAllDevices();
    // pass the device cache to the device page Polymer element and set its hasDevices flag to true
    var page = Polymer.dom(document).querySelector('#device-page');
    page.deviceObject = deviceCache;
    page.hasDevices = true;
  });
...

Final run

Save all modified files, run gulp, and start the app again. Now, it should look like this:

Go ahead and update the target temperature in the App. It should be reflected in the read-only section above. If you're modifying a physical thermostat, you should see it change as well.

Congratulations, the app can now interact with Nest devices!

What we've covered

Next Steps

Learn More

Feedback

Any issues should be submitted to the github repo here.