private static async Task SubscribeAllAsync() { using (subscriptionsLock.Lock()) { if (endpoints.Count == 0) { await GetEndpointsAsync().ConfigureAwait(false); } if (subscriptions.Count != 0) { await UnsubscribeAllAsync().ConfigureAwait(false); } Action <dynamic> callback = AlexaPropertyChanged; using (endpointsLock.Lock()) { foreach (DiscoveryEndpoint discoveryEndpoint in endpoints) { Guid premiseId = new Guid(discoveryEndpoint.endpointId); IPremiseObject endpoint = await HomeObject.GetObjectAsync(premiseId.ToString("B")).ConfigureAwait(false); if (!endpoint.IsValidObject()) { await NotifyErrorAsync(EventLogEntryType.Warning, $"Cannot find object {discoveryEndpoint.friendlyName} ({premiseId.ToString()})to subscribe on premise server.", 250).ConfigureAwait(false); continue; } // use reflection to instantiate all device type controllers var interfaceType = typeof(IAlexaDeviceType); var all = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(x => x.GetTypes()) .Where(x => interfaceType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract) .Select(Activator.CreateInstance); foreach (IAlexaDeviceType deviceType in all) { Dictionary <string, IPremiseSubscription> subs = deviceType.SubscribeToSupportedProperties(endpoint, discoveryEndpoint, callback); foreach (string key in subs.Keys) { subscriptions.Add(key, subs[key]); } } } } } }
public static void AlexaPropertyChanged(dynamic @params) { Subscription sub = (Subscription)@params; using (deDupeLock.Lock()) { // Premise can send multiple notifications for a single object, one for each // subscribed property that changes. The state report function here will capture // states of all properties, so the DeDupeDictionary prevents multiple state reports // from being sent for essentially the same event. if (DeDupeDictionary.ContainsKey(sub.sysObjectId)) { return; } DeDupeDictionary.Add(sub.sysObjectId, sub); } Task.Run(() => { // get the endpoint and endpoint capabilities Guid premiseId = new Guid(sub.sysObjectId); IPremiseObject endpoint = HomeObject.GetObjectAsync(premiseId.ToString("B")).GetAwaiter().GetResult(); if (!endpoint.IsValidObject()) { return; } DiscoveryEndpoint discoveryEndpoint = GetDiscoveryEndpointAsync(endpoint).GetAwaiter().GetResult(); if (discoveryEndpoint == null) { return; } // get the authorization code for the notification string authCode; using (asyncObjectsLock.Lock()) { authCode = (string)HomeObject.GetValueAsync("AlexaAsyncAuthorizationCode").GetAwaiter().GetResult(); } // build the change report AlexaChangeReport changeReport = new AlexaChangeReport(); [email protected] = Guid.NewGuid().ToString("D"); [email protected].@namespace = "Alexa"; [email protected] = "3"; [email protected] = "BearerToken"; [email protected] = authCode; [email protected] = premiseId.ToString("D").ToUpper(); [email protected] = discoveryEndpoint.cookie; [email protected] = "PHYSICAL_INTERACTION"; // get the device type and controller (e.g. AlexaAV, AlexaHVAC) IAlexaDeviceType deviceType = null; IAlexaController controller = null; List <AlexaProperty> relatedPropertyStates = null; bool hasScene = false; foreach (IAlexaController controllerToTest in Controllers.Values) { if (!controllerToTest.HasPremiseProperty(sub.propertyName)) { continue; } controller = controllerToTest; Type type = Type.GetType(controller.GetAssemblyTypeName()); if (type == null) { continue; } // found a controller, get an instance of the assembly deviceType = (IAlexaDeviceType)Activator.CreateInstance(type); // Determine if this deviceType supports the desired capability // note: This handles situation where the same property name is used by different // controllers. e.g. "brightness" is used in both ColorController and BrightnessController relatedPropertyStates = deviceType.FindRelatedProperties(endpoint, ""); foreach (AlexaProperty property in relatedPropertyStates) { // if so, this is the correct type if (property.@namespace == controller.GetNameSpace()) { break; } } } // ReSharper disable once ConditionIsAlwaysTrueOrFalse if ((deviceType == null) || (controller == null || relatedPropertyStates == null)) { return; } foreach (AlexaProperty prop in relatedPropertyStates) { if (prop.@namespace == "Alexa.SceneController") { hasScene = true; continue; } if (([email protected] == 0) && (prop.name == controller.MapPremisePropertyToAlexaProperty(sub.propertyName))) { [email protected](prop); } else { string propKey = prop.@namespace + "." + prop.name; changeReport.context.propertiesInternal.Add(propKey, prop); } } [email protected] = "ChangeReport"; // scenes are special case if (hasScene) { AlexaSetSceneController sceneController = new AlexaSetSceneController(endpoint); changeReport = sceneController.AlterChangeReport(changeReport); } StateChangeReportWrapper item = new StateChangeReportWrapper { ChangeReport = changeReport }; stateReportQueue.Enqueue(item); using (deDupeLock.Lock()) { DeDupeDictionary.Remove(sub.sysObjectId); } }); }