How to use the NEST API using FirebaseSharp

This article demonstrates how to call Nest API from .NET using FirebaseSharp, an unofficial open source Firebase.NET client.

To follow along and test drive Nest API you do not need to own a Nest device, a simulator is available.

Background

Nest API enables developers to integrate with their Nest Learning Thermostat™ and Nest Protect: Smoke + Carbon Monoxide™.

But although the API comes in different flavours (Firebase, REST and REST Streaming), currently you’re a bit left in the cold when trying to consume the API’s real time features from .NET:

  • the official Firebase client libraries currently target Web (JavaScript client), iOS and Android
  • the alternative REST Streaming is based on EventSource, another option that doesn’t come out of the .NET box
  • and finally the REST option is not intended for real-time updates, with Nest placing limits on the number of calls you can make in a specific time period (so forget about polling for updates)

Looking for a solution I stumbled upon FirebaseSharp, which enables you to call Nest API using the Firebase protocol and get all the real time goodness.

Read below to discover what happened next.

Using the code

You can download the completed project.

Get access to Nest API

To get access to Nest API, you have to register your client.

Complete this easy no-hassle step at https://developer.nest.com/

  1. Sign in
    • Sign up
  2. Clients (available when signed in)
    • Register new client
      • OAuth Redirect URI
      • Permissions
        • Choose Thermostat > read permission at the minimum, to successfully run this demo

Well done, you now have a client ID and secret which are required for OAuth in the next step.

Get access to Nest device data

To get access to Nest device data, Nest explains why and how they use OAuth.

So let’s translate this to .NET

First update the App.config with your client OAuth settings, copy them from your Nest client settings:

<add key="client-id" value="<client-id>" />
<add key="client-secret" value ="<client-secret>" />

To request access, we simply browse to the authorization URL, which uses your client ID to identify the application requesting access:

var authorizationUrl = string.Format("https://home.nest.com/login/oauth2?client_id={0}&state={1}",
    ConfigurationManager.AppSettings["client-id"], "dummy-random-value-for-anti-csfr");

using (var process = Process.Start(authorizationUrl))
{
    Console.WriteLine("Awaiting response, please accept on the Works with Nest page to continue");
}

If the user accepts, Nest redirects to the OAuth redirect URI you configured.

To keep this demo simple and self contained in the console application, we self-host ASP .NET Web API, to handle the repsonse:

using (WebApp.Start<Startup>(url: "http://localhost:9000/"))
{
    // snip
}

So, first the state argument is validated, this should match the anti-cross-site forgery request token we sent to ensure the integrity of the communication.
Then the received authorization code is used to request an access token.
Again to keep it simple, the resulting access code response is cast to dynamic, so we can access the token property without having to properly deserialize to a strongly typed object.

/// <summary>
/// Called by Nest when user grants access
/// </summary>
/// <param name="state">Anti-cross-site forgery request token</param>
/// <param name="code">Code to request access token</param>
/// <returns>Access code</returns>
public HttpResponseMessage Get(string state, string code)
{
     if (!string.Equals("dummy-random-value-for-anti-csfr", state))
         throw new HttpResponseException(HttpStatusCode.BadRequest);

     var accessToken = GetAccessToken(code);
     Program.SubscribeToNestDeviceDataUpdates(accessToken);

     var response = new HttpResponseMessage(HttpStatusCode.OK) 
     {
         Content = new StringContent("Well done, you now have an access token which allows you to call Nest API on behalf of the user.") 
     };
     response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");

     return response;
}

private async Task<string> GetAccessToken(string authorizationCode)
{
    var url = string.Format("https://api.home.nest.com/oauth2/access_token?code={0}&client_id={1}&client_secret={2}&grant_type=authorization_code",
                authorizationCode, ConfigurationManager.AppSettings["client-id"], ConfigurationManager.AppSettings["client-secret"]);

    using (var httpClient = new HttpClient())
    {
        using (var response = httpClient.PostAsync(url, content: null).Result)
        {
            var accessToken = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result);

            return (accessToken as dynamic).access_token;
        }
    }
}

Well done, you now have an access token which allows you to call Nest API on behalf of the user.

Simulate Nest device

To simulate a Nest device, you have to use the Nest Developer Chrome Extension.

If you have any trouble with this, follow the easy steps at https://developer.nest.com/documentation/chrome-extension, in a nutshell:

  1. Launch Google Chrome
  2. Install the Nest Developer Chrome Extension
  3. Browse to https://home.nest.com
  4. Open the Developer tools
  5. Open the Nest tab
  6. Add a thermostat

Well done, you now have a virtual device which can simulate real time events which we’ll consume in the next step.

Consume real-time updates

Get FirebaseSharp through nuget, to install through the Nuget Package Manager Console:

Install-Package FirebaseSharp

Once the access token is in, we initialize a Firebase client, that points to Nest API using the access token we retrieved. In this case we listen to the devices, but go ahead and consult the Nest API reference to find out your options on how granular you want to be.

Change the current temperature in the Nest Developer Chrome Extension and witness the real-time updates 🙂

var firebaseClient = new Firebase("https://developer-api.nest.com", _accessToken);
var response = firebaseClient.GetStreaming("devices",
        changed: (s, e) => {
            if (e.Path.Contains("ambient_temperature_f"))
                Console.WriteLine("Current temperature has been updated to: {0}.", e.Data);
        });

Well done, you have a working solution!

Points of Interest

Official support for C# by Firebase might come, mentioned in a blog post by the author of FirebaseSharp, read it here http://www.roberthorvick.com/2014/03/26/firebase-net-client-library/.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.