Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
I glimpsed a post in the RSS feeds today on how to connect Nest data with a Shiny dashboard and was compelled to post a less brute-force way to get data from the Nest API. The authors of the Shiny+Nest post used system
calls to curl
and regular expression character vector operations to slice, dice & work with the Nest API/data. However, we have packages like RCurl
, curl
and httr
that all make system
calls unnecessary. Here’s how to use the Nest API in a more R-like (or httr
-like) fashion.
Nest & OAuth 2.0
Nest uses OAuth 2.0 for authentication. As the authors of the other post pointed out, you’ll need to go to https://developer.nest.com/clients
(create an account if you don’t already have one) to setup a new client, making sure to leave the OAuth Redirect URL
field blank. Copy the Client ID for use later and store the Client secret in your .Renviron
file as NEST_CONSUMER_SECRET=...
(restart any open R sessions so R will re-read the .Renviron
file).
Once your API client information is setup, you’ll need a way of working with it. We first create a Nest OAuth endpoint that has the core URLs that httr
will use to help authorize the client with. Unfortunately, not all OAuth 2.0 endpoints work the same way. For the Nest API an initial state
parameter is required even if using PIN-based authentication (which we are in this example since Nest doesn’t honor a dynamic callback URL as far as I can tell). This is how top setup the httr
endpoint.
library(httr) library(jsonlite) nest <- oauth_endpoint( request=NULL, authorize="https://home.nest.com/login/oauth2?state=login", access="https://api.home.nest.com/oauth2/access_token" ) |
Now, we need to setup the “app”. This is more of an “R” need than an “OAuth” need. Use the Client ID you copied earlier. httr
will pull the secret from the environment variable you created.
nest_app <- oauth_app("nest", key="a8bf6e0c-89a0-40ae-869a-943e928316f5") |
With that out of the way, now we authorize the client. Because we’re using PIN-based authentication, the user will have to cut/paste the URL displayed in the R Console into a browser then cut/paste the PIN displayed in the browser back into the R Console. With cache=TRUE
this will be a one-time event.
nest_token <- oauth2.0_token(nest, nest_app, use_oob=TRUE, cache=TRUE) |
We can now use our shiny new token to make Nest API calls.
Using the Nest API
Since this is not a detailed introduction to the Nest API in general, you may want to take the time to read their documentation. Here’s how to get a list of all the devices for the account and then read the data from the first thermostat. I’m gaming this a bit since I only have one Nest device and it is a thermostat, but you can use their simulator to play with more data.
To get all the devices in use, it’s just a call do the devices
path. Again, not all OAuth 2.0 APIs work the same way, so instead of embedding the access token into the http request headers, you need to specify it in the query parameters:
req <- GET("https://developer-api.nest.com", path="devices", query=list(auth=nest_token$credentials$access_token)) stop_for_status(req) devices <- fromJSON(content(req, as=text)) |
Now, devices
contains a very ugly list (most JSON APIs return really ugly responses) but we can easily get the ID of the first thermometer (which we’ll need to use in the next API call) by doing:
first_thermostat <- names(devices$thermostats)[1] |
Use str(devices)
to see what else is there for use.
Now, to get the data from thermostat, all you have to do is:
req <- GET("https://developer-api.nest.com/", path=sprintf("devices/thermostats/%s", first_thermostat), query=list(auth=nest_token$credentials$access_token)) stop_for_status(req) thermo <- data.frame(fromJSON(content(req, as="text")), stringsAsFactors=FALSE) |
And, you can display the current temperature/humidity via:
cat(thermo$ambient_temperature_f, "F / ", thermo$humidity, "%", sep="") |
Fin
Ideally, one would wrap this into a package (which I may do but feel free to take this code and make one before I get the cycles to get to it) and add more error checking and convenience functions for working with the data. But, you can now adapt the Nest+Shiny dashboard post code to use proper API calls and data structures vs system("curl…")
and gsub()
.
A contiguous version of the above code is in this gist.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.