diff --git a/README.md b/README.md
index 70dc686e..eef6bc2a 100644
--- a/README.md
+++ b/README.md
@@ -77,10 +77,11 @@ It's not trivial to convert the light colors to a color system developers like t
## Remote API
There is also a Philips Hue Remote API. It allows you to send commands to a bridge over the internet. You can request access here: http://www.developers.meethue.com/content/remote-api
Q42.HueApi is compatible with the remote API.
-You need an Access Token and a Bridge Id. Please refer to the Philips Hue API documentation on how to obtain them. This library does not have support for it yet. Pull Requests are welcome!
+You need an Access Token and a Bridge Id. Please refer to the Philips Hue API documentation on how to obtain them.
+**NOTE** Remote API support is untested. Testing and PRs are very much appreciated.
IRemoteHueClient remoteHueClient = new RemoteHueClient("access token");
- remoteHueClient.Initialize("bridge id");
+ remoteHueClient.Initialize("bridge id", "whitelist_id");
After the setup, you can send normal commands to the remote API:
diff --git a/src/Q42.HueApi.Tests/Q42.HueApi.Tests.csproj b/src/Q42.HueApi.Tests/Q42.HueApi.Tests.csproj
index faeae91d..087bef33 100644
--- a/src/Q42.HueApi.Tests/Q42.HueApi.Tests.csproj
+++ b/src/Q42.HueApi.Tests/Q42.HueApi.Tests.csproj
@@ -87,6 +87,10 @@
+
+ {C7305601-B583-479D-9A08-D6DA0A63AB85}
+ Q42.HueApi.ColorConverters
+
{e59a16b4-6756-4576-ab63-6a9b2cf2892b}
Q42.HueApi
diff --git a/src/Q42.HueApi.Tests/Remote/RemoteLightsTests.cs b/src/Q42.HueApi.Tests/Remote/RemoteLightsTests.cs
index 32368c87..40ba5a08 100644
--- a/src/Q42.HueApi.Tests/Remote/RemoteLightsTests.cs
+++ b/src/Q42.HueApi.Tests/Remote/RemoteLightsTests.cs
@@ -1,4 +1,5 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Q42.HueApi.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -13,12 +14,20 @@ public class RemoteLightsTests : LightsTests
[TestInitialize]
public new void Initialize()
{
- var remoteBridge = new RemoteHueClient("test");
- //remoteBridge.Initialize("bridgeId");
+ IRemoteHueClient remoteBridge = new RemoteHueClient("test");
+ remoteBridge.Initialize("bridgeId", "key");
_client = remoteBridge;
}
+ [TestMethod]
+ public async Task RegisterBridgeTest()
+ {
+ await ((IRemoteHueClient)_client).RegisterAsync("1", "test");
+ var result = await _client.GetLightAsync("1");
+ Assert.AreEqual("test", result.Name);
+ }
+
[TestMethod]
public async Task SetLightNameTest()
{
diff --git a/src/Q42.HueApi.WinRT.Sample/ViewModel/MainViewModel.cs b/src/Q42.HueApi.WinRT.Sample/ViewModel/MainViewModel.cs
index 10da6266..6787b8df 100644
--- a/src/Q42.HueApi.WinRT.Sample/ViewModel/MainViewModel.cs
+++ b/src/Q42.HueApi.WinRT.Sample/ViewModel/MainViewModel.cs
@@ -173,7 +173,7 @@ private async void GetLightsAction()
private void RedAction()
{
LightCommand command = new LightCommand();
- command.TurnOn().SetColor(new RGBColor("FF0000)"));
+ command.TurnOn().SetColor(new RGBColor("FF0000"));
_hueClient.SendCommandAsync(command);
}
diff --git a/src/Q42.HueApi/HueClient.cs b/src/Q42.HueApi/HueClient.cs
index 0050eb4b..474edbc4 100644
--- a/src/Q42.HueApi/HueClient.cs
+++ b/src/Q42.HueApi/HueClient.cs
@@ -24,26 +24,45 @@ public partial class HueClient : IHueClient
private readonly int _parallelRequests = 5;
+ ///
+ /// Whitelist ID
+ ///
+ protected string _appKey;
+
+
///
/// Indicates the HueClient is initialized with an AppKey
///
public bool IsInitialized { get; protected set; }
- protected HueClient()
- {
+ protected virtual string ApiBase { get; private set; }
- }
+ protected static HttpClient _httpClient;
- protected virtual string ApiBase { get; private set; }
+ protected HueClient()
+ {
- [ThreadStatic]
- protected static HttpClient _httpClient;
-
- public static HttpClient GetHttpClient()
+ }
+
+ ///
+ /// Initialize client with your app key
+ ///
+ ///
+ public void Initialize(string appKey)
+ {
+ if (appKey == null)
+ throw new ArgumentNullException(nameof(appKey));
+
+ _appKey = appKey;
+
+ IsInitialized = true;
+ }
+
+ public static HttpClient GetHttpClient()
{
// return per-thread HttpClient
- if (_httpClient == null)
- _httpClient = new HttpClient();
+ if (_httpClient == null)
+ _httpClient = new HttpClient();
return _httpClient;
}
diff --git a/src/Q42.HueApi/Interfaces/IHueClient.cs b/src/Q42.HueApi/Interfaces/IHueClient.cs
index a4e8f86d..4cfd41c3 100644
--- a/src/Q42.HueApi/Interfaces/IHueClient.cs
+++ b/src/Q42.HueApi/Interfaces/IHueClient.cs
@@ -13,13 +13,14 @@ namespace Q42.HueApi.Interfaces
///
public interface IHueClient
{
-
-
- ///
- /// Asynchronously gets all lights registered with the bridge.
- ///
- /// An enumerable of s registered with the bridge.
- Task> GetWhiteListAsync();
+
+
+
+ ///
+ /// Asynchronously gets all lights registered with the bridge.
+ ///
+ /// An enumerable of s registered with the bridge.
+ Task> GetWhiteListAsync();
///
/// Get bridge info
diff --git a/src/Q42.HueApi/Interfaces/ILocalHueClient.cs b/src/Q42.HueApi/Interfaces/ILocalHueClient.cs
index 4269cecb..08b4a634 100644
--- a/src/Q42.HueApi/Interfaces/ILocalHueClient.cs
+++ b/src/Q42.HueApi/Interfaces/ILocalHueClient.cs
@@ -13,12 +13,6 @@ namespace Q42.HueApi.Interfaces
///
public interface ILocalHueClient : IHueClient
{
- ///
- /// Initialize the client with your app key
- ///
- ///
- void Initialize(string appKey);
-
///
/// Register your and at the Hue Bridge.
///
@@ -29,11 +23,17 @@ public interface ILocalHueClient : IHueClient
/// or aren't long enough, are empty or contains spaces.
Task RegisterAsync(string appName, string appKey);
- ///
- /// Check if there is a working connection with the bridge
- ///
- ///
- Task CheckConnection();
+ ///
+ /// Initialize the client with your app key
+ ///
+ ///
+ void Initialize(string appKey);
+
+ ///
+ /// Check if there is a working connection with the bridge
+ ///
+ ///
+ Task CheckConnection();
}
diff --git a/src/Q42.HueApi/Interfaces/IRemoteHueClient.cs b/src/Q42.HueApi/Interfaces/IRemoteHueClient.cs
index 1b0c0009..04688555 100644
--- a/src/Q42.HueApi/Interfaces/IRemoteHueClient.cs
+++ b/src/Q42.HueApi/Interfaces/IRemoteHueClient.cs
@@ -2,11 +2,50 @@
namespace Q42.HueApi.Interfaces
{
+ ///
+ /// Remote Hue Client responsible for interacting with the bridge using the remote API
+ ///
public interface IRemoteHueClient : IHueClient
{
+ ///
+ /// Untested
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
Task Authorize(string clientId, string state, string deviceId, string appId, string deviceName = null, string responseType = "code");
- void Initialize(string bridgeId);
- Task RefreshToken(string refreshToken, string clientId, string clientSecret);
+
+ ///
+ /// Initialize the client with a bridgeId and appKey (whitelist identifier)
+ ///
+ ///
+ ///
+ void Initialize(string bridgeId, string appKey);
+
+ ///
+ /// Registers bridge for remote communication. Returns appKey and Initialized the client with this appkey
+ ///
+ ///
+ ///
+ Task RegisterAsync(string bridgeId, string appId);
+
+ ///
+ /// Set the accessToken for the RemoteHueClient
+ ///
+ ///
void SetRemoteAccessToken(string accessToken);
+
+ ///
+ /// Untested
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task RefreshToken(string refreshToken, string clientId, string clientSecret);
}
}
\ No newline at end of file
diff --git a/src/Q42.HueApi/LocalHueClient.cs b/src/Q42.HueApi/LocalHueClient.cs
index bbd43c73..30a217d8 100644
--- a/src/Q42.HueApi/LocalHueClient.cs
+++ b/src/Q42.HueApi/LocalHueClient.cs
@@ -24,7 +24,6 @@ public partial class LocalHueClient : HueClient, ILocalHueClient
private readonly string _ip;
- private string _appKey;
///
@@ -86,19 +85,7 @@ public LocalHueClient(string ip, string appKey)
}
- ///
- /// Initialize client with your app key
- ///
- ///
- public void Initialize(string appKey)
- {
- if (appKey == null)
- throw new ArgumentNullException(nameof(appKey));
-
- _appKey = appKey;
-
- IsInitialized = true;
- }
+
}
}
diff --git a/src/Q42.HueApi/RemoteHueClient-Authentication.cs b/src/Q42.HueApi/RemoteHueClient-Authentication.cs
index d93bf61d..dfc57989 100644
--- a/src/Q42.HueApi/RemoteHueClient-Authentication.cs
+++ b/src/Q42.HueApi/RemoteHueClient-Authentication.cs
@@ -1,4 +1,5 @@
-using System;
+using Newtonsoft.Json.Linq;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
@@ -65,5 +66,53 @@ public async Task RefreshToken(string refreshToken, string clientId, str
return string.Empty;
}
+
+
+ public async Task RegisterAsync(string bridgeId, string appId)
+ {
+ if (string.IsNullOrEmpty(bridgeId))
+ throw new ArgumentNullException(nameof(bridgeId));
+ if (string.IsNullOrEmpty(appId))
+ throw new ArgumentNullException(nameof(appId));
+
+ JObject obj = new JObject();
+ obj["linkbutton"] = true;
+
+ HttpClient client = HueClient.GetHttpClient();
+ var configResponse = await client.PutAsync(new Uri($"{_apiBase}{bridgeId}/0/config"), new StringContent(obj.ToString())).ConfigureAwait(false);
+
+ JObject bridge = new JObject();
+ bridge["devicetype"] = appId;
+
+ var response = await client.PostAsync(new Uri($"{_apiBase}{bridgeId}/"), new StringContent(bridge.ToString())).ConfigureAwait(false);
+ var stringResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+
+
+ JObject result;
+ try
+ {
+ JArray jresponse = JArray.Parse(stringResponse);
+ result = (JObject)jresponse.First;
+ }
+ catch
+ {
+ //Not an expected response. Return response as exception
+ throw new Exception(stringResponse);
+ }
+
+ JToken error;
+ if (result.TryGetValue("error", out error))
+ {
+ if (error["type"].Value() == 101) // link button not pressed
+ throw new Exception("Link button not pressed");
+ else
+ throw new Exception(error["description"].Value());
+ }
+
+ var key = result["success"]["username"].Value();
+ Initialize(key);
+
+ return key;
+ }
}
}
diff --git a/src/Q42.HueApi/RemoteHueClient.cs b/src/Q42.HueApi/RemoteHueClient.cs
index d0d73b70..a697c3aa 100644
--- a/src/Q42.HueApi/RemoteHueClient.cs
+++ b/src/Q42.HueApi/RemoteHueClient.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
+using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
@@ -10,6 +11,7 @@ namespace Q42.HueApi
{
public partial class RemoteHueClient : HueClient, IRemoteHueClient
{
+ private readonly string _apiBase = "https://api.meethue.com/v2/bridges/";
private static string _remoteAccessToken;
private string _bridgeId;
@@ -25,23 +27,23 @@ public void SetRemoteAccessToken(string accessToken)
var client = GetHttpClient();
if (!string.IsNullOrEmpty(_remoteAccessToken))
- _httpClient.DefaultRequestHeaders.Add("access_token", _remoteAccessToken);
+ _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _remoteAccessToken);
else
- _httpClient.DefaultRequestHeaders.Remove("access_token");
+ _httpClient.DefaultRequestHeaders.Authorization = null;
}
///
/// Initialize client with your app key
///
///
- public void Initialize(string bridgeId)
+ public void Initialize(string bridgeId, string appKey)
{
if (bridgeId == null)
throw new ArgumentNullException(nameof(bridgeId));
_bridgeId = bridgeId;
- IsInitialized = true;
+ Initialize(appKey);
}
@@ -53,7 +55,7 @@ public void Initialize(string bridgeId)
_httpClient = new HttpClient();
if (!string.IsNullOrEmpty(_remoteAccessToken))
- _httpClient.DefaultRequestHeaders.Add("access_token", _remoteAccessToken);
+ _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _remoteAccessToken);
}
return _httpClient;
@@ -67,7 +69,7 @@ protected override string ApiBase
{
get
{
- return string.Format("https://api.meethue.com/v1/bridges/{0}/", _bridgeId);
+ return $"{_apiBase}{_bridgeId}/{_appKey}/";
}
}
}