Created
December 10, 2019 12:28
-
-
Save Indigo744/fd55456077450bce1382cf1f957b6b59 to your computer and use it in GitHub Desktop.
Some Hue Bridge Discovery approaches using the Q42.HueApi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using Q42.HueApi; | |
/// <summary> | |
/// Some Hue Bridge Discovery approaches using the Q42.HueApi | |
/// See https://developers.meethue.com/develop/application-design-guidance/hue-bridge-discovery/ | |
/// </summary> | |
public class HueBridgeDiscovery | |
{ | |
/// <summary> | |
/// Discovery of Hue Bridges: | |
/// - Run all locators (N-UPNP, MDNS, SSDP, network scan) in parallel | |
/// - Check first with N-UPNP, then MDNS/SSDP | |
/// - If nothing found, continue with network scan | |
/// </summary> | |
/// <remarks>General purpose approach for comprehensive search</remarks> | |
/// <remarks>Max awaited time if nothing found is maxNetwScanTimeout</remarks> | |
/// <param name="fastTimeout">Timeout for the fast locators (at least a few seconds, usually around 5 seconds)</param> | |
/// <param name="maxNetwScanTimeout">Timeout for the slow network scan (at least a 30 seconds, to few minutes)</param> | |
/// <returns>List of bridges found</returns> | |
public async Task<List<LocatedBridge>> CompleteDiscoveryAsync(TimeSpan fastTimeout, TimeSpan maxNetwScanTimeout) | |
{ | |
using (var fastLocatorsCancelSrc = new CancellationTokenSource(fastTimeout)) | |
using (var slowNetwScanCancelSrc = new CancellationTokenSource(maxNetwScanTimeout)) | |
{ | |
// Start all tasks in parallel without awaiting | |
// Pack all fast locators in an array so we can await them in order | |
var fastLocateTask = new Task<IEnumerable<LocatedBridge>>[] { | |
// N-UPNP is the fastest (only one endpoint to check) | |
(new HttpBridgeLocator()).LocateBridgesAsync(fastLocatorsCancelSrc.Token), | |
// MDNS is the most reliable for bridge V2 | |
(new MdnsBridgeLocator()).LocateBridgesAsync(fastLocatorsCancelSrc.Token), | |
// SSDP is older but works for bridge V1 & V2 | |
(new SsdpBridgeLocator()).LocateBridgesAsync(fastLocatorsCancelSrc.Token), | |
}; | |
// The network scan locator is clearly the slowest | |
var slowNetwScanTask = (new LocalNetworkScanBridgeLocator()).LocateBridgesAsync(slowNetwScanCancelSrc.Token); | |
IEnumerable<LocatedBridge> result; | |
// We will loop through the fast locators and await each one in order | |
foreach (var fastTask in fastLocateTask) | |
{ | |
// Await this task to get its result | |
result = await fastTask; | |
// Check if it contains anything | |
if (result.Any()) | |
{ | |
// Cancel all remaining tasks and return | |
fastLocatorsCancelSrc.Cancel(); | |
slowNetwScanCancelSrc.Cancel(); | |
return result.ToList(); | |
} | |
else | |
{ | |
// Nothing found using this locator | |
} | |
} | |
// All fast locators failed, we wait for the network scan to complete and return whatever we found | |
result = await slowNetwScanTask; | |
return result.ToList(); | |
} | |
} | |
/// <summary> | |
/// Discovery of Hue Bridges: | |
/// - Run all fast locators (N-UPNP, MDNS, SSDP) in parallel | |
/// - Check first with N-UPNP, then MDNS/SSDP after 5 seconds | |
/// - If nothing found, run network scan up to 1 minute | |
/// </summary> | |
/// <remarks>Better approach for comprehensive search for smartphone environment</remarks> | |
/// <remarks>Max awaited time if nothing found is fastTimeout+maxNetwScanTimeout</remarks> | |
/// <param name="fastTimeout">Timeout for the fast locators (at least a few seconds, usually around 5 seconds)</param> | |
/// <param name="maxNetwScanTimeout">Timeout for the slow network scan (at least a 30 seconds, to few minutes)</param> | |
/// <returns>List of bridges found</returns> | |
public async Task<List<LocatedBridge>> FastDiscoveryWithNetworkScanFallbackAsync(TimeSpan fastTimeout, TimeSpan maxNetwScanTimeout) | |
{ | |
using (var fastLocatorsCancelSrc = new CancellationTokenSource(fastTimeout)) | |
{ | |
// Start all tasks in parallel without awaiting | |
// Pack all fast locators in an array so we can await them in order | |
var fastLocateTask = new Task<IEnumerable<LocatedBridge>>[] { | |
// N-UPNP is the fastest (only one endpoint to check) | |
(new HttpBridgeLocator()).LocateBridgesAsync(fastLocatorsCancelSrc.Token), | |
// MDNS is the most reliable for bridge V2 | |
(new MdnsBridgeLocator()).LocateBridgesAsync(fastLocatorsCancelSrc.Token), | |
// SSDP is older but works for bridge V1 & V2 | |
(new SsdpBridgeLocator()).LocateBridgesAsync(fastLocatorsCancelSrc.Token), | |
}; | |
IEnumerable<LocatedBridge> result; | |
// We will loop through the fast locators and await each one in order | |
foreach (var fastTask in fastLocateTask) | |
{ | |
// Await this task to get its result | |
result = await fastTask; | |
// Check if it contains anything | |
if (result.Any()) | |
{ | |
// Cancel all remaining tasks and return | |
fastLocatorsCancelSrc.Cancel(); | |
return result.ToList(); | |
} | |
else | |
{ | |
// Nothing found using this locator | |
} | |
} | |
// All fast locators failed, let's try the network scan and return whatever we found | |
result = await (new LocalNetworkScanBridgeLocator()).LocateBridgesAsync(maxNetwScanTimeout); | |
return result.ToList(); | |
} | |
} | |
/// <summary> | |
/// Discovery of Hue Bridges: | |
/// - Run only the fast locators (N-UPNP, MDNS, SSDP) in parallel | |
/// - Check first with N-UPNP, then MDNS/SSDP | |
/// </summary> | |
/// <remarks>Best approach if network scan is not desirable</remarks> | |
/// <param name="timeout">Timeout for the search (at least a few seconds, usually around 5 seconds)</param> | |
/// <returns>List of bridges found</returns> | |
public async Task<List<LocatedBridge>> FastDiscoveryAsync(TimeSpan timeout) | |
{ | |
using (var fastLocatorsCancelSrc = new CancellationTokenSource(timeout)) | |
{ | |
// Start all tasks in parallel without awaiting | |
// Pack all fast locators in an array so we can await them in order | |
var fastLocateTask = new Task<IEnumerable<LocatedBridge>>[] { | |
// N-UPNP is the fastest (only one endpoint to check) | |
(new HttpBridgeLocator()).LocateBridgesAsync(fastLocatorsCancelSrc.Token), | |
// MDNS is the most reliable for bridge V2 | |
(new MdnsBridgeLocator()).LocateBridgesAsync(fastLocatorsCancelSrc.Token), | |
// SSDP is older but works for bridge V1 & V2 | |
(new SsdpBridgeLocator()).LocateBridgesAsync(fastLocatorsCancelSrc.Token), | |
}; | |
IEnumerable<LocatedBridge> result = new List<LocatedBridge>(); | |
// We will loop through the fast locators and await each one in order | |
foreach (var fastTask in fastLocateTask) | |
{ | |
// Await this task to get its result | |
result = await fastTask; | |
// Check if it contains anything | |
if (result.Any()) | |
{ | |
// Cancel all remaining tasks and break | |
fastLocatorsCancelSrc.Cancel(); | |
break; | |
} | |
else | |
{ | |
// Nothing found using this locator | |
} | |
} | |
return result.ToList(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment