In this codelab, you'll build a simple web app that talks to the Works with Nest API using Node.js, Electron, and Polymer.
You can either download all the sample code to your computer...
...or clone the GitHub repository from the command line.
git clone https://github.com/googlecodelabs/nest-cloud-nodejs.git
Head over to home.nest.com and log in with your given credentials. On the home page, add your thermostat by clicking on the ‘Add product' button and selecting ‘Nest Thermostat' from the popup menu.
Click through the installation instructions until you are prompted for an entry key. You can find your thermostat's entry key by pressing the thermostat's ring to bring up the menu. From there, navigate to Settings > Nest Account > Get Entry Key. Your device should look like this:
Now, type the entry key into the prompt from home.nest.com:
More info about device pairing can be found here.
Now, navigate to developers.nest.com and sign in with your given credentials. 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. Make sure you include Thermostat read/write v4 permissions as they will be required for this codelab. Include more if you like.
Now click on ‘Create Product'. Now you will see a page with your newly created product integration.
Click on your product and look for the ‘Keys' section over on the right-hand side. 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.
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
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)
To preview the app using Electron, run the following command:
node_modules/.bin/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:
NestApplicationInterface
and attaches it to the windowA 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:
// 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.
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 && node_modules/.bin/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.
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:
...
<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
.
...
<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:
...
<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:
...
// 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;
});
...
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.
Finally, you should remove your thermostat from your account. Head over to home.nest.com and click on your thermostat. From the thermostat control page, click on the gear icon in the top right corner to open the device settings menu. Scroll to the bottom and click on ‘Remove Thermostat'.
Congratulations, the app can now interact with Nest devices!
Any issues should be submitted to the github repo here.