Skip to content

Instantly share code, notes, and snippets.

@tylerdave
Last active January 6, 2022 22:34
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tylerdave/409ffa08e1d47b1a1e23 to your computer and use it in GitHub Desktop.
Save tylerdave/409ffa08e1d47b1a1e23 to your computer and use it in GitHub Desktop.
Nest API Example
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": "Nest API Example"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": "You must have a Nest developer account client ID and client secret to proceed. If you don't already have a developer account, sign up here and create a new client:\n\nhttps://developer.nest.com/clients "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "Import the modules we'll use:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "import hashlib\nimport json\nimport os\nimport requests",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": "Enter your Nest developer account client's credentials here:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "CLIENT_ID = 'CLIENT_ID_HERE'\nCLIENT_SECRET = 'CLIENT_SECRET_HERE'",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": "Define URLs and data used:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "AUTHORIZATION_URL = 'https://home.nest.com/login/oauth2?client_id={0}&state={1}'\nACCESS_TOKEN_URL = 'https://api.home.nest.com/oauth2/access_token'\nACCESS_TOKEN_POST_DATA = {\n 'code': '',\n 'client_id': CLIENT_ID,\n 'client_secret': CLIENT_SECRET,\n 'grant_type': 'authorization_code'\n }\nNEST_API_URL = 'https://developer-api.nest.com/devices.json?auth={0}'\nNEST_API_URL = 'https://developer-api.nest.com/?auth={0}'",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": "Generate an authorization URL:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "state = hashlib.md5(os.urandom(32)).hexdigest() # 'state' is just a random string of text\nprint AUTHORIZATION_URL.format(CLIENT_ID, state)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "https://home.nest.com/login/oauth2?client_id=CLIENT_ID_HERE&state=8199d94c7c08de7791e3a67b8384c4b2\n"
}
],
"prompt_number": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": "Visit the URL printed by the cell above, authorize the application to use your Nest account and enter the pincode in the cell below:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "ACCESS_TOKEN_POST_DATA['code'] = 'PINCODE_HERE'",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": "Request an access token:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "token_response = requests.post(ACCESS_TOKEN_URL, data=ACCESS_TOKEN_POST_DATA)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 6
},
{
"cell_type": "markdown",
"metadata": {},
"source": "Get the access token from the response. Raise an exception if there's an error:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "try:\n token_response.raise_for_status() # Rasie and exception if the token request results in an error\n access_token = token_response.json()['access_token']\nexcept Exception as e:\n print token_response.content\n raise e",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 7
},
{
"cell_type": "markdown",
"metadata": {},
"source": "Read data from the Nest API:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "nest_response = requests.get(NEST_API_URL.format(access_token))",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 8
},
{
"cell_type": "markdown",
"metadata": {},
"source": "Print the response nicely:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "print json.dumps(nest_response.json(), sort_keys=True, indent=4)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "{\n \"devices\": {\n \"thermostats\": {\n \"\": {\n \"ambient_temperature_c\": 21.5, \n \"ambient_temperature_f\": 72, \n \"away_temperature_high_c\": 29.0, \n \"away_temperature_high_f\": 85, \n \"away_temperature_low_c\": 15.5, \n \"away_temperature_low_f\": 60, \n \"can_cool\": true, \n \"can_heat\": true, \n \"device_id\": \"\", \n \"fan_timer_active\": false, \n \"has_fan\": true, \n \"has_leaf\": false, \n \"hvac_mode\": \"cool\", \n \"is_online\": true, \n \"is_using_emergency_heat\": false, \n \"last_connection\": \"2014-07-15T19:56:11.988Z\", \n \"locale\": \"en-US\", \n \"name\": \"Entryway (Home)\", \n \"name_long\": \"Entryway Thermostat (Home)\", \n \"software_version\": \"4.2.4\", \n \"structure_id\": \"\", \n \"target_temperature_c\": 21.5, \n \"target_temperature_f\": 71, \n \"target_temperature_high_c\": 20.5, \n \"target_temperature_high_f\": 69, \n \"target_temperature_low_c\": 19.0, \n \"target_temperature_low_f\": 67, \n \"temperature_scale\": \"F\"\n }\n }\n }, \n \"structures\": {\n \"\": {\n \"away\": \"home\", \n \"country_code\": \"US\", \n \"name\": \"Name\", \n \"structure_id\": \"\", \n \"thermostats\": [\n \"\"\n ]\n }\n }\n}\n"
}
],
"prompt_number": 9
},
{
"cell_type": "markdown",
"metadata": {},
"source": "More details here: https://developer.nest.com/documentation/api-reference"
}
],
"metadata": {}
}
]
}
@chrisbsmith
Copy link

Thanks for the write up. This was exactly what I had been hunting for. One question, have you found a way to make the authorization_code be persistent? I can run the python code once per authorization_code. Second run I have get a new authorization code. This doesn't help with a cron'd script.

@anupama-kumar
Copy link

Hi !

The last line - print json.dumps(nest_response.json() ..
I don't see a device key, only structures and metadata -- have I made a mistake while registering the product?

Would be really thankful.

@technicalpickles
Copy link

This was really helpful, thanks!

I was trying to do this following https://developers.nest.com/documentation/cloud/rest-quick-guide which says to use the Authorization header with your access_token, and that was consistently failing with 401 Unauthorized. Using an auth param instead seems to work, but I haven't seen documentation for it (that doesn't say much though, the documentation is pretty scattered).

@technicalpickles
Copy link

Actually, I figured out why the authorization header wasn't working. Making requests to developer-api.nest.com ends up doing a redirect to a firebase hostname, and the requests library strips authorization headers when doing redirects. https://github.com/kennethreitz/requests/issues/2949 talks about this more, specifically about how it happens working with the Nest API.

@diegodeodati
Copy link

Hi, if i want to set temperature?

regards

@pratapkrish
Copy link

What programming language do I have to use in order to do this? I'm new to Nest development.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment