Introduction: Nest Wifi Proximity C# Windows Phone App

Picture of Nest Wifi Proximity C# Windows Phone App

The following Instructable takes you through my creation of the Windows 8.1 Mobile Phone App "Nest Away". Nest Away controls my Nest Thermostat by detecting if my phone is within Wifi range of my home. As soon as I leave Wifi range the Nest Thermostat is automatically set to "Away" mode and when I re-enter Wifi range it switched to "Home" mode.

This Instructable assumes the reader has some knowledge of programming, as I will not be teaching you how to program, but I hope to show you the power of those little computers that we carry around with us each day that some people like to call "Phones".

I will be including the source code to the App so that anyone can use it as a starting point for their own development.

Step 1: The Problem...

Picture of The Problem...

I have a "Nest Thermostat" that controls the heating and cooling in my condo. These are amazing little devices that are "Learning Thermostats" that program themselves to your schedule and auto adjust their programming to be more energy efficient. It is also Wifi enabled and comes with its own app and also a open API.

One of the features that made me buy the unit was the "Auto Away" setting. The way they explain it is:

"The Nest Learning Thermostat uses Nest Sense™ (an exclusive combination of sensors and algorithms) to notice when you’re away and when you come home. With Auto-Away, the Nest Thermostat turns itself down automatically when you're away to prevent heating or cooling an empty home. Upon your arrival, the Nest Thermostat will return to your regular schedule."

In reality, in order for it to sense that you are at home you have to walk fairly close in front of the unit on a regular basis for it to detect you are home. The location of my Nest is not in a place that I walk by often and so I will be sitting at my desk only 10 feet away and the Nest will go into Auto Away mode which is annoying as I then have to get up and walk in front of the unit or open the app and click to tell it I am at home.

My other issue is that I live alone and do not keep a regular schedule (except for leaving for work at the same time each day). Sometimes I come straight home from work other days I could be out till midnight or any time in between, there is no pattern. I have come home to find that the nest ahs had the air conditioning or the heating running for hours even with out me home.

What I need it to be able to disable the Auto Away feature and have some other automated method to tell the Nest when I am home or when I am away without me having to perform a physical action.

Step 2: My Solution...

Picture of My Solution...

My initial thought was to use the Microsoft Phone Geo-Fencing ( https://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn342943.aspx ) option to detect when I enter of leave a certain radius of my home. This seemed to be a perfect solution but quickly fell apart for me as I discovered that I could not run the Windows phone emulator on my older computer / OS ( https://msdn.microsoft.com/en-us/library/windows/apps/jj863509(v=vs.105).aspx ). So in order to test I would need to move a physical device in and out of the geo range which was not practical especially since if I wanted it to be in debug mode the phone would have to be attached by a USB cable to my computer.

Also I was not keen on always having GPS on and being constantly checked as I was unsure on what that would do to the battery life of the phone.

Back to the Drawing Board....

As I was watching a video ( http://channel9.msdn.com/Series/Building-Apps-for-Windows-Phone-8-1/11 ) they made a passing reference to the phones ability to trigger an alert based on a "Network State Change" after a bit of digging I found that the Windows phone could report on the Public name of it current Wifi connection and, that when that network changed, that it could trigger an event (even in the background).

Since I live alone and I always have my phone with me then "Home" state became when my phone was connected to my own Wifi, "Away" is when I am connected to any other network including using the phones Data plan. This binary view of my life could control my Nest thermostat.

In order to test the App I would just need to be able to switch Wifi connections and monitor my Nest Status. To do this I pulled out my Android Tablet which has its own Sim card so that I could use it a second Wifi connection (My connection needed to be active in order to call the nest API when I was not connected to my home network). I used the Nest App on my work iPhone to monitor the Nest Status. My Nokia Windows Phone would run my Custom Windows 8.1 App.

I was Good to go!

Step 3: Nest API...

Picture of Nest API...

In order for this to work I needed to use the Nest API ( https://developer.nest.com/documentation/api-reference ) to change the settings on my thermostat. I signed up as a Nest Developer in order to access the API. Once registered you then need to go to: https://developer.nest.com/clients/ to create your OAUTH settings and describe your API use. Follow the instructions here: https://developer.nest.com/documentation/cloud/how-to-auth/ once you get your OAUTH settings in order to get your AUTH token that you can use in your API calls.

With the AUTH token you can now easily test the API. In Firefox (it handles JSON return code well) type the following in the address bar: (remove the space between "http" and "s" the editor here kept messing up the url by thinking it was a link and trying to format it)

http s://developer-api.nest.com/structures/?auth=[authToken]

It will return the following JSON (as seen in the second screen shot above):

{"xxxxxxxxxxxxxxxxxxxxxxxx":
    {
        "name":"Location Name",
        "country_code":"CA",
        "time_zone":"America/Montreal",
        "away":"home",
        "thermostats":["yyyyyyyyyyyyyyyyyyyy"],
        "structure_id":"xxxxxxxxxxxxxxxxxxxxxxxx"
    }
}

The "X's" are the Strcture code and the "Y's" are the Device Id. In order to change the status of the "away" (to either "home" or "away") you will need the "structure_id" that is returned. To change the status you must pass JSON to the API endpoint:


http s://developer-api.nest.com/structures/[structure_code]/?auth=[authToken]

And pass it either:

{"away":"away"}

or:

{"away":"home"}

Now to the coding...

Step 4: The Nest Away Windows App...

Picture of The Nest Away Windows App...

While I have been programming for many years and had even in the past (8years ago) have done some minimal .NET programming this is the first Phone App I have built in .NET. So I started like a Newbie by downloading Visual Studio Express 2013 for Windows (Free!) and then added the appropriate addins for Windows Phone development. I then downloaded the C# HelloWorld sample from MSDN to get a feel of things... and I was off...

I am not going to go through every iteration of the development but as a highlight these are the steps that I followed:

  1. Played with HelloWorld until I understood all the moving parts.
  2. Developed code to call the Nest API and display the results in the app when triggered by a button click.
  3. Expanded code to allow update through nest API (toggle between Home & Away - if current settings is away set to home etc.). This was the most time consuming as I could not find any examples of the correct syntax to use for the Nest API.
  4. Built Wifi active name detection called from a button click and displayed on the screen.
  5. Expand to save Wifi name to local storage.
  6. Implement backend process to register the event and to issue a simple static "TOAST" alert. (lol Toast! - I love how things are named sometimes.)
  7. Expand backend process to detect Wifi using previously created code from #4 above.
  8. Expand backend process again to communicate with Nest API using code from #3 above.
  9. Cleaned up app...

In the next section I will walk through the code and identify some tips & tricks and areas that made me stumble...

Step 5: The Interface...

Picture of The Interface...

Since this is basically a background App the interface is pretty basic. Just one button and a text block along with the header and footer.. I am sure that there are more preferred ways of doing this but this was simple and it worked. I basically just dragged the components from the toolbox, positioned them and updated the settings.

I also wanted a nice Logo and Splash screen so being Dutch I chose orange! then I added a circle to represent the Nest device and inside of that the Wifi Symbol. I really like how it came out.. It reminds me of a Radar Sweep that is used to detect objects - which is exactly what my App is supposed to do! Detect where I am..

Step 6: Start-up Settings...

Picture of Start-up Settings...

On app start-up, if the Home Wifi has been already set it is read from local storage and displayed on the screen so that you can verify that it is correct.

public MainPage()
        {
            this.InitializeComponent();
            this.NavigationCacheMode = NavigationCacheMode.Required;
            var settings = ApplicationData.Current.LocalSettings;
            var key = "nameHomeWifi";
            textWifiName.Text = " " + settings.Values[key];
        }

If the Home Wifi has not been set or needs to be reset because you changed your Wifi Name then the following code is called when the "Set Wifi Home Monitor" button is clicked. Basically it loops through the network connections on the phone and finds the active one. This name is then written to local storage and then displayed in the app in the text block.

private async void buttonRegisterWifiMonitor_Click(object sender, RoutedEventArgs e)
        {
            // Get Home Wifi Name
            var ssid = "";
            foreach (var connectionProfile in NetworkInformation.GetConnectionProfiles())
            {
                if (connectionProfile.IsWlanConnectionProfile && connectionProfile.GetNetworkConnectivityLevel() != NetworkConnectivityLevel.None)
                {
                    ssid = connectionProfile.ProfileName;
                    var settings = ApplicationData.Current.LocalSettings;
                    var key = "nameHomeWifi";
                    settings.Values[key] = ssid;
                    textWifiName.Text = ssid;
                    break;
                }
            }

Once the Name is determined the same button click continues and registers the background task.

// Register Background process
            string myTaskName = "BackgroundWifiCheck";
            // check if task is already registered
            foreach (var cur in BackgroundTaskRegistration.AllTasks)
                if (cur.Value.Name == myTaskName)
                {
                    await (new MessageDialog("Wifi Monitor is already registered")).ShowAsync();
                    return;
                }
            // Windows Phone app must call this to use trigger types (see MSDN)
            await BackgroundExecutionManager.RequestAccessAsync();
            // register a new task
            BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder();
            taskBuilder.Name = myTaskName;
            SystemTrigger trigger = new SystemTrigger(SystemTriggerType.NetworkStateChange, false);
            taskBuilder.SetTrigger(trigger);
            taskBuilder.TaskEntryPoint = typeof(BackgroundWifiCheck.TheTask).FullName;
            BackgroundTaskRegistration registration = taskBuilder.Register();
            await (new MessageDialog("Wifi Monitor is now registered")).ShowAsync();

It registers the event that is triggered when a "NetworkStateChange" is detected. When it is successfully registered a message appears informing you of its success.

That is all that the Human facing part of the app does... but for the magic... continue to the next step!

Step 7: The Magic Behind...

Picture of The Magic Behind...

When the backend process is called from a network state change the first thing it does is to get the current Wifi connection name. This is then used to compare to the stored Home Wifi name.

var deferral = taskInstance.GetDeferral();
var settings = ApplicationData.Current.LocalSettings;
  var key = "theCurrentWifi";
  var ssid = "";
  var checkHomeWifi = "";
  foreach (var connectionProfile in NetworkInformation.GetConnectionProfiles())
  {
      if (connectionProfile.IsWlanConnectionProfile && connectionProfile.GetNetworkConnectivityLevel() != NetworkConnectivityLevel.None)
      {
          ssid = connectionProfile.ProfileName;
          break;
      }
  }
  settings.Values[key] = ssid;

Once it detects the network I put in a 5 second delay as I found sometimes that my API call to Nest would not always connect. (I am sure there are better ways of doing this but it seems to work for me.)

var = Task.Run(async delegate<br>{
    await Task.Delay(TimeSpan.FromSeconds(5));
    return 0;
});
t.Wait();

Now we communicate with Nest and see what the status of the Thermostat currently is in order to know if we need to change its status.

Now I am sure all you programmers out there will be cringing right now as I am not using JSON components to read the results of the Nest API call... Believe me I tried but the way the return is formatted I was having a heck of a time and since I only needed 2 values from the response: The Structure Id & The Current Away Status I took the easy route and just used old school string parsing... :-)

Oh, another shortcut I took which is bad.. but I had meant to change it and then I forgot... The "Auth Code" for Nest is hardcoded into the app (first line below). This means that the app cannot be shared as it is. What I will do next (when I have some time) is to create a variable for Auth Code and have it enterable on initial setup of the app just like the Home Wifi Name. Except it would need to be entered into a text box and then saved in local storage. It is a very LONG code so that is why I initially took the shortcut, but you could always email it to your phone and then just cut and paste it into the setting screen.

string authToken = " --- Your Auth Code ---";<br>string uriNest = "https://developer-api.nest.com/structures/?auth=" + authToken;
            try
            {
                var client = new HttpClient();
                var uri = new Uri(uriNest);
                var Response = await client.GetAsync(uri);
                var statusCode = Response.StatusCode;
                Response.EnsureSuccessStatusCode();
                var ResponseText = await Response.Content.ReadAsStringAsync();
                string json = ResponseText;
                int structureFirst = json.IndexOf("{\"") + 2;
                int structureNext = json.IndexOf("\":{\"name\"");
                string structure = json.Substring(structureFirst, structureNext - structureFirst);
                int awayFirst = json.IndexOf("\"away\":") + 8;
                int awayNext = json.IndexOf("\",\"", awayFirst);
                string away = json.Substring(awayFirst, awayNext - awayFirst);
                homeStatus = "Already: " + away;

The next step is to determine if you need to update the Nest. I check the Home Wifi Name against the Current Wifi Name and if they are equal AND the current status is "Away" then I call the Nest API to set the status to "Home" if the status is already Home I do nothing. Same for if the Wifi names do not match, if current status is Home I update it to Away else do nothing...

uriNest = "https://developer-api.nest.com/structures/" + structure + "/?auth=" + authToken;<br>if (checkHomeWifi == ssid)
{
    if (away == "away")
    {
        setAway = new Away() { away = "home" };
        HttpResponseMessage response = await client.PutAsJsonAsync(uriNest, setAway);
        if (response.IsSuccessStatusCode)
        {
            homeStatus = "Home - Success!";
        }
        else
        {
            homeStatus = "Home - Fail!";
        }
    }
}
else
{
    if (away == "home")
    {
        setAway = new Away() { away = "away" };
        HttpResponseMessage response = await client.PutAsJsonAsync(uriNest, setAway);
        if (response.IsSuccessStatusCode)
        {
            homeStatus = "Away - Success!";
        }
        else 
        {
            homeStatus = "Away - Fail!";
        }
    }
 }

Lastly the background App sends a Toast to the phone. This will show a status alert on the phone identifying if there was a change and if it was successful based on the logic above.

ToastTemplateType toastTemplate = ToastTemplateType.ToastText02;<br>XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList textElements = toastXml.GetElementsByTagName("text");
textElements[0].AppendChild(toastXml.CreateTextNode("Nest Wifi change alert!"));
textElements[1].AppendChild(toastXml.CreateTextNode(homeStatus));
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));

That is my logic.

Step 8: The Full Code...

Picture of The Full Code...

I will not go into detail on the above screen shots but basically they are the settings that are needed to have the background process run correctly. I also included the Solution tree to give you an idea of the project structure.

And finally, the big Kahuna, I have also attached a zip file of my full source code so that if you want to try this on your own you can or you can use it as a starting point for your own project whether it is a Nest API project or a Wifi network detection app.

Step 9: App in Action

Picture of App in Action

This is my first "Coding" Instructable so it was quite hard to format it into a sensible flow... it is not like building something where you go in a straight line from beginning to end but I hope it I presented it in a way that inspires you.

I have added Notes to the Images above to help you follow along with the process of how the app functions from a human usabilty standpoint.

Step 10: And in Real Life...

Picture of And in Real Life...

Just to prove it is not just mockups! :-)

Note: This is not meant to be a commercial app, it is something that I can use to help me and that I can learn from but there would have to be a lot more work done to make it a "product". For instance what if there are two people sharing an apartment? How would that work? Maybe use Microsoft Azure and store multiple device statuses in the cloud...

Comments

unlucky.break (author)2015-11-25

Hello there. Nice instructable. How would you make this so that multiple phones could use the same program? Would they interfere with each other?

MadDocks (author)unlucky.break2015-11-25

Thanks, basically this could work with multiple users as long as you had a database that your phone would check & update and you would need a setting page on your phone. So the settings would give the number of people in your "home" and a unique code for each one. Initial state of database has say both people at home. If one person leaves their phone checks the database and sees that the other person is still home so it doe snot change the Nest setting. If the other person leaves then it check the database and sees no one home so it sets the nest to away. If one arrives home it sets the nest to home. If the second person comes home they are logged as home but the setting on the Nest do not change. Only potential problem is that if you both leave at the same time and they both read the db that says the other one is there before the other gets a chance to turn of the Nest. This can be overcome if they do a double check as both then will be set as away.

Funky Diver (author)2015-05-20

Awesome.... I haven't read it all as I don't need this facility to control our Nest... And then I had a think, why not develop this further with a Geo-Ring fence, possibly even a pop up, so that when your phone "thinks" you're on your way he it activates heating/cooling to suit. Just a thought :)

MadDocks (author)Funky Diver2015-05-20

My initial thought was the same as yours and if you read my "Step 2: The Solution" you will see I wanted to use that but there were a few issues that I ran into first it was very hard for me to test as I do not have the most up to date computer which does not allow me to run the windows phone emulator. Without it testing different Geo points is very difficult. If I wanted to test in debug mode I would need to tether the phone to my computer with a usb cable.. then to test Geo I would need a REALLY long cable :-) My other concern was battery life with the GPS always active, I am a heavy phone user and am usually sitting on 1% battery anyways so the less active features the better.

I find the WiFi solution is actually better for the environment because I have to be physically in the Apartment for it to activate and as soon as I leave it deactivates. So even if I go down to the coffeshop in the lobby for a hour I am set to be "Away" where the GPS could not really detect that difference.

But please vote for me so I can get a new laptop! :-)

jfonseca lópez (author)2015-05-18

Wow dude, you make it awesome, I jus develop on android, some windows, some Linux and arduino so I can't really help you but... What if yo make the program support multiple devices (At least WiFi does) so it doesn't matter who is left on home any time that there's at least one, another problem is multi schedule app so every one an be comfortable when alone in house. The way I do it on Arduino is something like ping, if all devices saved on memory doesn't respond it's mode Away, if at least one respond OK well time to get on and you can check who responds and make average of all the schedules active so every one will be comfortable.
This is making long and long so it's time to stop. Sorry if I make a mistake writing cause my Mather language isn't English haha.

About This Instructable

4,986views

78favorites

License:

More by MadDocks:No Smoker Smoked Burger aka Seasoning Meat with Meat!Nest Wifi Proximity C# Windows Phone AppModern Industrial Copper Room Lighting
Add instructable to: