I debated posting this as it may bring a tidal wave of PM's and whatnot that I don't have much time for (my second child is being born in a few days). However after more thought I figured I could at least give people some direction.
I have finished writing code that pulls together Alexa, Hue Emulator 0.2.1, Logitech Harmony, Google Nest, and RainMachine. I can do things like:
“Alexa turn on TV”
“Alexa turn on Playstation”
“Alexa set Thermostat 74”
“Alexa turn on Sprinkler 2”
It's the first C# app I have ever wrote, my code is sloppy, has hard coded values for IP, Username, and Passwords, not very oop, requires IIS/.Net4.5, and in no shape to share. But I will post as-is below as I thought I would let people know the basics of how I did it in case anyone else would like to make a more refined version.
Everything gets setup in the Hue Bridge as a Light.
All on and off urls point back at my custom Microsoft C# .NET ASPX web site.
It's a single page takes in two URL parms (Operation and Intensity[Optional])
Thermostat uses Intensity Percentage to get back a numerical value, if its outside of 65 - 81 I hard code 74 to make sure things dont get out of hand
Website has "If" sections for each Operation type, examples of Operations are like "Light-Kitchen-On" or "Nest" or "RainMahine-Zone2-On"
In each If section I do whatever option is needed,
for ISY I simply call the REST API accordingly
for Harmony I actually call a prebuilt c++ application that takes command line parms (http://sourceforge.net/projects/harmonyhubcontrol/files/)Note: I really tried hard to use other 3rd party c# code to do it directly within the web app but I failed alot due to the messed up XMPP protocol Harmony uses and finally just had the website execute this exe which works flawlessly (and still quick)
for the Nest I call their REST API accordingly
for RainMachine again I call their REST API Accordingly
Most of my web calls use the WebRequest or WebClient .NET classes
Notes about Nest
Nest's API's are great, you do have to go and sign up for a web developer account.
Then create a program (put anything it wont really matter)
Once you have a program you will get a client ID and Client Secret
Go here in a browser and get a PIN
https://home.nest.com/login/oauth2?client_id=<clientID>&state=Balls
Then go here with your client ID, Client secret, and PIN (note: PIN is a one time use)
https://api.home.nest.com/oauth2/access_token?code=<PIN>&client_id=<clientid>&client_secret=<client_secret>&grant_type=authorization_code
You should get back a session key
"{\"access_token\":\"c.fyCVHgmvY1bCXchYdfjhfjghfjhgfjgdfkhfkghfkghfFGRgrtR3rChnjrSEZmc\",\"expires_in\":315360000}"
This session key can be hardcoded into the code below as its good for 10 years then you never have to worry about coding a logon to Nest (quicker too)
Harmony Notes:
Used this code to compile an exe: (http://sourceforge.net/projects/harmonyhubcontrol/files/)
Simply call the exe with switches
can use exe tool to discover commands, devices, activities
RainMachine Notes:
By far the best documented API, was quick and easy, you shouldn't have any problems with this one
CODE:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Net;
using System.Web.Script.Serialization;
using System.Collections.Specialized;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Net.Security;
namespace ISY_Pokey
{
public partial class _Default : System.Web.UI.Page
{
class RainMachine
{
public string Password { get; set; }
public string access_token { get; set; }
public string checksum { get; set; }
public string expiration { get; set; }
public string statusCode { get; set; }
}
public void ProcessURI(string URI)
{
try
{
WebClient webClient = new WebClient();
webClient.Credentials = new NetworkCredential("ISYUsername", "ISYPassword");
Stream stream = webClient.OpenRead(URI);
}
catch (WebException ex)
{
if (ex.Response is HttpWebResponse)
{
switch (((HttpWebResponse)ex.Response).StatusCode)
{
case HttpStatusCode.NotFound:
break;
default:
throw ex;
}
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["operation"] != null)
{
int intLightLevel;
string LightLevel = "255";
if (Request.QueryString["LightLevel"] != null)
{
if (int.TryParse(Request.QueryString["LightLevel"], out intLightLevel)) { LightLevel =intLightLevel.ToString(); }
}
int intNestLevel;
string NestLevel = "76";
if (Request.QueryString["NestLevel"] != null)
{
if (int.TryParse(Request.QueryString["NestLevel"], out intNestLevel))
{
if (intNestLevel > 68 && intNestLevel < 81)
{
NestLevel = intNestLevel.ToString();
}
}
}
if (Request.QueryString["operation"] == "Light-On-LivingRoomLED")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/36981/cmd/DON/");
}
if (Request.QueryString["operation"] == "Light-Off-LivingRoomLED")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/36981/cmd/DOF/");
}
if (Request.QueryString["operation"] == "Light-On-LivingRoom")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/2F%20CF%20A6%201/cmd/DON/" + LightLevel);
}
if (Request.QueryString["operation"] == "Light-Off-LivingRoom")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/2F%20CF%20A6%201/cmd/DOF/");
}
if (Request.QueryString["operation"] == "Light-On-Breakfast")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/8052/cmd/DON/" + LightLevel);
}
if (Request.QueryString["operation"] == "Light-Off-Breakfast")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/8052/cmd/DOF/" );
}
if (Request.QueryString["operation"] == "Light-On-Kitchen")
{
ltNotify.Text = Request.QueryString["operation"];
//Breakfast
ProcessURI("http://192.168.1.10/rest/nodes/8052/cmd/DON/");
//Kitchen Main
ProcessURI("http://192.168.1.10/rest/nodes/21177/cmd/DON/");
//Kitchen Under Cab
ProcessURI("http://192.168.1.10/rest/nodes/19847/cmd/DON/");
//Kitchen Island
ProcessURI("http://192.168.1.10/rest/nodes/2B%20FD%2080%201/cmd/DON/");
}
if (Request.QueryString["operation"] == "Light-Off-Kitchen")
{
ltNotify.Text = Request.QueryString["operation"];
//Breakfast
ProcessURI("http://192.168.1.10/rest/nodes/8052/cmd/DOF/");
//Kitchen Main
ProcessURI("http://192.168.1.10/rest/nodes/21177/cmd/DOF/");
//Kitchen Under Cab
ProcessURI("http://192.168.1.10/rest/nodes/19847/cmd/DOF/");
//Kitchen Island
ProcessURI("http://192.168.1.10/rest/nodes/2B%20FD%2080%201/cmd/DOF/");
}
if (Request.QueryString["operation"] == "Light-On-Laundry")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/47290/cmd/DON/");
}
if (Request.QueryString["operation"] == "Light-Off-Laundry")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/47290/cmd/DOF/");
}
if (Request.QueryString["operation"] == "Light-On-Hallway")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/2F%20CB%2050%201/cmd/DON/" + LightLevel);
}
if (Request.QueryString["operation"] == "Light-Off-Hallway")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/2F%20CB%2050%201/cmd/DOF/");
}
if (Request.QueryString["operation"] == "Light-On-Patio")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/48068/cmd/DON/" + LightLevel);
}
if (Request.QueryString["operation"] == "Light-Off-Patio")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/48068/cmd/DOF/");
}
if (Request.QueryString["operation"] == "Light-On-Foyer")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/4669/cmd/DON/" + LightLevel);
}
if (Request.QueryString["operation"] == "Light-Off-Foyer")
{
ltNotify.Text = Request.QueryString["operation"];
ProcessURI("http://192.168.1.10/rest/nodes/4669/cmd/DOF/");
}
if (Request.QueryString["operation"] == "Shit-On")
{
ltNotify.Text = Request.QueryString["operation"];
//TVLED
ProcessURI("http://192.168.1.10/rest/nodes/36981/cmd/DON/");
//Breakfast
ProcessURI("http://192.168.1.10/rest/nodes/8052/cmd/DON/");
//Kitchen Main
ProcessURI("http://192.168.1.10/rest/nodes/21177/cmd/DON/");
//Kitchen Under Cab
ProcessURI("http://192.168.1.10/rest/nodes/19847/cmd/DON/");
//Kitchen Island
ProcessURI("http://192.168.1.10/rest/nodes/2B%20FD%2080%201/cmd/DON/");
//LivingRoom
ProcessURI("http://192.168.1.10/rest/nodes/2F%20CF%20A6%201/cmd/DON/");
}
if (Request.QueryString["operation"] == "Shit-Off")
{
ltNotify.Text = Request.QueryString["operation"];
//TVLED
ProcessURI("http://192.168.1.10/rest/nodes/36981/cmd/DOF/");
//LivingRoom
ProcessURI("http://192.168.1.10/rest/nodes/2F%20CF%20A6%201/cmd/DOF/");
//Breakfast
ProcessURI("http://192.168.1.10/rest/nodes/8052/cmd/DOF/");
//Kitchen Main
ProcessURI("http://192.168.1.10/rest/nodes/21177/cmd/DOF/");
//Kitchen Under Cab
ProcessURI("http://192.168.1.10/rest/nodes/19847/cmd/DOF/");
//Kitchen Island
ProcessURI("http://192.168.1.10/rest/nodes/2B%20FD%2080%201/cmd/DOF/");
//Laundry
ProcessURI("http://192.168.1.10/rest/nodes/47290/cmd/DOF/");
//Downstairs Hallway
ProcessURI("http://192.168.1.10/rest/nodes/2F%20CB%2050%201/cmd/DOF/");
//Patio
ProcessURI("http://192.168.1.10/rest/nodes/48068/cmd/DOF/");
//Foyer
ProcessURI("http://192.168.1.10/rest/nodes/4669/cmd/DOF/");
}
if (Request.QueryString["operation"] == "Harmony-TV-On")
{
ltNotify.Text = Request.QueryString["operation"];
//Turn on TV
var p = new System.Diagnostics.Process();
p.StartInfo.FileName = "D:\\websites\\ISY_Pokey\\Tools\\HarmonyHubControl.exe";
p.StartInfo.Arguments = String.Format("logitechlogon logitechpassword 192.168.1.11 start_activity 15941161");
p.Start();
}
if (Request.QueryString["operation"] == "Harmony-TV-OFF")
{
ltNotify.Text = Request.QueryString["operation"];
//Turn off TV
var p = new System.Diagnostics.Process();
p.StartInfo.FileName = "D:\\websites\\ISY_Pokey\\Tools\\HarmonyHubControl.exe";
p.StartInfo.Arguments = String.Format("logitechlogon logitechpassword 192.168.1.11 start_activity -1");
p.Start();
}
if (Request.QueryString["operation"] == "Harmony-Playstation-On")
{
ltNotify.Text = Request.QueryString["operation"];
//Turn on Playstation
var p = new System.Diagnostics.Process();
p.StartInfo.FileName = "D:\\websites\\ISY_Pokey\\Tools\\HarmonyHubControl.exe";
p.StartInfo.Arguments = String.Format("logitechlogon logitechpassword 192.168.1.11 start_activity 15491165");
p.Start();
}
if (Request.QueryString["operation"] == "Harmony-Playstation-OFF")
{
ltNotify.Text = Request.QueryString["operation"];
//Turn off Playstation
var p = new System.Diagnostics.Process();
p.StartInfo.FileName = "D:\\websites\\ISY_Pokey\\Tools\\HarmonyHubControl.exe";
p.StartInfo.Arguments = String.Format("logitechlogon logitechpassword 192.168.1.11 start_activity -1");
p.Start();
}
if (Request.QueryString["operation"] == "Harmony-AppleTV-On")
{
ltNotify.Text = Request.QueryString["operation"];
//Turn on AppleTV
var p = new System.Diagnostics.Process();
p.StartInfo.FileName = "D:\\websites\\ISY_Pokey\\Tools\\HarmonyHubControl.exe";
p.StartInfo.Arguments = String.Format("logitechlogon logitechpassword 192.168.1.11 start_activity 15941146");
p.Start();
}
if (Request.QueryString["operation"] == "Harmony-AppleTV-OFF")
{
ltNotify.Text = Request.QueryString["operation"];
//Turn off AppleTV
var p = new System.Diagnostics.Process();
p.StartInfo.FileName = "D:\\websites\\ISY_Pokey\\Tools\\HarmonyHubControl.exe";
p.StartInfo.Arguments = String.Format("logitechlogon logitechpassword 192.168.1.11 start_activity -1");
p.Start();
}
if (Request.QueryString["operation"] == "Nest")
{
ltNotify.Text = Request.QueryString["operation"];
PutObject("https://developer-api.nest.com/devices/thermostats/rUhPyxoY8fRMSEGr_d2q94RJ8Vs75QJ6/target_temperature_f?auth=<NestAPIAuthKey>", NestLevel);
}
if (Request.QueryString["operation"] == "Sprinkler-One-On")
{
ltNotify.Text = Request.QueryString["operation"];
string URI_Auth = "https://192.168.1.13/api/4/auth/login";
string PayLoad_Auth = "{\"pwd\":\"RainMachinePWD\",\"remember\": 1}";
string Content_Auth = HTTPPostJSONString(URI_Auth, PayLoad_Auth, 1);
var json_serializer_Auth = new JavaScriptSerializer();
RainMachine RainMachine = json_serializer_Auth.Deserialize<RainMachine>(Content_Auth);
Console.WriteLine(RainMachine.access_token);
string URI_WaterZone_1 = "https://192.168.1.13/api/4/zone/1/start?access_token=" + RainMachine.access_token;
string PayLoad_WaterZone_1 = "{\"time\":600}";
string Content_WaterZone_1 = HTTPPostJSONString(URI_WaterZone_1, PayLoad_WaterZone_1, 1);
Console.WriteLine(Content_WaterZone_1);
}
if (Request.QueryString["operation"] == "Sprinkler-One-Off")
{
ltNotify.Text = Request.QueryString["operation"];
string URI_Auth = "https://192.168.1.13/api/4/auth/login";
string PayLoad_Auth = "{\"pwd\":\"RainMachinePWD\",\"remember\": 1}";
string Content_Auth = HTTPPostJSONString(URI_Auth, PayLoad_Auth, 1);
var json_serializer_Auth = new JavaScriptSerializer();
RainMachine RainMachine = json_serializer_Auth.Deserialize<RainMachine>(Content_Auth);
Console.WriteLine(RainMachine.access_token);
string URI_WaterZone_1 = "https://192.168.1.13/api/4/zone/1/stop?access_token=" + RainMachine.access_token;
string PayLoad_WaterZone_1 = "{\"time\":\"10\"}";
string Content_WaterZone_1 = HTTPPostJSONString(URI_WaterZone_1, PayLoad_WaterZone_1, 1);
Console.WriteLine(Content_WaterZone_1);
}
if (Request.QueryString["operation"] == "Sprinkler-Two-On")
{
ltNotify.Text = Request.QueryString["operation"];
string URI_Auth = "https://192.168.1.13/api/4/auth/login";
string PayLoad_Auth = "{\"pwd\":\"RainMachinePWD\",\"remember\": 1}";
string Content_Auth = HTTPPostJSONString(URI_Auth, PayLoad_Auth, 1);
var json_serializer_Auth = new JavaScriptSerializer();
RainMachine RainMachine = json_serializer_Auth.Deserialize<RainMachine>(Content_Auth);
Console.WriteLine(RainMachine.access_token);
string URI_WaterZone_2 = "https://192.168.1.13/api/4/zone/2/start?access_token=" + RainMachine.access_token;
string PayLoad_WaterZone_2 = "{\"time\":600}";
string Content_WaterZone_2 = HTTPPostJSONString(URI_WaterZone_2, PayLoad_WaterZone_2, 1);
ltNotify.Text = ltNotify.Text + "<br>" + Content_WaterZone_2;
}
if (Request.QueryString["operation"] == "Sprinkler-Two-Off")
{
ltNotify.Text = Request.QueryString["operation"];
string URI_Auth = "https://192.168.1.13/api/4/auth/login";
string PayLoad_Auth = "{\"pwd\":\"RainMachinePWD\",\"remember\": 1}";
string Content_Auth = HTTPPostJSONString(URI_Auth, PayLoad_Auth, 1);
var json_serializer_Auth = new JavaScriptSerializer();
RainMachine RainMachine = json_serializer_Auth.Deserialize<RainMachine>(Content_Auth);
Console.WriteLine(RainMachine.access_token);
string URI_WaterZone_2 = "https://192.168.1.13/api/4/zone/2/stop?access_token=" + RainMachine.access_token;
string PayLoad_WaterZone_2 = "{\"time\":\"10\"}";
string Content_WaterZone_2 = HTTPPostJSONString(URI_WaterZone_2, PayLoad_WaterZone_2, 1);
Console.WriteLine(Content_WaterZone_2);
}
if (Request.QueryString["operation"] == "Sprinkler-Three-On")
{
ltNotify.Text = Request.QueryString["operation"];
string URI_Auth = "https://192.168.1.13/api/4/auth/login";
string PayLoad_Auth = "{\"pwd\":\"RainMachinePWD\",\"remember\": 1}";
string Content_Auth = HTTPPostJSONString(URI_Auth, PayLoad_Auth, 1);
var json_serializer_Auth = new JavaScriptSerializer();
RainMachine RainMachine = json_serializer_Auth.Deserialize<RainMachine>(Content_Auth);
Console.WriteLine(RainMachine.access_token);
string URI_WaterZone_3 = "https://192.168.1.13/api/4/zone/3/start?access_token=" + RainMachine.access_token;
string PayLoad_WaterZone_3 = "{\"time\":600}";
string Content_WaterZone_3 = HTTPPostJSONString(URI_WaterZone_3, PayLoad_WaterZone_3, 1);
Console.WriteLine(Content_WaterZone_3);
}
if (Request.QueryString["operation"] == "Sprinkler-Three-Off")
{
ltNotify.Text = Request.QueryString["operation"];
string URI_Auth = "https://192.168.1.13/api/4/auth/login";
string PayLoad_Auth = "{\"pwd\":\"RainMachinePWD\",\"remember\": 1}";
string Content_Auth = HTTPPostJSONString(URI_Auth, PayLoad_Auth, 1);
var json_serializer_Auth = new JavaScriptSerializer();
RainMachine RainMachine = json_serializer_Auth.Deserialize<RainMachine>(Content_Auth);
Console.WriteLine(RainMachine.access_token);
string URI_WaterZone_3 = "https://192.168.1.13/api/4/zone/3/stop?access_token=" + RainMachine.access_token;
string PayLoad_WaterZone_3 = "{\"time\":\"10\"}";
string Content_WaterZone_3 = HTTPPostJSONString(URI_WaterZone_3, PayLoad_WaterZone_3, 1);
Console.WriteLine(Content_WaterZone_3);
}
}
else
{
ltNotify.Text = "<br><br><strong>Things that can be called</strong><hr><br>Light-On-LivingRoomLED<br>Light-Off-LivingRoomLED<br>Light-On-LivingRoom<br>Light-Off-LivingRoom<br>Light-On-Breakfast<br>Light-Off-Breakfast<br>Light-On-Kitchen<br>Light-Off-Kitchen<br>Light-On-Laundry<br>Light-Off-Laundry<br>Light-On-Hallway<br>Light-Off-Hallway<br>Light-On-Patio<br>Light-Off-Patio<br>Light-On-Foryer<br>Light-Off-Foryer<br>Other Stuff I am too lazy to put in here";
}
}
public void PutObject(string postUrl, string payload)
{
var request = (HttpWebRequest)WebRequest.Create(postUrl);
request.Method = "PUT";
request.ContentType = "application/json";
if (payload != null)
{
Stream dataStream = request.GetRequestStream();
// Invoke GetBytes method.
// ... You can store this array as a field!
byte[] array = Encoding.ASCII.GetBytes(payload);
// Loop through contents of the array.
foreach (byte element in array)
{
Console.WriteLine("{0} = {1}", element, (char)element);
}
dataStream.Write(array, 0, array.Length);
dataStream.Close();
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string returnString = response.StatusCode.ToString();
}
public static string HTTPPostJSONString(string URI, string payload, int DisableSSL)
{
if (DisableSSL == 1)
{
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(delegate { return true; });
}
var http = (HttpWebRequest)WebRequest.Create(new Uri(URI));
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";
UTF8Encoding encoding = new UTF8Encoding();
Byte[] bytes = encoding.GetBytes(payload);
Stream newStream = http.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
var response = http.GetResponse();
var stream = response.GetResponseStream();
var sr = new StreamReader(stream);
var content = sr.ReadToEnd();
return content;
}
public static string HTTPGetString(string URI, int DisableSSL)
{
if (DisableSSL == 1)
{
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(delegate { return true; });
}
WebClient clnt = new WebClient();
string strResponse = clnt.DownloadString(URI);
return strResponse;
}
}
}